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
}