问个关于DLL内存拷贝的问题

mdejtod 2009-09-04 05:48:26
RT,在DLL中定义一个结构体
TBusinessData = packed reocrd
FSevice : char[0..50];
FStyle : char[0..50];
FPrice : integer;
FYear : Word;
FMoney : Doubel;
end;
TReportData = array of TBusinessData ;
PReportData = ^TReportData;
然后定义一函数,原型是:
function GetReportData(nStart,nEnd : TSYSTEMTIME;var aCount : integer) : pointer ;Export;Stdcall;
var pData : PReportData;
begin
//acount 为查询得到的记录数
GetMem(pData,Sizeof(TBusinessData ) * acount);
Setlength(TReportData(pData^),acount);
for i := low(TReportData(pData^)) to high(TReportData(pData^)) do
begin
with TReportData(pData^)[i] do
begin
lstrcpy(FSevice,pchar('测试'));
.
.
.
end;
end;
result := pdata;
end;

然后我在DLPHI里面可以调用,并且能够从返回的指针中正确的取出所有值,但是VC调用时,它返回的值都是乱码
如果在DLL中只返回一个结构体指针,那也可以正确的获取结构体指针中的数据,一旦改为上面这种方式就不行了,不知道什么原因!!!!!
...全文
246 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
sanguomi 2009-09-06
  • 打赏
  • 举报
回复
str.Format("Äê%d,ÔÂ%d,ÈÕ%d,±àºÅ%s,·þÎñÀàÐÍ%s",pBData[i].FYear,pBData[i].FMonth,pBData[i].FDay,pBData[i].FFrameId,pBData[i].FSevic);
//不知道打印字符串的函数是啥 -_-....
打印函数用MFC 函数 afxMessagebox 或者API MessageBox都可以
mdejtod 2009-09-06
  • 打赏
  • 举报
回复
贴出代码给大家参考一下,以免大家以后遇到同样的问题!
Dll代码:

library GetData;
uses
SysUtils,
Windows,
Classes;
type
TBusinessData = packed record
FYear : Word;
FMonth : Word;
FDay : Word;
FFrameId : array[0..19] of Char;
FSevice : array[0..9] of Char;
end;
PBusinessData = ^TBusinessData;
TBlah = array[0..0] of TBusinessData;
PBlah = ^TBlah;
{$R *.res}
function GetReportData(nStart : TSystemTime;nEnd : TSystemTime; var pData : PBlah ) : Integer; export; stdcall;
var i : Integer;
FData : array of TBusinessData;
begin
SetLength(FData,5);
GetMem(pData, SizeOf(pData^) * 5) ;
for i := Low(FData) to High(FData) do
begin
with FData[i] do
begin
FYear := 2009 + i ;
FMonth := 8 + i;
FDay := 3 + I;
lstrcpy(FSevice,PChar('FSevice'));
lstrcpy(FFrameId,PChar('FFrameId' + IntToStr(I)));
end;
end;
CopyMemory(pData,@FData[0],SizeOf(pData^) * 5);
Result := 5;
end;
exports GetReportData;

begin

end.

//delphi中的调用方法:
数据结构与DLL中定义一样,装载DLL代码就不写了,
type
TFunc_GetReportData = function(nStart : TSystemTime;nEnd : TSystemTime; var pData : PBlah ) : Integer; stdcall;
var
Func_GetReportData : TFunc_GetReportData;
procedure TForm1.btn1Click(Sender: TObject);
var nStart, nEnd : TSystemTime;
pData : PBlah;
aCount : Integer;
i : Integer;
begin
pData := nil;
aCount := Func_GetReportData(nStart,nEnd,pData);
for i := 0 to aCount - 1 do
begin
ShowMessage(TBlah(pData^)[i].FFrameId);
end;
end;


以下是VC的代码

HINSTANCE dllTest;
typedef struct TBusinessData
{
WORD FYear;
WORD FMonth;
WORD FDay;
char FFrameId[20];
char FSevic[10];
}_TBusinessData;

typedef int(_stdcall *GetData)(SYSTEMTIME nStart,SYSTEMTIME nEnd,TBusinessData** pData);

