delphi调用DLL中的函数,函数类型要一样吗?请大家看看

wzg1031 2007-05-21 09:20:53
情况如下:
用delphi做一DLL,里面有一输出函数;定义如下:
function GetMax: integer; stdcall;
实现代码:
function GetMax: Integer;
begin
Result := 100;
end;
工程文件:
library Project1;

uses
SysUtils,
Classes,
Unit1 in 'Unit1.pas' {Form1};

exports
GetMax;

{$R *.res}

begin
end.

调用DLL的代码如下:
procedure button1OnClick(sender: TObject);
var
a: function(b: PChar; c: boolean): Integer; // 此函数类型与DLL中定义的函数参数个数不一样,但调用没有问题,不知道是什么原因?
max: integer;
LibHandle: THandle;
begin
LibHandle := LoadLibrary('DLL路径'); // 成功
try
if LibHandle <> 0 then
begin
@a := GetProcAddress(LibHandle, 'GetMax'); // 取函数地址
max := a('',true); // 成功,取得100,为什么,DLL中定义的方法是没有参数的啊?
end;
finally
FreeLibrary(LibHandle);
end;
end;

请各位高手帮忙解释下,小弟搞不懂是什么原因,为什么只要函数名称和DLL中定义的函数名称相同,参数不一样都可以调用啊。
...全文
637 28 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
28 条回复
切换为时间正序
请发表友善的回复…
发表回复
liangpei2008 2007-05-24
  • 打赏
  • 举报
回复
学习ing..
lihuasoft 2007-05-24
  • 打赏
  • 举报
回复
//四个参数入栈,所以下一条指令偏移16个字节
--------------
应该说四个整型入栈. 另外, 上面的程序没有利用第四个参数Len. 不过应该可以人工控制了.
上面的程序, 函数中的RET指令, 已经越过了编译器给的RET指令, 直接返回.

^_^
lihuasoft 2007-05-24
  • 打赏
  • 举报
回复
终于明白了:

ret X //这个X就是所有通过栈传递的实参的长度和

例如:

function Test(a,b,c,Len: integer): integer; stdcall;//函数作用:返回前三个参数和
asm
mov ebp, esp
xor eax, eax
add eax, [ebp+$08]//第1个参数
add eax, [ebp+$0C]//第2个参数
add eax, [ebp+$10]//第3个参数,这三个参数累加到EAX做为返回值
pop ebp
ret 16 //四个参数入栈,所以下一条指令偏移16个字节
end;

procedure TForm1.Button1Click(Sender: TObject);
var
R : integer;
begin
R := Test(10,20,30,16);
ShowMessage(IntToStr(R));//60
end;
王集鹄 2007-05-24
  • 打赏
  • 举报
回复
返回值就是通过eax寄存器得到的
function f(): Integer;
begin
Result := $1234;
end;
//...
var
I: Integer;
begin
I := f();
end;

译为:
@f:
mov eax,$00001234
ret
//....
call f
mov esi,eax
ScriptBaby 2007-05-24
  • 打赏
  • 举报
回复
函数被调用的位置是不可预测的, 所以无论如何一定有一个地方会保存运行中的返回地址, 但是究竟怎么实现我也不知道, 你们写的汇编我能看懂一小部分就已经万幸了...

另外eax返回我在楼上就已经知道了哈
lihuasoft 2007-05-24
  • 打赏
  • 举报
回复
或者说:我如何才能得到本应由编译器给出的那个ret后面的偏移地址,通过压栈,传入函数,然后直接在函数里ret返回。
lihuasoft 2007-05-24
  • 打赏
  • 举报
回复
ret X '这个X是一个偶数立即数,是编译器给出的,使指针返回到调用这个子程序的下一句程序。我的意思不是要函数返回值。
lihuasoft 2007-05-24
  • 打赏
  • 举报
回复
其实,伴水,我的意思是:
function Test:integer; stdcall;
asm
push ebp
mov ebp, esp
mov ecx, [ebp+$08]//---//那就用ECX吧
//... // |
pop ebp // |
ret X <--------------/ 子程序直接从这里返回
end;//以下是编译后才有的
pop ebp //以下是编译器将添加的两句, 直接越过它们返回
ret $C //
...

