Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-apps-script/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 如何链接包含WinAPI的C代码?_Delphi_Delphi Xe8 - Fatal编程技术网

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

Delphi 如何链接包含WinAPI的C代码?,delphi,delphi-xe8,Delphi,Delphi Xe8,如何链接包含WinAPI调用的C代码?链接时,我遇到以下错误: [dcc32错误]项目1.dpr(16):E2065未满足远期或外部声明:''__GetCurrentThreadId@0" 考虑下面的例子 德尔菲: program Project1; uses Windows; {$L C:\Source.obj} function Test: DWORD; cdecl; external name '_Test'; begin WriteLn(Test); end. C: #

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

[dcc32错误]项目1.dpr(16):E2065未满足远期或外部声明:''__GetCurrentThreadId@0"

考虑下面的例子

德尔菲:

program Project1;

uses
  Windows;

{$L C:\Source.obj}

function Test: DWORD; cdecl; external name '_Test';

begin
  WriteLn(Test);
end.
C:

#包括
德沃德测试(无效)
{
返回GetCurrentThreadId();
}

之所以发生这种情况,是因为Windows头文件在声明函数时通常使用
\u declspec(dllimport)
。对于所讨论的函数,其在
WinBase.h
中的定义为:

WINBASEAPI
德沃德
WINAPI
GetCurrentThreadId(
无效的
);
当您展开所有宏并重新格式化为:

\uuu declspec(dllimport)DWORD\uu stdcall GetCurrentThreadId(void);
现在,使用
\uuu declspec(dllimport)
\uu stdcall
告诉链接器函数的修饰名称是
\uu imp__GetCurrentThreadId@0
。您需要在SDK提供的导入库中提供该函数。您不能在Delphi中这样做,因为它不接受它。你有多种选择。最明显的是在Delphi代码中实现该函数。但这是相当棘手的,因为这个名字是无法形容的。您不能给Delphi函数这个名称

您可以在您的C代码中避开Windows头文件,并用您自己的变体替换它们,这些变体包括您所需要的类型和函数。并在不使用
的情况下定义函数。例如:

C

typedef无符号长DWORD;//取自Windows头文件
DWORD GetCurrentThreadId(无效);//这是在您链接到的Delphi代码中实现的
DWORD MyGetCurrentThreadId(无效)
{
返回GetCurrentThreadId();
}
Delphi

{$APPTYPE控制台}
使用
Winapi.Windows;
{$LINK MyGetCurrentThreadId.obj}
函数_GetCurrentThreadId:DWORD;cdecl;
开始
结果:=Winapi.Windows.GetCurrentThreadId;
结束;
函数MyGetCurrentThreadId:DWORD;cdecl;外部名称“_MyGetCurrentThreadId”;
开始
Writeln(MyGetCurrentThreadId);
Readln;
结束。
这没什么意思。但我看不出有多少选择。
\uu stdcall
装饰将把
@XX
放在您的函数名上,就我所知,您无法在Delphi中实现这些函数,因为有一个难以形容的字符
@

显然,在实际代码中,您会将类型和函数声明放在一个头文件中,该头文件可以用来代替Windows头文件


通过对对象文件进行后处理,可以避免所有这些混乱。我不知道是否存在工具,但您可以处理对象文件以替换对
\uu imp的引用__GetCurrentThreadId@0
引用
GetCurrentThreadId
生活就会简单。Delphi链接器将查找该函数名,并在
Winapi.Windows
中找到它


在注释中,您已经演示了如何使用来准确地执行此操作。它是这样运行的:

C

#包括
DWORD MyGetCurrentThreadId(无效)
{
返回GetCurrentThreadId();
}
C代码的编译

cl /c MyGetCurrentThreadId.c
由于我不知道的原因,我无法说服链接器直接选择
Winapi.Windows.GetCurrentThreadId
。如果我取消装饰到
GetCurrentThreadId
而不是
\u GetCurrentThreadId
,并删除
常量,则程序将编译并链接。但在运行时抛出访问冲突。无论如何,@user15124建议的这个技巧提供了一个可管理的解决方法。

这意味着什么?你心目中的Delphi功能是什么?请记住,您没有访问C++链接器的权限。这不是在玩。我无法绕过
@
API函数的
\uu stdcall
装饰。你知道如何以名称的形式来声明Delphi函数吗?我想你需要更好地理解C++链接器进程。如果按原样包含WIndows头文件,则它们只定义函数。实现在链接时提供。通过在其中一个obj文件中的实际实现,或在lib文件中(静态或导入)。但是Windows头文件中定义的函数的修饰不是您可以影响的。您无法停止添加
@
。在Delphi中进行链接时,必须实现该功能。如何实现一个名为
@
的函数?我确实设法用
objconv.exe
objconv-nr:\uu imp__GetCurrentThreadId@0:GetCurrentThreadId source.obj source2.obj
我已经添加了一个postscript。确切地说,您将使用什么工具来实现这一点,这在很大程度上取决于您使用的编译器、obj格式等,我不知道。无论如何,如果这样的工具不存在,您肯定可以编写它。大概在x64上,装饰没有添加无法说出的
@
,因此您可以使用函数重定向?不过我猜。在你的评论中多加一些细节就好了。这是我给你的建议。多注意细节。请我会在我的答案中写下objconv技巧。 objconv -nr:__imp__GetCurrentThreadId@0:GetCurrentThreadId MyGetCurrentThreadId.obj MyGetCurrentThreadId_undecorated.obj