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