delphi调用c++做的dll,涉及到联合体union,请帮我诊断一下。谢! ( 积分: 100 )

  • 主题发起人 主题发起人 coolnerd
  • 开始时间 开始时间
C

coolnerd

Unregistered / Unconfirmed
GUEST, unregistred user!
一个c++做的someName.dll中,有一个函数原型如下:
int GetRealData(int type, PRealData pRD, int num);

其中,第二个参数PRealData定义如下:
typedef struct tagRealData {
BYTE ID1;
BYTE ID2;
USHORT ID3;
union {
float YCValue

int YXValue;
double DDValue;
char unuse[8]

};
} RealData, *PRealData;

该函数的作用是通过传入3个ID(ID1,ID2,ID3),将需要的结果放在上述的联合体中,具体到我的实际中,只会用到YCValue.

我在Delphi中是调用过程如下,但不能取到正确的结果.请帮我诊断一下,谢谢!

unit Unit1;

interface

uses
...;

type
TYCData = packed record
ID1 : Byte;
ID2 : Byte;
ID3 : Word;
case Integer of
0:(YCValue : Single);
1:(YXValue : Integer);
2:(DDValue : Real);
3:(unuse : array[0..7] of char);
end;

type
TFrmMain = class(TForm)
...
private
procedure Button1Click(Sender: TObject);
public
{ Public declarations }
end;

var
FrmMain: TFrmMain;
function GetRealData(typeid:Integer;pRD:TYCData;num:Integer):Integer
Stdcall
external 'someName.dll';

implementation

{$R *.dfm}

procedure TFrmMain.Button1Click(Sender: TObject);
var
thisID1,thisID2:Byte;
thisID3:Integer;
t_Data:TYCData;
returnInt:Integer;
begin
thisID1:=1;
thisID2:=1;
thisID3:=1;
FillChar(t_Data, Sizeof(t_Data), 0);
try
t_Data.ID1 :=thisID1;
t_Data.ID2 :=thisID1;
t_Data.ID3 :=thisID1;
returnInt:=GetRealData(0,t_Data,1)
//前后两个参数是常量,没有问题
showmessage(format('%f',[t_Data.YCValue]))
//为什么不能返还正确的值?
except
on E: Exception do
showmessage('调用出错:'+E.Message);
end;
end;

...

end.
 
一个c++做的someName.dll中,有一个函数原型如下:
int GetRealData(int type, PRealData pRD, int num);

其中,第二个参数PRealData定义如下:
typedef struct tagRealData {
BYTE ID1;
BYTE ID2;
USHORT ID3;
union {
float YCValue

int YXValue;
double DDValue;
char unuse[8]

};
} RealData, *PRealData;

该函数的作用是通过传入3个ID(ID1,ID2,ID3),将需要的结果放在上述的联合体中,具体到我的实际中,只会用到YCValue.

我在Delphi中是调用过程如下,但不能取到正确的结果.请帮我诊断一下,谢谢!

unit Unit1;

interface

uses
...;

type
TYCData = packed record
ID1 : Byte;
ID2 : Byte;
ID3 : Word;
case Integer of
0:(YCValue : Single);
1:(YXValue : Integer);
2:(DDValue : Real);
3:(unuse : array[0..7] of char);
end;

type
TFrmMain = class(TForm)
...
private
procedure Button1Click(Sender: TObject);
public
{ Public declarations }
end;

var
FrmMain: TFrmMain;
function GetRealData(typeid:Integer;pRD:TYCData;num:Integer):Integer
Stdcall
external 'someName.dll';

implementation

{$R *.dfm}

procedure TFrmMain.Button1Click(Sender: TObject);
var
thisID1,thisID2:Byte;
thisID3:Integer;
t_Data:TYCData;
returnInt:Integer;
begin
thisID1:=1;
thisID2:=1;
thisID3:=1;
FillChar(t_Data, Sizeof(t_Data), 0);
try
t_Data.ID1 :=thisID1;
t_Data.ID2 :=thisID1;
t_Data.ID3 :=thisID1;
returnInt:=GetRealData(0,t_Data,1)
//前后两个参数是常量,没有问题
showmessage(format('%f',[t_Data.YCValue]))
//为什么不能返还正确的值?
except
on E: Exception do
showmessage('调用出错:'+E.Message);
end;
end;

...

end.
 
你可以DUMP数据出来.比对一下,自然可以清楚地了解,然后在确定兼容的数据类型(似乎是正确的翻译,除了real不推荐)
 
在结构体中最好不要传递 float 型,
最好直接传递 double ,
因为非双精度型在不同的语言中,存储的格式可能是不同的,
CPU本身并不支持这种类型,
是一种被淘汰了的类型,计算效率远远低于 double 型
 
搂住的函数翻译的不对
//结构还是翻译到这个比较明了
type
tagRealData = record
ID1: Byte;
ID2: Byte;
ID3: Word;
case Integer of
0: (YCValue: Single);
1: (YXValue: Integer);
2: (DDValue: Double);
3: (unuse: array[0..7] of char);
end;
RealData = tagRealData;
PRealData = ^RealData;
//楼主注意到没有C++函数里面第二个参数是指针,也可以说是按地址传值.
//可以翻译到这两种形式

//形式1,传递一个指针
Function GetRealData1(AType:Integer;pRD: PRealData;num:Integer):Integer
Stdcall
external 'someName.dll';
//形式2,按地址传递
Function GetRealData2(AType:Integer;var pRD: RealData;num:Integer):Integer
Stdcall
external 'someName.dll';

//不过这两种本质是一样的
 
//pRD:应该是指针类型

function GetRealData(typeid:Integer;pRD:^TYCData;num:Integer):Integer
Stdcall
external 'someName.dll';

procedure TFrmMain.Button1Click(Sender: TObject);
var
thisID1,thisID2:Byte;
thisID3:Integer;
t_Data:^TYCData;
returnInt:Integer;
begin
thisID1:=1;
thisID2:=1;
thisID3:=1;
new(t_Data)
//add
try
begin
FillChar(t_Data, Sizeof(t_Data), 0);
try
t_Data.ID1 :=thisID1;
t_Data.ID2 :=thisID1;
t_Data.ID3 :=thisID1;
returnInt:=GetRealData(0,t_Data,1)
//前后两个参数是常量,没有问题
showmessage(format('%f',[t_Data.YCValue]))
//为什么不能返还正确的值?
except
on E: Exception do
showmessage('调用出错:'+E.Message);
end;
end
finally
destroy(t_Data);
end;
end;
 
//in vc++

#pragma pack(push)
#pragma pack(1)
typedef struct tagRealData {
BYTE ID1;
BYTE ID2;
USHORT ID3;
union {
float YCValue

int YXValue;
double DDValue;
char unuse[8]

};
} RealData, *PRealData;
#pragma pack(pop)



//in delphi

type
TYCData = packed record
ID1 : Byte;
ID2 : Byte;
ID3 : Word;
case Integer of
0:(YCValue : Single);
1:(YXValue : Integer);
2:(DDValue : Real);
3:(unuse : array[0..7] of char);
end;
 
呵呵,确实是函数声明问题.还觉得奇怪呢
 
to wr960204:你好,谢谢你的讲解,那后面的程序该如何调用这个函数呢? 烦请在我上面的程序上修改一下.

to wqyzsh: 按你写的function GetRealData typeid:Integer;pRD:^TYCData;num:Integer):Integer
Stdcall
external 'someName.dll';编译报错: Identifier expected but '^' found.

to iamy: 你写的delphi翻译结构,好像和我的一样啊,有什么区别么?倒是c++的写法和我拿到几乎一模样.
 
//形式1,传递一个指针
Function GetRealData(AType:Integer;pRD: PRealData;num:Integer):Integer
Stdcall
external 'someName.dll';
//形式2,按地址传递
Function GetRealData(AType:Integer;var pRD: RealData;num:Integer):Integer
Stdcall
external 'someName.dll';

按照我上面生命的函数形式
t_Data.ID1 :=1;
t_Data.ID2 :=1;
t_Data.ID3 :=1;
如果你采用的是方案1
returnInt:=GetRealData(0,@t_Data,1)

如果你采用的是方案2
returnInt:=GetRealData(0,t_Data,1)

showmessage(format('%f',[t_Data.YCValue]))

还要注意你的C++函数是不是stdcall调用约定的,如果不是的话Delphi也要相应修改为一样的约定.
 
