On 1/2/21 11:38 PM, Paul Procacci wrote:
I don't have a C string that's terminated by null.
I have a CArray[int16] of length 260 that's passed to and filled in by the windows api.

https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot <https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot> https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32first <https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32first> https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32next <https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32next>

Take the following for example which I quickly whipped up that is supposed to iterate over the processes running on the given windows machine:

-------------------------------------------------------------

use NativeCall;

constant \MAX_PATH = 260;
constant \TH32CS_SNAPPROCESS = 0x00000002;

class PROCESSENTRY32 is repr('CStruct') {
     has int32 $.dwSize;
     has int32 $.cntUsage;
     has int32 $.th32ProcessID;
     has int32 $.th32DefaultHeapID;
     has int32 $.th32ModuleID;
     has int32 $.cntThreads;
     has int32 $.th32ParentProcessID;
     has int32 $.pcPriClassBase;
     has int32 $.dwFlags is rw;
     HAS uint16 @.szExeFile[MAX_PATH] is CArray;
};

sub CreateToolhelp32Snapshot(int32,int32 -->Pointer)is native('Kernel32') { * };
sub Process32First(Pointer,Pointer -->Bool)is native('Kernel32') { * };
sub Process32Next(Pointer,Pointer -->Bool)is native('Kernel32') { * };

my $ptr = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
die 'Failed to retreive process list.' if $ptr == Bool::False;
my PROCESSENTRY32 $entry .= new(:dwSize(nativesizeof(PROCESSENTRY32)));
die 'Unable to iterate over process list' if Process32First($ptr, 
nativecast(Pointer, $entry))== Bool::False;

repeat {
     say $entry.szExeFile[0].ord;
     say $entry.szExeFile[1].ord;
}while Process32Next($ptr, nativecast(Pointer, $entry));

------------------------------------------

The output of the above is:
48
48

This is clearly wrong.  This is either a) my misunderstanding of these api 
calls b) raku bug or c) a usage error on my part.

~Paul

Hi Paul,

Please bottom post.  It removes a lot of confusion.

~~~~~~~~~~~~~~~~~~~~~~
CreateToolhelp32Snapshot:

   C++

   HANDLE CreateToolhelp32Snapshot(
     DWORD dwFlags,
     DWORD th32ProcessID
   );


The return is a "handle", not a pointer.

You declare it as such:

sub CreateToolhelp32Snapshot(int32, int32 --> Pointer) is native('Kernel32') { * };

    my $ptr = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);


I am not sure you are declaring that correctly.

I would declare it:
sub CreateToolhelp32Snapshot(int32, int32 --> int32) is native('Kernel32') { * };

   my $handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)


~~~~~~~~~~~~~~~~~~~~~~

Process32First:

   C++

   BOOL Process32First(
     HANDLE           hSnapshot,
     LPPROCESSENTRY32 lppe
   );

Returns a True or False for success/failure.

You give it the "handle" you got from
CreateToolhelp32Snapshot

lppe is actually a C Pointer point to a c++
structure called PROCESSENTRY32

   C++

   typedef struct tagPROCESSENTRY32 {
     DWORD     dwSize;
     DWORD     cntUsage;
     DWORD     th32ProcessID;
     ULONG_PTR th32DefaultHeapID;
     DWORD     th32ModuleID;
     DWORD     cntThreads;
     DWORD     th32ParentProcessID;
     LONG      pcPriClassBase;
     DWORD     dwFlags;
    CHAR      szExeFile[MAX_PATH];
   } PROCESSENTRY32;

You are duplicating this structure with

   constant \MAX_PATH = 260;
   constant \TH32CS_SNAPPROCESS = 0x00000002;

   class PROCESSENTRY32 is repr('CStruct') {
       has int32 $.dwSize;
       has int32 $.cntUsage;
       has int32 $.th32ProcessID;
       has int32 $.th32DefaultHeapID;
       has int32 $.th32ModuleID;
       has int32 $.cntThreads;
       has int32 $.th32ParentProcessID;
       has int32 $.pcPriClassBase;
       has int32 $.dwFlags is rw;
       HAS uint16 @.szExeFile[MAX_PATH] is CArray;
   };

And calling it with:

   my PROCESSENTRY32 $entry .= new(:dwSize(nativesizeof(PROCESSENTRY32)));

   Process32First($ptr, nativecast(Pointer, $entry));

I would tend to do it this way:

   my $entry = PROCESSENTRY32,new();
   sub  Process32First( int32, PROCESSENTRY32 is rw --> Bool );
   my Bool $PassFail = Process32First( $handle, $entry)


lppe, on the other hard is a pointer.  Adding "is rw" will
read the structure it points to into your object.


~~~~~~~~~~~~~~~~~~~~~~

Process32Next:

   C++

   BOOL Process32Next(
     HANDLE           hSnapshot,
     LPPROCESSENTRY32 lppe
   );

   sub  Process32Next( int32, PROCESSENTRY32 is rw --> Bool );

    while Process32Next( handle, $entry )  {
       say $entry.szExeFile[0].ord;
       say $entry.szExeFile[1].ord;
    }

~~~~~~~~~~~~~~~~~~~~~~

By the way, the uint16 size is going to be a "little ending".

    0xF5D3 comes out [0]=0xD3 and [1] 0xF4

Native call will not convert it for you if you addess it as
a CArray.

I have a conversion for that too.


HTH,
-T


Reply via email to