void CTetDlg::OnOK()
{
dllTest=LoadLibrary("GetData.dll");
GetData pGetData;
SYSTEMTIME s,e;
memset(&s,0,sizeof(s));
memset(&e,0,sizeof(e));
s.wYear = 2009;s.wMonth = 8; s.wDay = 3;
e.wYear = 2009;e.wMonth = 9; e.wDay = 3;
pGetData = (GetData)GetProcAddress (dllTest,"GetReportData");
TBusinessData* aData;
int iRecordCount;
CString str;
iRecordCount = pGetData(s,e,&aData);
TBusinessData* pBData = (TBusinessData*)(*&aData);
for(int i = 0; i < iRecordCount ; i ++)
str.Format("Äê%d,ÔÂ%d,ÈÕ%d,±àºÅ%s,·þÎñÀàÐÍ%s",pBData[i].FYear,pBData[i].FMonth,pBData[i].FDay,pBData[i].FFrameId,pBData[i].FSevic);
//不知道打印字符串的函数是啥 -_-....
FreeLibrary(dllTest);

mdejtod 2009-09-06
  • 打赏
  • 举报
回复
谢谢楼上的指点,VC成功返回DLL中的值!!谢谢!!!
Seamour 2009-09-06
  • 打赏
  • 举报
回复
有啥不明白的啊,GetMem(pData, SizeOf(pData^) * count)之后pData就不是nil了啊
另外你的接口也够混乱的了
你的 LPFNDLLFUNC1 到底是要定义成
typedef int(callback* LPFNDLLFUNC1)(SYSTEMTIME, SYSTEMTIME, TBusinessData*);
还是
typedef int(callback* LPFNDLLFUNC1)(SYSTEMTIME, SYSTEMTIME, TBusinessData**);

假设在delphi中定义了
PBusinessData = ^TBusinessData;
TBlah = array[0..0]of TBusinessData;
PBlah = ^TBlah;
那么前者对应的delphi声明是
function(st1, st2: SYSTEMTIME; p: PBlah);
或者 p: PBusinessData / var blah: TBlah / var blah: TBusinessData
后者则是:
function(st1, st2: SYSTEMTIME; var p: PBlah);

你要是把该传 TBusinessData** 写成了 TBusinessData*,还是自己好好琢磨一下到底传来传去的都变成什么了吧
mdejtod 2009-09-06
  • 打赏
  • 举报
回复
谢谢。。。明天再试
xiaoxiao_8 2009-09-06
  • 打赏
  • 举报
回复
改为这样试试:
result:=@TReportData(pData^)[0];
mdejtod 2009-09-06
  • 打赏
  • 举报
回复
还是不太明白。顶起来,
直接用 GetMem(pData, SizeOf(pData^) * count) 分配,pData^[index]访问
传进来的时候,这个pData是为nil的.....
mdejtod 2009-09-05
  • 打赏
  • 举报
回复
谢谢楼上的,那我该怎么改呢?
阿呆_ 2009-09-05
  • 打赏
  • 举报
回复
关键的vc的调用代码没贴出来。 不过估计楼主和前面各位都没有注意到一个问题:
TReportData = array of TBusinessData;
这里的TReportData其实是个指针而不是一个数组类型
(注意:它和TReportData = array [0..0] of TBusinessData;完全是两码事, 后者的TReportData才是一个数组类型),所以PReportData是指向一个指针的指针。
估计问题就出在这里吧。 Delphi中xxx.yyy中的'.'操作符即是取指针指向内容的操作符又是取结构内容的操作符即合并了c/c++中的'.'和'->'操作,估计这就是c/c++调用失败而delphi调用可以成功的原因,其实是delphi自动将PReportData(...).xxx的代码转成了PReportData(...)^.xxx
mdejtod 2009-09-05
  • 打赏
  • 举报
回复
看来还是不行,我DLL中的结构体的packed去掉,并且只有三个word类型变量,结果只要是返回的还是乱码,如果是这样,则可以正确的读到值
var FData : TBusinessData ;
pData : PReportData ;
begin
acount := 1;
GetMem(pData,Sizeof(TBusinessData ) * acount);
Setlength(TReportData(pData^),acount);
with FData do
begin
lstrcpy(FSevice,pchar('测试'));
.
.
.
end;
copymemory(pData,@FData,Sizeof(TBusinessData ) * acount);
result := pdata;
end;

也就是说,如果返回的只是一个指向一个结构体的指针,那它不管是否字对齐,都可以正常读取值,如果是一个指向数组的指针,就算这个数组只有一个元素,那就会有乱码。。。如以下代码

function GetReportData(nStart,nEnd : TSYSTEMTIME;var aCount : integer) : pointer ;Export;Stdcall;
var pData : PReportData;
begin
//acount 为查询得到的记录数
GetMem(pData,Sizeof(TBusinessData ) * acount);
Setlength(TReportData(pData^),acount);
for i := low(TReportData(pData^)) to high(TReportData(pData^)) do
begin
with TReportData(pData^)[i] do
begin
lstrcpy(FSevice,pchar('测试'));
.
.
.
end;
end;
还特地进行内在拷贝一次,结果还是乱码
GetMem(result,Sizeof(TBusinessData ) * acount);
Setlength(TReportData(result^),acount);
copymemory(result,pData,Sizeof(TBusinessData ) * acount);
freemem(pData,Sizeof(TBusinessData ) * acount);
end;
哪位高人帮忙测试一下?这些写法,用DELPHI来调用的话,怎么取都是正常的。。
Seamour 2009-09-05
  • 打赏
  • 举报
回复
11楼已经说了,array[0..0]of T
直接用 GetMem(pData, SizeOf(pData^) * count) 分配,pData^[index]访问
starluck 2009-09-05
  • 打赏
  • 举报
回复
#pragma pack(1)

应该是按1个字节对齐,如果你确定用 package

在通讯的时候我们经常会用通过增加字段达到四字节的对齐,当然设计结构前期就要注意了。
mdejtod 2009-09-05
  • 打赏
  • 举报
回复
贴上DLL的函数原型和数据结构
TBusinessData = packed reocrd
FSevice : char[0..50];
FStyle : char[0..50];
FPrice : integer;
FYear : Word;
FMonth : word;
FDay : word;
FMoney : Doubel;
end;
TReportData = array of TBusinessData ;
PReportData = ^TReportData;
然后定义一函数,原型是:
function GetReportData(nStart,nEnd : TSYSTEMTIME;var pData : pointer ) : integer; Export;Stdcall;
begin
//acount 为查询得到的记录数
GetMem(pData,Sizeof(TBusinessData ) * acount);
Setlength(TReportData(pData^),acount);
for i := low(TReportData(pData^)) to high(TReportData(pData^)) do
begin
with TReportData(pData^)[i] do
begin
lstrcpy(FSevice,pchar('测试'));
.
.
.
end;
end;
result := acount ;
end;


以下是VC的调用代码
typedef int(callback* LPFNDLLFUNC1)(SYSTEMTIME nStart,SYSTEMTIME nEnd,TBusinessData*);
LPFNDLLFUNC1 lpfnDllFunc1;
lfpnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(dllTest,"GetReportData");
SYSTEMTIME s,e;
memset(&s,0,Sizeof(s));
memset(&e,0,sizeof(e));
s.wYear = 2009;s.wMonth = 8; s.wDay = 3;
e.wYear = 2009;e.wMonth = 9; e.wDay = 3;
TBusinessData* aReportData = new TBusinessData[];
TBusinessData* pData;
int iRecordCount;
iRecordCount = lpfnDllFunc1(s,e,&pData);//aReportData 传入,取出来的也是乱码
TBusinessData* pBData = (TBusinessData*)&pData;
for(i = 0; i < iRecordCount ; i ++)
str.Format("年%d,月%d,日%d",pBData[i].FYear,pBData[i].FMonth,pBData[i].FDay);
pBData[i]里面的东西全是乱码......
mdejtod 2009-09-04
  • 打赏
  • 举报
回复
谢谢,明天再试了,自己电脑上没代码....
sanguomi 2009-09-04
  • 打赏
  • 举报
回复
怀疑字节对奇问题,你在结构体内就放一个整型,测试你调用方法有没问题
mdejtod 2009-09-04
  • 打赏
  • 举报
回复
在DELPHI中,动态调用没有任何问题,在VC中也是动态调用,估计是结构体字对齐方面出的问题!!
mdejtod 2009-09-04
  • 打赏
  • 举报
回复
在DELPHI中,动态调用没有任何问题,在VC中也是动态调用,估计是结构体字对齐方面出的问题!!
mdejtod 2009-09-04
  • 打赏
  • 举报
回复
谢谢楼上的,明天试下,由于对VC不熟悉,自己搞了半天还是不行,测试了一下结构体的长度,在D中占332字节,在VC中占336字节,我加上#pragma pack(4)后还是不行,不太明白怎么用
另外,改为输出参数的试过了,也一样,不知道这两种方法有何区别。。。。
gyk120 2009-09-04
  • 打赏
  • 举报
回复
VC的指针和Delphi有点区别,用动态加载调用这个函数会出错吗?
sanguomi 2009-09-04
  • 打赏
  • 举报
回复
返回指针感觉不是个好办法,你把它改成参数方式(指针或者引用)好点
加载更多回复(1)

16,748

社区成员

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

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