Re: initializing Pointer

[email protected] (ToddAndMargo via perl6-users)
Newsgroups perl.perl6.users
Message-ID <[email protected]>
On 12/20/23 11:12, Marcel Timmerman wrote:
> Hi,
> 
> I would like to initialize a Pointer with some value but get an error. 
> For example;
> 
> my $a = Pointer[Str].new('text');
> 
> The error thrown:
> 
> Default constructor for 'NativeCall::Types::Pointer[Str]' only takes 
> named arguments
> 
> The way I can do it now is by creating a CArray and then do a nativecast 
> which is a bit cumbersome.
> The reason I would like to use Pointers is when there is only one object 
> to point to, not an array. Secondly, for the use of the deref() function 
> to get the value it points to.
> 
> Is there another way to solve this or is it a bug in the 
> NativeCall::Types module. I have noticed that there  are 3 new() methods 
> defined accepting positional arguments.
> 
> Regards,
> Marcel

Hi Marcel,

I always initialize a pointer with a binary zero.  This is
a null pointer in C.  A "DWORD" is a 32 bit unsigned integer.

Here is some code of mine to work with Windows error messages.
Maybe there is something in it that will give you some examples.
Unfortunately, I did this years ago and have forgotten most of
how I did it.

Note.  Anything that starts with "LP" is a (LONG or 32 bit
not 64 bit -- it'sa Windows thing) pointer.  For example
"LPCWSTR lpSubKey".

Also note that C string are terminated with a nul.  Or
in the case of UTF-16, two nuls.  This is not the case in
Raku as a Raku string comes with a hidden structure
that tells you the length of the string, meaning a
Raku string can contain nuls.

You will see me doing

    my BYTES  $lpBuffer = CArray[BYTE].new( 0xFF xx $nSize );

in places.  This is to help me troubleshoot.  You will
get back "blah blah blah null 0xFF 0xFF ..."

HTH,
-T


constant NULL     = 0x0000;
sub WinFormatMessage( uint32 $ErrorNumber, Bool $Debug = False ) returns 
Str is export( :WinFormatMessage ) {


#`{

      Return a string with the error message corresponding to the error 
number

 
https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-formatmessagew


      DWORD FormatMessageW(
          DWORD   dwFlags,      # bitwise OR 
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | 
FORMAT_MESSAGE_IGNORE_INSERTS
          LPCVOID lpSource,     # NULL.  The location of the message 
definition. The type of this parameter depends upon the settings in the 
dwFlags parameter.
          DWORD   dwMessageId,  # the error message number ($ErrorNumber)
          DWORD   dwLanguageId, # 0 for system's language
          LPTSTR  lpBuffer,     # the return string, give it 1024
          DWORD   nSize,        # 0  nubmer of bytes in the return
          va_list *Arguments    # NULL
      );
 
https://social.msdn.microsoft.com/Forums/vstudio/en-US/8f0eed1f-a180-4a08-bda9-3dc61e4fdd02/what-is-the-function-to-turn-an-error-number-into-an-error-message?forum=vcgeneral
         RLWA comments:  Don't worry about the va_list* parameter in the 
FormatMessageA or
                         FormatMessageW functions.  Pass NULL and make 
sure to specify
                         FORMAT_MESSAGE_IGNORE_INSERTS in the dwFlags 
parameter

         Note: "LPTSTR is a [long] pointer to a (non-const) TCHAR string"
                LPTSTR: null-terminated string of TCHAR (Long Pointer)

      R. Wieser's declaration:
          DWORD   dwFlags,               // FORMAT_MESSAGE_FROM_SYSTEM 
or FORMAT_MESSAGE_IGNORE_INSERTS
          LPCVOID lpSource,              // 0
          DWORD   dwMessageId,      // The error code
          DWORD   dwLanguageId,     // 0
          LPWSTR  lpBuffer,                // RW ptr to the string buffer
          DWORD   nSize,                   // RW ptr to variable holding 
available string buffer size
          va_list *Arguments                 // null

}

    my Str $SubName = &?ROUTINE.name;
    my Str $OS      = $*KERNEL.name;
    if not $OS eq "win32" {
       say "Sorry, $SubName only work in Windows.";
       exit; }

    my DWORD  $dwFlags      = FORMAT_MESSAGE_FROM_SYSTEM +| 
FORMAT_MESSAGE_IGNORE_INSERTS;
    my DWORD  $lpSource     = NULL;
    my DWORD  $dwMessageId  = $ErrorNumber;   # error number from the 
calling function
    my DWORD  $dwLanguageId = LANG_USER_DEFAULT;   # 0 is the delault 
system language

    my DWORD  $nSize        = 1024;  # number of bytes in $lpBuffer, maybe
    # my BYTES  $lpBuffer     = CArray[BYTE].new( 0 xx $nSize );
    my BYTES  $lpBuffer     = CArray[BYTE].new( 0xFF xx $nSize );
    my DWORD  $va_list      = NULL;
    my Str    $ErrorString  = "";
    my DWORD  $RtnCode      = 0;
    my DWORD  $LastError    = 0;


    sub FormatMessageW( DWORD, DWORD, DWORD, DWORD, CArray[BYTE] is rw, 
DWORD is rw, DWORD )
       is native("Kernel32")
       is symbol("FormatMessageW")
       returns DWORD
    { * };

    $RtnCode = FormatMessageW( $dwFlags, $lpSource, $dwMessageId, 
$dwLanguageId, $lpBuffer, $nSize, $va_list );

    # say "$lpBuffer";
    # say $lpBuffer[ 0 ];
    # say $lpBuffer[ 0 ] +| 0x00;
    if not $lpBuffer[ 0 ] == -1  {    # -1 = 0xFF (it gets coersed) 
means nothing was returned
       loop (my $Index=0; $Index < $nSize  - 2 ; $Index += 2) {
          my byte $i = $lpBuffer[ $Index ] +| 0x00;
          if $i eq 0x00  { last; }
          $ErrorString ~= chr ( $i );
       }
    }

    $ErrorString ~~ s/ "{chr(13)}{chr(10)}" //;
    if $ErrorString.chars == 0 {
       $LastError   = WinGetLastError();
       $ErrorString = WinFormatMessage( $LastError );
       WinMsg( "$SubName Error:", "FormatMessageW returned a failure 
error code of\n" ~
               "$LastError\n\n" ~ Q[(] ~ $ErrorString ~ Q[)] ~ "\n\n" ~
               "for error request of $ErrorNumber" );
       $ErrorString = "Bad Error Code";
    }

    if $Debug eq True  {
       say( "$SubName" ~ Q[:] ~ " Debug" ~ Q[:] ~ "\n" ~
             "   WinGetLastError          $LastError\n" ~
             "   Error Number             $dwMessageId\n" ~
             "   nSize                    $nSize\n" ~
             "   RtnCode                  $RtnCode\n" ~
             "   Error String Characters  " ~ $ErrorString.chars ~ "\n" ~
             "   ErrorString              " ~ Q[<] ~ $ErrorString ~ Q[>] 
~ "\n" ~
             # "   lpBuffer\n\n$lpBuffer" ~
             "\n" );
    }

    return $ErrorString
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.