简体   繁体   中英

Wrap C++ class DLL in C#

I have to use C++ existing code in a new C# project. This C++ code is an unmanaged code contained in a DLL. One of my colleague already did this with "C" code, but in my case, my DLL contain a "Class" and I don't know if it is possible to do this.

What is the right way to use this C++ Class in my C# Application?

Update:

thanks for all theses answers. I tried do it with a simple class by following this article Using Unmanaged C Libraries DLLS in NET Application

My initial class is coded on 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

The compilation of this class is OK :D

Then I tried to create the unmanaged class like in the article. But I have a problem to create this class in 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

When I want to compile this unmanaged class I have these errors :/

[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)

I can propose 2 solutions. (1) Export the whole C++ by marking it __declspec(dllexport). All its method will be exported from DLL with some mangled names. Find these names (eg by means of Depends utility) and write DllImport wrappers in C# code.

(2) Implement basic COM features in your class and use COM interop . Minimal action set:

a) implement IUnknown and IMarshal methods:

class YourClass: public IMarshal
{
  // override AddRef, Release, QueryInterface and Marshal here
  ...

  int __declspec(stdcall) foo(int x);
}

b) Then ComImport your class in C#:

[ComImport, Guid("5BADB572-FE70-4602-8854-E4B461FC5DAE")] 
class YourClass
{ 
  [PreserveSig] int foo(int x);
}

c) Write a C++ function creating YourClass instances, export it from DLL and write DllImport wrapper for it.

There are several prerequisites to accomplish your task.

  1. You have to knpw where the file resides.
  2. You have to knpw the signature for the method(s) you wish to call.

Suppose that your dll (mycpp.dll) is at location "c:\\mycpp.dll" and there is a method named " Sum ", which takes two int parameters a and b respectively and returns int. You can use the following code:

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

PS: You can find the original piece of code at : Dynamic Invoke C++ DLL function in C#

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM