在C#中包装C++类DLL
Wrap C++ class DLL in C#
我必须在一个新的C#项目中使用C++现有代码。此C++代码是包含在DLL中的非托管代码。我的一位同事已经用"C"代码做到了这一点,但在我的情况下,我的DLL包含一个"类",我不知道是否可以做到这一点。
在我的C#应用程序中使用这个C++类的正确方法是什么?
更新:
谢谢你的回答。我试着用一个简单的类来完成它,方法是按照这篇文章在NET应用程序中使用非托管的C库DLL
我的初始类是在Borland C++Builder 6:上编码的
测试.cpp:
#include <basepch.h>
#pragma hdrstop
#include "Test.h"
#pragma package(smart_init)
__fastcall TTest::TTest() {
//rien
}
__fastcall TTest::~TTest() {
//rien
}
void __fastcall TTest::setNombre(int nbr) {
nombre = nbr;
}
int __fastcall TTest::getNombre() {
return nombre;
}
测试.h:
#ifndef TestH
#define TestH
#include <SysUtils.hpp>
#include <Classes.hpp>
#include <string.h>
#include <stdio.h>
#include <StrUtils.hpp>
#include <time.h>
class PACKAGE TTest
{
private:
int nombre;
protected:
public:
__fastcall TTest();
__fastcall ~TTest();
void __fastcall setNombre(int nbr);
int __fastcall getNombre();
};
extern PACKAGE TTest *Test;
#endif
这个类的编译是可以的:D
然后我尝试像文章中那样创建非托管类。但是我在C++Builder中创建这个类时遇到了一个问题。
未管理.cpp:
#pragma hdrstop
#include "Unmanaged.h"
#pragma package(smart_init)
struct UnmanagedClasseTest
{
int nombre;
[DllImport("ClasseTest.dll", EntryPoint="@TTest@$bctr$qqrv", CallingConvention=CallingConvention::ThisCall)]
static void ctor(UnmanagedClasseTest* c);
[DllImport("ClasseTest.dll", EntryPoint="@TTest@$bdtr$qqrv", CallingConvention=CallingConvention::ThisCall)]
static void dtor(UnmanagedClasseTest* c);
[DllImport("ClasseTest.dll", EntryPoint="@TTest@setNombre$qqri", CallingConvention=CallingConvention::ThisCall)]
static void setNombre(UnmanagedClasseTest* c, int nbr*);
[DllImport("ClasseTest.dll", EntryPoint="@TTest@getNombre$qqrv", CallingConvention=CallingConvention::ThisCall)]
static int getNombre(UnmanagedClasseTest* c);
static void Uctor(UnmanagedClasseTest* c) {
ctor(c);
}
static void Udtor(UnmanagedClasseTest* c) {
dtor(c);
}
static void UsetNombre(UnmanagedClasseTest* c, int i) {
nombre = setNombre(c);
}
static int UgetNombre(UnmanagedClasseTest* c) {
return getNombre(c);
}
};
未管理。h:
#ifndef UnmanagedH
#define UnmanagedH
static void ctor(UnmanagedClasseTest* c);
static void dtor(UnmanagedClasseTest* c);
static void setNombre(UnmanagedClasseTest* c, int nbr*);
static int getNombre(UnmanagedClasseTest* c);
static void Uctor(UnmanagedClasseTest* c);
static void Udtor(UnmanagedClasseTest* c);
static void UsetNombre(UnmanagedClasseTest* c, int i);
static int UgetNombre(UnmanagedClasseTest* c);
#endif
当我想编译这个非托管类时,我会出现以下错误://
[C++ Erreur] Unmanaged.h(6): E2147 'UnmanagedClasseTest' ne peut pas démarrer une déclaration de parameter
[C++ Erreur] Unmanaged.h(7): E2147 'UnmanagedClasseTest' ne peut pas démarrer une déclaration de parameter
[C++ Erreur] Unmanaged.h(8): E2451 Symbole 'UnmanagedClasseTest' non define
[C++ Erreur] Unmanaged.h(9): E2147 'UnmanagedClasseTest' ne peut pas démarrer une déclaration de parameter
[C++ Erreur] Unmanaged.h(10): E2147 'UnmanagedClasseTest' ne peut pas démarrer une déclaration de parameter
[C++ Erreur] Unmanaged.h(11): E2147 'UnmanagedClasseTest' ne peut pas démarrer une déclaration de parameter
[C++ Erreur] Unmanaged.h(12): E2147 'UnmanagedClasseTest' ne peut pas démarrer une déclaration de parameter
[C++ Erreur] Unmanaged.h(13): E2147 'UnmanagedClasseTest' ne peut pas démarrer une déclaration de parameter
[C++ Erreur] Unmanaged.cpp(17): E2040 Déclaration terminée incorrectement
[C++ Erreur] Unmanaged.cpp(20): E2040 Déclaration terminée incorrectement
[C++ Erreur] Unmanaged.cpp(23): E2040 Déclaration terminée incorrectement
[C++ Erreur] Unmanaged.cpp(26): E2040 Déclaration terminée incorrectement
[C++ Erreur] Unmanaged.cpp(30): E2034 Impossible de convertir 'UnmanagedClasseTest *' en 'int *'
[C++ Erreur] Unmanaged.cpp(30): E2342 Mauvaise correspondance de type dans le paramètre 'c' ('int *' désiré, 'UnmanagedClasseTest *' obtenu)
[C++ Erreur] Unmanaged.cpp(33): E2034 Impossible de convertir 'UnmanagedClasseTest *' en 'int *'
[C++ Erreur] Unmanaged.cpp(33): E2342 Mauvaise correspondance de type dans le paramètre 'c' ('int *' désiré, 'UnmanagedClasseTest *' obtenu)
[C++ Erreur] Unmanaged.cpp(36): E2268 Appel à une fonction non définie 'setNombre'
[C++ Erreur] Unmanaged.cpp(36): E2231 Le membre UnmanagedClasseTest::nombre ne peut pas être utilisé sans un objet
[C++ Erreur] Unmanaged.cpp(39): E2034 Impossible de convertir 'UnmanagedClasseTest *' en 'int *'
[C++ Erreur] Unmanaged.cpp(39): E2342 Mauvaise correspondance de type dans le paramètre 'c' ('int *' désiré, 'UnmanagedClasseTest *' obtenu)
我可以提出两个解决方案。(1) 通过标记为__declspec(dllexport)导出整个C++。它的所有方法都将从DLL中导出,并带有一些损坏的名称。找到这些名称(例如,通过Depends实用程序)并在C#代码中编写DllImport包装器。
(2) 在类中实现基本的COM功能并使用COM互操作。最小动作集:
a) 实现IUnknown和IMarshal方法:
class YourClass: public IMarshal
{
// override AddRef, Release, QueryInterface and Marshal here
...
int __declspec(stdcall) foo(int x);
}
b) 然后ComImport你的类在C#:
[ComImport, Guid("5BADB572-FE70-4602-8854-E4B461FC5DAE")]
class YourClass
{
[PreserveSig] int foo(int x);
}
c) 编写一个创建YourClass实例的c++函数,将其从DLL导出并为其编写DllImport包装。
完成任务有几个先决条件。
- 您必须确认文件所在的位置
- 您必须为要调用的方法输入签名
假设您的dll(mycpp.dll)位于位置"c:\mycpp.dll",并且有一个名为"Sum"的方法,它分别接受两个int参数a和b并返回int。您可以使用以下代码:
public class Program
{
[DllImport(@"c:mycpp.dll")]
private static extern int Sum(int a, int b);
static void Main(string[] args)
{
Console.WriteLine(Sum(3,5));
}
}
p.S:您可以在以下位置找到原始代码:C#中的动态调用C++DLL函数
- 挂起和取消挂起一个文件DLL
- std::threads可以从Windows DLL中的全局变量创建/销毁吗?
- 导入库可以跨dll版本工作吗
- 从C++dll访问C#中的一行主要参数
- 链接到自行创建的dll失败
- 为什么使用 P/Invoke 调用 dll 时,某些计算机中的 LoadLibrary 失败?
- 在调用FreeLibrary后,释放动态链接到具有相同版本的CRT堆的DLL的内存
- 如何指定我希望我的LIB链接到的DLL文件?-Visual Studio 2019
- 如何将图像传输到c++(dll)中的缓冲区,然后在c#的缓冲区中读/写
- C++:将外部库链接到dll库
- 在 Windows 上,是否可以让 dll 在不使用 PATH 环境变量的情况下在另一个文件夹中查找依赖项?
- 不同的Visual Studio版本中缺少.dll
- 从DLL中删除类的实例
- 如何包装第三方DLL在R中使用
- 使用c#访问c++dll中带有char*参数的函数时发生AccessViolationException
- 系统.将数组移交给c#中动态加载的c++DLL时发生AccessViolationException
- 为什么导入Mixed native/CLR lib.dll的本机C++应用程序没有在Mixed lib.dll中的外部变
- 当我使用 C++ 中的 C# dll 来使用 Selenium 时,存在异常处理问题
- Python ctypes:不会按预期加载 dll
- 在 C++/CLI 中将 .NET 事件从一个 DLL 引发到另一个 DLL