Nativecall - Help with converting wchar_t CArray to something printable

--000000000000cb9c3405b7f731b9
Content-Type: text/plain; charset="UTF-8"

Hey gents (again),

I'm having on awful time with decoding UTF16LE character sequences that are
placed into a Nativecall CArray that I've defined as an interface between
Raku and a windows library call.

The structure used by the windows function includes a static wchar_t field
that's PATH_MAX in
length (260 wchar_t's).  It would look like the following in C:

struct Something {
  int32_t dwSize;
  wchar_t a[260];
};

I've written the following as the Raku counterpart to the above:

class Something is repr('CStruct') {
   has int32 $.dwsize;
   HAS int16 @.a[260] is CArray;
};

Given the following definition for the windows library call:

bool Test(Something *x);

... I've defined the following on the raku side of things:

sub Test(Pointer --> Bool) is native('Kernel32') { * };

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

The function is supposed to write characters into the space allotted,
namely a.
The only required set member prior to calling the subroutine is that the
size of the structure.
It gets set in dwSize like so:

my Something $a .= new(:dwSize(nativesizeof(Something)));

Then the actual function call from the raku side of things:

Test(nativecast(Pointer, $a));

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

All the above is working.  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".

What's the cleanest way of doing this in raku?  I've tried variations of
"join" and "encode", simple printf's, say's, etc., and even tried
manipulating this data with Buf's, but I can't seem to get it quite right.

Any help is appreciated.
~Paul
-- 
__________________

:(){ :|:& };:

--000000000000cb9c3405b7f731b9
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div><div><div><div>Hey gents (again),<br><br>I&#39;m havi=
ng on awful time with decoding UTF16LE character sequences that are placed =
into a Nativecall CArray that I&#39;ve defined as an interface between Raku=
 and a windows library call.<br><br>The structure used by the windows funct=
ion includes a static wchar_t field that&#39;s PATH_MAX in</div><div>length=
 (260 wchar_t&#39;s).=C2=A0 It would look like the following in C:<br><br>s=
truct Something {</div><div>=C2=A0 int32_t dwSize;<br></div><div>=C2=A0 wch=
ar_t a[260];<br></div><div>};<br></div><div><br></div><div>I&#39;ve written=
 the following as the Raku counterpart to the above: <br></div><div><br></d=
iv><div>class Something is repr(&#39;CStruct&#39;) {</div><div>=C2=A0=C2=A0=
 has int32 $.dwsize;<br></div><div>=C2=A0=C2=A0 HAS int16 @.a[260] is CArra=
y;</div><div>};</div><br></div>Given the following definition for the windo=
ws library call:<br><br></div>bool Test(Something *x);<br><br></div>.. I&#3=
9;ve defined the following on the raku side of things:<br><div><div><div><d=
iv><div><div><pre style=3D"background-color:rgb(255,255,255);color:rgb(8,8,=
8);font-family:&quot;JetBrains Mono&quot;,monospace;font-size:9.8pt">sub Te=
st(Pointer --&gt; Bool) is native(&#39;Kernel32&#39;) { * };<br></pre></div=
><div>----------------------------------------------------------<br></div><=
div><br></div><div>The function is supposed to write characters into the sp=
ace allotted, namely a. <br></div><div>The only required set member prior t=
o calling the subroutine is that the size of the structure.<br></div><div>I=
t gets set in dwSize like so:<br><br></div><div>my Something $a .=3D new(:d=
wSize(nativesizeof(Something)));<br><br></div><div>Then the actual function=
 call from the raku side of things:<br><br></div><div>Test(nativecast(Point=
er, $a));<br><br>
----------------------------------------------------------

<br><br></div><div>All the above is working.=C2=A0 What I&#39;m trying to a=
ttempt to do now is display the contents of that</div><div>CArray (raku mem=
ber a).=C2=A0 In my mind, this is an &quot;array of utf16LE byte sequences =
terminated by 0&quot;.<br></div><div><br></div><div>What&#39;s the cleanest=
 way of doing this in raku?=C2=A0 I&#39;ve tried variations of &quot;join&q=
uot; and &quot;encode&quot;, simple printf&#39;s, say&#39;s, etc., and even=
 tried manipulating this data with Buf&#39;s, but I can&#39;t seem to get i=
t quite right.<br><br></div><div>Any help is appreciated.</div><div>~Paul<b=
r></div>-- <br><div><div dir=3D"ltr" class=3D"gmail_signature" data-smartma=
il=3D"gmail_signature">__________________<br><br>:(){ :|:&amp; };:</div></d=
iv></div></div></div></div></div></div>

--000000000000cb9c3405b7f731b9--
0
pprocacci
1/3/2021 4:13:12 AM
perl.perl6.users 1547 articles. 0 followers. Follow

15 Replies
22 Views

Similar Articles

[PageSpeed] 45

--00000000000076589905b7f9176c
Content-Type: text/plain; charset="UTF-8"

A follow-up to my initial message.

I think the following is relevant:

https://github.com/rakudo/rakudo/issues/3633

I think my inlined array is actually being filled with zero's.

say $a.a[0];
say $a.a[1];

Yields:

0
0

I'm using the comma ide:

>raku -v
Welcome to Rakudo(tm) v2020.12.
Implementing the Raku(tm) programming language v6.d.
Built on MoarVM version 2020.12.

~Paul

On Sat, Jan 2, 2021 at 11:13 PM Paul Procacci <pprocacci@gmail.com> wrote:

> Hey gents (again),
>
> I'm having on awful time with decoding UTF16LE character sequences that
> are placed into a Nativecall CArray that I've defined as an interface
> between Raku and a windows library call.
>
> The structure used by the windows function includes a static wchar_t field
> that's PATH_MAX in
> length (260 wchar_t's).  It would look like the following in C:
>
> struct Something {
>   int32_t dwSize;
>   wchar_t a[260];
> };
>
> I've written the following as the Raku counterpart to the above:
>
> class Something is repr('CStruct') {
>    has int32 $.dwsize;
>    HAS int16 @.a[260] is CArray;
> };
>
> Given the following definition for the windows library call:
>
> bool Test(Something *x);
>
> .. I've defined the following on the raku side of things:
>
> sub Test(Pointer --> Bool) is native('Kernel32') { * };
>
> ----------------------------------------------------------
>
> The function is supposed to write characters into the space allotted,
> namely a.
> The only required set member prior to calling the subroutine is that the
> size of the structure.
> It gets set in dwSize like so:
>
> my Something $a .= new(:dwSize(nativesizeof(Something)));
>
> Then the actual function call from the raku side of things:
>
> Test(nativecast(Pointer, $a));
>
> ----------------------------------------------------------
>
> All the above is working.  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".
>
> What's the cleanest way of doing this in raku?  I've tried variations of
> "join" and "encode", simple printf's, say's, etc., and even tried
> manipulating this data with Buf's, but I can't seem to get it quite right.
>
> Any help is appreciated.
> ~Paul
> --
> __________________
>
> :(){ :|:& };:
>


-- 
__________________

:(){ :|:& };:

--00000000000076589905b7f9176c
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div>A follow-up to my initial message.</div><div><br></di=
v><div>I think the following is relevant:<br><br><a href=3D"https://github.=
com/rakudo/rakudo/issues/3633">https://github.com/rakudo/rakudo/issues/3633=
</a></div><div><br></div><div>I think my inlined array is actually being fi=
lled with zero&#39;s.<br><br><pre style=3D"background-color:rgb(255,255,255=
);color:rgb(8,8,8);font-family:&quot;JetBrains Mono&quot;,monospace;font-si=
ze:9.8pt"><span style=3D"color:rgb(255,69,0)">say </span><span style=3D"col=
or:rgb(128,0,128)">$a</span><span style=3D"color:rgb(139,0,0)">.</span><spa=
n style=3D"color:rgb(255,69,0)">a</span>[<span style=3D"color:rgb(23,80,235=
)">0</span>];<br><span style=3D"color:rgb(255,69,0)">say </span><span style=
=3D"color:rgb(128,0,128)">$a</span><span style=3D"color:rgb(139,0,0)"></spa=
n><span style=3D"color:rgb(255,69,0)">.a</span>[<span style=3D"color:rgb(23=
,80,235)">1</span>];<br><br></pre><pre style=3D"background-color:rgb(255,25=
5,255);color:rgb(8,8,8);font-family:&quot;JetBrains Mono&quot;,monospace;fo=
nt-size:9.8pt">Yields:<br><br>0<br>0<br><br></pre><pre style=3D"background-=
color:rgb(255,255,255);color:rgb(8,8,8);font-family:&quot;JetBrains Mono&qu=
ot;,monospace;font-size:9.8pt">I&#39;m using the comma ide:<br><br>&gt;raku=
 -v<br>Welcome to Rakudo(tm) v2020.12.<br>Implementing the Raku(tm) program=
ming language v6.d.<br>Built on MoarVM version 2020.12.<br><br></pre></div>=
<div>~Paul<br></div></div><br><div class=3D"gmail_quote"><div dir=3D"ltr" c=
lass=3D"gmail_attr">On Sat, Jan 2, 2021 at 11:13 PM Paul Procacci &lt;<a hr=
ef=3D"mailto:pprocacci@gmail.com">pprocacci@gmail.com</a>&gt; wrote:<br></d=
iv><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;bord=
er-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div>=
<div><div><div>Hey gents (again),<br><br>I&#39;m having on awful time with =
decoding UTF16LE character sequences that are placed into a Nativecall CArr=
ay that I&#39;ve defined as an interface between Raku and a windows library=
 call.<br><br>The structure used by the windows function includes a static =
wchar_t field that&#39;s PATH_MAX in</div><div>length (260 wchar_t&#39;s).=
=C2=A0 It would look like the following in C:<br><br>struct Something {</di=
v><div>=C2=A0 int32_t dwSize;<br></div><div>=C2=A0 wchar_t a[260];<br></div=
><div>};<br></div><div><br></div><div>I&#39;ve written the following as the=
 Raku counterpart to the above: <br></div><div><br></div><div>class Somethi=
ng is repr(&#39;CStruct&#39;) {</div><div>=C2=A0=C2=A0 has int32 $.dwsize;<=
br></div><div>=C2=A0=C2=A0 HAS int16 @.a[260] is CArray;</div><div>};</div>=
<br></div>Given the following definition for the windows library call:<br><=
br></div>bool Test(Something *x);<br><br></div>.. I&#39;ve defined the foll=
owing on the raku side of things:<br><div><div><div><div><div><div><pre sty=
le=3D"background-color:rgb(255,255,255);color:rgb(8,8,8);font-family:&quot;=
JetBrains Mono&quot;,monospace;font-size:9.8pt">sub Test(Pointer --&gt; Boo=
l) is native(&#39;Kernel32&#39;) { * };<br></pre></div><div>---------------=
-------------------------------------------<br></div><div><br></div><div>Th=
e function is supposed to write characters into the space allotted, namely =
a. <br></div><div>The only required set member prior to calling the subrout=
ine is that the size of the structure.<br></div><div>It gets set in dwSize =
like so:<br><br></div><div>my Something $a .=3D new(:dwSize(nativesizeof(So=
mething)));<br><br></div><div>Then the actual function call from the raku s=
ide of things:<br><br></div><div>Test(nativecast(Pointer, $a));<br><br>
----------------------------------------------------------

<br><br></div><div>All the above is working.=C2=A0 What I&#39;m trying to a=
ttempt to do now is display the contents of that</div><div>CArray (raku mem=
ber a).=C2=A0 In my mind, this is an &quot;array of utf16LE byte sequences =
terminated by 0&quot;.<br></div><div><br></div><div>What&#39;s the cleanest=
 way of doing this in raku?=C2=A0 I&#39;ve tried variations of &quot;join&q=
uot; and &quot;encode&quot;, simple printf&#39;s, say&#39;s, etc., and even=
 tried manipulating this data with Buf&#39;s, but I can&#39;t seem to get i=
t quite right.<br><br></div><div>Any help is appreciated.</div><div>~Paul<b=
r></div>-- <br><div><div dir=3D"ltr">__________________<br><br>:(){ :|:&amp=
; };:</div></div></div></div></div></div></div></div>
</blockquote></div><br clear=3D"all"><br>-- <br><div dir=3D"ltr" class=3D"g=
mail_signature">__________________<br><br>:(){ :|:&amp; };:</div>

--00000000000076589905b7f9176c--
0
pprocacci
1/3/2021 6:29:00 AM
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).=C2=A0 In my mind, this is an "array of utf16LE =
byte=20
> 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=20
malfunction without it.
    # Note: presumes a UTF16 little endian C String and converts to UTF8

    my Str    $SubName   =3D &?ROUTINE.name;
    my Str    $RakuStr   =3D "";
    my Str    $Msg       =3D "";
    my uint32 $CStrElems =3D $CStr.elems;
    # say $CStrElems;

    loop (my $i =3D 0; $i < $CStrElems - 2 ; $i +=3D 2) {
       if  $CStr[ $i ] =3D=3D 0  &&  $CStr[ $i + 1 ] =3D=3D 0  { last; }

       if $i =3D=3D $CStrElems - 4  {
          $Msg =3D "$SubName ERROR:" ~ " C Strings are required to be=20
terminated with a nul\n\n" ~
                 "                     Returning an empty string\n" ~
                 "                     Cowardly existing\n";
          exit;
       }

       # print $CStr[ $i ] ~ "," ~ $CStr[ $i + 1 ] ~ ",  ";
       $RakuStr ~=3D chr( $CStr[ $i ] );
    }
    # say "";

    # say "$RakuStr";
    return $RakuStr;
}


0
perl6
1/3/2021 7:11:48 AM
--000000000000a36e3f05b7fa0f17
Content-Type: text/plain; charset="UTF-8"

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

-- 
__________________

:(){ :|:& };:

--000000000000a36e3f05b7fa0f17
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div>
I don&#39;t have a C string that&#39;s terminated by null.

<br>I have a CArray[int16] of length 260 that&#39;s passed to and filled in=
 by the windows api.</div><br><div><a href=3D"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-createtoo=
lhelp32snapshot</a></div><div><a href=3D"https://docs.microsoft.com/en-us/w=
indows/win32/api/tlhelp32/nf-tlhelp32-process32first">https://docs.microsof=
t.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32first</a></div>=
<div><a href=3D"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</a></div><div><br></div><div>
<div>Take the following for example which I quickly whipped up that is supp=
osed to iterate over the processes running on the given windows machine:</d=
iv><div><br></div>

</div><div>-------------------------------------------------------------<br=
></div><div><pre style=3D"background-color:rgb(255,255,255);color:rgb(8,8,8=
);font-family:&quot;JetBrains Mono&quot;,monospace;font-size:9.8pt"><span s=
tyle=3D"color:rgb(0,51,179)">use </span><span style=3D"color:rgb(75,0,130)"=
>NativeCall</span>;<br><br><span style=3D"color:rgb(0,51,179)">constant </s=
pan>\<span style=3D"color:rgb(75,0,130)">MAX_PATH </span><span style=3D"col=
or:rgb(139,0,0)">=3D </span><span style=3D"color:rgb(23,80,235)">260</span>=
;<br><span style=3D"color:rgb(0,51,179)">constant </span>\<span style=3D"co=
lor:rgb(75,0,130)">TH32CS_SNAPPROCESS </span><span style=3D"color:rgb(139,0=
,0)">=3D </span><span style=3D"color:rgb(23,80,235)">0x00000002</span>;<br>=
<br><span style=3D"color:rgb(0,51,179)">class </span><span style=3D"color:r=
gb(75,0,130)">PROCESSENTRY32 </span><span style=3D"color:rgb(0,51,179)">is =
</span><span style=3D"color:rgb(75,0,130)">repr</span>(<span style=3D"color=
:rgb(6,125,23)">&#39;CStruct&#39;</span>) {<br>    <span style=3D"color:rgb=
(0,51,179)">has </span><span style=3D"color:rgb(75,0,130)">int32 </span><sp=
an style=3D"color:rgb(128,0,128)">$.dwSize</span>;<br>    <span style=3D"co=
lor:rgb(0,51,179)">has </span><span style=3D"color:rgb(75,0,130)">int32 </s=
pan><span style=3D"color:rgb(128,0,128)">$.cntUsage</span>;<br>    <span st=
yle=3D"color:rgb(0,51,179)">has </span><span style=3D"color:rgb(75,0,130)">=
int32 </span><span style=3D"color:rgb(128,0,128)">$.th32ProcessID</span>;<b=
r>    <span style=3D"color:rgb(0,51,179)">has </span><span style=3D"color:r=
gb(75,0,130)">int32 </span><span style=3D"color:rgb(128,0,128)">$.th32Defau=
ltHeapID</span>;<br>    <span style=3D"color:rgb(0,51,179)">has </span><spa=
n style=3D"color:rgb(75,0,130)">int32 </span><span style=3D"color:rgb(128,0=
,128)">$.th32ModuleID</span>;<br>    <span style=3D"color:rgb(0,51,179)">ha=
s </span><span style=3D"color:rgb(75,0,130)">int32 </span><span style=3D"co=
lor:rgb(128,0,128)">$.cntThreads</span>;<br>    <span style=3D"color:rgb(0,=
51,179)">has </span><span style=3D"color:rgb(75,0,130)">int32 </span><span =
style=3D"color:rgb(128,0,128)">$.th32ParentProcessID</span>;<br>    <span s=
tyle=3D"color:rgb(0,51,179)">has </span><span style=3D"color:rgb(75,0,130)"=
>int32 </span><span style=3D"color:rgb(128,0,128)">$.pcPriClassBase</span>;=
<br>    <span style=3D"color:rgb(0,51,179)">has </span><span style=3D"color=
:rgb(75,0,130)">int32 </span><span style=3D"color:rgb(128,0,128)">$.dwFlags=
 </span><span style=3D"color:rgb(0,51,179)">is </span><span style=3D"color:=
