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
}