views:

855

answers:

5

Hi, I am trying to passing in 3 pointers to a DLL function. I have:

{

$code=1;
$len=100;
$str=" " x $len;

$function = new Win32::API(DLLNAME,'dllfunction','PPP','V');

$function->Call($code,$str,$len);

}

The DLL is defined as void dllfunction(int* a, char* str, int* len); The DLL will modify all the variables pointed by the three pointers.

However, I am segfaulting when I run this. The documentation for Win32::API specified that I should use actual variable name instead of the Perl variable references. Can anyone tell me what I am missing? Thanks.

*more information:

I added printf() in the DLL to print out the address of the three pointers, and printf in Perl to print out the reference of the three variables. And I get the following

DLL : Code = 0x10107458 Error = 0x10046b50 str = 0x10107460

Perl : Code = 0x101311b8 Error = 0x101312a8 str = 0x10131230

Any idea why the DLL is getting the wrong addresses?

****More information

After much debugging, I found out that this is happening when returning from the DLL function. I added printf("done\n"); as the very last line of this DLL function, and this does output, then the program segfaults. I guess its happening in Win32::API? Has anyone experienced this?

Also, I am able to access the initial variables of all the three variables from the DLL. So the pointer is passed correctly, but for some reason it causes a segfault when returning from the DLL. Maybe it's segfaulting when trying to copy the new data into the Perl variable?

A: 

IANAPH, but I think you need to do use a reference, like so:

$function->Call(\$code, \$str, \$len)

The one I'm least sure about is $str - it may not need a reference. The segfault is almost certainly coming from the DLL trying to write to memory address 1 (or 100, depending on which it tries to write first).

Harper Shelby
IANAPH either, but according to http://search.cpan.org/~acalpini/Win32-API-0.41/API.pm#CALLING_AN_IMPORTED_FUNCTION you shouldn't use a reference for the $str parameter; I'm not sure about the other two parameters.
Adam Rosenfield
I tried that too, both sending all three references, and sending 2 int references and 1 str variable. However, its still seg faulting. I agree with you that seg fault is certainly happening when the dll is trying to access bad memory address, but I can't quit figure out whats causing it :<
arnold
A: 

I tried that too, both sending all three references, and sending 2 int references and 1 str variable. However, its still seg faulting. I agree with you that seg fault is certainly happening when the dll is trying to access bad memory address, but I can't quit figure out whats causing it :<

arnold
A: 

OK, I followed Adam's link to this page. According to that, the call should be:

$function->Call(code, $str, len)

The example code uses a function with an LPSTR (essentially a char*) parameter, and it uses the variable as you'd expect, but this bit here:

for pointers you must use a variable name (no Perl references, just a plain variable name).

seems to indicate that the code I listed in this post should work.

Harper Shelby
I tried that as well but I am still getting seg fault. I took > for pointers you must use a variable name (no Perl references, just a plain variable name).as to do $function->Call($code, $str, $len) instead of $functino->Call(\$code,\$str,\$len);
arnold
A: 

I'm not a windows programmer but seeing:

for pointers you must use a variable name

to me means the variable names, not the variables themselves. Does this work?

$function->Call('code', 'str', 'len');

or maybe

$function->Call('$code', '$str', '$len');

Btw, I wouldn't expect the memory addresses to be the same. Win32::API will need to convert the Perl data elements into something that Windows can understand and I seriously doubt they would occupy the same physical memory space.

mpeters
I figured as much after thinking about the pointers little bit. But I am able to read the initial value of each of the variable from the DLL. So its passing the point correctly, but seg faults when returning from the DLL.
arnold
+3  A: 

AH!! I figured it out.

The problem was this

  1. And optionally you can specify the calling convention, this defaults to '__stdcall', alternatively you can specify '_cdecl'.

The dll function was exported with extern "C" __declspec(dllexport) so I figured maybe I should be using '_cdecl' flag.

Win32::API('dll','dllfunction','PPP','V','_cdecl');

works!

thanks everyone.

arnold
Good find - I didn't even think about calling convention (but I should have, since most Win32 APIs use __stdcall instead of _cdecl).
Harper Shelby