rgb(75,0,130)">rw</span>;<br>    <span style=3D"color:rgb(0,51,179)">HAS </=
span><span style=3D"color:rgb(75,0,130)">uint16 </span><span style=3D"color=
:rgb(128,0,128)">@.szExeFile[</span><span style=3D"color:rgb(75,0,130)">MAX=
_PATH</span><span style=3D"color:rgb(128,0,128)">] </span><span style=3D"co=
lor:rgb(0,51,179)">is </span><span style=3D"color:rgb(75,0,130)">CArray</sp=
an>;<span style=3D"color:rgb(140,140,140);font-style:italic"><br></span>};<=
br><br><span style=3D"color:rgb(0,51,179)">sub </span><span style=3D"color:=
rgb(255,69,0)">CreateToolhelp32Snapshot</span>(<span style=3D"color:rgb(75,=
0,130)">int32</span>, <span style=3D"color:rgb(75,0,130)">int32 </span>--&g=
t; <span style=3D"color:rgb(75,0,130)">Pointer</span>) <span style=3D"color=
:rgb(0,51,179)">is </span><span style=3D"color:rgb(75,0,130)">native</span>=
(<span style=3D"color:rgb(6,125,23)">&#39;Kernel32&#39;</span>) { * };<br><=
span style=3D"color:rgb(0,51,179)">sub </span><span style=3D"color:rgb(255,=
69,0)">Process32First</span>(<span style=3D"color:rgb(75,0,130)">Pointer</s=
pan>, <span style=3D"color:rgb(75,0,130)">Pointer </span>--&gt; <span style=
=3D"color:rgb(75,0,130)">Bool</span>) <span style=3D"color:rgb(0,51,179)">i=
s </span><span style=3D"color:rgb(75,0,130)">native</span>(<span style=3D"c=
olor:rgb(6,125,23)">&#39;Kernel32&#39;</span>) { * };<br><span style=3D"col=
or:rgb(0,51,179)">sub </span><span style=3D"color:rgb(255,69,0)">Process32N=
ext</span>(<span style=3D"color:rgb(75,0,130)">Pointer</span>, <span style=
=3D"color:rgb(75,0,130)">Pointer </span>--&gt; <span style=3D"color:rgb(75,=
0,130)">Bool</span>) <span style=3D"color:rgb(0,51,179)">is </span><span st=
yle=3D"color:rgb(75,0,130)">native</span>(<span style=3D"color:rgb(6,125,23=
)">&#39;Kernel32&#39;</span>) { * };<br><br><span style=3D"color:rgb(0,51,1=
79)">my </span><span style=3D"color:rgb(128,0,128)">$ptr </span><span style=
=3D"color:rgb(139,0,0)">=3D </span><span style=3D"color:rgb(255,69,0)">Crea=
teToolhelp32Snapshot</span>(<span style=3D"color:rgb(75,0,130)">TH32CS_SNAP=
PROCESS</span><span style=3D"color:rgb(139,0,0)">, </span><span style=3D"co=
lor:rgb(23,80,235)">0</span>);<br><span style=3D"color:rgb(255,69,0)">die <=
/span><span style=3D"color:rgb(6,125,23)">&#39;Failed to retreive process l=
ist.&#39; </span><span style=3D"color:rgb(0,51,179)">if </span><span style=
=3D"color:rgb(128,0,128)">$ptr </span><span style=3D"color:rgb(139,0,0)">=
=3D=3D </span><span style=3D"color:rgb(75,0,130)">Bool::False</span>;<br><s=
pan style=3D"color:rgb(0,51,179)">my </span><span style=3D"color:rgb(75,0,1=
30)">PROCESSENTRY32 </span><span style=3D"color:rgb(128,0,128)">$entry </sp=
an><span style=3D"color:rgb(139,0,0)">.=3D </span><span style=3D"color:rgb(=
255,69,0)">new</span>(<span style=3D"color:rgb(6,125,23)">:dwSize</span>(<s=
pan style=3D"color:rgb(255,69,0)">nativesizeof</span>(<span style=3D"color:=
rgb(75,0,130)">PROCESSENTRY32</span>)));<br><span style=3D"color:rgb(255,69=
,0)">die </span><span style=3D"color:rgb(6,125,23)">&#39;Unable to iterate =
over process list&#39; </span><span style=3D"color:rgb(0,51,179)">if </span=
><span style=3D"color:rgb(255,69,0)">Process32First</span>(<span style=3D"c=
olor:rgb(128,0,128)">$ptr</span><span style=3D"color:rgb(139,0,0)">, </span=
><span style=3D"color:rgb(255,69,0)">nativecast</span>(<span style=3D"color=
:rgb(75,0,130)">Pointer</span><span style=3D"color:rgb(139,0,0)">, </span><=
span style=3D"color:rgb(128,0,128)">$entry</span>)) <span style=3D"color:rg=
b(139,0,0)">=3D=3D </span><span style=3D"color:rgb(75,0,130)">Bool::False</=
span>;<br><br><span style=3D"color:rgb(0,51,179)">repeat </span>{<br>    <s=
pan style=3D"color:rgb(255,69,0)">say </span><span style=3D"color:rgb(128,0=
,128)">$entry</span><span style=3D"color:rgb(139,0,0)">.</span><span style=
=3D"color:rgb(255,69,0)">szExeFile</span><span style=3D"color:rgb(23,80,235=
)"></span>[0].ord;<br>    <span style=3D"color:rgb(255,69,0)">say </span><s=
pan style=3D"color:rgb(128,0,128)">$entry</span><span style=3D"color:rgb(13=
9,0,0)">.</span><span style=3D"color:rgb(255,69,0)">szExeFile</span><span s=
tyle=3D"color:rgb(23,80,235)"></span>[1].ord;<br>} <span style=3D"color:rgb=
(0,51,179)">while </span><span style=3D"color:rgb(255,69,0)">Process32Next<=
/span>(<span style=3D"color:rgb(128,0,128)">$ptr</span><span style=3D"color=
:rgb(139,0,0)">, </span><span style=3D"color:rgb(255,69,0)">nativecast</spa=
n>(<span style=3D"color:rgb(75,0,130)">Pointer</span><span style=3D"color:r=
gb(139,0,0)">, </span><span style=3D"color:rgb(128,0,128)">$entry</span>));=
<br><br>------------------------------------------<br></pre><pre style=3D"b=
ackground-color:rgb(255,255,255);color:rgb(8,8,8);font-family:&quot;JetBrai=
ns Mono&quot;,monospace;font-size:9.8pt">The output of the above is:<br>48<=
br>48<br><br></pre><pre style=3D"background-color:rgb(255,255,255);color:rg=
b(8,8,8);font-family:&quot;JetBrains Mono&quot;,monospace;font-size:9.8pt">=
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.<br><br></pre><pre style=
=3D"background-color:rgb(255,255,255);color:rgb(8,8,8);font-family:&quot;Je=
tBrains Mono&quot;,monospace;font-size:9.8pt">~Paul<br></pre></div></div><b=
r><div class=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail_attr">On Sun, =
Jan 3, 2021 at 2:12 AM ToddAndMargo via perl6-users &lt;<a href=3D"mailto:p=
erl6-users@perl.org">perl6-users@perl.org</a>&gt; wrote:<br></div><blockquo=
te class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px =
solid rgb(204,204,204);padding-left:1ex">On 1/2/21 8:13 PM, Paul Procacci w=
rote:<br>
&gt; What I&#39;m trying to attempt to do now is display the contents of th=
at<br>
&gt; CArray (raku member a).=C2=A0 In my mind, this is an &quot;array of ut=
f16LE byte <br>
&gt; sequences terminated by 0&quot;.<br>
<br>
Hi Paul,<br>
<br>
If I understand your problem, you are having trouble<br>
extracting something usable from Windows return UTF16<br>
string.<br>
<br>
I have a series of modules I wrote to read and write<br>
to the Windows registry.=C2=A0 The strings I got back were<br>
all &quot;UTF16 little ending C Strings&quot;.<br>
<br>
This means that every character is a TWO byte word<br>
(16 bits) with the first byte containing the low<br>
value byte.=C2=A0 And they terminate with both bytes<br>
being a numerical zero.=C2=A0 It is a little weird to get<br>
use to.<br>
<br>
There was some interesting conversation in these<br>
parts a bit ago as to if a C string could ever<br>
not be terminated with a nul.=C2=A0 They are always<br>
terminated with a nul.<br>
<br>
The following is from one of the modules I wrote to<br>
support this.=C2=A0 I used brute force, rather than<br>
rely on UTF conversion utilities as I found them<br>
unreliable.<br>
<br>
If you un-comment<br>
=C2=A0 =C2=A0 # print $CStr[ $i ] ~ &quot;,&quot; ~ $CStr[ $i + 1 ] ~ &quot=
;,=C2=A0 &quot;;<br>
you can watch the sub do its thing.<br>
<br>
I have a sub to go the other way too, if you want it.<br>
<br>
HTH,<br>
-T<br>
<br>
<br>
<br>
use NativeCall;<br>
<br>
sub c-to-raku-str( BYTES $CStr ) returns Str=C2=A0 is export( :c-to-raku-st=
r ) {<br>
=C2=A0 =C2=A0 # Note: C Strings are always terminated with a nul.=C2=A0 Thi=
s sub will <br>
malfunction without it.<br>
=C2=A0 =C2=A0 # Note: presumes a UTF16 little endian C String and converts =
to UTF8<br>
<br>
=C2=A0 =C2=A0 my Str=C2=A0 =C2=A0 $SubName=C2=A0 =C2=A0=3D &amp;?ROUTINE.na=
me;<br>
=C2=A0 =C2=A0 my Str=C2=A0 =C2=A0 $RakuStr=C2=A0 =C2=A0=3D &quot;&quot;;<br=
>
=C2=A0 =C2=A0 my Str=C2=A0 =C2=A0 $Msg=C2=A0 =C2=A0 =C2=A0 =C2=A0=3D &quot;=
&quot;;<br>
=C2=A0 =C2=A0 my uint32 $CStrElems =3D $CStr.elems;<br>
=C2=A0 =C2=A0 # say $CStrElems;<br>
<br>
=C2=A0 =C2=A0 loop (my $i =3D 0; $i &lt; $CStrElems - 2 ; $i +=3D 2) {<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0if=C2=A0 $CStr[ $i ] =3D=3D 0=C2=A0 &amp;&amp;=
=C2=A0 $CStr[ $i + 1 ] =3D=3D 0=C2=A0 { last; }<br>
<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0if $i =3D=3D $CStrElems - 4=C2=A0 {<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 $Msg =3D &quot;$SubName ERROR:&quot; ~ &=
quot; C Strings are required to be <br>
terminated with a nul\n\n&quot; ~<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&quot;=C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Return=
ing an empty string\n&quot; ~<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&quot;=C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Coward=
ly existing\n&quot;;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 exit;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0# print $CStr[ $i ] ~ &quot;,&quot; ~ $CStr[ $i =
+ 1 ] ~ &quot;,=C2=A0 &quot;;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0$RakuStr ~=3D chr( $CStr[ $i ] );<br>
=C2=A0 =C2=A0 }<br>
=C2=A0 =C2=A0 # say &quot;&quot;;<br>
<br>
=C2=A0 =C2=A0 # say &quot;$RakuStr&quot;;<br>
=C2=A0 =C2=A0 return $RakuStr;<br>
}<br>
<br>
<br>
</blockquote></div><br clear=3D"all"><br>-- <br><div dir=3D"ltr" class=3D"g=
mail_signature">__________________<br><br>:(){ :|:&amp; };:</div>

--000000000000a36e3f05b7fa0f17--
0
pprocacci
1/3/2021 7:38:24 AM
--00000000000061a83705b7fc0514
Content-Type: text/plain; charset="UTF-8"

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 <pprocacci@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-users@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

--00000000000061a83705b7fc0514
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div class=3D"gmail_default" style=3D"color:#000000">Hi Pa=
ul,</div><div class=3D"gmail_default" style=3D"color:#000000">I can&#39;t h=
elp, since I haven&#39;t a Windows PC, but I noticed that you initialize yo=
ur $entry variable like this:</div><div class=3D"gmail_default" style=3D"co=
lor:#000000"><br></div><div class=3D"gmail_default" style=3D"color:#000000"=
>my PROCESSENTRY32 $entry .=3D new(:dwSize(nativesizeof(PROCESSENTRY32)));<=
/div><div class=3D"gmail_default" style=3D"color:#000000"><br></div><div cl=
ass=3D"gmail_default" style=3D"color:#000000">I don&#39;t think the argumen=
t to the &quot;new&quot; call is necessary. Try this:</div><div class=3D"gm=
ail_default" style=3D"color:#000000"><br></div><div class=3D"gmail_default"=
 style=3D"color:#000000">my PROCESSENTRY32 $entry .=3D new;<br>say nativesi=
zeof($entry); =C2=A0# output: 556</div><div class=3D"gmail_default" style=
=3D"color:#000000"><br></div><div class=3D"gmail_default" style=3D"color:#0=
00000">Raku already knows the native size of the CStruct class.<br></div><d=
iv class=3D"gmail_default" style=3D"color:#000000">Other than that I can&#3=
9;t say anything useful.<br></div></div><br><div class=3D"gmail_quote"><div=
 dir=3D"ltr" class=3D"gmail_attr">On Sun, Jan 3, 2021 at 8:38 AM Paul Proca=
cci &lt;<a href=3D"mailto:pprocacci@gmail.com">pprocacci@gmail.com</a>&gt; =
wrote:<br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0=
px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=
=3D"ltr"><div>
I don&#39;t have a C string that&#39;s terminated by null.

<br>I have a CArray[int16] of length 260 that&#39;s passed to and filled in=
 by the windows api.</div><br><div><a href=3D"https://docs.microsoft.com/en=
-us/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot" target=
=3D"_blank">https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-=
tlhelp32-createtoolhelp32snapshot</a></div><div><a href=3D"https://docs.mic=
rosoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32first" tar=
get=3D"_blank">https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/=
nf-tlhelp32-process32first</a></div><div><a href=3D"https://docs.microsoft.=
com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32next" target=3D"_=
blank">https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhel=
p32-process32next</a></div><div><br></div><div>
<div>Take the following for example which I quickly whipped up that is supp=
osed to iterate over the processes running on the given windows machine:</d=
iv><div><br></div>

</div><div>-------------------------------------------------------------<br=
></div><div><pre style=3D"background-color:rgb(255,255,255);color:rgb(8,8,8=
);font-family:&quot;JetBrains Mono&quot;,monospace;font-size:9.8pt"><span s=
tyle=3D"color:rgb(0,51,179)">use </span><span style=3D"color:rgb(75,0,130)"=
>NativeCall</span>;<br><br><span style=3D"color:rgb(0,51,179)">constant </s=
pan>\<span style=3D"color:rgb(75,0,130)">MAX_PATH </span><span style=3D"col=
or:rgb(139,0,0)">=3D </span><span style=3D"color:rgb(23,80,235)">260</span>=
;<br><span style=3D"color:rgb(0,51,179)">constant </span>\<span style=3D"co=
lor:rgb(75,0,130)">TH32CS_SNAPPROCESS </span><span style=3D"color:rgb(139,0=
,0)">=3D </span><span style=3D"color:rgb(23,80,235)">0x00000002</span>;<br>=
<br><span style=3D"color:rgb(0,51,179)">class </span><span style=3D"color:r=
gb(75,0,130)">PROCESSENTRY32 </span><span style=3D"color:rgb(0,51,179)">is =
</span><span style=3D"color:rgb(75,0,130)">repr</span>(<span style=3D"color=
:rgb(6,125,23)">&#39;CStruct&#39;</span>) {<br>    <span style=3D"color:rgb=
(0,51,179)">has </span><span style=3D"color:rgb(75,0,130)">int32 </span><sp=
an style=3D"color:rgb(128,0,128)">$.dwSize</span>;<br>    <span style=3D"co=
lor:rgb(0,51,179)">has </span><span style=3D"color:rgb(75,0,130)">int32 </s=
pan><span style=3D"color:rgb(128,0,128)">$.cntUsage</span>;<br>    <span st=
yle=3D"color:rgb(0,51,179)">has </span><span style=3D"color:rgb(75,0,130)">=
int32 </span><span style=3D"color:rgb(128,0,128)">$.th32ProcessID</span>;<b=
r>    <span style=3D"color:rgb(0,51,179)">has </span><span style=3D"color:r=
gb(75,0,130)">int32 </span><span style=3D"color:rgb(128,0,128)">$.th32Defau=
ltHeapID</span>;<br>    <span style=3D"color:rgb(0,51,179)">has </span><spa=
n style=3D"color:rgb(75,0,130)">int32 </span><span style=3D"color:rgb(128,0=
,128)">$.th32ModuleID</span>;<br>    <span style=3D"color:rgb(0,51,179)">ha=
s </span><span style=3D"color:rgb(75,0,130)">int32 </span><span style=3D"co=
lor:rgb(128,0,128)">$.cntThreads</span>;<br>    <span style=3D"color:rgb(0,=
51,179)">has </span><span style=3D"color:rgb(75,0,130)">int32 </span><span =
style=3D"color:rgb(128,0,128)">$.th32ParentProcessID</span>;<br>    <span s=
tyle=3D"color:rgb(0,51,179)">has </span><span style=3D"color:rgb(75,0,130)"=
>int32 </span><span style=3D"color:rgb(128,0,128)">$.pcPriClassBase</span>;=
<br>    <span style=3D"color:rgb(0,51,179)">has </span><span style=3D"color=
:rgb(75,0,130)">int32 </span><span style=3D"color:rgb(128,0,128)">$.dwFlags=
 </span><span style=3D"color:rgb(0,51,179)">is </span><span style=3D"color:=
rgb(75,0,130)">rw</span>;<br>    <span style=3D"color:rgb(0,51,179)">HAS </=
span><span style=3D"color:rgb(75,0,130)">uint16 </span><span style=3D"color=
:rgb(128,0,128)">@.szExeFile[</span><span style=3D"color:rgb(75,0,130)">MAX=
_PATH</span><span style=3D"color:rgb(128,0,128)">] </span><span style=3D"co=
lor:rgb(0,51,179)">is </span><span style=3D"color:rgb(75,0,130)">CArray</sp=
an>;<span style=3D"color:rgb(140,140,140);font-style:italic"><br></span>};<=
br><br><span style=3D"color:rgb(0,51,179)">sub </span><span style=3D"color:=
rgb(255,69,0)">CreateToolhelp32Snapshot</span>(<span style=3D"color:rgb(75,=
0,130)">int32</span>, <span style=3D"color:rgb(75,0,130)">int32 </span>--&g=
t; <span style=3D"color:rgb(75,0,130)">Pointer</span>) <span style=3D"color=
:rgb(0,51,179)">is </span><span style=3D"color:rgb(75,0,130)">native</span>=
(<span style=3D"color:rgb(6,125,23)">&#39;Kernel32&#39;</span>) { * };<br><=
span style=3D"color:rgb(0,51,179)">sub </span><span style=3D"color:rgb(255,=
69,0)">Process32First</span>(<span style=3D"color:rgb(75,0,130)">Pointer</s=
pan>, <span style=3D"color:rgb(75,0,130)">Pointer </span>--&gt; <span style=
=3D"color:rgb(75,0,130)">Bool</span>) <span style=3D"color:rgb(0,51,179)">i=
s </span><span style=3D"color:rgb(75,0,130)">native</span>(<span style=3D"c=
olor:rgb(6,125,23)">&#39;Kernel32&#39;</span>) { * };<br><span style=3D"col=
or:rgb(0,51,179)">sub </span><span style=3D"color:rgb(255,69,0)">Process32N=
ext</span>(<span style=3D"color:rgb(75,0,130)">Pointer</span>, <span style=
=3D"color:rgb(75,0,130)">Pointer </span>--&gt; <span style=3D"color:rgb(75,=
0,130)">Bool</span>) <span style=3D"color:rgb(0,51,179)">is </span><span st=
yle=3D"color:rgb(75,0,130)">native</span>(<span style=3D"color:rgb(6,125,23=
)">&#39;Kernel32&#39;</span>) { * };<br><br><span style=3D"color:rgb(0,51,1=
79)">my </span><span style=3D"color:rgb(128,0,128)">$ptr </span><span style=
=3D"color:rgb(139,0,0)">=3D </span><span style=3D"color:rgb(255,69,0)">Crea=
teToolhelp32Snapshot</span>(<span style=3D"color:rgb(75,0,130)">TH32CS_SNAP=
PROCESS</span><span style=3D"color:rgb(139,0,0)">, </span><span style=3D"co=
lor:rgb(23,80,235)">0</span>);<br><span style=3D"color:rgb(255,69,0)">die <=
/span><span style=3D"color:rgb(6,125,23)">&#39;Failed to retreive process l=
ist.&#39; </span><span style=3D"color:rgb(0,51,179)">if </span><span style=
=3D"color:rgb(128,0,128)">$ptr </span><span style=3D"color:rgb(139,0,0)">=
=3D=3D </span><span style=3D"color:rgb(75,0,130)">Bool::False</span>;<br><s=
pan style=3D"color:rgb(0,51,179)">my </span><span style=3D"color:rgb(75,0,1=
30)">PROCESSENTRY32 </span><span style=3D"color:rgb(128,0,128)">$entry </sp=
an><span style=3D"color:rgb(139,0,0)">.=3D </span><span style=3D"color:rgb(=
255,69,0)">new</span>(<span style=3D"color:rgb(6,125,23)">:dwSize</span>(<s=
pan style=3D"color:rgb(255,69,0)">nativesizeof</span>(<span style=3D"color:=
rgb(75,0,130)">PROCESSENTRY32</span>)));<br><span style=3D"color:rgb(255,69=
,0)">die </span><span style=3D"color:rgb(6,125,23)">&#39;Unable to iterate =
over process list&#39; </span><span style=3D"color:rgb(0,51,179)">if </span=
><span style=3D"color:rgb(255,69,0)">Process32First</span>(<span style=3D"c=
olor:rgb(128,0,128)">$ptr</span><span style=3D"color:rgb(139,0,0)">, </span=
><span style=3D"color:rgb(255,69,0)">nativecast</span>(<span style=3D"color=
:rgb(75,0,130)">Pointer</span><span style=3D"color:rgb(139,0,0)">, </span><=
span style=3D"color:rgb(128,0,128)">$entry</span>)) <span style=3D"color:rg=
b(139,0,0)">=3D=3D </span><span style=3D"color:rgb(75,0,130)">Bool::False</=
span>;<br><br><span style=3D"color:rgb(0,51,179)">repeat </span>{<br>    <s=
pan style=3D"color:rgb(255,69,0)">say </span><span style=3D"color:rgb(128,0=
,128)">$entry</span><span style=3D"color:rgb(139,0,0)">.</span><span style=
=3D"color:rgb(255,69,0)">szExeFile</span><span style=3D"color:rgb(23,80,235=
)"></span>[0].ord;<br>    <span style=3D"color:rgb(255,69,0)">say </span><s=
pan style=3D"color:rgb(128,0,128)">$entry</span><span style=3D"color:rgb(13=
9,0,0)">.</span><span style=3D"color:rgb(255,69,0)">szExeFile</span><span s=
tyle=3D"color:rgb(23,80,235)"></span>[1].ord;<br>} <span style=3D"color:rgb=
(0,51,179)">while </span><span style=3D"color:rgb(255,69,0)">Process32Next<=
/span>(<span style=3D"color:rgb(128,0,128)">$ptr</span><span style=3D"color=
:rgb(139,0,0)">, </span><span style=3D"color:rgb(255,69,0)">nativecast</spa=
n>(<span style=3D"color:rgb(75,0,130)">Pointer</span><span style=3D"color:r=
gb(139,0,0)">, </span><span style=3D"color:rgb(128,0,128)">$entry</span>));=
<br><br>------------------------------------------<br></pre><pre style=3D"b=
ackground-color:rgb(255,255,255);color:rgb(8,8,8);font-family:&quot;JetBrai=
ns Mono&quot;,monospace;font-size:9.8pt">The output of the above is:<br>48<=
br>48<br><br></pre><pre style=3D"background-color:rgb(255,255,255);color:rg=
b(8,8,8);font-family:&quot;JetBrains Mono&quot;,monospace;font-size:9.8pt">=
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.<br><br></pre><pre style=
=3D"background-color:rgb(255,255,255);color:rgb(8,8,8);font-family:&quot;Je=
tBrains Mono&quot;,monospace;font-size:9.8pt">~Paul<br></pre></div></div><b=
r><div class=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail_attr">On Sun, =
Jan 3, 2021 at 2:12 AM ToddAndMargo via perl6-users &lt;<a href=3D"mailto:p=
erl6-users@perl.org" target=3D"_blank">perl6-users@perl.org</a>&gt; wrote:<=
br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8e=
x;border-left:1px solid rgb(204,204,204);padding-left:1ex">On 1/2/21 8:13 P=
M, Paul Procacci wrote:<br>
&gt; What I&#39;m trying to attempt to do now is display the contents of th=
at<br>
&gt; CArray (raku member a).=C2=A0 In my mind, this is an &quot;array of ut=
f16LE byte <br>
&gt; sequences terminated by 0&quot;.<br>
<br>
Hi Paul,<br>
<br>
If I understand your problem, you are having trouble<br>
extracting something usable from Windows return UTF16<br>
string.<br>
<br>
I have a series of modules I wrote to read and write<br>
to the Windows registry.=C2=A0 The strings I got back were<br>
all &quot;UTF16 little ending C Strings&quot;.<br>
<br>
This means that every character is a TWO byte word<br>
(16 bits) with the first byte containing the low<br>
value byte.=C2=A0 And they terminate with both bytes<br>
being a numerical zero.=C2=A0 It is a little weird to get<br>
use to.<br>
<br>
There was some interesting conversation in these<br>
parts a bit ago as to if a C string could ever<br>
not be terminated with a nul.=C2=A0 They are always<br>
terminated with a nul.<br>
<br>
The following is from one of the modules I wrote to<br>
support this.=C2=A0 I used brute force, rather than<br>
rely on UTF conversion utilities as I found them<br>
unreliable.<br>
<br>
If you un-comment<br>
=C2=A0 =C2=A0 # print $CStr[ $i ] ~ &quot;,&quot; ~ $CStr[ $i + 1 ] ~ &quot=
;,=C2=A0 &quot;;<br>
you can watch the sub do its thing.<br>
<br>
I have a sub to go the other way too, if you want it.<br>
<br>
HTH,<br>
-T<br>
<br>
<br>
<br>
use NativeCall;<br>
<br>
sub c-to-raku-str( BYTES $CStr ) returns Str=C2=A0 is export( :c-to-raku-st=
r ) {<br>
=C2=A0 =C2=A0 # Note: C Strings are always terminated with a nul.=C2=A0 Thi=
s sub will <br>
malfunction without it.<br>
=C2=A0 =C2=A0 # Note: presumes a UTF16 little endian C String and converts =
to UTF8<br>
<br>
=C2=A0 =C2=A0 my Str=C2=A0 =C2=A0 $SubName=C2=A0 =C2=A0=3D &amp;?ROUTINE.na=
me;<br>
=C2=A0 =C2=A0 my Str=C2=A0 =C2=A0 $RakuStr=C2=A0 =C2=A0=3D &quot;&quot;;<br=
>
=C2=A0 =C2=A0 my Str=C2=A0 =C2=A0 $Msg=C2=A0 =C2=A0 =C2=A0 =C2=A0=3D &quot;=
&quot;;<br>
=C2=A0 =C2=A0 my uint32 $CStrElems =3D $CStr.elems;<br>
=C2=A0 =C2=A0 # say $CStrElems;<br>
<br>
=C2=A0 =C2=A0 loop (my $i =3D 0; $i &lt; $CStrElems - 2 ; $i +=3D 2) {<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0if=C2=A0 $CStr[ $i ] =3D=3D 0=C2=A0 &amp;&amp;=
=C2=A0 $CStr[ $i + 1 ] =3D=3D 0=C2=A0 { last; }<br>
<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0if $i =3D=3D $CStrElems - 4=C2=A0 {<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 $Msg =3D &quot;$SubName ERROR:&quot; ~ &=
quot; C Strings are required to be <br>
terminated with a nul\n\n&quot; ~<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&quot;=C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Return=
ing an empty string\n&quot; ~<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&quot;=C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Coward=
ly existing\n&quot;;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 exit;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0# print $CStr[ $i ] ~ &quot;,&quot; ~ $CStr[ $i =
+ 1 ] ~ &quot;,=C2=A0 &quot;;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0$RakuStr ~=3D chr( $CStr[ $i ] );<br>
=C2=A0 =C2=A0 }<br>
=C2=A0 =C2=A0 # say &quot;&quot;;<br>
<br>
=C2=A0 =C2=A0 # say &quot;$RakuStr&quot;;<br>
=C2=A0 =C2=A0 return $RakuStr;<br>
}<br>
<br>
<br>
</blockquote></div><br clear=3D"all"><br>-- <br><div dir=3D"ltr">__________=
________<br><br>:(){ :|:&amp; };:</div>
</blockquote></div><br clear=3D"all"><br>-- <br><div dir=3D"ltr" class=3D"g=
mail_signature">Fernando Santagata</div>

--00000000000061a83705b7fc0514--
0
nando
1/3/2021 9:58:42 AM
--000000000000034c9405b7fc1373
Content-Type: text/plain; charset="UTF-8"

Hi Fernando,

I appreciate your response.
The windows api requires that the dwSize member of the structure gets set
to the size of the structure.
This is the reason why the object is being constructed as I've provided.

~Paul

On Sun, Jan 3, 2021 at 4:58 AM Fernando Santagata <nando.santagata@gmail.com>
wrote:

> 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 <pprocacci@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-users@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
>


-- 
__________________

:(){ :|:& };:

--000000000000034c9405b7fc1373
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div>Hi Fernando,</div><div><br></div><div>I appreciate yo=
ur response.</div><div>The windows api requires that the dwSize member of t=
he structure gets set to the size of the structure.</div><div>This is the r=
eason why the object is being constructed as I&#39;ve provided.</div><div><=
br></div><div>~Paul<br></div></div><br><div class=3D"gmail_quote"><div dir=
=3D"ltr" class=3D"gmail_attr">On Sun, Jan 3, 2021 at 4:58 AM Fernando Santa=
gata &lt;<a href=3D"mailto:nando.santagata@gmail.com">nando.santagata@gmail=
..com</a>&gt; wrote:<br></div><blockquote class=3D"gmail_quote" style=3D"mar=
gin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1=
ex"><div dir=3D"ltr"><div class=3D"gmail_default" style=3D"color:rgb(0,0,0)=
">Hi Paul,</div><div class=3D"gmail_default" style=3D"color:rgb(0,0,0)">I c=
an&#39;t help, since I haven&#39;t a Windows PC, but I noticed that you ini=
tialize your $entry variable like this:</div><div class=3D"gmail_default" s=
tyle=3D"color:rgb(0,0,0)"><br></div><div class=3D"gmail_default" style=3D"c=
olor:rgb(0,0,0)">my PROCESSENTRY32 $entry .=3D new(:dwSize(nativesizeof(PRO=
CESSENTRY32)));</div><div class=3D"gmail_default" style=3D"color:rgb(0,0,0)=
"><br></div><div class=3D"gmail_default" style=3D"color:rgb(0,0,0)">I don&#=
39;t think the argument to the &quot;new&quot; call is necessary. Try this:=
</div><div class=3D"gmail_default" style=3D"color:rgb(0,0,0)"><br></div><di=
v class=3D"gmail_default" style=3D"color:rgb(0,0,0)">my PROCESSENTRY32 $ent=
ry .=3D new;<br>say nativesizeof($entry); =C2=A0# output: 556</div><div cla=
ss=3D"gmail_default" style=3D"color:rgb(0,0,0)"><br></div><div class=3D"gma=
il_default" style=3D"color:rgb(0,0,0)">Raku already knows the native size o=
f the CStruct class.<br></div><div class=3D"gmail_default" style=3D"color:r=
gb(0,0,0)">Other than that I can&#39;t say anything useful.<br></div></div>=
<br><div class=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail_attr">On Sun=
, Jan 3, 2021 at 8:38 AM Paul Procacci &lt;<a href=3D"mailto:pprocacci@gmai=
l.com" target=3D"_blank">pprocacci@gmail.com</a>&gt; wrote:<br></div><block=
quote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1=
px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div>
I don&#39;t have a C string that&#39;s terminated by null.