to ScriptBaby(Kanna·Naraku) :
返回值就是通过EAX,如果返回值是64位的,就用EDX:EAX双寄存器返回。
ScriptBaby 2007-05-24
  • 打赏
  • 举报
回复
坐井观天同学研究比我要深入, 不佩服不行
lihuasoft 2007-05-24
  • 打赏
  • 举报
回复
再画蛇添足一把:

如果用register约定调用函数, 则DLL函数应为:

function GetMax: integer; stdcall; export;
//~~~~~~这里虽为stdcall, 无关痛痒, 前面已解释
asm
push ebp
mov ebp, esp
add eax, edx //第1、2个参数
add eax, ecx //第3个参数
add eax, [ebp+$08]//第4个参数
add eax, [ebp+$0C]//第5个参数
pop ebp
ret 8 //第4、5个参数入栈,所以下一条指令偏移2*sizeof(integer)=8个字节
end;
ScriptBaby 2007-05-24
  • 打赏
  • 举报
回复
看来我蒙对了...
lihuasoft 2007-05-24
  • 打赏
  • 举报
回复
另外, 楼主把上面这个函数稍加改动, 放入DLL, 做为一个无参函数:

function GetMax: integer; stdcall; export;
asm
push ebp //////!!
mov ebp, esp
xor eax, eax
add eax, [ebp+$08]//第1个参数
add eax, [ebp+$0C]//第2个参数
add eax, [ebp+$10]//第3个参数,这三个参数累加到EAX做为返回值
pop ebp
ret 16//四个参数入栈,所以下一条指令偏移16个字节
end;

然后, 在application里调用:

var
Func : function(var1,var2,var3,var4 : integer): Integer; stdcall;
//~~~~~~~~~~
max: integer;
LibHandle: THandle;
begin
LibHandle := LoadLibrary('Test.dll');
@Func := GetProcAddress(LibHandle, 'GetMax');
max := Func(10,20,30,16);//60
Showmessage(inttostr(max));
FreeLibrary(LibHandle);
end;

应该就是不出错的了.

所以, 我认为, 之所以用register约定调用不出错, 是因为register约定前三个参数通过寄存器传递, 而如果超过三个参数, 将会是与stdcall一样的结果. 之所以stdcall会出错, 就是因为参数压栈修改了栈顶指针, 所以在子程序返回时一定要维护栈顶, 并指向下一条指令的正确位置.
lihuasoft 2007-05-23
  • 打赏
  • 举报
回复
算了, 看书去. 汗自己一个. ^_^
lihuasoft 2007-05-23
  • 打赏
  • 举报
回复
哦,我看错了. 是的是的.
lihuasoft 2007-05-23
  • 打赏
  • 举报
回复
要用到eax? 那函数的返回值?
王集鹄 2007-05-23
  • 打赏
  • 举报
回复
汇编里的ret和C里的return是有区别的
具体可以找找关于汇编的资料

return 0x01234567;
编译为:

mov eax,0x01234567
ret
lihuasoft 2007-05-23
  • 打赏
  • 举报
回复
也就是这个意思:
push ebp
mov ebp, esp
mov eax, [ebp+$08]//---
//... // |
pop ebp // |
ret X <--------------/

pop ebp //以下是编译器将添加的两句, 直接越过它们返回
ret $C //

占用楼主贴子了. 不好意思. 不过话题仍然与本贴有关.
lihuasoft 2007-05-23
  • 打赏
  • 举报
回复
我的意思就是说,在代码里这样写:

function Test: integer; stdcall;
asm
push ebp //保存基址?
mov ebp, esp
mov eax, [ebp+$08] //取第一个参数
//...
pop ebp
ret 数 //就是这个立即数,可不可以人工给出
end;

编译后将是

push ebp //保存基址?
mov ebp, esp
mov eax, [ebp+$08] //取第一个参数
//...
pop ebp
ret 数 //就是这个立即数,可不可以人工给出
pop ebp //让这两句失效
ret $C //

在摸索着学习,别笑我
lihuasoft 2007-05-23
  • 打赏
  • 举报
回复
有一事不明请教伴水清清:

编译器在子程序结束后, 有一句:

RET 立即数

这个立即数是主程序指令的段内偏移地址吗?必须由编译器给出吗?可不可以人工控制?
王集鹄 2007-05-23
  • 打赏
  • 举报
回复
鼓掌 啪啪啪啪啪啪啪啪啪啪啪啪啪啪啪啪

首先感谢CCTV、感谢MTV、感谢政府、感谢党,让我把程序调试出来... ...
加载更多回复(8)
作为Microsoft 32位平台的应用程序编程接口, Win32 API是从事Windows应用程序开发所必备的。 首先对Win32 API函数做完整的概述;然后收录五大类函数: 窗口管理、图形设备接口、系统服务、国际特性以及网络服务; 在附录部分,讲解如何在Visual Basic和Delphi对其调用。 本书是从事Windows应用程序开发的软件工程师的必备参考手册。 控件与消息函数 共91个函数 硬件与系统函数 共98个函数 设备场景函数 共73个函数 绘图函数 共105个函数 位图、图标和光栅运算函数 共39个函数 菜单函数 共37个函数 文本和字体函数 共41个函数 打印函数 共66个函数 文件处理函数 共118个函数 进程和线程函数 共40个函数 Windows消息函数 共11个函数 网络函数 共14个函数 目 录 第一章 Win32 API概论…………………………………………………………………………1 1.1 为什么使用Win32 API …………………………………………………………………1 1.2 Win32 API简介 …………………………………………………………………………1 1.3 综述………………………………………………………………………………………11 第二章 窗口管理函数(Windows Control Function) ……………………………………13 2.1 易用特性函数(Accessibility Features)…………………………………………13 2.2 按钮函数(Button)……………………………………………………………………20 2.3 插入标记(^)函数(Caret)…………………………………………………………21 2.4 组合框函数(Combo box) ……………………………………………………………24 2.5 通用对话框函数(Common Dialog Box) ……………………………………………25 2.6 标函数(Cursor)………………………………………………………………………36 2.7 对话框函数(Dialog Box)……………………………………………………………40 2.8 编辑控制函数(Edit Control)………………………………………………………54 2.9 图标函数(Icon)………………………………………………………………………54 2.10 键盘加速器函数(Keyboard Accelerator)……………………………………… 61 2.11 键盘输入函数(Keyboard InPut) …………………………………………………63 2.12 列表框函数(List box) ……………………………………………………………75 2.13 菜单函数(Menu) ……………………………………………………………………76 2.14 消息和消息队列函数(Message and Message Queue)……………………………90 2.15 鼠标输入函数(Mouse Input) ……………………………………………………100 2.16 多文档接口函数(Multiple Document Interface) ……………………………103 2.17 资源函数(Resource)………………………………………………………………105 2.18 滚动条函数(Scroll Bar)…………………………………………………………113 2.19 窗口函数(Window)…………………………………………………………………119 2.20 窗口类函数(Window Class)………………………………………………………144 2.21 窗口过程函数(Window Procedure)………………………………………………150 2.22 窗口属性函数(Window Property) ………………………………………………152 第三章 图形设备接口函数(Graphic Device Interface Function) …………………155 3.1 位图函数(Bitmap) …………………………………………………………………155 3.2 笔刷函数(Brush)……………………………………………………………………171 3.3 剪切函数(Clipping) ………………………………………………………………176 3.4 颜色函数(Color)……………………………………………………………………179 3.5 坐标空间与变换函数(Coordinate Space Transformation)……………………186 3.6 设备环境函数(Device Context) …………………………………………………195 3.7 填充形态函数(Filled shape) ……………………………………………………211 3.8 字体和正文函数(Font and Text)…………………………………………………215 3.9 ICM 2.0函数 …………………………………………………………………………238 3.10 线段和曲线函数(Line and Curve)………………………………………………295 3.11 图元文件函数(Metafile)…………………………………………………………300 3.12 多显示器函数(Multiple Display Monitors) …………………………………311 3.13 绘图函数和画图函数(Painting and Drawing)…………………………………313 3.14 路径函数(Path)……………………………………………………………………328 3.15 画笔函数(Pen) ……………………………………………………………………332 3.16 打印及打印假脱机程序函数(Printing and Print Spooler)…………………334 3.17 矩形函数(Rectangle) ……………………………………………………………371 3.18 区域函数(Region)…………………………………………………………………374 第四章 系统服务函数(System Service Function) ……………………………………383 4.1 访问控制函数(Access Control) …………………………………………………383 4.2 原子函数(Atom) ……………………………………………………………………406 4.3 客户/服务器访问控制函数(Client/Server Access Control) ………………409 4.4 剪贴板函数(Clipboard)……………………………………………………………431 4.5 通信函数(Communication)…………………………………………………………436 4.6 控制台函数(Console)………………………………………………………………444 4.7 数据解压库函数(Data Decompression Library) ………………………………463 4.8 调试函数(Debugging)………………………………………………………………466 4.9 设备输入输出函数(Device Input and Output)…………………………………472 4.10 动态数据交换函数(Dynamic Data Exchange) …………………………………474 4.11 动态数据交换管理函数(Dynamic Data Exchange Management)………………476 4.12 动态链接库函数(Dynamic-Link Library)………………………………………489 4.13 错误函数(Error) …………………………………………………………………496 4.14 事件日志函数(Event Logging) …………………………………………………499 4.15 文件函数(File)……………………………………………………………………503 4.16 文件安装库函数(File Installation Library) ………………………………542 4.17 文件映射函数(File Mapping)……………………………………………………546 4.18 文件系统函数 File System)………………………………………………………551 4.19 句柄和对象函数(Handle and Object)………………………………………………556 4.20 挂钩函数(Hook)………………………………………………………………………560 4.21 ImageHlp函数…………………………………………………………………………572 4.22 大整数操作函数(Iarge Integer Operations)……………………………………594 4.23 低层访问控制函数(Low-Level Access Control)………………………………596 4.24 LSAPI函数 …………………………………………………………………………617 4.25 邮槽函数(Mailslot)………………………………………………………………622 4.26 内存管理函数(Memory Management) ……………………………………………623 4.27 管道函数(Pipe) …………………………………………………………………655 4.28 电源管理函数(Power Management) …………………………………………… 663 4.29 进程和线程函数(Process and Thread)…………………………………………666 4.30 注册表函数(Registry)……………………………………………………………700 4.31 字符串操作函数(String Manipulation)……………………………………… 724 4.32 结构化异常处理函数(Structured Exception Handling) ……………………742 4.33 同步函数(Synchronization) ……………………………………………………745 4.34 系统信息函数(System Information)……………………………………………766 4.35 系统消息函数(System Message)…………………………………………………780 4.36 系统关机函数(System Shutdown) ………………………………………………781 4.37 磁带备份函数(Tape Backup) ……………………………………………………783 4.38 时间函数(Time)……………………………………………………………………789 4.39 计时器函数(Timer) ………………………………………………………………795 4.40 工具帮助函数(Tool Help) ………………………………………………………796 4.41 窗口站和桌面函数(Window Station and Desktop)……………………………799 4.42 Windows NT 4.0访问控制函数(Window NT 4.0 Access-Control)……………808 4.43 WinTrust函数(WinTrust)…………………………………………………………814 第五章 国际特性函数(International Peatures Punction)时性…………………………815 5.1 输入方法编辑函数(Input Method Editor)…………………………………………815 5.2 国家语言支持函数(National Language Support)………………………………… 828 5.3 Unicode和字符集函数(Unicode and Character Set)……………………………… 843 第六章 网络服务函数(Networding Service Function)……………………………………849 6.1 数据链路控制函数(DLC)………………………………………………………………849 6.2 网络函数(Net)…………………………………………………………………………849 6.3 NetBIOS函数……………………………………………………………………………896 6.4 网络DDE函数(Networking DDE)……………………………………………………897 6.5 RAS服务器管理函数(RAS Server Administration)………………………………901 6.6 远程访问服务函数(Remote Access Administration)………………………………910 6.7 服务函数(Service)……………………………………………………………………929 6.8 Windows网络函数(Windows Networking)……………………………………………930 附录1 如何在VB调用DLL API ……………………………………………………………945 1 DLL API的声明……………………………………………………………………………945 2 DLL API的调用……………………………………………………………………………947 附录2 在Delphi直接调用Windows API…………………………………………………953

5,930

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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