一个关于dll的简单问题已接近解决,再加110分共260分酬谢(110)

  • 主题发起人 主题发起人 laowt
  • 开始时间 开始时间
L

laowt

Unregistered / Unconfirmed
GUEST, unregistred user!
http://www.delphibbs.com/delphibbs/dispq.asp?lid=3992430上帖,我现在有一个dll的vc创建新应用程序的说明,delphi中如何调用?得到dark_power请帮助,不过问题还没有解决。 现在我找到了调用该dll的vb程序代码,已编辑通过,贴出来供各位分析,看如何改成delphi的代码(上帖给热心的dark_power70分,加上本帖100分,给出代码能通过的可得190分),谢谢!Option Explicit'以下是ABCD_DLL的函数定义Private Declare Sub ABCD_Init Lib "ABCD_dll.dll" ()Private Declare Function ABCD_Read Lib "ABCD_dll.dll" () As LongPrivate Declare Sub ABCD_Write Lib "ABCD_dll.dll" (ByVal port As Long)Private Sub Command1_Click() ABCD_Write (Val(Text1.Text))End SubPrivate Sub Command2_Click() Text1.Text = ABCD_ReadEnd Sub
 
申明的过程与函数名必须与dll中导出的一致,并且区分大小写的。如果你不知道你的dll导出的函数名字可以用eXeScope查看此dll得到导出的正确函数名。按照你给出的C的例子,改出如下代码:procedure abcd_Init(); cdecl; external 'ABCD_dll.dll';function abcd_Read(var data1, data2, data3: Pbyte): Longint; cdecl; external 'ABCD_dll.dll';procedure abcd_Write(var data1, data2, data3: Pbyte); cdecl; external 'ABCD_dll.dll';按照你给出的VB例子,改成了如下代码:procedure ABCD_Init(); stdcall; external 'ABCD_dll.dll';function ABCD_Read(): Longint; stdcall; external 'ABCD_dll.dll';procedure ABCD_Write(var port: Longint); stdcall; external 'ABCD_dll.dll';
 
确实,我忘记提醒你有关大小写的问题了(因为我当这是理所当然的了,至少我在Delphi中依然使用大小写区别的命名和引用),因为C编译的内容是区分大小写的,所以,要导出的函数名必须大小写一致,而且external后的dll文件的大小写貌似也保持一致比较好,反正我没试过不一致的情况。也正因为如此我把dll文件名定义为常量串。另外,我觉得Vsun没必要在指针变量前再加var关键字,当我们传递指针并不期望修改指针本身(我是说修改指针指向的地址)时,所以我没加var。加了var可以使我们将指针指向新的内存位置,但这有时并非我们所期望的。
 
const ABCDdll = 'abcd_DLL.dll'; //一定要保证函数名的大小写与dll中的一致。procedure ABCD_Init; cdecl; external ABCDdll;//这里又冒出一个返回值了,正如Vsun说的,得改成function并加上返回值。function ABCD_Read(pData1, pData2, pData3: PByte) :Cardinal; cdecl; external ABCDdll;procedure ABCD_Write(pData1, pData2, pData3: PByte); cdecl; external ABCDdll;我不知道VB代码是怎么做到Read函数不需要任何输入就能读取数据并给出返回值的,至少我觉得他的做法是欠妥的。如果他能通过,那么Read函数(Delphi中的)就应该去掉所有参数,只保留返回值,形如:function ABCD_Read:Cardinal; cdecl; external ABCDdll;但这又和你在ABCD_DLL.h中给出的C++函数原型不符。
 
非常感谢各位!由于咱是业余爱好,只能下午回家实验,我看应该差不多了!弱弱的再问一下: 1、我知道函数function ABCD_Read(pData1, pData2, pData3: PByte) :Cardinal; cdecl; external ABCDdll; 可以加到implementation以下任一处地方; 2、procedure ABCD_Write... 和procedure ABCD_Init... 过程内容加入方法如上;而上边的声明,最好加在什么地方? 3、const ABCDdll = 'abcd_DLL.dll'; 还需要加吗,加到什么位置最好?
 
因为是函数导入,一般的是公共属性的,放在最外层的uses语句之后即可。Unit xxxuses yyy,zzz;//放在这里就可以了,但缺点/好处是——凡是引用这个单元的个体都可以调用这些函数。//如果不期望引用该单元的个体引用这些函数可以在implementation下声明。function ABCD_Init...procedure ABCD....对于第三个问题,因为你的导入声明中用了这个常量,所以必须声明它,而且要加在函数声明之前。
 
dark_power和Vsun,也许问题出在别处。我将0写入,显示成功,但读老是出错。用vb编译的程序读,发现数字变成16145628,而且无论写入什么信息,用vb编译的程序读都是16145628。
 
