The CPAN version of Win32::API is 0.68, that version has alot of problems. I found that it was faster for me to write and compile XS code than use Win32::API 0.68. I found myself spending more time in the C debugger looking at the C stack and overriding package level subs in Win32::API with my own implementations at runtime, stepping through the Perl code in Win32::API and finding silent failures instead of fatal errors when things go wrong inside Win32::API's Perl side or api usage mistakes from the user/me, and basically saying to myself, is this a Win32::API bug, or my Perl code's bug all the time. Wasn't Win32::API made for the case where you want it to be EASIER than C? My Win32::API prototypes looked like
$api = Win32::API::new->($dll, $function, "N", "NNNNNNNNNNNN");
with me doing all the zero/sign extends, packing, [pack a double to a 8 byte string, split into 2 4 byte chunks, unpack the 2 4 byte strings to pack's J letter, then feed as 2 numeric scalar integers into 2 "N"s into Win32::API, remember endianess!], pointer contents reading into scalar, struct building, by hand with un/pack(). Just use XS at this point. So I tried to fix Win32::API.
"In any case, you can't return a Win32::API::Struct as the return value since its not implemented"".
Does this mean that I can't use Win32::API to link to this function? Is ther any workaround? Because without this functionality, I think I may not be able to call any other function. At the end of the day, tables need to be created to pass them as parameters.
The LPHANDLE I tell you to use will not be packed and unpacked automatically with 0.68, LPHANDLE (and all pointers to numeric things) are pointers to strings in 0.68, and the C API will get a char * with a printable number in ASCII if you dont
pack it yourself. The "Pack()" command warnings you see are because Pack() is broken in 0.68 (and has been since Day 1 of C prototype parsing in Win32::API, late 1990/early 2000s). Try installing my non-CPAN .70/.71 of Win32::API
https://github.com/bulk88/perl5-win32-api and read its pod and changes file too, you might find you problems went away. If you must use the CPAN version, here is an example how to use LPHANDLE with 0.68.
{
#old API psuedo pointer handling
my $pass = 1;
my $hnd = "\x00" x length(pack('J', 0));
$function = new Win32::API($test_dll, 'BOOL __stdcall GetHandle(LPHAND
+LE pHandle)');
$pass = $pass && defined($function);
#takes "\xAB\xCD\xED\x00"
$pass = $pass && $function->Call($hnd) == 1;
$hnd = unpack('J', $hnd);
$pass = $pass && $hnd == 4000;
ok($pass, 'GetHandle operates correctly');
$pass = 1;
$function = new Win32::API($test_dll, 'BOOL __stdcall FreeHandle(HANDL
+E Handle)');
$pass = $pass && defined($function);
#takes 123
$pass = $pass && $function->Call($hnd) == 1;
ok($pass, 'FreeHandle operates correctly');
}
IMHP myTableCreate basically returns a "HANDLE" in Win32 API speak, or a void * in C. PVOID is a char * in Win32 API, which will never work for you, since Win32 API will try to read the string that is AT the mem address that myTableCreate returns. When you pass that "char *" back to your C API in myTableLoadFromFile, the C API will get some truncation of what it expects at the target of "opaque" (null character means end of string), at a totally different memory address that is from the Perl Scalar and not the memory address myTableCreate returned, and myTableCreate better be returning a valid memory address and not a handle/record number/GUID/encrypted pointer. I seriously would try your best NOT to use Win32::API::Struct unless you have to, I tried to clean it up somewhat for 0.71 (check my github commits) but there are too many architectural flaws with how C type intelligence works with Win32::API/::Struct/::Type. myTable after call contains 1 and only 1 member, which is a opaque pointer, so its really a void ** at the end of the day, and since you create the myTable, and it comes from your memory, it has no other slices after opaque.
Unrelated to Win32::API, would myTableLoadFromFile ever change the value of member opaque between calls to myTableLoadFromFile? I know from COM-ish APIes, void ** is used to pass in a object, with the function possibly destroying the existing one, and putting in a new one. Unless the api designer is crazy (he might already be from what you said), if myTableLoadFromFile just wanted an object instance, it would ask for the void *. If it wants be able to destroy, and/or replace the object instance, it will ask for a void **. Some C APIs, unlike Kernel32 Windows, return error/status codes/integers from all functions, so to create an object instance a void ** must be supplied, because the return value is used for something else and there can only be 1 return value.
Final note, neither 0.68 or my 0.71 support pass by copy structs. There is a hack around it on 32 bit Windows. I mentioned it above briefly.