delphi调用c动态库Word格式.docx
- 文档编号:17483536
- 上传时间:2022-12-06
- 格式:DOCX
- 页数:11
- 大小:19.43KB
delphi调用c动态库Word格式.docx
《delphi调用c动态库Word格式.docx》由会员分享,可在线阅读,更多相关《delphi调用c动态库Word格式.docx(11页珍藏版)》请在冰豆网上搜索。
参数删除者
寄存器传递参数
register
从左到右
例程
是
pascal
否
cdecl
从右到左
调用者
stdcall
safecall
fastcall
函数前两个参数通过ecx和edx传递,其他参数从右向左的顺序压栈
部分是
thiscall
(非关键词)
(this指针保存在ecx,仅用于c++)
nakedcall
一般用于实模式驱动程序设计
-
补充说明:
·
cdecl调用约定又称为C调用约定,是C语言缺省的调用约定.
register约定最多可以使用三个CPU寄存器传递参数,而其他的约定都通过栈传递所有的参数。
safecall约定实现了异常防火墙。
在Windows中,这一实现在内部处理COM错误通知。
缺省的register约定是效率最高的,因为它通常避免了栈中新帧的创建。
调用来自用C或C++编写的共享库的函数时,cdecl约定是很有用的;
而对外部代码的调用,一般而言,推荐使用stdcall和safecall约定。
在Windows中,操作系统API函数使用的是stdcall和safecall约定。
其他操作系统通常使用cdecl约定。
(注意,stdcall约定比cdecl约定具有更高的效率。
)
safecall约定必需用于声明双重接口的方法。
pascal约定用于维持向后(旧版本)兼容。
三、实例分析
3.1、实例功能概述
动态库功能:
C语言开发,修正将某个工友的工号以及薪资,将其工号增加10,薪资增加1000。
当然,实际生活中估计不会出现这种情况,这里只是为了展示这种调用技术而假想的例子。
Delphi程序功能:
调用动态库,将工友的资料作为入参传入动态库,由动态库对工友资料做相关调整,然后动态库通过回调函数将处理后的数据传给调用程序并在控制台显示出来。
C调用程序功能:
与Delphi程序功能一致,提供它主要便于大家对比参照。
3.2、代码分析
完整的代码在附件中,如果大家要实践的话,可以参考它。
3.2.1、C动态库实现说明
3.2.1.1、testdll.h:
这里定义了一个工友结构信息_TEST_WORKER,由工号、姓名、年龄、薪水组成,定义了一个回调函数结构,用于注册外部调用的处理函数;
同时申明了一个动态库导出函数。
详细的注释列在代码中:
//定义工友结构信息_TEST_WORKER
typedefstruct_TEST_WORKER
{
intnNO;
//工号
charchName[16];
//姓名
intnAge;
//年龄
intnSalary;
//薪水
}TEST_WORKER,*PTEST_WORKER;
//定义回调函数结构,用于将处理后的工友结构信息传递给调用程序
typedefstruct
void(*CallbackAlertRes)(TEST_WORKER*);
}CallbackFuncDef;
//申明动态库导出函数:
//注意,这里没有stdcall修饰,使用的是cdecl
TESTDLL_APIintfnTestdll(PTEST_WORKER*p,CallbackFuncDef*pCallbackFuncDef);
//其中TESTDLL_API的定义如下:
#ifdefTESTDLL_EXPORTS
#defineTESTDLL_API__declspec(dllexport)
#else
#defineTESTDLL_API__declspec(dllimport)
#endif
3.2.1.2、testdll.cpp:
//导出函数的函数体
TESTDLL_APIintfnTestdll(PTEST_WORKER*p,CallbackFuncDef*pCallbackFuncDef)
FILE*fp;
charszStr[100];
//以下用于测试跟踪传入的参数,显示数据在文本文件中
fp=fopen("
zhouys.txt"
"
a+"
);
//thisfortest
if(!
fp)return-1;
memset(szStr,'
\0'
sizeof(szStr));
sprintf(szStr,"
%d%s%d%d\n"
(*p)->
nNO,(*p)->
chName,(*p)->
nAge,(*p)->
nSalary);
fwrite(szStr,sizeof(szStr),1,fp);
fclose(fp);
//操作、处理
(*p)->
nNO+=10;
nSalary+=1000;
//回调通知,将处理后的信息传递给外部注册的函数
if(pCallbackFuncDef!
=NULL)
pCallbackFuncDef->
CallbackAlertRes(*p);
return0;
}
3.2.2、C调用程序
全部处理代码在calldll.cpp中,为控制台程序
3.2.2.1、先申明函数接口
//动态调用方式
typedefint(*pfnTestdll)(PTEST_WORKER*p,CallbackFuncDef*pCallbackFuncDef);
3.2.2.2、再编写回调处理函数:
//用于接收动态库处理后的数据,以做相关处理。
此处在控制台上打印处理后的结果信息
voidCallbackAlertRes(TEST_WORKER*p)
printf("
p->
nNO,p->
chName,p->
nAge,p->
3.2.2.3、主函数内容:
//申明结构指针
PTEST_WORKERp;
//加载动态库
HINSTANCE_hDll=LoadLibrary("
mydll.dll"
if(_hDll==NULL)
{
LoadLibraryerror,pleasecheckmydll.dllfileisexist?
\n"
return-1;
}
//获取动态库函数指针
pfnTestdllmycall=(pfnTestdll)GetProcAddress(_hDll,"
fnTestdll"
mycall)
FreeLibrary(_hDll);
getdllfunctionpointerfaild,pleasecheck!
//生成需要处理的数据
p=newTEST_WORKER;
//赋初始值
p->
nNO=10;
strcpy(p->
chName,"
李宇春"
nAge=20;
nSalary=2000;
//注册回调函数
CallbackFuncDefcallback_fun;
callback_fun.CallbackAlertRes=CallbackAlertRes;
//调用动态库函数处理
mycall(&
p,&
callback_fun);
//释放内存
deletep;
运行程序:
可以看到控制台输出了处理后的信息,
可以看到生成了zhouys.txt文本文件,记录了初始数据信息
3.2.3、delphi调用程序
3.2.3.1、转换数据结构类型:
本例有三处需要转换的地方:
1、C结构体转换为Delphi的记录结构
2、C字符串转换为Delphi的字符数组结构
3、C结构指针转换为Delphi的指针对象
转换结构如下
type{此处引入结构变量}
TEST_WEORKER=record
nNO:
integer;
cName:
array[1..16]ofchar;
nAge:
nSalary:
end;
PTEST_WEORKER=^TEST_WEORKER;
PPTEST_WEORKER=^PTEST_WEORKER;
3.2.3.2、申明函数:
定义回调函数结构,并申明回调结构指针:
//{此处引入函数指针}
TCallbackAlertRes=procedure(p:
PTEST_WEORKER);
{回调函数结构}
CallbackFuncDef=record
CallbackAlertRes:
TCallbackAlertRes;
PCallbackFuncDef=^CallbackFuncDef;
//申明调用函数指针,注意此处申明为cdecl调用方式,与动态库中函数一致
TFunTestDLL=function(p:
PPTEST_WEORKER;
pp:
PCallbackFuncDef):
cdecl;
注意:
TFunTestDLL为调用函数指针,它将被赋值为指向动态库所导出的函数的地址,由于C语言的函数调用参数入栈规则是从右到左,即stdcall,所以此处需申明为C调用方式stdcall。
3.2.3.3、回调处理函数:
//生成回调处理函数体,以cdecl修饰符申明,遵循C的调用方式
proceduremyCallbackAlertRes(p:
cdecl;
begin
//打印到控制台
Writeln(Format('
%d%s%d%d'
[p^.nNO,string(p^.cName),p^.nAge,p^.nSalary]));
end;
3.2.3.4、申明全局变量:
var
_hDll:
THandle;
pdll_fun:
TFunTestDLL;
p:
PTEST_WEORKER;
pmycallback:
PCallbackFuncDef;
3.2.3.5、调用函数:
_hDll:
=LoadLibrary('
mydll.dll'
if_hDll<
>
0then
begin
@pdll_fun:
=GetProcAddress(_hDll,'
fnTestdll'
if@pdll_fun<
nilthen
New(p);
New(pmycallback);
//符初值
p^.nNO:
=10;
p^.nAge:
=20;
p^.nSalary:
=2000;
FillChar(p^.cName,SizeOf(p^.cName),Ord('
'
));
StrCopy(@(p^.cName),'
李宇春'
//注册回调函数
pmycallback^.CallbackAlertRes:
=@myCallbackAlertRes;
//调用动态库函数进行处理
pdll_fun(@p,pmycallback);
//释放资源
Dispose(pmycallback);
Dispose(p);
四、结束语
通过上面的代码展示,相信大家都明白了delphi是如何调用c动态库的。
其实在实际工作过程中,也有delphi调用C静态库,以及kylix调用linux下C开发的.so和.a库的情况,我自己也做了一些实践,有一定的了解,感觉各种情况下的调用原理都大同小异。
有兴趣的同志可以和我联系一同探讨,这里就不赘述了。
五、参考资料
1、delphi7帮助系统
2、ObjectPascalReference.chm
3、ProgrammingwithDelphi.chm
六、附件
本文来自CSDN博客,转载请标明出处:
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- delphi 调用 动态