data1:=PChar(edit1.text) ; //data2:=nil; data3:=nil; ABCD_Write(Pbyte(data1));无论写入什么信息,用vb编译的程序读都是15621332。 这里问题可能出在Pbyte参数上
 
1、没想到这么一个简单问题居然挂了这么些天,[:(]2、弄清楚这个DLL的功能是什么,是否能正常工作。3、翻译是最简单的,但要找到正确的“原文”。 如果按照VB范例翻译,相应Delphi代码如下const ABCDdll = 'abcd_DLL.dll';procedure abcd_Init; stdcall; external 'ABCD_dll.dll';function abcd_Read: Integer; stdcall; external 'ABCD_dll.dll';procedure abcd_Write(port:Integer); stdcall; external 'ABCD_dll.dll';4、参考VB范例,你在调用abcd_Read,abcd_Write之前应该先调用abcd_Init。5、对应Delphi代码如下unit Unit3;interfaceuses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;type TForm3 = class(TForm) edPort: TEdit; btnRead: TButton; edValue: TEdit; btnWrite: TButton; procedure FormCreate(Sender: TObject); procedure btnReadClick(Sender: TObject); procedure btnWriteClick(Sender: TObject); private { Private declarations } public { Public declarations } end;var Form3: TForm3;implementation{$R *.dfm}const ABCDdll = 'abcd_DLL.dll';procedure abcd_Init; stdcall; external 'ABCD_dll.dll';function abcd_Read: Integer; stdcall; external 'ABCD_dll.dll';procedure abcd_Write(port:Integer); stdcall; external 'ABCD_dll.dll';procedure TForm3.btnReadClick(Sender: TObject);begin edValue.Text := IntToStr(abcd_Read);end;procedure TForm3.btnWriteClick(Sender: TObject);begin abcd_Write(StrToInt(edPort.Text));end;procedure TForm3.FormCreate(Sender: TObject);begin abcd_Init;end;end.6、没见过那个DLL,所以以上回复只是猜测,[:D]
 
tseug的第六句话和第一句话并在一起读的话,让人觉得非常有趣。而且,还声明了一个根本就没有使用的常量串。。。让人觉得有粘贴之嫌。。。哎,到底是以ABCD_DLL.h的头文件为准还是以 VB的dll函数导入代码为准?Read和Write函数根据 ABCD_DLL.h头文件,传入/传出的都是字节指针,传入的话,要事先申请足够的内存。通常,像写入字节这类问题,至少要给两个参数,一个是字节指针,一个是要写入的字节长度,你的Write函数确实比较强悍,只需要一个指针就搞定一切。像函数导入这类问题,我们只能保证帮你帮到让你可以正常调用外部函数(dll中的例程)。你也可以试一下,将参数前加var关键字,如果问题解决,说明是例程内部修改了指针;如果问题依旧,请找软件供应商(dll的发布者)询问,因为这应该是软件内部逻辑的问题。要么,干脆,你把你的ABCD_DLL.h的头文件,dll文件都发上来,我帮你调试一下看看。认识认识到底何方神圣,同一dll同一函数居然可以导出两种截然不同的声明。
 
tseug所说的第四句很重要.这个dll是有个初始化过程的,在使用前要先调用初始化过程的.4、参考VB范例,你在调用abcd_Read,abcd_Write之前应该先调用abcd_Init。还有一点,用C写的dll在D中调用申明的时候需使用 cdecl 而不是stdcall.
 
//abcd_DLL.h文件#include <windows.h>extern "C" __declspec(dllimport) void abcd_Init();extern "C" __declspec(dllimport) void abcd_Read(BYTE *data1,BYTE *data2,BYTE *data3);extern "C" __declspec(dllimport) void abcd_Write(BYTE data1,BYTE data2,BYTE data3);
 
既然已经声明ABCDdll = 'abcd_DLL.dll';三句中'ABCD_dll.dll';可替换掉同时在句中用cdecl 替换stdcall.
 
abcd_Write虽有问题还可用,abcd_Read函数一用就报错。
 
1、部分代码的确是粘贴后修改的2、说问题简单,是因为通常翻译的工作不需要动脑筋,纯粹一个体力活3、C语言写的DLL不一定都采用cdecl,也可以采用stdcall等方式4、如果这个DLL是设备厂家为二次开发提供的接口,那么通常会采用stdcall方式5、这个DLL声明采用了 __declspec(dllimport) 比较奇怪,一般来说不导出静态变量 是不需要这样做的6、如果想知道到底是VB范例正确还是C声明正确,要么查找文档,要么反汇编DLL看看
 
tseug和dark_power,如果你们有兴趣,给个Email我把dll发给你们
 
tseug(at)263.net,发个完整的包
 
建议你先去 http://www.schoolboy.com.cn/list.asp?ProdId=0001 看看
 
先按照文档说明用它的VC范例测试,应该确保工作正常
 
amazesam@gmail.com还没解决的话就发过来看看吧。
 
后退
顶部