[dcc32 Error] Project1.dpr(16): E2065 Unsatisfied forward or external declaration: ‘__imp__GetCurrentThreadId@0’
请考虑以下示例.
德尔福:
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,并删除const,那么程序将编译并链接.但是在运行时抛出访问冲突.无论如何,@ user15124建议的这个技巧提供了一个可管理的解决方法.