<br>I have a CArray[int16] of length 260 that&#39;s passed to and filled in=
 by the windows api.</div><br><div><a href=3D"https://docs.microsoft.com/en=
-us/windows/win32/api/tlhelp32/nf-tlhelp32-createtoolhelp32snapshot" target=
=3D"_blank">https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-=
tlhelp32-createtoolhelp32snapshot</a></div><div><a href=3D"https://docs.mic=
rosoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32first" tar=
get=3D"_blank">https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/=
nf-tlhelp32-process32first</a></div><div><a href=3D"https://docs.microsoft.=
com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32next" target=3D"_=
blank">https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhel=
p32-process32next</a></div><div><br></div><div>
<div>Take the following for example which I quickly whipped up that is supp=
osed to iterate over the processes running on the given windows machine:</d=
iv><div><br></div>

</div><div>-------------------------------------------------------------<br=
></div><div><pre style=3D"background-color:rgb(255,255,255);color:rgb(8,8,8=
);font-family:&quot;JetBrains Mono&quot;,monospace;font-size:9.8pt"><span s=
tyle=3D"color:rgb(0,51,179)">use </span><span style=3D"color:rgb(75,0,130)"=
>NativeCall</span>;<br><br><span style=3D"color:rgb(0,51,179)">constant </s=
pan>\<span style=3D"color:rgb(75,0,130)">MAX_PATH </span><span style=3D"col=
or:rgb(139,0,0)">=3D </span><span style=3D"color:rgb(23,80,235)">260</span>=
;<br><span style=3D"color:rgb(0,51,179)">constant </span>\<span style=3D"co=
lor:rgb(75,0,130)">TH32CS_SNAPPROCESS </span><span style=3D"color:rgb(139,0=
,0)">=3D </span><span style=3D"color:rgb(23,80,235)">0x00000002</span>;<br>=
<br><span style=3D"color:rgb(0,51,179)">class </span><span style=3D"color:r=
gb(75,0,130)">PROCESSENTRY32 </span><span style=3D"color:rgb(0,51,179)">is =
</span><span style=3D"color:rgb(75,0,130)">repr</span>(<span style=3D"color=
:rgb(6,125,23)">&#39;CStruct&#39;</span>) {<br>    <span style=3D"color:rgb=
(0,51,179)">has </span><span style=3D"color:rgb(75,0,130)">int32 </span><sp=
an style=3D"color:rgb(128,0,128)">$.dwSize</span>;<br>    <span style=3D"co=
lor:rgb(0,51,179)">has </span><span style=3D"color:rgb(75,0,130)">int32 </s=
pan><span style=3D"color:rgb(128,0,128)">$.cntUsage</span>;<br>    <span st=
yle=3D"color:rgb(0,51,179)">has </span><span style=3D"color:rgb(75,0,130)">=
int32 </span><span style=3D"color:rgb(128,0,128)">$.th32ProcessID</span>;<b=
r>    <span style=3D"color:rgb(0,51,179)">has </span><span style=3D"color:r=
gb(75,0,130)">int32 </span><span style=3D"color:rgb(128,0,128)">$.th32Defau=
ltHeapID</span>;<br>    <span style=3D"color:rgb(0,51,179)">has </span><spa=
n style=3D"color:rgb(75,0,130)">int32 </span><span style=3D"color:rgb(128,0=
,128)">$.th32ModuleID</span>;<br>    <span style=3D"color:rgb(0,51,179)">ha=
s </span><span style=3D"color:rgb(75,0,130)">int32 </span><span style=3D"co=
lor:rgb(128,0,128)">$.cntThreads</span>;<br>    <span style=3D"color:rgb(0,=
51,179)">has </span><span style=3D"color:rgb(75,0,130)">int32 </span><span =
style=3D"color:rgb(128,0,128)">$.th32ParentProcessID</span>;<br>    <span s=
tyle=3D"color:rgb(0,51,179)">has </span><span style=3D"color:rgb(75,0,130)"=
>int32 </span><span style=3D"color:rgb(128,0,128)">$.pcPriClassBase</span>;=
<br>    <span style=3D"color:rgb(0,51,179)">has </span><span style=3D"color=
:rgb(75,0,130)">int32 </span><span style=3D"color:rgb(128,0,128)">$.dwFlags=
 </span><span style=3D"color:rgb(0,51,179)">is </span><span style=3D"color:=
