Delphi 调用 C++动态库的参数问题

weixin_38409885 2018-08-24 09:38:26
我是初学者,希望得到大家的帮助,先谢谢了!


C++ 动态库中定义了两个结构体:
struct AteData
{
USHORT *pBuff = NULL;
USHORT nFrm = 0;
USHORT nr = 0;
USHORT nc = 0;
float k = 0;
float bias = 0;
};

struct AteResultData
{
USHORT nFrm = 0;
USHORT nr = 0;
USHORT nc = 0;
double *pBuff = NULL;
};
并定义了如下两个接口函数:
int __stdcall AteLoadData(char *fileName, AteData &oriData);
//其中 fileName 输入文件名,oriData,返回从文件中解析出来的数据

int __stdcall AtePPT(const AteData *ateInputData, AteResultData *ampData, AteResultData *phaData);//
//其中 ateInputData 为 AteLoadData 函数返回的 oriData,其它两个参数为本函数返回的内容。


Delphi XE 中应该如何声明并调用这两个函数?
...全文
547 34 打赏 收藏 转发到动态 举报
写回复
用AI写文章
34 条回复
切换为时间正序
请发表友善的回复…
发表回复
BlueStorm 2018-09-13
  • 打赏
  • 举报
回复
我的10.2.2版本默认是OFF的。
BlueStorm 2018-09-13
  • 打赏
  • 举报
回复
PByte也是默认支持的
  • 打赏
  • 举报
回复
我印象从D2009开始指针运算默认是ON,之前版本只有PChar/PAnsiChar支持指针运算

BlueStorm 2018-09-12
  • 打赏
  • 举报
回复

type
TAteResultData =record
nFrm : Word;
nr : Word;
nc : Word;
{$POINTERMATH ON}
pBuff: ^double;
{$POINTERMATH OFF}
end;
//你就可以用dMax := ampData.pBuff[i]这种方式了。
weixin_38409885 2018-09-07
  • 打赏
  • 举报
回复
好的。谢谢 BlueStorm 和 早打大打打核战争 两位!

结贴了。
  • 打赏
  • 举报
回复
直接cast一下就可以了:dMax := TArray<double>(ampData.pBuff)[i];
weixin_38409885 2018-09-07
  • 打赏
  • 举报
回复
引用 26 楼 BlueStorm 的回复:
^double改为array of double是不合适的, 因为array of double是动态数组,不是静态数组。
对于pBuff: array of double来说,pBuff并 不等于@pBuff[0]
而pBuff: array[0..100] of double来说,pBuff=是等于@pBuff[0]的

最好还是用^double


再问个低级问题:
我原来是这样调用的:dMax := ampData.pBuff[i];
pBuff 改成 ^Double 后,上面这句应该怎么写了?
  • 打赏
  • 举报
回复
TAteResultData =record
nFrm : Word;
nr : Word;
nc : Word;
pBuff: array of double; //这里有修改
end;

这么修改是有隐患的,pBuff应该是用于返回数据,C++端会修改这个指针,Delphi端如果只读数据(元素)没问题,如果修改动态数组,比如SetLength,或者动态数组间赋值,就会出现异常。
weixin_38409885 2018-09-05
  • 打赏
  • 举报
回复
我的工程好像是Delphi 7创建的,没看到有字节对齐的信息。现在直接用 Delphi XE 修改编译。
weixin_38409885 2018-09-05
  • 打赏
  • 举报
回复
现已正常,谢谢各位的帮助!
最终,我修改后的代码如下:
//定义
type
TAteData = record
pBuff:^Word;
nFrm : Word;
nr : Word;
nc : Word;
k : Single;
bias : Single;
end;
PAteData = ^TAteData; //这句是新增的。

TAteResultData =record
nFrm : Word;
nr : Word;
nc : Word;
pBuff: array of double; //这里有修改
end;

function AteLoadData(FileName: PAnsiChar; var OriData: TAteData): Integer;
stdcall; external 'YourDLL.dll'; //这里有修改,FileName 的类型改了
function AtePPT(const AteInputData: PAteData; var AmpData: TAteResultData;
var PhaData: TAteResultData): Integer; stdcall; external 'YourDLL.dll'; //这里有修改,第一个参数的类型改了


是这样调用的:
oriData: TAteData;
ampData, phaData: TAteResultData;

result := AteLoadData(PAnsiChar(sFileName), oriData);
result := AtePPT(@oriData, ampData, phaData);

