Perl Win32::API-向DLL函数传递数组和从DLL函数传递数组时出现问题

Perl Win32::API-向DLL函数传递数组和从DLL函数传递数组时出现问题,perl,Perl,系统环境:64位Windows 7旗舰版;活动状态Perl版本5版本24 subversion 3;Build 2404[404865]于2017年12月11日11:09:26编译 我试图编写一个perl脚本,调用声明为以下内容的函数: extern "C" POLYFITGSL_API int PolyFit(int numPts, const double* xVals, const double* yVals, int fitOrder, double* coef, d

系统环境:64位Windows 7旗舰版;活动状态Perl版本5版本24 subversion 3;Build 2404[404865]于2017年12月11日11:09:26编译

我试图编写一个perl脚本,调用声明为以下内容的函数:

extern "C" POLYFITGSL_API int PolyFit(int numPts, const double* xVals, const double* yVals, int fitOrder, double* coef, double* fitVals, double* rSquared);
前四个参数是PolyFit的输入,后三个是输出

对于在C程序中分配的指针,其调用形式如下:

 coef = (double*)malloc((fitOrder + 1) * sizeof(double));
 estYVals = (double*)malloc(n * sizeof(double));
 rSquared = (double*)malloc(sizeof(double));
 resFit = PolyFit(n, xVals, yVals, fitOrder, coef, estYVals, rSquared);
DLL将导出:

使用参数列表选项的尝试未成功。此外,建议通过原型导入。但是我不知道怎么写,也找不到一个例子

使用下面代码片段中的参数列表选项,除了两个整数外,所有都定义为指针,对于输出,引用的数组和最终浮点已预定义并用零填充

# This assumes that the integers are 4 bytes wide and all others are 8:
$returnbuf = " " x 48;
$parmsbuf = " " x 48;

my $PolyFit = Win32::API::More->new('D:/prjct/model/code/SRS1/binaries/PolyFitGSL','PolyFit','PNP','N');
die $! unless defined $PolyFit;
# no error is produced here

$parmsbuf = pack('iNNiNNN', $numvals, $xValsptr, $yValsptr, $fitorder, $coeffsptr, $fitValsptr, $rSquaredptr);

# display the parameters
@outref = unpack('iNNiNNN', $parmsbuf);
print ("The unpacked calling buffer:  @outref \n");

$returncode = $PolyFit ->Call($parmsbuf, 3, $returnbuf);
# the return value is 52

$error = Win32::GetLastError();
if ($error) {print("function call failed: $^E \n")};

@returnvals = unpack('iNNiNNN', $returnbuf);
print ("Return values:  @returnvals \n");
在执行时,这将产生: 未打包的呼叫缓冲区:600 58497768 58498512 3 58497816 58497840 58489400

返回值:538976288 538976288 538976288 538976288 538976288 538976288 538976288 538976288 538976288

在所有测试条件下,调用的返回值为52

$coeffsptr、$fitValsptr和$rSquaredptr引用的输出数组和标量保持其初始化状态

输入缓冲区的值在我看来是正确的,指针值在perl的地址空间中看起来是合理的位置

未检测到执行错误,但返回的值显然无效。我在这里犯了错误,但我不知道如何解决它们

当局之间在参数类型标识符上存在分歧。表示用D指定了双浮点,但pack函数将其作为无效类型拒绝

我依赖此源来指定GSL PolyFit函数期望的变量大小:

如果我改为通过原型导入,那么一个如何编写import和call语句的示例将非常有价值。我不是开发人员,我只是想做一些科学研究,快速多项式拟合程序至关重要。在这台3.5 GHz、有7年历史的计算机上,GSL PolyFit函数可以在大约350微秒的时间内将一个三次多项式拟合到600个数据点

非常感谢你的帮助

有很多问题

  • 对于一个有7个参数的函数,
    PNP
    显然是错误的
  • 类似地,调用($parmsbuf,3,$returnbuf)又是怎么回事
  • N
    不是正确的返回值类型
  • Win32::API默认使用
    stdcall
    调用约定,但函数似乎使用
    cdecl
    调用约定
您可以使用以下内容:(注意事项如下)

使用功能qw(状态);
使用配置qw(%Config);
使用Win32::API qw();
使用常量PTR_SIZE=>$Config{ptrsize};
使用常量PTR_PACK_格式=>
PTR_尺寸==8?'Q'
:PTR_大小==4?'我是
:die(“无法识别的ptrsize\n”);
使用常量PTR_WIN32API_TYPE=>
PTR_尺寸==8?'DWORD64'
:PTR_大小==4?'DWORD32'
:die(“无法识别的ptrsize\n”);
Win32::API::Type->typedef('uintpttr\u t'=>PTR\u WIN32API\u Type);
my$dll='D:/prjct/model/code/SRS1/binaries/PolyFitGSL';
子get_buffer_addr{unpack(PTR_PACK_格式,PACK('P',$[0]))
亚多边形拟合{
我的($VAL,$fit_订单)=@;
国家$PolyFit;
如果(!$PolyFit){
我的$adjusted_proto=
int\uuuu cdecl PolyFit(
int numPts,
Uintpttr_t xVals,
uintptr_t yVals,
国际金融秩序,
uintptr_t coef,
uintptr_t fitVals,
uintptr\t平方
)
';
$PolyFit=Win32::API::More->new($dll,$adjusted_proto)
或死亡(“无法链接到PolyFit:$^E\n”);
}
我的$n=@$VAL;
my$x_VAL=pack(“d$n”,map$\>[0],@$VAL);
my$y_vals=pack(“d$n”,map$\>[1],@$vals);
我的$coef=pack($d.)($fit_order+1),(0)x($fit_order+1));
my$fit_vals=包装(“d$n”,(0)x($n));
我的$r_平方=包装('d',0);
my$rv=$PolyFit->呼叫(
$n,
获取缓冲区地址($x\u vals),
获取缓冲区地址($y\u vals),
$fit_订单,
获取缓冲区地址($coef),
获取缓冲区地址($fit\u vals),
获取缓冲区地址($r_平方),
);
#我假设返回值指示调用是否成功?
如果返回!$rv;
返回(
[拆包('d')($fit_订单+1),$coef)],
[拆包(“d$n”,$fit_VAL)],
[拆包('d',$r_平方)],
);
}
my($coef,$fit\u vals,$r\u squared)=多边形拟合(
[$x1,$y1],$x2,$y2],$x3,$y3],…],
$fit_订单,
)
或死亡(“错误”);
或者,如果您喜欢使用并行阵列作为输入