rgb(75,0,130)">rw</span>;<br>    <span style=3D"color:rgb(0,51,179)">HAS </=
span><span style=3D"color:rgb(75,0,130)">uint16 </span><span style=3D"color=
:rgb(128,0,128)">@.szExeFile[</span><span style=3D"color:rgb(75,0,130)">MAX=
_PATH</span><span style=3D"color:rgb(128,0,128)">] </span><span style=3D"co=
lor:rgb(0,51,179)">is </span><span style=3D"color:rgb(75,0,130)">CArray</sp=
an>;<span style=3D"color:rgb(140,140,140);font-style:italic"><br></span>};<=
br><br><span style=3D"color:rgb(0,51,179)">sub </span><span style=3D"color:=
rgb(255,69,0)">CreateToolhelp32Snapshot</span>(<span style=3D"color:rgb(75,=
0,130)">int32</span>, <span style=3D"color:rgb(75,0,130)">int32 </span>--&g=
t; <span style=3D"color:rgb(75,0,130)">Pointer</span>) <span style=3D"color=
:rgb(0,51,179)">is </span><span style=3D"color:rgb(75,0,130)">native</span>=
(<span style=3D"color:rgb(6,125,23)">&#39;Kernel32&#39;</span>) { * };<br><=
span style=3D"color:rgb(0,51,179)">sub </span><span style=3D"color:rgb(255,=
69,0)">Process32First</span>(<span style=3D"color:rgb(75,0,130)">Pointer</s=
pan>, <span style=3D"color:rgb(75,0,130)">Pointer </span>--&gt; <span style=
=3D"color:rgb(75,0,130)">Bool</span>) <span style=3D"color:rgb(0,51,179)">i=
s </span><span style=3D"color:rgb(75,0,130)">native</span>(<span style=3D"c=
olor:rgb(6,125,23)">&#39;Kernel32&#39;</span>) { * };<br><span style=3D"col=
or:rgb(0,51,179)">sub </span><span style=3D"color:rgb(255,69,0)">Process32N=
ext</span>(<span style=3D"color:rgb(75,0,130)">Pointer</span>, <span style=
=3D"color:rgb(75,0,130)">Pointer </span>--&gt; <span style=3D"color:rgb(75,=
0,130)">Bool</span>) <span style=3D"color:rgb(0,51,179)">is </span><span st=
yle=3D"color:rgb(75,0,130)">native</span>(<span style=3D"color:rgb(6,125,23=
)">&#39;Kernel32&#39;</span>) { * };<br><br><span style=3D"color:rgb(0,51,1=
79)">my </span><span style=3D"color:rgb(128,0,128)">$ptr </span><span style=
=3D"color:rgb(139,0,0)">=3D </span><span style=3D"color:rgb(255,69,0)">Crea=
teToolhelp32Snapshot</span>(<span style=3D"color:rgb(75,0,130)">TH32CS_SNAP=
PROCESS</span><span style=3D"color:rgb(139,0,0)">, </span><span style=3D"co=
lor:rgb(23,80,235)">0</span>);<br><span style=3D"color:rgb(255,69,0)">die <=
/span><span style=3D"color:rgb(6,125,23)">&#39;Failed to retreive process l=
ist.&#39; </span><span style=3D"color:rgb(0,51,179)">if </span><span style=
=3D"color:rgb(128,0,128)">$ptr </span><span style=3D"color:rgb(139,0,0)">=
=3D=3D </span><span style=3D"color:rgb(75,0,130)">Bool::False</span>;<br><s=
pan style=3D"color:rgb(0,51,179)">my </span><span style=3D"color:rgb(75,0,1=
30)">PROCESSENTRY32 </span><span style=3D"color:rgb(128,0,128)">$entry </sp=
an><span style=3D"color:rgb(139,0,0)">.=3D </span><span style=3D"color:rgb(=
255,69,0)">new</span>(<span style=3D"color:rgb(6,125,23)">:dwSize</span>(<s=
pan style=3D"color:rgb(255,69,0)">nativesizeof</span>(<span style=3D"color:=
rgb(75,0,130)">PROCESSENTRY32</span>)));<br><span style=3D"color:rgb(255,69=
,0)">die </span><span style=3D"color:rgb(6,125,23)">&#39;Unable to iterate =
over process list&#39; </span><span style=3D"color:rgb(0,51,179)">if </span=
><span style=3D"color:rgb(255,69,0)">Process32First</span>(<span style=3D"c=
olor:rgb(128,0,128)">$ptr</span><span style=3D"color:rgb(139,0,0)">, </span=
><span style=3D"color:rgb(255,69,0)">nativecast</span>(<span style=3D"color=
:rgb(75,0,130)">Pointer</span><span style=3D"color:rgb(139,0,0)">, </span><=
span style=3D"color:rgb(128,0,128)">$entry</span>)) <span style=3D"color:rg=
b(139,0,0)">=3D=3D </span><span style=3D"color:rgb(75,0,130)">Bool::False</=
span>;<br><br><span style=3D"color:rgb(0,51,179)">repeat </span>{<br>    <s=
pan style=3D"color:rgb(255,69,0)">say </span><span style=3D"color:rgb(128,0=
,128)">$entry</span><span style=3D"color:rgb(139,0,0)">.</span><span style=
=3D"color:rgb(255,69,0)">szExeFile</span><span style=3D"color:rgb(23,80,235=
)"></span>[0].ord;<br>    <span style=3D"color:rgb(255,69,0)">say </span><s=
pan style=3D"color:rgb(128,0,128)">$entry</span><span style=3D"color:rgb(13=
9,0,0)">.</span><span style=3D"color:rgb(255,69,0)">szExeFile</span><span s=
tyle=3D"color:rgb(23,80,235)"></span>[1].ord;<br>} <span style=3D"color:rgb=
(0,51,179)">while </span><span style=3D"color:rgb(255,69,0)">Process32Next<=
/span>(<span style=3D"color:rgb(128,0,128)">$ptr</span><span style=3D"color=
:rgb(139,0,0)">, </span><span style=3D"color:rgb(255,69,0)">nativecast</spa=
n>(<span style=3D"color:rgb(75,0,130)">Pointer</span><span style=3D"color:r=
gb(139,0,0)">, </span><span style=3D"color:rgb(128,0,128)">$entry</span>));=
<br><br>------------------------------------------<br></pre><pre style=3D"b=
ackground-color:rgb(255,255,255);color:rgb(8,8,8);font-family:&quot;JetBrai=
ns Mono&quot;,monospace;font-size:9.8pt">The output of the above is:<br>48<=
br>48<br><br></pre><pre style=3D"background-color:rgb(255,255,255);color:rg=
b(8,8,8);font-family:&quot;JetBrains Mono&quot;,monospace;font-size:9.8pt">=
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.<br><br></pre><pre style=
=3D"background-color:rgb(255,255,255);color:rgb(8,8,8);font-family:&quot;Je=
tBrains Mono&quot;,monospace;font-size:9.8pt">~Paul<br></pre></div></div><b=
r><div class=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail_attr">On Sun, =
Jan 3, 2021 at 2:12 AM ToddAndMargo via perl6-users &lt;<a href=3D"mailto:p=
erl6-users@perl.org" target=3D"_blank">perl6-users@perl.org</a>&gt; wrote:<=
br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8e=
x;border-left:1px solid rgb(204,204,204);padding-left:1ex">On 1/2/21 8:13 P=
M, Paul Procacci wrote:<br>
&gt; What I&#39;m trying to attempt to do now is display the contents of th=
at<br>
&gt; CArray (raku member a).=C2=A0 In my mind, this is an &quot;array of ut=
f16LE byte <br>
&gt; sequences terminated by 0&quot;.<br>
<br>
Hi Paul,<br>
<br>
If I understand your problem, you are having trouble<br>
extracting something usable from Windows return UTF16<br>
string.<br>
<br>
I have a series of modules I wrote to read and write<br>
to the Windows registry.=C2=A0 The strings I got back were<br>
all &quot;UTF16 little ending C Strings&quot;.<br>
<br>
This means that every character is a TWO byte word<br>
(16 bits) with the first byte containing the low<br>
value byte.=C2=A0 And they terminate with both bytes<br>
being a numerical zero.=C2=A0 It is a little weird to get<br>
use to.<br>
<br>
There was some interesting conversation in these<br>
parts a bit ago as to if a C string could ever<br>
not be terminated with a nul.=C2=A0 They are always<br>
terminated with a nul.<br>
<br>
The following is from one of the modules I wrote to<br>
support this.=C2=A0 I used brute force, rather than<br>
rely on UTF conversion utilities as I found them<br>
unreliable.<br>
<br>
If you un-comment<br>
=C2=A0 =C2=A0 # print $CStr[ $i ] ~ &quot;,&quot; ~ $CStr[ $i + 1 ] ~ &quot=
;,=C2=A0 &quot;;<br>
you can watch the sub do its thing.<br>
<br>
I have a sub to go the other way too, if you want it.<br>
<br>
HTH,<br>
-T<br>
<br>
<br>
<br>
use NativeCall;<br>
<br>
sub c-to-raku-str( BYTES $CStr ) returns Str=C2=A0 is export( :c-to-raku-st=
r ) {<br>
=C2=A0 =C2=A0 # Note: C Strings are always terminated with a nul.=C2=A0 Thi=
s sub will <br>
malfunction without it.<br>
=C2=A0 =C2=A0 # Note: presumes a UTF16 little endian C String and converts =
to UTF8<br>
<br>
=C2=A0 =C2=A0 my Str=C2=A0 =C2=A0 $SubName=C2=A0 =C2=A0=3D &amp;?ROUTINE.na=
me;<br>
=C2=A0 =C2=A0 my Str=C2=A0 =C2=A0 $RakuStr=C2=A0 =C2=A0=3D &quot;&quot;;<br=
>
=C2=A0 =C2=A0 my Str=C2=A0 =C2=A0 $Msg=C2=A0 =C2=A0 =C2=A0 =C2=A0=3D &quot;=
&quot;;<br>
=C2=A0 =C2=A0 my uint32 $CStrElems =3D $CStr.elems;<br>
=C2=A0 =C2=A0 # say $CStrElems;<br>
<br>
=C2=A0 =C2=A0 loop (my $i =3D 0; $i &lt; $CStrElems - 2 ; $i +=3D 2) {<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0if=C2=A0 $CStr[ $i ] =3D=3D 0=C2=A0 &amp;&amp;=
=C2=A0 $CStr[ $i + 1 ] =3D=3D 0=C2=A0 { last; }<br>
<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0if $i =3D=3D $CStrElems - 4=C2=A0 {<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 $Msg =3D &quot;$SubName ERROR:&quot; ~ &=
quot; C Strings are required to be <br>
terminated with a nul\n\n&quot; ~<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&quot;=C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Return=
ing an empty string\n&quot; ~<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&quot;=C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Coward=
ly existing\n&quot;;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 exit;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0# print $CStr[ $i ] ~ &quot;,&quot; ~ $CStr[ $i =
+ 1 ] ~ &quot;,=C2=A0 &quot;;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0$RakuStr ~=3D chr( $CStr[ $i ] );<br>
=C2=A0 =C2=A0 }<br>
=C2=A0 =C2=A0 # say &quot;&quot;;<br>
<br>
=C2=A0 =C2=A0 # say &quot;$RakuStr&quot;;<br>
=C2=A0 =C2=A0 return $RakuStr;<br>
}<br>
<br>
<br>
</blockquote></div><br clear=3D"all"><br>-- <br><div dir=3D"ltr">__________=
________<br><br>:(){ :|:&amp; };:</div>
</blockquote></div><br clear=3D"all"><br>-- <br><div dir=3D"ltr">Fernando S=
antagata</div>
</blockquote></div><br clear=3D"all"><br>-- <br><div dir=3D"ltr" class=3D"g=
mail_signature">__________________<br><br>:(){ :|:&amp; };:</div>

--000000000000034c9405b7fc1373--
0
pprocacci
1/3/2021 10:02:30 AM
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


0
perl6
1/3/2021 10:36:59 AM
--0000000000000c503505b8034e43
Content-Type: text/plain; charset="UTF-8"

Todd,

Nothing you stated addresses my initial question nor subsequent findings.
My question is simply how to retrieve the value that gets stored in the
CArray; nothing more.
My subsequent findings included the following as I believe I'm running into
it: https://github.com/rakudo/rakudo/issues/3633


Irrelevant musings:
--
A windows handle is a pointer.
A handle is an abstraction to a memory location that can be used in
subsequent api calls.
Declaring it as any incarnation of an int is a mistake and will not
function properly across all machines.

--
The windows api requires the PROCESSENTRY32 structure member dwSize to be
set to size of the structure.
There's nothing wrong with my instantiation.
Passing this structure to Process32First and Process32Next in the manner I
have done so works.

Furthermore you can't pass a naked $entry to like so:
Process32First($handle, $entry)
It has to be a pointer;  had you tried what you suggested, raku would have
thrown errors and for good reason.

--
My suggestion is to try it yourself.  Utilize the windows api in a manner
in which you'd expect it to run
properly and see what happens.  Retrieve the value in szExeFile.  If you'd
get it to work properly, show me
what version of raku you are using and supply it as it could be a bug in
the version I'm running.

~Paul

On Sun, Jan 3, 2021 at 5:37 AM ToddAndMargo via perl6-users <
perl6-users@perl.org> wrote:

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

-- 
__________________

:(){ :|:& };:

--0000000000000c503505b8034e43
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div>Todd,</div><div><br></div><div>Nothing you stated add=
resses my initial question nor subsequent findings.</div><div>My question i=
s simply how to retrieve the value that gets stored in the CArray; nothing =
more.<br></div><div>My subsequent findings included the following as I beli=
eve I&#39;m running into it: <a href=3D"https://github.com/rakudo/rakudo/is=
sues/3633">https://github.com/rakudo/rakudo/issues/3633</a><br><br></div><d=
iv><br></div><div>Irrelevant musings:<br></div><div>--</div><div> A windows=
 handle is a pointer.</div><div>A handle is an abstraction to a memory loca=
tion that can be used in subsequent api calls.</div><div>Declaring it as an=
y incarnation of an int is a mistake and will not function properly across =
all machines.<br></div><div><br></div><div>--<br></div><div>The windows api=
 requires the <span class=3D"gmail-im">PROCESSENTRY32 structure member </sp=
an>dwSize to be set to<span class=3D"gmail-im"> size of the structure.<br>T=
here&#39;s nothing wrong with my instantiation.<br>Passing this structure t=
o Process32First and Process32Next in the manner I have done so works.<br><=
br>Furthermore you can&#39;t pass a naked $entry to=20
like so:=C2=A0=C2=A0 Process32First($handle, $entry)<br>It has to be a poin=
ter;=C2=A0 had you tried what you suggested, raku would have thrown errors =
and for good reason.</span><br><br>--<br></div><div>My suggestion is to try=
 it yourself.=C2=A0 Utilize the windows api in a manner in which you&#39;d =
expect it to run</div><div>properly and see what happens.=C2=A0 Retrieve th=
e value in szExeFile.=C2=A0 If you&#39;d get it to work properly, show me</=
div><div>what version of raku you are using and supply it as it could be a =
bug in the version I&#39;m running.<br><br></div><div>~Paul<br></div></div>=
<br><div class=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail_attr">On Sun=
, Jan 3, 2021 at 5:37 AM ToddAndMargo via perl6-users &lt;<a href=3D"mailto=
:perl6-users@perl.org">perl6-users@perl.org</a>&gt; wrote:<br></div><blockq=
uote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1p=
x solid rgb(204,204,204);padding-left:1ex">On 1/2/21 11:38 PM, Paul Procacc=
i wrote:<br>
&gt; I don&#39;t have a C string that&#39;s terminated by null.<br>
&gt; I have a CArray[int16] of length 260 that&#39;s passed to and filled i=
n by <br>
&gt; the windows api.<br>
&gt; <br>
&gt; <a href=3D"https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32=
/nf-tlhelp32-createtoolhelp32snapshot" rel=3D"noreferrer" target=3D"_blank"=
>https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-cr=
eatetoolhelp32snapshot</a> <br>
&gt; &lt;<a href=3D"https://docs.microsoft.com/en-us/windows/win32/api/tlhe=
lp32/nf-tlhelp32-createtoolhelp32snapshot" rel=3D"noreferrer" target=3D"_bl=
ank">https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp3=
2-createtoolhelp32snapshot</a>&gt;<br>
&gt; <a href=3D"https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32=
/nf-tlhelp32-process32first" rel=3D"noreferrer" target=3D"_blank">https://d=
ocs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32fir=
st</a> <br>
&gt; &lt;<a href=3D"https://docs.microsoft.com/en-us/windows/win32/api/tlhe=
lp32/nf-tlhelp32-process32first" rel=3D"noreferrer" target=3D"_blank">https=
://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process3=
2first</a>&gt;<br>
&gt; <a href=3D"https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32=
/nf-tlhelp32-process32next" rel=3D"noreferrer" target=3D"_blank">https://do=
cs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32next=
</a> <br>
&gt; &lt;<a href=3D"https://docs.microsoft.com/en-us/windows/win32/api/tlhe=
lp32/nf-tlhelp32-process32next" rel=3D"noreferrer" target=3D"_blank">https:=
//docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32=
next</a>&gt;<br>
&gt; <br>
&gt; Take the following for example which I quickly whipped up that is <br>
&gt; supposed to iterate over the processes running on the given windows ma=
chine:<br>
&gt; <br>
&gt; -------------------------------------------------------------<br>
&gt; <br>
&gt; use NativeCall;<br>
&gt; <br>
&gt; constant \MAX_PATH =3D 260;<br>
&gt; constant \TH32CS_SNAPPROCESS =3D 0x00000002;<br>
&gt; <br>
&gt; class PROCESSENTRY32 is repr(&#39;CStruct&#39;) {<br>
&gt;=C2=A0 =C2=A0 =C2=A0 has int32 $.dwSize;<br>
&gt;=C2=A0 =C2=A0 =C2=A0 has int32 $.cntUsage;<br>
&gt;=C2=A0 =C2=A0 =C2=A0 has int32 $.th32ProcessID;<br>
&gt;=C2=A0 =C2=A0 =C2=A0 has int32 $.th32DefaultHeapID;<br>
&gt;=C2=A0 =C2=A0 =C2=A0 has int32 $.th32ModuleID;<br>
&gt;=C2=A0 =C2=A0 =C2=A0 has int32 $.cntThreads;<br>
&gt;=C2=A0 =C2=A0 =C2=A0 has int32 $.th32ParentProcessID;<br>
&gt;=C2=A0 =C2=A0 =C2=A0 has int32 $.pcPriClassBase;<br>
&gt;=C2=A0 =C2=A0 =C2=A0 has int32 $.dwFlags is rw;<br>
&gt;=C2=A0 =C2=A0 =C2=A0 HAS uint16 @.szExeFile[MAX_PATH] is CArray;<br>
&gt; };<br>
&gt; <br>
&gt; sub CreateToolhelp32Snapshot(int32,int32 --&gt;Pointer)is native(&#39;=
Kernel32&#39;) { * };<br>
&gt; sub Process32First(Pointer,Pointer --&gt;Bool)is native(&#39;Kernel32&=
#39;) { * };<br>
&gt; sub Process32Next(Pointer,Pointer --&gt;Bool)is native(&#39;Kernel32&#=
39;) { * };<br>
&gt; <br>
&gt; my $ptr =3D CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);<br>
&gt; die &#39;Failed to retreive process list.&#39; if $ptr =3D=3D Bool::Fa=
lse;<br>
&gt; my PROCESSENTRY32 $entry .=3D new(:dwSize(nativesizeof(PROCESSENTRY32)=
));<br>
&gt; die &#39;Unable to iterate over process list&#39; if Process32First($p=
tr, nativecast(Pointer, $entry))=3D=3D Bool::False;<br>
&gt; <br>
&gt; repeat {<br>
&gt;=C2=A0 =C2=A0 =C2=A0 say $entry.szExeFile[0].ord;<br>
&gt;=C2=A0 =C2=A0 =C2=A0 say $entry.szExeFile[1].ord;<br>
&gt; }while Process32Next($ptr, nativecast(Pointer, $entry));<br>
&gt; <br>
&gt; ------------------------------------------<br>
&gt; <br>
&gt; The output of the above is:<br>
&gt; 48<br>
&gt; 48<br>
&gt; <br>
&gt; This is clearly wrong.=C2=A0 This is either a) my misunderstanding of =
these api calls b) raku bug or c) a usage error on my part.<br>
&gt; <br>
&gt; ~Paul<br>
<br>
Hi Paul,<br>
<br>
Please bottom post.=C2=A0 It removes a lot of confusion.<br>
<br>
~~~~~~~~~~~~~~~~~~~~~~<br>
CreateToolhelp32Snapshot:<br>
<br>
=C2=A0 =C2=A0 C++<br>
<br>
=C2=A0 =C2=A0 HANDLE CreateToolhelp32Snapshot(<br>
=C2=A0 =C2=A0 =C2=A0 DWORD dwFlags,<br>
=C2=A0 =C2=A0 =C2=A0 DWORD th32ProcessID<br>
=C2=A0 =C2=A0 );<br>
<br>
<br>
The return is a &quot;handle&quot;, not a pointer.<br>
<br>
You declare it as such:<br>
<br>
=C2=A0 =C2=A0 =C2=A0sub CreateToolhelp32Snapshot(int32, int32 --&gt; Pointe=
r) is <br>
native(&#39;Kernel32&#39;) { * };<br>
<br>
=C2=A0 =C2=A0 =C2=A0my $ptr =3D CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS=
, 0);<br>
<br>
<br>
I am not sure you are declaring that correctly.<br>
<br>
I would declare it:<br>
=C2=A0 =C2=A0 sub CreateToolhelp32Snapshot(int32, int32 --&gt; int32) is <b=
r>
native(&#39;Kernel32&#39;) { * };<br>
<br>
=C2=A0 =C2=A0 my $handle =3D CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0=
)<br>
<br>
<br>
~~~~~~~~~~~~~~~~~~~~~~<br>
<br>
Process32First:<br>
<br>
=C2=A0 =C2=A0 C++<br>
<br>
=C2=A0 =C2=A0 BOOL Process32First(<br>
=C2=A0 =C2=A0 =C2=A0 HANDLE=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0hSnapsh=
ot,<br>
=C2=A0 =C2=A0 =C2=A0 LPPROCESSENTRY32 lppe<br>
=C2=A0 =C2=A0 );<br>
<br>
Returns a True or False for success/failure.<br>
<br>
You give it the &quot;handle&quot; you got from<br>
CreateToolhelp32Snapshot<br>
<br>
lppe is actually a C Pointer point to a c++<br>
structure called PROCESSENTRY32<br>
<br>
=C2=A0 =C2=A0 C++<br>
<br>
=C2=A0 =C2=A0 typedef struct tagPROCESSENTRY32 {<br>
=C2=A0 =C2=A0 =C2=A0 DWORD=C2=A0 =C2=A0 =C2=A0dwSize;<br>
=C2=A0 =C2=A0 =C2=A0 DWORD=C2=A0 =C2=A0 =C2=A0cntUsage;<br>
=C2=A0 =C2=A0 =C2=A0 DWORD=C2=A0 =C2=A0 =C2=A0th32ProcessID;<br>
=C2=A0 =C2=A0 =C2=A0 ULONG_PTR th32DefaultHeapID;<br>
=C2=A0 =C2=A0 =C2=A0 DWORD=C2=A0 =C2=A0 =C2=A0th32ModuleID;<br>
=C2=A0 =C2=A0 =C2=A0 DWORD=C2=A0 =C2=A0 =C2=A0cntThreads;<br>
=C2=A0 =C2=A0 =C2=A0 DWORD=C2=A0 =C2=A0 =C2=A0th32ParentProcessID;<br>
=C2=A0 =C2=A0 =C2=A0 LONG=C2=A0 =C2=A0 =C2=A0 pcPriClassBase;<br>
=C2=A0 =C2=A0 =C2=A0 DWORD=C2=A0 =C2=A0 =C2=A0dwFlags;<br>
=C2=A0 =C2=A0 =C2=A0CHAR=C2=A0 =C2=A0 =C2=A0 szExeFile[MAX_PATH];<br>
=C2=A0 =C2=A0 } PROCESSENTRY32;<br>
<br>
You are duplicating this structure with<br>
<br>
=C2=A0 =C2=A0 constant \MAX_PATH =3D 260;<br>
=C2=A0 =C2=A0 constant \TH32CS_SNAPPROCESS =3D 0x00000002;<br>
<br>
=C2=A0 =C2=A0 class PROCESSENTRY32 is repr(&#39;CStruct&#39;) {<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 has int32 $.dwSize;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 has int32 $.cntUsage;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 has int32 $.th32ProcessID;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 has int32 $.th32DefaultHeapID;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 has int32 $.th32ModuleID;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 has int32 $.cntThreads;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 has int32 $.th32ParentProcessID;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 has int32 $.pcPriClassBase;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 has int32 $.dwFlags is rw;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 HAS uint16 @.szExeFile[MAX_PATH] is CArray;<br>
=C2=A0 =C2=A0 };<br>
<br>
And calling it with:<br>
<br>
=C2=A0 =C2=A0 my PROCESSENTRY32 $entry .=3D new(:dwSize(nativesizeof(PROCES=
SENTRY32)));<br>
<br>
=C2=A0 =C2=A0 Process32First($ptr, nativecast(Pointer, $entry));<br>
<br>
I would tend to do it this way:<br>
<br>
=C2=A0 =C2=A0 my $entry =3D PROCESSENTRY32,new();<br>
=C2=A0 =C2=A0 sub=C2=A0 Process32First( int32, PROCESSENTRY32 is rw --&gt; =
Bool );<br>
=C2=A0 =C2=A0 my Bool $PassFail =3D Process32First( $handle, $entry)<br>
<br>
<br>
lppe, on the other hard is a pointer.=C2=A0 Adding &quot;is rw&quot; will<b=
r>
read the structure it points to into your object.<br>
<br>
<br>
~~~~~~~~~~~~~~~~~~~~~~<br>
<br>
Process32Next:<br>
<br>
=C2=A0 =C2=A0 C++<br>
<br>
=C2=A0 =C2=A0 BOOL Process32Next(<br>
=C2=A0 =C2=A0 =C2=A0 HANDLE=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0hSnapsh=
ot,<br>
=C2=A0 =C2=A0 =C2=A0 LPPROCESSENTRY32 lppe<br>
=C2=A0 =C2=A0 );<br>
<br>
=C2=A0 =C2=A0 sub=C2=A0 Process32Next( int32, PROCESSENTRY32 is rw --&gt; B=
ool );<br>
<br>
=C2=A0 =C2=A0 =C2=A0while Process32Next( handle, $entry )=C2=A0 {<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 say $entry.szExeFile[0].ord;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 say $entry.szExeFile[1].ord;<br>
=C2=A0 =C2=A0 =C2=A0}<br>
<br>
~~~~~~~~~~~~~~~~~~~~~~<br>
<br>
By the way, the uint16 size is going to be a &quot;little ending&quot;.<br>
<br>
=C2=A0 =C2=A0 =C2=A00xF5D3 comes out [0]=3D0xD3 and [1] 0xF4<br>
<br>
Native call will not convert it for you if you addess it as<br>
a CArray.<br>
<br>
I have a conversion for that too.<br>
<br>
<br>
HTH,<br>
-T<br>
<br>
<br>
</blockquote></div><br clear=3D"all"><br>-- <br><div dir=3D"ltr" class=3D"g=
mail_signature">__________________<br><br>:(){ :|:&amp; };:</div>

