Search code examples
cpointersrakunativecall

How do I "assign" the value in `CArray` that contains a memory address to a `Pointer`?


This is a NativeCall question.

I have 8 bytes (little endian) in a CArray representing a memory address. How do I create a Pointer out it?

(CArray and Pointer are two of NativeCall's C compatible types. Pointers are 8 bytes long. Things should line up, but how does one put the pointer address in a CArray into a Pointer in a way acceptable to NativeCall?)


Solution

  • Here is an example of using the windows api call WTSEnumerateSessionsA() you mentioned in the comments:

    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;
    }
    

    Output (windows 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