【问题标题】:Call C++ dll from with Delphi使用 Delphi 调用 C++ dll
【发布时间】: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 类型,例如 LONGDWORD 等,而不是 C++ 类型,例如 int。无法保证 int 将是 32 位,因为 C++ 不做这样的保证。此外,您导出的名称已损坏 - 正如其他评论所建议的那样,请使用 Dependency Walker 查看您导出的函数。

标签: c++ delphi


【解决方案1】:

您没有导出函数。这样做:

extern "C" 
{
    __declspec(dllexport) int next(int n)
    {
        return n + 1;
    }
}

使用extern "C"__declspec(dllexport)__cdecl 的默认调用约定将倾向于导出未修饰的函数。任何其他选择都会导致装饰。

在 Delphi 方面是:

function next(a: Integer): Integer; cdecl;
  external '...';

装饰并不是一件坏事,但是如果你想使用stdcall,并且避免装饰,那么你应该使用.def文件来导出函数。

【讨论】:

  • 它不起作用。我曾尝试这样做,并且 tdump -ee library.dll 告诉我 next 已导出,但 Delphi 应用程序在运行时崩溃。但如果我用 RAD Studio XE6 编译它,它就可以正常工作。您是否曾经设法混合使用来自 Visual Studio 2013 和 Delphi XE6 的代码?
  • 它工作正常。我不知道你有什么问题。 “崩溃”没有提供任何信息。
  • 它说:“应用程序无法正确启动(0xc000a200)。单击确定关闭应用程序。”。然后它在“mov ex,[edi]”处中断。所以你知道,我使用 Visual Studio 2013 创建了我的 Dll,使用:New Project->Visual C++->DLL (Windows)。您能否确认您已使用 Visual Studio 编译了 C++ 代码?
  • 我没有编译任何东西。错误代码是 STATUS_NOT_APPCONTAINER。您正在构建 WinRT DLL 吗? Windows 应用商店 DLL。
  • 我不知道(我更像是一个 Unix 人)。我们怎么知道?我是否应该创建 WinRT Dll?我应该创建什么样的 Dll? (该项目说:DLL(Windows):本机动态链接库 (DLL) 的项目,可由 Windows 应用程序或运行时组件使用。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-08
  • 1970-01-01
  • 1970-01-01
  • 2013-03-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多