--0000000000000c503505b8034e43--
0
pprocacci
1/3/2021 6:40:06 PM
--000000000000a9161605b8043074
Content-Type: text/plain; charset="UTF-8"

To expand further on the problem I'm running into, take the following C
function:

--------------------
#include <string.h>

typedef struct T {
        char a[260];
        int32_t  b;
} T;

void setTest(T *t)
{
        (void)memset(t->a, 'T', 260);
        t->b = 1;
}
---------------------

gcc -c -O3 -Wextra -Wall -Wno-unused-parameter -Wno-unused-function
-Wno-missing-braces -Werror=pointer-arith -O3 -DNDEBUG -D_REENTRANT
-D_FILE_OFFSET_BITS=64 -DMVM_HEAPSNAPSHOT_FORMAT=2 -o test.o test.c
gcc -shared -fPIC -O3 -DNDEBUG -Wl,-rpath,"//opt/rakudo-pkg/lib" -o test.so
test.o

.... and the following raku program:

---------------------
#!/usr/bin/env raku

use NativeCall;

class T is repr('CStruct') {
        HAS int8 @.a[260] is CArray;
        has int32 $.b;
};

sub setTest(T) is native('./test.so') { * };

my T $t .= new;
setTest($t);
say $t.a[0];
say $t.b;
---------------------

Running this yields:

# ./test.raku
0
1

What's expected is:

# ./test.raku
T
1

On Sun, Jan 3, 2021 at 1:29 AM Paul Procacci <pprocacci@gmail.com> wrote:

> A follow-up to my initial message.
>
> I think the following is relevant:
>
> https://github.com/rakudo/rakudo/issues/3633
>
> I think my inlined array is actually being filled with zero's.
>
> say $a.a[0];
> say $a.a[1];
>
> Yields:
>
> 0
> 0
>
> I'm using the comma ide:
>
> >raku -v
> Welcome to Rakudo(tm) v2020.12.
> Implementing the Raku(tm) programming language v6.d.
> Built on MoarVM version 2020.12.
>
> ~Paul
>
> On Sat, Jan 2, 2021 at 11:13 PM Paul Procacci <pprocacci@gmail.com> wrote:
>
>> Hey gents (again),
>>
>> I'm having on awful time with decoding UTF16LE character sequences that
>> are placed into a Nativecall CArray that I've defined as an interface
>> between Raku and a windows library call.
>>
>> The structure used by the windows function includes a static wchar_t
>> field that's PATH_MAX in
>> length (260 wchar_t's).  It would look like the following in C:
>>
>> struct Something {
>>   int32_t dwSize;
>>   wchar_t a[260];
>> };
>>
>> I've written the following as the Raku counterpart to the above:
>>
>> class Something is repr('CStruct') {
>>    has int32 $.dwsize;
>>    HAS int16 @.a[260] is CArray;
>> };
>>
>> Given the following definition for the windows library call:
>>
>> bool Test(Something *x);
>>
>> .. I've defined the following on the raku side of things:
>>
>> sub Test(Pointer --> Bool) is native('Kernel32') { * };
>>
>> ----------------------------------------------------------
>>
>> The function is supposed to write characters into the space allotted,
>> namely a.
>> The only required set member prior to calling the subroutine is that the
>> size of the structure.
>> It gets set in dwSize like so:
>>
>> my Something $a .= new(:dwSize(nativesizeof(Something)));
>>
>> Then the actual function call from the raku side of things:
>>
>> Test(nativecast(Pointer, $a));
>>
>> ----------------------------------------------------------
>>
>> All the above is working.  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".
>>
>> What's the cleanest way of doing this in raku?  I've tried variations of
>> "join" and "encode", simple printf's, say's, etc., and even tried
>> manipulating this data with Buf's, but I can't seem to get it quite right.
>>
>> Any help is appreciated.
>> ~Paul
>> --
>> __________________
>>
>> :(){ :|:& };:
>>
>
>
> --
> __________________
>
> :(){ :|:& };:
>


-- 
__________________

:(){ :|:& };:

--000000000000a9161605b8043074
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">To expand further on the problem I&#39;m running into, tak=
e the following C function:<br><br><div>--------------------</div><div>#inc=
lude &lt;string.h&gt;<br><br>typedef struct T {<br>=C2=A0 =C2=A0 =C2=A0 =C2=
=A0 char a[260];<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 int32_t=C2=A0 b;<br>} T;<br=
><br>void setTest(T *t)<br>{<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 (void)memset(t-=
&gt;a, &#39;T&#39;, 260);<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 t-&gt;b =3D 1;<br>=
}</div><div>---------------------<br><br>gcc -c -O3 -Wextra -Wall -Wno-unus=
ed-parameter -Wno-unused-function -Wno-missing-braces -Werror=3Dpointer-ari=
th -O3 -DNDEBUG -D_REENTRANT -D_FILE_OFFSET_BITS=3D64 -DMVM_HEAPSNAPSHOT_FO=
RMAT=3D2 -o test.o test.c<br>gcc -shared -fPIC -O3 -DNDEBUG -Wl,-rpath,&quo=
t;//opt/rakudo-pkg/lib&quot; -o test.so test.o<br><br></div><div>... and th=
e following raku program:<br><br>
---------------------

<br>#!/usr/bin/env raku<br><br>use NativeCall;<br><br>class T is repr(&#39;=
CStruct&#39;) {<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 HAS int8 @.a[260] is CArray;=
<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 has int32 $.b;<br>};<br><br>sub setTest(T) =
is native(&#39;./test.so&#39;) { * };<br><br>my T $t .=3D new;<br>setTest($=
t);<br>say $t.a[0];<br>say $t.b;<br>
---------------------

<br><br></div><div>Running this yields:<br><br># ./test.raku<br>0<br>1<br><=
br></div><div>What&#39;s expected is:<br><br># ./test.raku<br></div><div>T<=
br></div><div>1<br></div></div><br><div class=3D"gmail_quote"><div dir=3D"l=
tr" class=3D"gmail_attr">On Sun, Jan 3, 2021 at 1:29 AM Paul Procacci &lt;<=
a href=3D"mailto:pprocacci@gmail.com">pprocacci@gmail.com</a>&gt; wrote:<br=
></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;=
border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><=
div>A follow-up to my initial message.</div><div><br></div><div>I think the=
 following is relevant:<br><br><a href=3D"https://github.com/rakudo/rakudo/=
issues/3633" target=3D"_blank">https://github.com/rakudo/rakudo/issues/3633=
</a></div><div><br></div><div>I think my inlined array is actually being fi=
lled with zero&#39;s.<br><br><pre style=3D"background-color:rgb(255,255,255=
);color:rgb(8,8,8);font-family:&quot;JetBrains Mono&quot;,monospace;font-si=
ze:9.8pt"><span style=3D"color:rgb(255,69,0)">say </span><span style=3D"col=
or:rgb(128,0,128)">$a</span><span style=3D"color:rgb(139,0,0)">.</span><spa=
n style=3D"color:rgb(255,69,0)">a</span>[<span style=3D"color:rgb(23,80,235=
)">0</span>];<br><span style=3D"color:rgb(255,69,0)">say </span><span style=
=3D"color:rgb(128,0,128)">$a</span><span style=3D"color:rgb(139,0,0)"></spa=
n><span style=3D"color:rgb(255,69,0)">.a</span>[<span style=3D"color:rgb(23=
,80,235)">1</span>];<br><br></pre><pre style=3D"background-color:rgb(255,25=
5,255);color:rgb(8,8,8);font-family:&quot;JetBrains Mono&quot;,monospace;fo=
nt-size:9.8pt">Yields:<br><br>0<br>0<br><br></pre><pre style=3D"background-=
color:rgb(255,255,255);color:rgb(8,8,8);font-family:&quot;JetBrains Mono&qu=
ot;,monospace;font-size:9.8pt">I&#39;m using the comma ide:<br><br>&gt;raku=
 -v<br>Welcome to Rakudo(tm) v2020.12.<br>Implementing the Raku(tm) program=
