【发布时间】:2014-11-10 09:58:53
【问题描述】:
我的目标是在 Delphi (RAD Studio XE6) 中调用用 C++(带有 C 接口)编写的函数。最后,dll 将由 Visual Studio 2013 生成,但我尝试从 RAD Studio XE6 生成 Dll 开始。
所以,我在 Rad Studio 中创建了一个 Dll 项目(使用 VC++ 样式的 Dll)。文件在这里
#include <vcl.h>
#include <windows.h>
#pragma hdrstop
#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
return 1;
}
extern "C" int next(int n) {
return n + 1;
}
它编译为 Dll。 Delphi端代码如下:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, Windows;
function next(a: Int32): Int32; cdecl;
external 'Project3.dll';
var
a: Int32;
begin
try
a := 3;
Writeln('Hello world!', next(a));
sleep(3000);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
项目编译但不运行。它给出了以下错误:
*** A stack buffer overrun occurred in "C:\...\Debug\Project1.exe"
在下面的装配线上失败了
mov eax,[edi]
我尝试将 cdecl 更改为 std 调用、pascal 或寄存器。但没有任何效果。
解决方案:感谢 Rudy,以下代码确实有效。首先是 C++ 方面:
#include <vcl.h>
#include <windows.h>
#pragma hdrstop
#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
return 1;
}
extern "C" __declspec(dllexport) int __stdcall next(int n) {
return n + 1;
}
然后是 Delphi 方面。
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, Windows;
function next(a: Int32): Int32; stdcall;
external 'Project3.dll';
var
a: Int32;
begin
try
a := 3;
Writeln('Hello world!', next(a));
sleep(3000);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
【问题讨论】:
-
这不是真正的 C++ 导出,该函数使用 C 调用约定。也许添加
extern "C"? Delphi 不太可能支持 C++,通常纯 C 函数是任何其他语言都可以导入的最低公分母。 -
@sashoalm:谢谢。我已经尝试过并更新了我的问题。但它也不起作用。
-
你确定函数导出了吗?看起来不像。看看像 Dependency Walker 这样的工具。如果没有,请阅读有关如何导出函数的在线帮助。我想一个简单的指令就足够了,例如__declspec(dllexport) 或 __export 之类的。
-
FWIW,看看this article of mine。
-
@InsideLoop - 此外,您应该真正使用 Windows API 类型,例如
LONG、DWORD等,而不是 C++ 类型,例如int。无法保证int将是 32 位,因为 C++ 不做这样的保证。此外,您导出的名称已损坏 - 正如其他评论所建议的那样,请使用 Dependency Walker 查看您导出的函数。