Hi Paul, I can't help, since I haven't a Windows PC, but I noticed that you initialize your $entry variable like this:
my PROCESSENTRY32 $entry .= new(:dwSize(nativesizeof(PROCESSENTRY32))); I don't think the argument to the "new" call is necessary. Try this: my PROCESSENTRY32 $entry .= new; say nativesizeof($entry); # output: 556 Raku already knows the native size of the CStruct class. Other than that I can't say anything useful. On Sun, Jan 3, 2021 at 8:38 AM Paul Procacci <pproca...@gmail.com> 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-process32first > > 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 > > > On Sun, Jan 3, 2021 at 2:12 AM ToddAndMargo via perl6-users < > perl6-us...@perl.org> wrote: > >> On 1/2/21 8:13 PM, Paul Procacci wrote: >> > What I'm trying to attempt to do now is display the contents of that >> > CArray (raku member a). In my mind, this is an "array of utf16LE byte >> > sequences terminated by 0". >> >> Hi Paul, >> >> If I understand your problem, you are having trouble >> extracting something usable from Windows return UTF16 >> string. >> >> I have a series of modules I wrote to read and write >> to the Windows registry. The strings I got back were >> all "UTF16 little ending C Strings". >> >> This means that every character is a TWO byte word >> (16 bits) with the first byte containing the low >> value byte. And they terminate with both bytes >> being a numerical zero. It is a little weird to get >> use to. >> >> There was some interesting conversation in these >> parts a bit ago as to if a C string could ever >> not be terminated with a nul. They are always >> terminated with a nul. >> >> The following is from one of the modules I wrote to >> support this. I used brute force, rather than >> rely on UTF conversion utilities as I found them >> unreliable. >> >> If you un-comment >> # print $CStr[ $i ] ~ "," ~ $CStr[ $i + 1 ] ~ ", "; >> you can watch the sub do its thing. >> >> I have a sub to go the other way too, if you want it. >> >> HTH, >> -T >> >> >> >> use NativeCall; >> >> sub c-to-raku-str( BYTES $CStr ) returns Str is export( :c-to-raku-str ) >> { >> # Note: C Strings are always terminated with a nul. This sub will >> malfunction without it. >> # Note: presumes a UTF16 little endian C String and converts to UTF8 >> >> my Str $SubName = &?ROUTINE.name; >> my Str $RakuStr = ""; >> my Str $Msg = ""; >> my uint32 $CStrElems = $CStr.elems; >> # say $CStrElems; >> >> loop (my $i = 0; $i < $CStrElems - 2 ; $i += 2) { >> if $CStr[ $i ] == 0 && $CStr[ $i + 1 ] == 0 { last; } >> >> if $i == $CStrElems - 4 { >> $Msg = "$SubName ERROR:" ~ " C Strings are required to be >> terminated with a nul\n\n" ~ >> " Returning an empty string\n" ~ >> " Cowardly existing\n"; >> exit; >> } >> >> # print $CStr[ $i ] ~ "," ~ $CStr[ $i + 1 ] ~ ", "; >> $RakuStr ~= chr( $CStr[ $i ] ); >> } >> # say ""; >> >> # say "$RakuStr"; >> return $RakuStr; >> } >> >> >> > > -- > __________________ > > :(){ :|:& };: > -- Fernando Santagata