ming language v6.d.<br>Built on MoarVM version 2020.12.<br><br></pre></div>=
<div>~Paul<br></div></div><br><div class=3D"gmail_quote"><div dir=3D"ltr" c=
lass=3D"gmail_attr">On Sat, Jan 2, 2021 at 11:13 PM Paul Procacci &lt;<a hr=
ef=3D"mailto:pprocacci@gmail.com" target=3D"_blank">pprocacci@gmail.com</a>=
&gt; wrote:<br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px =
0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div=
 dir=3D"ltr"><div><div><div><div>Hey gents (again),<br><br>I&#39;m having o=
n awful time with decoding UTF16LE character sequences that are placed into=
 a Nativecall CArray that I&#39;ve defined as an interface between Raku and=
 a windows library call.<br><br>The structure used by the windows function =
includes a static wchar_t field that&#39;s PATH_MAX in</div><div>length (26=
0 wchar_t&#39;s).=C2=A0 It would look like the following in C:<br><br>struc=
t Something {</div><div>=C2=A0 int32_t dwSize;<br></div><div>=C2=A0 wchar_t=
 a[260];<br></div><div>};<br></div><div><br></div><div>I&#39;ve written the=
 following as the Raku counterpart to the above: <br></div><div><br></div><=
div>class Something is repr(&#39;CStruct&#39;) {</div><div>=C2=A0=C2=A0 has=
 int32 $.dwsize;<br></div><div>=C2=A0=C2=A0 HAS int16 @.a[260] is CArray;</=
div><div>};</div><br></div>Given the following definition for the windows l=
ibrary call:<br><br></div>bool Test(Something *x);<br><br></div>.. I&#39;ve=
 defined the following on the raku side of things:<br><div><div><div><div><=
div><div><pre style=3D"background-color:rgb(255,255,255);color:rgb(8,8,8);f=
ont-family:&quot;JetBrains Mono&quot;,monospace;font-size:9.8pt">sub Test(P=
ointer --&gt; Bool) is native(&#39;Kernel32&#39;) { * };<br></pre></div><di=
v>----------------------------------------------------------<br></div><div>=
<br></div><div>The function is supposed to write characters into the space =
allotted, namely a. <br></div><div>The only required set member prior to ca=
lling the subroutine is that the size of the structure.<br></div><div>It ge=
ts set in dwSize like so:<br><br></div><div>my Something $a .=3D new(:dwSiz=
e(nativesizeof(Something)));<br><br></div><div>Then the actual function cal=
l from the raku side of things:<br><br></div><div>Test(nativecast(Pointer, =
$a));<br><br>
----------------------------------------------------------

<br><br></div><div>All the above is working.=C2=A0 What I&#39;m trying to a=
ttempt to do now is display the contents of that</div><div>CArray (raku mem=
ber a).=C2=A0 In my mind, this is an &quot;array of utf16LE byte sequences =
terminated by 0&quot;.<br></div><div><br></div><div>What&#39;s the cleanest=
 way of doing this in raku?=C2=A0 I&#39;ve tried variations of &quot;join&q=
uot; and &quot;encode&quot;, simple printf&#39;s, say&#39;s, etc., and even=
 tried manipulating this data with Buf&#39;s, but I can&#39;t seem to get i=
t quite right.<br><br></div><div>Any help is appreciated.</div><div>~Paul<b=
r></div>-- <br><div><div dir=3D"ltr">__________________<br><br>:(){ :|:&amp=
; };:</div></div></div></div></div></div></div></div>
</blockquote></div><br clear=3D"all"><br>-- <br><div dir=3D"ltr">__________=
________<br><br>:(){ :|:&amp; };:</div>
</blockquote></div><br clear=3D"all"><br>-- <br><div dir=3D"ltr" class=3D"g=
mail_signature">__________________<br><br>:(){ :|:&amp; };:</div>

--000000000000a9161605b8043074--
0
pprocacci
1/3/2021 7:43:28 PM
--00000000000048360f05b8046ffa
Content-Type: text/plain; charset="UTF-8"

Todd,

I've made a mistake.  Raku does ensure a pointer gets passed to the
function transparently when referencing a structure and doesn't require one
to be explicit.
I stand corrected.

~Paul

On Sun, Jan 3, 2021 at 1:40 PM Paul Procacci <pprocacci@gmail.com> wrote:

> Todd,
>
> Nothing you stated addresses my initial question nor subsequent findings.
> My question is simply how to retrieve the value that gets stored in the
> CArray; nothing more.
> My subsequent findings included the following as I believe I'm running
> into it: https://github.com/rakudo/rakudo/issues/3633
>
>
> Irrelevant musings:
> --
> A windows handle is a pointer.
> A handle is an abstraction to a memory location that can be used in
> subsequent api calls.
> Declaring it as any incarnation of an int is a mistake and will not
> function properly across all machines.
>
> --
> The windows api requires the PROCESSENTRY32 structure member dwSize to be
> set to size of the structure.
> There's nothing wrong with my instantiation.
> Passing this structure to Process32First and Process32Next in the manner I
> have done so works.
>
> Furthermore you can't pass a naked $entry to like so:
> Process32First($handle, $entry)
> It has to be a pointer;  had you tried what you suggested, raku would have
> thrown errors and for good reason.
>
> --
> My suggestion is to try it yourself.  Utilize the windows api in a manner
> in which you'd expect it to run
> properly and see what happens.  Retrieve the value in szExeFile.  If you'd
> get it to work properly, show me
> what version of raku you are using and supply it as it could be a bug in
> the version I'm running.
>
> ~Paul
>
> On Sun, Jan 3, 2021 at 5:37 AM ToddAndMargo via perl6-users <
> perl6-users@perl.org> wrote:
>
>> 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
>>
>>
>>
>
> --
> __________________
>
> :(){ :|:& };:
>


-- 
__________________

:(){ :|:& };:

--00000000000048360f05b8046ffa
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div>Todd,</div><div><br></div><div>I&#39;ve made a mistak=
e.=C2=A0 Raku does ensure a pointer gets passed to the function transparent=
ly when referencing a structure and doesn&#39;t require one to be explicit.=
</div><div>I stand corrected.<br></div><div><br></div><div>~Paul<br></div><=
/div><br><div class=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail_attr">O=
n Sun, Jan 3, 2021 at 1:40 PM Paul Procacci &lt;<a href=3D"mailto:pprocacci=
@gmail.com">pprocacci@gmail.com</a>&gt; wrote:<br></div><blockquote class=
=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rg=
b(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div>Todd,</div><div><br>=
</div><div>Nothing you stated addresses my initial question nor subsequent =
findings.</div><div>My question is simply how to retrieve the value that ge=
ts stored in the CArray; nothing more.<br></div><div>My subsequent findings=
 included the following as I believe I&#39;m running into it: <a href=3D"ht=
tps://github.com/rakudo/rakudo/issues/3633" target=3D"_blank">https://githu=
b.com/rakudo/rakudo/issues/3633</a><br><br></div><div><br></div><div>Irrele=
vant musings:<br></div><div>--</div><div> A windows handle is a pointer.</d=
iv><div>A handle is an abstraction to a memory location that can be used in=
 subsequent api calls.</div><div>Declaring it as any incarnation of an int =
is a mistake and will not function properly across all machines.<br></div><=
div><br></div><div>--<br></div><div>The windows api requires the <span>PROC=
ESSENTRY32 structure member </span>dwSize to be set to<span> size of the st=
ructure.<br>There&#39;s nothing wrong with my instantiation.<br>Passing thi=
s structure to Process32First and Process32Next in the manner I have done s=
o works.<br><br>Furthermore you can&#39;t pass a naked $entry to=20
like so:=C2=A0=C2=A0 Process32First($handle, $entry)<br>It has to be a poin=
ter;=C2=A0 had you tried what you suggested, raku would have thrown errors =
and for good reason.</span><br><br>--<br></div><div>My suggestion is to try=
 it yourself.=C2=A0 Utilize the windows api in a manner in which you&#39;d =
expect it to run</div><div>properly and see what happens.=C2=A0 Retrieve th=
e value in szExeFile.=C2=A0 If you&#39;d get it to work properly, show me</=
div><div>what version of raku you are using and supply it as it could be a =
bug in the version I&#39;m running.<br><br></div><div>~Paul<br></div></div>=
<br><div class=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail_attr">On Sun=
, Jan 3, 2021 at 5:37 AM ToddAndMargo via perl6-users &lt;<a href=3D"mailto=
:perl6-users@perl.org" target=3D"_blank">perl6-users@perl.org</a>&gt; wrote=
:<br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.=
8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On 1/2/21 11:3=
8 PM, Paul Procacci wrote:<br>
&gt; I don&#39;t have a C string that&#39;s terminated by null.<br>
&gt; I have a CArray[int16] of length 260 that&#39;s passed to and filled i=
n by <br>
&gt; the windows api.<br>
&gt; <br>
&gt; <a href=3D"https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32=
/nf-tlhelp32-createtoolhelp32snapshot" rel=3D"noreferrer" target=3D"_blank"=
>https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-cr=
eatetoolhelp32snapshot</a> <br>
&gt; &lt;<a href=3D"https://docs.microsoft.com/en-us/windows/win32/api/tlhe=
lp32/nf-tlhelp32-createtoolhelp32snapshot" rel=3D"noreferrer" target=3D"_bl=
ank">https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp3=
2-createtoolhelp32snapshot</a>&gt;<br>
&gt; <a href=3D"https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32=
/nf-tlhelp32-process32first" rel=3D"noreferrer" target=3D"_blank">https://d=
ocs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32fir=
st</a> <br>
&gt; &lt;<a href=3D"https://docs.microsoft.com/en-us/windows/win32/api/tlhe=
lp32/nf-tlhelp32-process32first" rel=3D"noreferrer" target=3D"_blank">https=
://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process3=
2first</a>&gt;<br>
&gt; <a href=3D"https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32=
/nf-tlhelp32-process32next" rel=3D"noreferrer" target=3D"_blank">https://do=
cs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32next=
</a> <br>
&gt; &lt;<a href=3D"https://docs.microsoft.com/en-us/windows/win32/api/tlhe=
lp32/nf-tlhelp32-process32next" rel=3D"noreferrer" target=3D"_blank">https:=
//docs.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32=
next</a>&gt;<br>
&gt; <br>
&gt; Take the following for example which I quickly whipped up that is <br>
&gt; supposed to iterate over the processes running on the given windows ma=
chine:<br>
&gt; <br>
&gt; -------------------------------------------------------------<br>
&gt; <br>
&gt; use NativeCall;<br>
&gt; <br>
&gt; constant \MAX_PATH =3D 260;<br>
&gt; constant \TH32CS_SNAPPROCESS =3D 0x00000002;<br>
&gt; <br>
&gt; class PROCESSENTRY32 is repr(&#39;CStruct&#39;) {<br>
&gt;=C2=A0 =C2=A0 =C2=A0 has int32 $.dwSize;<br>
&gt;=C2=A0 =C2=A0 =C2=A0 has int32 $.cntUsage;<br>
&gt;=C2=A0 =C2=A0 =C2=A0 has int32 $.th32ProcessID;<br>
&gt;=C2=A0 =C2=A0 =C2=A0 has int32 $.th32DefaultHeapID;<br>
&gt;=C2=A0 =C2=A0 =C2=A0 has int32 $.th32ModuleID;<br>
&gt;=C2=A0 =C2=A0 =C2=A0 has int32 $.cntThreads;<br>
&gt;=C2=A0 =C2=A0 =C2=A0 has int32 $.th32ParentProcessID;<br>
&gt;=C2=A0 =C2=A0 =C2=A0 has int32 $.pcPriClassBase;<br>
&gt;=C2=A0 =C2=A0 =C2=A0 has int32 $.dwFlags is rw;<br>
&gt;=C2=A0 =C2=A0 =C2=A0 HAS uint16 @.szExeFile[MAX_PATH] is CArray;<br>
&gt; };<br>
&gt; <br>
&gt; sub CreateToolhelp32Snapshot(int32,int32 --&gt;Pointer)is native(&#39;=
Kernel32&#39;) { * };<br>
&gt; sub Process32First(Pointer,Pointer --&gt;Bool)is native(&#39;Kernel32&=
#39;) { * };<br>
&gt; sub Process32Next(Pointer,Pointer --&gt;Bool)is native(&#39;Kernel32&#=
39;) { * };<br>
&gt; <br>
&gt; my $ptr =3D CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);<br>
&gt; die &#39;Failed to retreive process list.&#39; if $ptr =3D=3D Bool::Fa=
lse;<br>
&gt; my PROCESSENTRY32 $entry .=3D new(:dwSize(nativesizeof(PROCESSENTRY32)=
));<br>
&gt; die &#39;Unable to iterate over process list&#39; if Process32First($p=
tr, nativecast(Pointer, $entry))=3D=3D Bool::False;<br>
&gt; <br>
&gt; repeat {<br>
&gt;=C2=A0 =C2=A0 =C2=A0 say $entry.szExeFile[0].ord;<br>
&gt;=C2=A0 =C2=A0 =C2=A0 say $entry.szExeFile[1].ord;<br>
&gt; }while Process32Next($ptr, nativecast(Pointer, $entry));<br>
&gt; <br>
&gt; ------------------------------------------<br>
&gt; <br>
&gt; The output of the above is:<br>
&gt; 48<br>
&gt; 48<br>
&gt; <br>
&gt; This is clearly wrong.=C2=A0 This is either a) my misunderstanding of =
these api calls b) raku bug or c) a usage error on my part.<br>
&gt; <br>
&gt; ~Paul<br>
<br>
Hi Paul,<br>
<br>
Please bottom post.=C2=A0 It removes a lot of confusion.<br>
<br>
~~~~~~~~~~~~~~~~~~~~~~<br>
CreateToolhelp32Snapshot:<br>
<br>
=C2=A0 =C2=A0 C++<br>
<br>
=C2=A0 =C2=A0 HANDLE CreateToolhelp32Snapshot(<br>
=C2=A0 =C2=A0 =C2=A0 DWORD dwFlags,<br>
=C2=A0 =C2=A0 =C2=A0 DWORD th32ProcessID<br>
=C2=A0 =C2=A0 );<br>
<br>
<br>
The return is a &quot;handle&quot;, not a pointer.<br>
<br>
You declare it as such:<br>
<br>
=C2=A0 =C2=A0 =C2=A0sub CreateToolhelp32Snapshot(int32, int32 --&gt; Pointe=
r) is <br>
native(&#39;Kernel32&#39;) { * };<br>
<br>
=C2=A0 =C2=A0 =C2=A0my $ptr =3D CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS=
, 0);<br>
<br>
<br>
I am not sure you are declaring that correctly.<br>
<br>
I would declare it:<br>
=C2=A0 =C2=A0 sub CreateToolhelp32Snapshot(int32, int32 --&gt; int32) is <b=
r>
native(&#39;Kernel32&#39;) { * };<br>
<br>
=C2=A0 =C2=A0 my $handle =3D CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0=
)<br>
<br>
<br>
~~~~~~~~~~~~~~~~~~~~~~<br>
<br>
Process32First:<br>
<br>
=C2=A0 =C2=A0 C++<br>
<br>
=C2=A0 =C2=A0 BOOL Process32First(<br>
=C2=A0 =C2=A0 =C2=A0 HANDLE=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0hSnapsh=
ot,<br>
=C2=A0 =C2=A0 =C2=A0 LPPROCESSENTRY32 lppe<br>
=C2=A0 =C2=A0 );<br>
<br>
Returns a True or False for success/failure.<br>
<br>
You give it the &quot;handle&quot; you got from<br>
CreateToolhelp32Snapshot<br>
<br>
lppe is actually a C Pointer point to a c++<br>
structure called PROCESSENTRY32<br>
<br>
=C2=A0 =C2=A0 C++<br>
<br>
=C2=A0 =C2=A0 typedef struct tagPROCESSENTRY32 {<br>
=C2=A0 =C2=A0 =C2=A0 DWORD=C2=A0 =C2=A0 =C2=A0dwSize;<br>
=C2=A0 =C2=A0 =C2=A0 DWORD=C2=A0 =C2=A0 =C2=A0cntUsage;<br>
=C2=A0 =C2=A0 =C2=A0 DWORD=C2=A0 =C2=A0 =C2=A0th32ProcessID;<br>
=C2=A0 =C2=A0 =C2=A0 ULONG_PTR th32DefaultHeapID;<br>
=C2=A0 =C2=A0 =C2=A0 DWORD=C2=A0 =C2=A0 =C2=A0th32ModuleID;<br>
=C2=A0 =C2=A0 =C2=A0 DWORD=C2=A0 =C2=A0 =C2=A0cntThreads;<br>
=C2=A0 =C2=A0 =C2=A0 DWORD=C2=A0 =C2=A0 =C2=A0th32ParentProcessID;<br>
=C2=A0 =C2=A0 =C2=A0 LONG=C2=A0 =C2=A0 =C2=A0 pcPriClassBase;<br>
=C2=A0 =C2=A0 =C2=A0 DWORD=C2=A0 =C2=A0 =C2=A0dwFlags;<br>
=C2=A0 =C2=A0 =C2=A0CHAR=C2=A0 =C2=A0 =C2=A0 szExeFile[MAX_PATH];<br>
=C2=A0 =C2=A0 } PROCESSENTRY32;<br>
<br>
You are duplicating this structure with<br>
<br>
=C2=A0 =C2=A0 constant \MAX_PATH =3D 260;<br>
=C2=A0 =C2=A0 constant \TH32CS_SNAPPROCESS =3D 0x00000002;<br>
<br>
=C2=A0 =C2=A0 class PROCESSENTRY32 is repr(&#39;CStruct&#39;) {<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 has int32 $.dwSize;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 has int32 $.cntUsage;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 has int32 $.th32ProcessID;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 has int32 $.th32DefaultHeapID;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 has int32 $.th32ModuleID;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 has int32 $.cntThreads;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 has int32 $.th32ParentProcessID;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 has int32 $.pcPriClassBase;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 has int32 $.dwFlags is rw;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 HAS uint16 @.szExeFile[MAX_PATH] is CArray;<br>
=C2=A0 =C2=A0 };<br>
<br>
And calling it with:<br>
<br>
=C2=A0 =C2=A0 my PROCESSENTRY32 $entry .=3D new(:dwSize(nativesizeof(PROCES=
SENTRY32)));<br>
<br>
=C2=A0 =C2=A0 Process32First($ptr, nativecast(Pointer, $entry));<br>
<br>
I would tend to do it this way:<br>
<br>
=C2=A0 =C2=A0 my $entry =3D PROCESSENTRY32,new();<br>
=C2=A0 =C2=A0 sub=C2=A0 Process32First( int32, PROCESSENTRY32 is rw --&gt; =
Bool );<br>
=C2=A0 =C2=A0 my Bool $PassFail =3D Process32First( $handle, $entry)<br>
<br>
<br>
lppe, on the other hard is a pointer.=C2=A0 Adding &quot;is rw&quot; will<b=
r>
read the structure it points to into your object.<br>
<br>
<br>
~~~~~~~~~~~~~~~~~~~~~~<br>
<br>
Process32Next:<br>
<br>
=C2=A0 =C2=A0 C++<br>
<br>
=C2=A0 =C2=A0 BOOL Process32Next(<br>
=C2=A0 =C2=A0 =C2=A0 HANDLE=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0hSnapsh=
ot,<br>
=C2=A0 =C2=A0 =C2=A0 LPPROCESSENTRY32 lppe<br>
=C2=A0 =C2=A0 );<br>
<br>
=C2=A0 =C2=A0 sub=C2=A0 Process32Next( int32, PROCESSENTRY32 is rw --&gt; B=
ool );<br>
<br>
=C2=A0 =C2=A0 =C2=A0while Process32Next( handle, $entry )=C2=A0 {<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 say $entry.szExeFile[0].ord;<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 say $entry.szExeFile[1].ord;<br>
=C2=A0 =C2=A0 =C2=A0}<br>
<br>
~~~~~~~~~~~~~~~~~~~~~~<br>
<br>
By the way, the uint16 size is going to be a &quot;little ending&quot;.<br>
<br>
=C2=A0 =C2=A0 =C2=A00xF5D3 comes out [0]=3D0xD3 and [1] 0xF4<br>
<br>
Native call will not convert it for you if you addess it as<br>
a CArray.<br>
<br>
I have a conversion for that too.<br>
<br>
<br>
HTH,<br>
-T<br>
<br>
<br>
</blockquote></div><br clear=3D"all"><br>-- <br><div dir=3D"ltr">__________=
________<br><br>:(){ :|:&amp; };:</div>
</blockquote></div><br clear=3D"all"><br>-- <br><div dir=3D"ltr" class=3D"g=
mail_signature">__________________<br><br>:(){ :|:&amp; };:</div>