如果各位没有其它补充,那就本周末结贴。To: BlueStorm
weixin_38409885 2018-09-05
  • 打赏
  • 举报
回复
引用 18 楼 BlueStorm 的回复:
我用Delphi XE试了一下,两个record结构体的长度是20和12,应该是你用了packed record或者指定了{$A1}才导致了长度只用18和10。
实际上Delphi默认的对齐方式是A8(8-Byte对齐), 在此方式下那两个record结构体的长度就是20和12。


我就是直接用你写的代码,没有加其它东西。我的是32位 WinXP系统,不知道有没有关系。
BlueStorm 2018-09-05
  • 打赏
  • 举报
回复
C函数返回的pBuff是指向静态数组,不是动态数组。
BlueStorm 2018-09-05
  • 打赏
  • 举报
回复
^double改为array of double是不合适的, 因为array of double是动态数组,不是静态数组。
对于pBuff: array of double来说,@pBuff=并 不等于@pBuff[0]
而pBuff: array[0..100] of double来说,@pBuff=是等于@pBuff[0]的

最好还是用^double
BlueStorm 2018-09-05
  • 打赏
  • 举报
回复
^double改为array of double是不合适的, 因为array of double是动态数组,不是静态数组。
对于pBuff: array of double来说,pBuff并 不等于@pBuff[0]
而pBuff: array[0..100] of double来说,pBuff=是等于@pBuff[0]的

最好还是用^double
weixin_38409885 2018-09-05
  • 打赏
  • 举报
回复
引用 22 楼 DelphiGuy 的回复:
TAteResultData =record
nFrm : Word;
nr : Word;
nc : Word;
pBuff: array of double; //这里有修改
end;

这么修改是有隐患的,pBuff应该是用于返回数据,C++端会修改这个指针,Delphi端如果只读数据(元素)没问题,如果修改动态数组,比如SetLength,或者动态数组间赋值,就会出现异常。


pBuff 是返回的数据,内存空间是动态库里分配的,我只读取不修改。这样改成Double型数组,我外面调用时方便。
weixin_38409885 2018-09-05
  • 打赏
  • 举报
回复
20楼的代码有错误(复制源头错了)。
最终,我修改后的代码如下:
//定义
type
TAteData = record
pBuff:^Word;
nFrm : Word;
nr : Word;
nc : Word;
Tmp: Word; //没任何意义,仅仅是为了字节对齐
k : Single;
bias : Single;
end;
PAteData = ^TAteData; //这句是新增的。

TAteResultData =record
nFrm : Word;
nr : Word;
nc : Word;
Tmp: Word; //没任何意义,仅仅是为了字节对齐
pBuff: array of double; //这里有修改
end;

function AteLoadData(FileName: PAnsiChar; var OriData: TAteData): Integer;
stdcall; external 'YourDLL.dll'; //这里有修改,FileName 的类型改了
function AtePPT(const AteInputData: PAteData; var AmpData: TAteResultData;
var PhaData: TAteResultData): Integer; stdcall; external 'YourDLL.dll'; //这里有修改,第一个参数的类型改了


是这样调用的:
oriData: TAteData;
ampData, phaData: TAteResultData;

result := AteLoadData(PAnsiChar(sFileName), oriData);
result := AtePPT(@oriData, ampData, phaData);

如果各位没有其它补充,那就本周末结贴。To: BlueStorm
BlueStorm 2018-08-30
  • 打赏
  • 举报
回复
我用Delphi XE试了一下,两个record结构体的长度是20和12,应该是你用了packed record或者指定了{$A1}才导致了长度只用18和10。
实际上Delphi默认的对齐方式是A8(8-Byte对齐), 在此方式下那两个record结构体的长度就是20和12。
  • 打赏
  • 举报
回复
{$A4}
type
TAteData = record
// ...
weixin_38409885 2018-08-29
  • 打赏
  • 举报
回复
应该是字节对齐问题吧?
那么 Delphi XE 应该怎么做才能把字节数提到 20 和 12 呢?
weixin_38409885 2018-08-29
  • 打赏
  • 举报
回复
VS2013 里,单个分别求 unsigned short *、unsigned short、float、double *的长度,结果分别是 4、2、4、4。这样的话,AteData 各变量长度之和: 4 + 2 + 2+ 2 + 4 + 4 =18,为什么 sizeof(AteData) 求出来会是 20 呢?
加载更多回复(14)

16,748

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 语言基础/算法/系统设计
社区管理员
  • 语言基础/算法/系统设计社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