好像没问题,悄悄地说,是不是要先GetMem(pRD, sizeof(RealData))一下
 
谢谢各位的回复,特别是wr960204、wqyzsh。但问题似乎还是没有解决。索性我把问题再说的细一点,请大家给个完整的解答。
MSN:coolnerdXP[at]hotmail.com
Mail:guo.dehua[at]126.com
今日解决,酬劳100元,谢谢。

to wr960204: 如果你还能看到帖子,希望你能联系我,谢谢!

有一个C++(VC4)编译出来的DLL,现在需要用Delphi编写程序通过调用此Dll,获取一些数据。
我初步做了一下,但有些问题,调用一次,程序就会自己死掉了。
请熟悉Delphi调用Dll(C++做的)的朋友帮忙看一下。

//++++++++++++++++++++++++
// C++中的相关定义
//++++++++++++++++++++++++

//同名头文件:GetRealDataCall.h
//====================================================================
// 访问实时库所用数据结构
#pragma pack (push)
#pragma pack (1)
typedef struct tagRealData {
BYTE ID1;
BYTE ID2;
USHORT ID3;
union {
float YCValue;
int YXValue;
double DDValue;
char unuse[8];
};
} RealData, *PRealData;

#pragma pack (pop)

// 调用初始化
BOOL GetRDCallInit(char *szModuleName); // szModuleName 为模块名
// 调用退出
BOOL GetRDCallExit();

//获取数据
int GetRealData(int type, PRealData pRD, int num);
//======================================================================

函数GetRealData的作用是通过传入3个ID(ID1,ID2,ID3),将取到的结果放在上述的联合体中,具体到我的实际中,只会用到YCValue.

我在Delphi中是调用过程如下,但不能取到正确的结果.请帮我诊断一下,谢谢!


//++++++++++++++++++++++++++++++
// 目前Delphi中关于它的调用
//++++++++++++++++++++++++++++++

unit Unit1;

interface

uses
...;

type
TYCData = packed record
ID1 : Byte;
ID2 : Byte;
ID3 : Word;
case Integer of
0:(YCValue : Single);
1:(YXValue : Integer);
2:(DDValue : Real);
3:(unuse : array[0..7] of char);
end;

type
TFrmMain = class(TForm)
...
private
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
public
{ Public declarations }
end;

var
FrmMain: TFrmMain;
//目前这样申明的
function GetRealData(typeid:Integer;var pRD:TYCData;num:Integer):Integer
Stdcall
external 'GetRealDataCall.dll';

implementation

{$R *.dfm}


procedure TFrmMain.FormCreate(Sender: TObject);
begin
try
//向服务器进行注册模块
if not GetRDCallInit(pchar('FORECAST_00G')) then begin //这个是调用成功的。可以验证
showmessage('注册模块名【FORECAST_00G】失败');
end;
except
on E: Exception do begin
showmessage('注册模块名出错:'+E.Message);
end;
end;
end;

procedure TFrmMain.FormDestroy(Sender: TObject);
begin
try
//注销模块名称
GetRDCallExit()
//这个是调用成功的。可以验证
except
//on E: Exception do
end;
end;

procedure TFrmMain.Button1Click(Sender: TObject);
var
thisID1,thisID2:Byte;
thisID3:Integer;
t_Data:TYCData;
returnInt:Integer;
begin
thisID1:=1;
thisID2:=1;
thisID3:=1;
FillChar(t_Data, Sizeof(t_Data), 0);
try
t_Data.ID1 :=thisID1;
t_Data.ID2 :=thisID1;
t_Data.ID3 :=thisID1;
returnInt:=GetRealData(0,t_Data,1)
//前后两个参数是常量,没有问题
showmessage(format('%f',[t_Data.YCValue]))
//为什么上述调用,有问题呢?
except
on E: Exception do
showmessage('调用出错:'+E.Message);
end;
end;

...

end.
 
谢谢大家。
 
我怀疑你C++函数的调用约定不是stdcall.不知道你C++函数加了__stdcall修饰符没有?
可以联系我
QQ:42088303
 
天哪!好久没有用QQ了。我居然找不到从哪里添加好友了。请你加我吧:QQ:112622765
 
后退
顶部