--00000000000048360f05b8046ffa--
0
pprocacci
1/3/2021 8:00:58 PM
On 1/3/21 12:00 PM, Paul Procacci wrote:
> Todd,
> 
> I've made a mistake. Raku does ensure a pointer gets passed to the 
> function transparently when referencing a structure and doesn't require 
> one to be explicit.
> I stand corrected.
> 
> ~Paul

Did you get it working?
0
perl6
1/4/2021 2:37:32 AM
--0000000000004e4f9805b809fe28
Content-Type: text/plain; charset="UTF-8"

No, it doesn't work.
The inline statically defined array in Raku never gets filled with any data
from the win32 function call.

On Sun, Jan 3, 2021 at 9:37 PM ToddAndMargo via perl6-users <
perl6-users@perl.org> wrote:

> On 1/3/21 12:00 PM, Paul Procacci wrote:
> > Todd,
> >
> > I've made a mistake. Raku does ensure a pointer gets passed to the
> > function transparently when referencing a structure and doesn't require
> > one to be explicit.
> > I stand corrected.
> >
> > ~Paul
>
> Did you get it working?
>


-- 
__________________

:(){ :|:& };:

--0000000000004e4f9805b809fe28
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div>No, it doesn&#39;t work.</div><div>The inline statica=
lly defined array in Raku never gets filled with any data from the win32 fu=
nction call.<br></div></div><br><div class=3D"gmail_quote"><div dir=3D"ltr"=
 class=3D"gmail_attr">On Sun, Jan 3, 2021 at 9:37 PM ToddAndMargo via perl6=
-users &lt;<a href=3D"mailto:perl6-users@perl.org">perl6-users@perl.org</a>=
&gt; wrote:<br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px =
0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On 1=
/3/21 12:00 PM, Paul Procacci wrote:<br>
&gt; Todd,<br>
&gt; <br>
&gt; I&#39;ve made a mistake. Raku does ensure a pointer gets passed to the=
 <br>
&gt; function transparently when referencing a structure and doesn&#39;t re=
quire <br>
&gt; one to be explicit.<br>
&gt; I stand corrected.<br>
&gt; <br>
&gt; ~Paul<br>
<br>
Did you get it working?<br>
</blockquote></div><br clear=3D"all"><br>-- <br><div dir=3D"ltr" class=3D"g=
mail_signature">__________________<br><br>:(){ :|:&amp; };:</div>

--0000000000004e4f9805b809fe28--
0
pprocacci
1/4/2021 2:38:53 AM
On 1/3/21 10:40 AM, Paul Procacci wrote:
> Furthermore you can't pass a naked $entry to like so:  =20
> Process32First($handle, $entry)
> It has to be a pointer;=C2=A0 had you tried what you suggested, raku wo=
uld=20
> have thrown errors and for good reason.

Do you understand about "is rw" now?

     Process32First($handle, $entry is rw)


0
perl6
1/4/2021 2:43:00 AM
--00000000000033d85505b80a193a
Content-Type: text/plain; charset="UTF-8"

Todd,

I know what 'is rw' is for.  This isn't at all related to the problem I'm
having.

On Sun, Jan 3, 2021 at 9:43 PM ToddAndMargo via perl6-users <
perl6-users@perl.org> wrote:

> On 1/3/21 10:40 AM, Paul Procacci wrote:
> > Furthermore you can't pass a naked $entry to like so:
> > Process32First($handle, $entry)
> > It has to be a pointer;  had you tried what you suggested, raku would
> > have thrown errors and for good reason.
>
> Do you understand about "is rw" now?
>
>      Process32First($handle, $entry is rw)
>
>
>

-- 
__________________

:(){ :|:& };:

--00000000000033d85505b80a193a
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div>Todd,</div><div><br></div><div>I know what &#39;is rw=
&#39; is for.=C2=A0 This isn&#39;t at all related to the problem I&#39;m ha=
ving.<br></div></div><br><div class=3D"gmail_quote"><div dir=3D"ltr" class=
=3D"gmail_attr">On Sun, Jan 3, 2021 at 9:43 PM ToddAndMargo via perl6-users=
 &lt;<a href=3D"mailto:perl6-users@perl.org">perl6-users@perl.org</a>&gt; w=
rote:<br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0p=
x 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On 1/3/21 =
10:40 AM, Paul Procacci wrote:<br>
&gt; Furthermore you can&#39;t pass a naked $entry to like so:=C2=A0 =C2=A0=
<br>
&gt; Process32First($handle, $entry)<br>
&gt; It has to be a pointer;=C2=A0 had you tried what you suggested, raku w=
ould <br>
&gt; have thrown errors and for good reason.<br>
<br>
Do you understand about &quot;is rw&quot; now?<br>
<br>
=C2=A0 =C2=A0 =C2=A0Process32First($handle, $entry is rw)<br>
<br>
<br>
</blockquote></div><br clear=3D"all"><br>-- <br><div dir=3D"ltr" class=3D"g=
mail_signature">__________________<br><br>:(){ :|:&amp; };:</div>

--00000000000033d85505b80a193a--
0
pprocacci
1/4/2021 2:46:24 AM
On 1/3/21 6:46 PM, Paul Procacci wrote:
> Todd,
>=20
> I know what 'is rw' is for.=C2=A0 This isn't at all related to the prob=
lem=20
> I'm having.

Hi Paul,

I seems to be only annoying you, so I will stop here.
Good luck with your project.  Is sounds fun.

-T

0
perl6
1/4/2021 3:10:50 AM
On 1/3/21 10:40 AM, Paul Procacci wrote:
> Irrelevant musings:
> --
> A windows handle is a pointer.
> A handle is an abstraction to a memory location that can be used in 
> subsequent api calls.
> Declaring it as any incarnation of an int is a mistake and will not 
> function properly across all machines.

Here is a nice description of the difference:

https://stackoverflow.com/questions/13023405/what-is-the-difference-between-handle-pointer-and-reference

      A handle is usually an opaque reference to an object.
      The type of the handle is unrelated to the element
      referenced. Consider for example a file descriptor
      returned by open() system call. The type is int but
      it represents an entry in the open files table. The
      actual data stored in the table is unrelated to the
      int that was returned by open() freeing the
      implementation from having to maintain compatibility
      (i.e. the actual table can be refactored transparently
      without affecting user code. Handles can only be used
      by functions in the same library interface, that can
      remap the handle back to the actual object.

      A pointer is the combination of an address in memory
      and the type of the object that resides in that
      memory location. The value is the address, the
      type of the pointer tells the compiler what
      operations can be performed through that pointer,
      how to interpret the memory location. Pointers
      are transparent in that the object referenced
      has a concrete type that is present from the
      pointer. Note that in some cases a pointer can
      serve as a handle (a void* is fully opaque, a
      pointer to an empty interface is just as opaque).

0
perl6
1/4/2021 7:02:21 AM
Reply: