如何将Delphi程序与包含WinAPI的C代码无缝链接实现跨平台调用?

2026-04-10 16:383阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计951个文字,预计阅读时间需要4分钟。

如何将Delphi程序与包含WinAPI的C代码无缝链接实现跨平台调用?

要链接包含WinAPI调用的C代码,你需要确保在编译链接过程中正确地链接了Win32库。以下是一个简化的示例,展示如何链接包含WinAPI调用的C代码。

c#include // 包含Windows API头文件

int main() { // 调用WinAPI函数 DWORD threadID=GetCurrentThreadId();

// 其他代码...

return 0;}

链接错误:[dcc32 Error] Project1.dpr(16): E2065 Unsatisfied forward or external declaration: '__imp__GetCurrentThreadId@0'

这个错误表明链接器没有找到`GetCurrentThreadId`函数的实现。以下是一些可能的解决方案:

1. 确保在项目设置中包含了正确的库文件。通常,对于WinAPI函数,你需要链接`kernel32.lib`库。

2. 在链接器设置中添加`kernel32.lib`。

示例链接命令(假设使用的是MinGW或类似环境):

bashgcc -o myprogram.exe myprogram.c -lkernel32

3. 如果使用Visual Studio,可以在项目属性中设置:

- 在链接器->输入->附加依赖项中添加`kernel32.lib`。

请根据你的开发环境调整上述步骤。确保不要超出100个字符的限制。

如何链接包含WinAPI调用的C代码?链接时我收到以下错误:

[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(); }

德尔福

如何将Delphi程序与包含WinAPI的C代码无缝链接实现跨平台调用?

{$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建议的这个技巧提供了一个可管理的解决方法.

标签:代码

本文共计951个文字,预计阅读时间需要4分钟。

如何将Delphi程序与包含WinAPI的C代码无缝链接实现跨平台调用?

要链接包含WinAPI调用的C代码,你需要确保在编译链接过程中正确地链接了Win32库。以下是一个简化的示例,展示如何链接包含WinAPI调用的C代码。

c#include // 包含Windows API头文件

int main() { // 调用WinAPI函数 DWORD threadID=GetCurrentThreadId();

// 其他代码...

return 0;}

链接错误:[dcc32 Error] Project1.dpr(16): E2065 Unsatisfied forward or external declaration: '__imp__GetCurrentThreadId@0'

这个错误表明链接器没有找到`GetCurrentThreadId`函数的实现。以下是一些可能的解决方案:

1. 确保在项目设置中包含了正确的库文件。通常,对于WinAPI函数,你需要链接`kernel32.lib`库。

2. 在链接器设置中添加`kernel32.lib`。

示例链接命令(假设使用的是MinGW或类似环境):

bashgcc -o myprogram.exe myprogram.c -lkernel32

3. 如果使用Visual Studio,可以在项目属性中设置:

- 在链接器->输入->附加依赖项中添加`kernel32.lib`。

请根据你的开发环境调整上述步骤。确保不要超出100个字符的限制。

如何链接包含WinAPI调用的C代码?链接时我收到以下错误:

[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(); }

德尔福

如何将Delphi程序与包含WinAPI的C代码无缝链接实现跨平台调用?

{$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建议的这个技巧提供了一个可管理的解决方法.

标签:代码