【问题标题】:Wrap C++ class DLL in C#在 C# 中包装 C++ 类 DLL
【发布时间】:2015-02-05 08:13:22
【问题描述】:

我必须在新的 C# 项目中使用 C++ 现有代码。此 C++ 代码是包含在 DLL 中的非托管代码。我的一位同事已经使用“C”代码做到了这一点,但就我而言,我的 DLL 包含一个“类”,我不知道是否可以这样做。

在我的 C# 应用程序中使用这个 C++ 类的正确方法是什么?

更新:

感谢所有这些答案。我尝试按照这篇文章Using Unmanaged C Libraries DLLS in NET Application

用一个简单的类来做到这一点

我的初始课程是在 Borland C++ Builder 6 上编写的:

Test.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;
}

Test.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

这个类的编译OK :D

然后我尝试创建文章中的非托管类。但是我在 C++ Builder 中创建这个类时遇到了问题。

Unmanaged.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);
        }
};

Unmanaged.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)

【问题讨论】:

标签: c# c++ dll


【解决方案1】:

我可以提出 2 个解决方案。 (1) 通过标记 __declspec(dllexport) 导出整个 C++。它的所有方法都将从 DLL 中导出,并带有一些错误的名称。找到这些名称(例如,通过 Depends 实用程序)并在 C# 代码中编写 DllImport 包装器。

(2) 在您的班级中实现基本的 COM 功能并使用COM interop。最小动作集:

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 包装器。

【讨论】:

    【解决方案2】:

    完成您的任务有几个先决条件。

    1. 您必须知道文件所在的位置。
    2. 您必须知道要调用的方法的签名。

    假设您的 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:您可以在以下位置找到原始代码:Dynamic Invoke C++ DLL function in C#

    【讨论】:

    • 我不知道这是否回答了问题,因为它专门询问如何处理 DLL 中的 C++ 。我认为 OP 已经知道如何调用这些函数,因为他写道,他的同事使用 C 代码执行此操作。重要的部分似乎是这里的 class 。不幸的是,我不知道这是否可能或如何去做,但我也对这个案例很感兴趣。有一个相关的问题,虽然看起来很像。
    • 是的,这很重要。我有调用函数的代码,我知道该怎么做。我想要做的是在我的 C# 代码中使用在 C++ DLL 中定义的类,我不知道它是否可能。我还在寻找:D
    • 如果您正在考虑使用 C# 中的 MyClass.Sum(3, 5) 之类的代码,我认为您不能。由于非托管 dll 没有 CLR 标头,因此您无法以这种方式访问​​类信息。但是,正如here 中所建议的那样,为您的 C++ 代码提供 C 接口可能是一个好主意
    猜你喜欢
    • 1970-01-01
    • 2011-04-27
    • 1970-01-01
    • 2013-07-28
    • 2011-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多