如何将'CArray'中包含内存地址的值“赋值”给'Pointer'?

iyfjxgzm  于 2022-12-17  发布在  其他
关注(0)|答案(3)|浏览(107)

这是一个NativeCall问题。
我在CArray中有8个字节(小端)代表一个内存地址。我如何创建一个Pointer
CArrayPointer是NativeCall的两个C兼容类型。Pointer的长度为8个字节。事情应该是一致的,但是如何以NativeCall可以接受的方式将CArray中的指针地址放入Pointer中呢?)

z0qdvdin

z0qdvdin1#

下面是一个使用你在评论中提到的windows API调用WTSEnumerateSessionsA()的例子:

use NativeCall;

constant BYTE     := uint8;
constant DWORD    := uint32;
constant WTS_CURRENT_SERVER_HANDLE = 0;  # Current (local) server
constant LPSTR    := Str;

enum WTS_CONNECTSTATE_CLASS (
  WTSActive => 0,
  WTSConnected =>1,
  WTSConnectQuery => 2,
  WTSShadow => 3,
  WTSDisconnected => 4,
  WTSIdle => 5,
  WTSListen => 6,
  WTSReset => 7,
  WTSDown => 8,
  WTSInit => 9
);

constant WTS_CONNECTSTATE_CLASS_int := int32;

class WTS_SESSION_INFOA is repr('CStruct') {
    has DWORD $.SessionId is rw;
    has LPSTR $.pWinStationName is rw;
    has WTS_CONNECTSTATE_CLASS_int $.State;
}

sub GetWTSEnumerateSession(
   #`{
       C++
       BOOL WTSEnumerateSessionsA(
         [in]  HANDLE             hServer,
         [in]  DWORD              Reserved,
         [in]  DWORD              Version,
         [out] PWTS_SESSION_INFOA *ppSessionInfo,
         [out] DWORD              *pCount
       );
       Returns zero if this function fails.
   }
   DWORD $hServer,                        # [in]  HANDLE
   DWORD $Reserved,                       # [in] always 0
   DWORD $Version,                        # [in] always 1
   Pointer[Pointer] $ppSessionInf is rw,  # [out] see _WTS_SESSION_INFOA and _WTS_CONNECTSTATE_CLASS;
   DWORD $pCount         is rw            # [out] DWORD
   )
   is native("Wtsapi32.dll")
   is symbol("WTSEnumerateSessionsA")
   returns DWORD  # If the function fails, the return value is zero.
   { * };

my $hServer = Pointer[void].new();
$hServer = WTS_CURRENT_SERVER_HANDLE;   # let windows figure out what current handle is
my $ppSession  = Pointer[Pointer].new();  # A pointer to another pointer to an array of WTS_SESSION_INFO
my DWORD $pCount;

my $ret-code = GetWTSEnumerateSession $hServer, 0, 1, $ppSession, $pCount;
say "Return code: " ~ $ret-code;
my $array = nativecast(Pointer[WTS_SESSION_INFOA], $ppSession.deref);
say "Number of session info structs: " ~ $pCount;
for 0..^ $pCount -> $i {
    say "{$i} : Session id: " ~ $array[$i].SessionId;
    say "{$i} : Station name: " ~ $array[$i].pWinStationName;
    say "{$i} : Connection state: " ~ $array[$i].State;
}

输出(窗口11)

Return code: 1
Number of session info structs: 2
0 : Session id: 0
0 : Station name: Services
0 : Connection state: 4
1 : Session id: 1
1 : Station name: Console
1 : Connection state: 0
wooyq4lh

wooyq4lh2#

我如何创建一个指针了吗?
我认为您可以像这样使用nativecast

my $ptr = nativecast(CArray[Pointer], $array);
my Pointer $ptr2 = $ptr[$idx];
yacmzcpb

yacmzcpb3#

从注解中可以看出,native sub应该返回一个指向struct数组的指针。在linux上,我创建了以下示例:

测试c

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

typedef struct myStruct
{
    int32_t A;
    double B;
} mstruct;

void set_pointer(mstruct **arrayOfStruct)
{
    mstruct *ptr = (mstruct *) malloc(sizeof(mstruct)*2);
    printf("allocated memory at address: %p\n", ptr);
    ptr[0].A = 10;
    ptr[0].B = 1.1;
    ptr[1].A = 20;
    ptr[1].B = 2.1;
    *arrayOfStruct = ptr;
}

p.拉库

use v6;
use NativeCall;

class myStruct is repr('CStruct') {
    has int32 $.A is rw;
    has num64 $.B is rw;
}

sub set_pointer(Pointer[CArray[myStruct]] is rw) is native("./libtest.so") { * };

my $array-ptr = Pointer[CArray[myStruct]].new();
set_pointer($array-ptr);
my $array = nativecast(Pointer[myStruct], $array-ptr.deref);
say $array[0].A;
say $array[0].B;
say $array[1].A;
say $array[1].B;

输出

allocated memory at address: 0x5579f0d95ef0
10
1.1
20
2.1

相关问题