如何将指向Perl函数的指针作为回调函数传递给Windows DLL中具有指针作为参数的函数?

时间:2012-05-02 00:38:46

标签: windows perl api callback

Perl脚本

use Win32::API;  
use Win32::API::Callback;  

my $callback = Win32::API::Callback->new(Perl_Func,"PN", "N");  

 #Import 'C_Func' Function from dll  
my $test = Win32::API->new('dll_test','C_Func','KP','N');  
my $buf = pack('i*', (1, 2, 3));  
 #Calling the C dll Function 'C_Func' with arguments as pointer to 'Perl_Func' and integer array  
my $ret = $test->Call( $callback, $buf);  
print "final value=".$ret."\n";

定义'Perl_Func'

sub Perl_Func
{  

        ($a,$b)=@_;  
        print "entered into Perl Function"."\n";  
        print "int variable from dll=".$b."\n";  
        print "array first element from dll=".$a[0]."\n";  **#unable to access the value**  
        $res=$a[0]+$a[1]+$a[2]; **# unable to access the values here** 
        return $res;  
}

C Dll“dll_test”

int __stdcall C_Func( int (*PerlExpFunc)( int *, int ), int *d)  
{  

        int res,c[3]; 
        c[0]=d[0]; c[1]=d[1]; c[2]=d[2];   
        res=PerlExpFunc(c,10);  
        return(res);  
}

所以这里输出看起来像这样

    entered into Perl Function  
    int variable from dll=10  
    array first element from dll=    
    final value=0  

因此程序正在进入从dll调用的'Perl_Func'。但是在这个函数中,它无法访问作为指针传递的数组中的值(dll中的变量c和'Perl_Func'中的$a)。因此,$a[0]和最终值没有显示任何值,即1,2和3的总和出现为零。 我想我没有从指针到数组中提取值,从C部分传递,正确地在Perl部分中传递。请告诉我正确的方法。

1 个答案:

答案 0 :(得分:1)

您可以使用Win32::APIWin32::API::Callback执行此操作。如需更多帮助,您需要提供更多信息。

目前为止的进展如下:

mydll.c

#include <stdlib.h>
#include <windows.h>

__declspec(dllexport)
int __cdecl C_Func(LONG (*PerlExpFunc)(PLONG, LONG), PLONG c) {
    int result;
    result = PerlExpFunc(c, 10);
    return result;
}

使用编译:

C:\Temp> cl mydll.c /LD /Gd /W3

test.pl

use strict; use warnings;
use Win32::API;
use Win32::API::Callback;
use YAML;

my $C_Func = Win32::API->new('mydll', 'C_Func', 'KP', 'N', '_cdecl');

my $callback = Win32::API::Callback->new(sub {
        my ($x, $y) = @_;
        print Dump \@_;
        return 42;
    }, ['P', 'N'], 'N'
);

my $array = pack 'L*', 0x41, 0x42, 0x43;

my $ret = $C_Func->Call($callback, $array);

print "final value= $ret\n";

这个输出是:

---
- A
- 10
final value= 42

显然,回调是接收传递给它的数组的第一个元素。所有三个值都确实为C_Func。我不确定接收端有什么用。

更新

这是问题(来自Win32-API-0.68/Callback/Callback.xs)。在PerformCallback中,我们有:

for(i=0; i < nparams; i++) {
    switch(params[i].t) {
    case T_STRUCTURE:
        itoa(i, ikey, 10);
        XPUSHs(sv_2mortal(*(hv_fetch((HV*)SvRV(self), ikey, strlen(ikey), 0))));
        break;
    case T_POINTER:
        XPUSHs(sv_2mortal(newSVpv((char *) params[i].p, 0)));
        break;
    case T_INTEGER:
    case T_NUMBER:
        XPUSHs(sv_2mortal(newSViv((int) params[i].l)));
        break;
    }
}

查看T_POINTER的情况,很清楚为什么我们只返回数组的第一个元素(您可以通过传递0xdeadbeef并观察efbeadde来验证输出的十六进制转储。)