gpt4 book ai didi

delphi - 如何链接包含WinAPI的C代码?

转载 作者:行者123 更新时间:2023-12-03 15:28:38 25 4
gpt4 key购买 nike

如何链接包含 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();
}

德尔福

{$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 头文件的头文件中。

<小时/>

您可以通过对目标文件进行后处理来避免所有这些困惑。我不知道是否存在工具,但您可以处理对象文件,将对 __imp__GetCurrentThreadId@0 的引用替换为对 GetCurrentThreadId 的引用,那么生活就会变得简单。 Delphi 链接器将查找该函数名称并在 Winapi.Windows 中找到它。

<小时/>

在评论中您已经展示了如何使用 Agner Fog's objconv tool正是为了做到这一点。它的运行方式如下:

C

#include <Windows.h>

DWORD MyGetCurrentThreadId(void)
{
return GetCurrentThreadId();
}

C代码编译

cl /c MyGetCurrentThreadId.c

Post-processing of .obj file to undecorate names

objconv -nr:__imp__GetCurrentThreadId@0:GetCurrentThreadId MyGetCurrentThreadId.obj MyGetCurrentThreadId_undecorated.obj

Delphi

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

关于delphi - 如何链接包含WinAPI的C代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33279107/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com