delphi – 如何链接包含WinAPI的C代码?
如何链接包含WinAPI调用的C代码?链接时我收到以下错误:
请考虑以下示例. 德尔福: program Project1; uses Windows; {$L C:Source.obj} function Test: DWORD; cdecl; external name '_Test'; begin WriteLn(Test); end. C: #include <Windows.h> DWORD Test(void) { return GetCurrentThreadId(); } 解决方法
发生这种情况是因为Windows头文件在声明函数时通常使用__declspec(dllimport).对于有问题的函数,它在WinBase.h中的定义是:
WINBASEAPI DWORD WINAPI GetCurrentThreadId( VOID ); 展开所有宏时,重新格式化为: __declspec(dllimport) DWORD __stdcall GetCurrentThreadId(void); 现在,使用__declspec(dllimport)和__stdcall告诉链接器该函数的修饰名称是__imp__GetCurrentThreadId @ 0.您需要在随SDK提供的导入库中提供该功能.你不能在Delphi中这样做,因为它不接受它.你有多种选择.最明显的是在Delphi代码中实现该功能.但这样做非常棘手,因为这个名字无法形容.你不能给Delphi函数这个名字. 您可以避开C代码中的Windows头文件,并用您自己的变体替换它们,这些变体包含您在类型和功能方面所需的内容.并且在不使用__declspec(dllimport)的情况下定义函数.例如: C typedef unsigned long DWORD; // taken from the Windows header files DWORD GetCurrentThreadId(void); // this is implemented in the Delphi code to which you link DWORD MyGetCurrentThreadId(void) { return GetCurrentThreadId(); } 德尔福 {$APPTYPE CONSOLE} uses Winapi.Windows; {$LINK MyGetCurrentThreadId.obj} function _GetCurrentThreadId: DWORD; cdecl; begin Result := Winapi.Windows.GetCurrentThreadId; end; function MyGetCurrentThreadId: DWORD; cdecl; external name '_MyGetCurrentThreadId'; begin Writeln(MyGetCurrentThreadId); Readln; end. 这不是很有趣.但我没有看到太多选择. __stdcall装饰会在你的函数名称上放置@XX就足够了,据我所知,你不能在Delphi中实现这样的函数,因为它具有难以理解的字符@. 显然,在您的实际代码中,您将类型和函数声明放入一个头文件中,该头文件可用于代替Windows头文件. 您可以通过后处理目标文件来避免所有这些混乱.我不知道是否存在工具,但您可以处理目标文件以使用对GetCurrentThreadId的引用替换对__imp__GetCurrentThreadId @ 0的引用,那么生活将变得简单. Delphi链接器将查找该函数名称并在Winapi.Windows中找到它. 在评论中,您已经展示了如何使用Agner Fog’s objconv tool来完成此操作.它运行如下: C #include <Windows.h> DWORD MyGetCurrentThreadId(void) { return GetCurrentThreadId(); } 编译C代码 cl /c MyGetCurrentThreadId.c 对.obj文件进行后处理以取消设计名称 objconv -nr:__imp__GetCurrentThreadId@0:GetCurrentThreadId MyGetCurrentThreadId.obj MyGetCurrentThreadId_undecorated.obj 德尔福 {$APPTYPE CONSOLE} uses Winapi.Windows; {$LINK MyGetCurrentThreadId_undecorated.obj} const _GetCurrentThreadId: function: DWORD; stdcall = Winapi.Windows.GetCurrentThreadId; function MyGetCurrentThreadId: DWORD; cdecl; external name '_MyGetCurrentThreadId'; begin Writeln(MyGetCurrentThreadId); Readln; end. 由于我不知道的原因,我无法说服链接器直接获取Winapi.Windows.GetCurrentThreadId.如果我未设计到GetCurrentThreadId而不是_GetCurrentThreadId,并删除co??nst,那么程序将编译并链接.但是在运行时抛出访问冲突.无论如何,@ user15124建议的这个技巧提供了一个可管理的解决方法. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |