如何在Delphi 程序中调用任意 C++ DLL动态链接库

如何在任何 Delphi 程序中使用 C++ DLL

互联网上有大量有用的 C++ 库。我们也在这个博客上展示了C++ 的许多伟大用途。C++ 通常具有极高的性能。如果我们有 C++ 库的源代码,我们就可以创建一个包,然后我们就可以在 Delphi 程序中使用 C++。尽管 C++ 库的源代码通常不可用。在商业 C++ 库中,通常只获得几个 C++ 头文件和静态库文件 (.lib),而没有任何随附的 .cpp 源文件。因此,在这种情况下,当我们想在 Delphi 应用程序中使用那些 C++ 库时,我们可以使用代理 DLL 来实现。

如何创建一个代理DLL来连接C++ DLL和Delphi?

要将 Delphi 连接到 DLL,DLL 应该公开一个简单的 Windows API 样式 API,而不是 C++ 的东西。我们可以使用任何 C++ 编译器来编译代理 DLL。

Embarcadero Dev-Cpp 开源编译器

视觉工作室

我们举一个简单的例子。假设我们有一个 DLL 文件和一个带有此声明的更难的文件,而没有带有实现的 .cpp 文件。您可以在此链接中参考此示例的源代码:

https://github.com/PacktPublishing/Delphi-High-Performance/tree/master/Chapter%208/StaticLib1

1
2
3
4
5
6
7
8
9
10
#pragma once
class CppClass
{
  int data;
public:
  CppClass();
  ~CppClass();
  void setData(int);
  int getSquare();
};

下面介绍如何在带有代理dll的Delphi程序中使用C++库

现在我们需要创建代理DLL。

使用您喜欢的 IDE 创建一个新的 C++ DLL 项目。

如何在任何 Delphi 程序中使用 C++ DLL = 新的代理 DLL 项目

它会自动添加“dllmain.cpp”文件。但是我们需要另一个单元来包装静态库。添加名为“StaticLibWrapper.cpp”的新单元。

现在我们应该在我们的项目中包含我们想要导入的静态库的头文件。

1
2
#include "stdafx.h"
#include "CppClass.h"

现在将静态库的头文件复制到项目文件夹中。现在我们应该在我们的项目中包含静态库。为此,将静态库文件夹添加到库目录中:

如何在任何 Delphi 程序中使用 C++ DLL - import-static-library

或者在 Visual Studio 中转到“配置属性 链接器 一般 其他库目录 设置”。

如何将 C++ DLL 函数标记为“已导出”

现在我们定义一个宏来标记 DLL 函数被导出。

1
#define EXPORT comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__)

接下来,实现IndexAllocator类以缓存 C++ 对象。这个类包含一个指针数组。它具有“Allocate”、“Release”和“Get”三个函数,用于将指针存储在缓存中、释放缓存和通过索引获取指针。

1
2
3
bool Allocate(int& deviceIndex, void* obj)
bool Release(int deviceIndex)
void* Get(int deviceIndex)

然后我们需要 toInitialize和 Finalize 函数来分配和释放IndexAllocator对象。

1
2
extern "C" int WINAPI Initialize()
extern "C" int WINAPI Finalize()

然后我们创建一个 CppClass 类的实例,并用这个函数将它存储在缓存中。

1
extern "C" int WINAPI CreateCppClass (int& index)

在此语句中,我们使用“C”来确保导出相同的名称并WINAPI更改调用转换。DestroyCppClass 与此类似。接下来,看看主要的导出函数“CppClass_setValue”和“CppClass_getSquare”。当用户调用这些函数时,它会从缓存中获取对象并调用这些函数并取值。

1
2
3
4
5
6
7
8
9
10
11
extern "C" int WINAPI CppClass_setValue(int index, int value)
{
#pragma EXPORT
  CppClass* instance = (CppClass*)GAllocator->Get(index);
  if (instance == NULL)
    return -1;
  else {
    instance->setData(value);
    return 0;
  }
}
1
2
3
4
5
6
7
8
9
10
11
extern "C" int WINAPI CppClass_getSquare(int index, int& value)
{
#pragma EXPORT
  CppClass* instance = (CppClass*)GAllocator->Get(index);
  if (instance == NULL)
    return -1;
  else {
    value = instance->getSquare();
    return 0;
  }
}

第一个函数将获取对象的索引并设置变量的值。在第二个函数中,它获取对象的索引,调用对象的“ getSquare”函数,并将值存储在值变量中。

如何在 Delphi 应用程序中使用 C++ 代理 DLL?

我们可以静态或动态链接 DLL。对于静态加载,DLL 将在应用程序启动时加载。使用动态加载,DLL 将不会加载,直到我们调用“LoadLibrary”。让我们在这个例子中使用静态加载。让我们声明在 DLL 中导出的函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const
CPP_CLASS_LIB = 'DllLib1.dll';
function Initialize: integer;
  stdcall; external CPP_CLASS_LIB name 'Initialize' delayed;
 
function Finalize: integer;
  stdcall; external CPP_CLASS_LIB name 'Finalize' delayed;
 
function CreateCppClass(var index: integer): integer;
  stdcall; external CPP_CLASS_LIB name 'CreateCppClass' delayed;
 
function DestroyCppClass(index: integer): integer;
  stdcall; external CPP_CLASS_LIB name 'DestroyCppClass' delayed;
 
function CppClass_setValue(index: integer; value: integer): integer;
  stdcall; external CPP_CLASS_LIB name 'CppClass_setValue' delayed;
 
function CppClass_getSquare(index: integer; var value: integer): integer;
  stdcall; external CPP_CLASS_LIB name 'CppClass_getSquare' delayed;

我们应该在 Delphi 应用程序创建时调用“Initialize”函数,在我们的应用程序销毁时调用“Finalize”函数。然后当我们在 Delphi 代码中使用代理 DLL 时,首先我们必须调用“CreateCppClass”来创建一个对象。它将设置将来使用的类 ID。然后我们可以调用DLL的所有函数,最后我们应该调用“DestroyCppClass”函数来销毁类实例。颈椎枕在我们的例子中,我们这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
procedure TfrmCppClassDemo.btnImportLibClick(Sender: TObject);
var
idxClass: Integer;
value: Integer;
begin
if CreateCppClass(idxClass) <> 0 then
  ListBox1.Items.Add('CreateCppClass failed')
else if CppClass_setValue(idxClass, SpinEdit1.Value) <> 0 then
  ListBox1.Items.Add('CppClass_setValue failed')
else if CppClass_getSquare(idxClass, value) <> 0 then
  ListBox1.Items.Add('CppClass_getSquare failed')
else begin
  ListBox1.Items.Add(Format('square(%d) = %d', [SpinEdit1.Value, value]));
  if DestroyCppClass(idxClass) <> 0 then
   ListBox1.Items.Add('DestroyCppClass failed')
end;
end;

最后,Delphi 应用程序将像这样工作:

如何在任何 Delphi 程序中使用 C++ DLL = delphi cppclass import


RAD Studio 允许您快速创建可在 Windows、macOS、Linux、iOS 和 Android 上运行的 Delphi 和 C++ 程序。立即下载免费试用版,将您的程序创意带到客户实际使用的设备上!


使用 RAD Studio、Delphi 或 C++Builder 缩短开发时间并更快地进入市场。
设计。编码。编译。部署。

 

 

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值