sub-poly_-fit{
我的($x\u vals,$y\u vals,$fit\u order)=@;
@$x_vals==@$y_vals
或croak(“X VAL和Y VAL数量不匹配”);
...
my$n=@$x_vals;
my$x_vals=包装(“d$n”,@$x_vals);
my$y_vals=包装(“d$n”,@$y_vals);
...
}
my($coef,$fit\u vals,$r\u squared)=多边形拟合(
[$x1,$x2,$x3,…],
[$y1,$y2,$y3,…],
$fit_订单,
)
或死亡(“错误”);

注释

在编写上述代码时,我认为指定除
\uu stdcall
之外的调用约定需要切换到Win32:API的原型语法。但我错了。我本可以使用以下方法:

使用常量PTR\u WIN32API\u TYPE=>
PTR_尺寸==8?'Q'
:PTR_大小==4?'不
:die(“无法识别的ptrsize\n”);
$PolyFit=Win32::API::更多->新建(
$dll,'PolyFit','PPiPPP'=~s/P/PTR\u WIN32API\u TYPE/ger,'i','uu\cdecl')
Win32::API的原型解析器非常蹩脚。当它看到
const double*xVals@echo off
gcc -Wall -Wextra -pedantic -c -DPOLYFITGSL_EXPORTS a.c & gcc -shared -o a.dll a.o -Wl,--out-implib,liba.a & perl a.pl