15

I have an unmanaged dll with a class "MyClass" in it. Now is there a way to create an instance of this class in C# code? To call its constructor? I tried but the visual studio reports an error with a message that this memory area is corrupted or something.

Thanks in advance

Evgeny007
  • 642
  • 2
  • 6
  • 8
  • 1) static void Main(string[] args) { IntPtr p = new IntPtr(); Program.CreateObserv(ref p); } [DllImport(@"C:\mm_2008\liba.dll", EntryPoint = "??0CRls@fld@@QAE@ABV01@@Z", SetLastError = true, CallingConvention = CallingConvention.ThisCall)] internal static extern void CreateObserv(ref IntPtr p); this code throws an AccessViolationException: accessviolationexception attempted to read or write protected memory... – Evgeny007 Apr 14 '10 at 12:00
  • 2) static void Main(string[] args) { IntPtr p = Program.CreateObserv(); } [DllImport(@"C:\mm_2008\liba.dll", EntryPoint = "??0CRls@fld@@QAE@ABV01@@Z", SetLastError = true, allingConvention = CallingConvention.ThisCall)] internal static extern IntPtr CreateObserv(); - this code crushes the application and app host – Evgeny007 Apr 14 '10 at 12:01
  • To avoid mangled entry point names like "??0CRls@fld@@QAE@ABV01@@Z", use extern "C" in unmanaged Dll. Function declared as extern "C" is exported without name mangling. – Alex F Apr 14 '10 at 12:11
  • 1
    @Evgeny007 don't put code in comments, delete your comments and put the code in the question. – Scott Chamberlain Dec 07 '16 at 17:21

3 Answers3

22

C# cannot create class instance exported from native Dll. You have two options:

  1. Create C++/CLI wrapper. This is .NET Class Library which can be added as Reference to any other .NET project. Internally, C++/CLI class works with unmanaged class, linking to native Dll by standard C++ rules. For .NET client, this C++/CLI class looks like .NET class.

  2. Write C wrapper for C++ class, which can be used by .NET client with PInvoke. For example, over-simplified C++ class:


    class MyClass()
    {
    public:
        MyClass(int n){data=n;}
        ~MyClass(){}
        int GetData(){return data;}
    private:
        int data;
    };

C API wrapper for this class:


    void* CreateInstance()
    {
        MyClass* p = new MyClass();
        return p;
    }

    void ReleaseInstance(void* pInstance)
    {
        MyClass* p = (MyClass*)pInstance;
        delete p;
    }

    int GetData(void* pInstance)
    {
        MyClass* p = (MyClass*)pInstance;
        return p->GetData();
    }

    // Write wrapper function for every MyClass public method.
    // First parameter of every wrapper function should be class instance.

CreateInstance, ReleaseInstance and GetData may be declared in C# client using PInvoke, and called directly. void* parameter should be declared as IntPtr in PInvoke declaration.

user1278577
  • 325
  • 4
  • 7
Alex F
  • 42,307
  • 41
  • 144
  • 212
  • 1
    You miss an extern "C" in the wrapper functions. – Danvil Apr 16 '10 at 08:09
  • Danvil - this is what I wrote in the question note. Anyway, thanks, I really feel better now. – Alex F Apr 16 '10 at 15:02
  • @Alex What if there is a hierarchy of classes in the native C++ dll...?? – rsjethani May 07 '12 at 19:19
  • What makes it a "C" API? Aren't `new` and `delete` C++ constructs? Seems like just a static C++ API – Rotem Jan 22 '18 at 08:42
  • @Rotem: I mean, this wrapper is available for C client, as well as any client working with C-style API: .NET PInvoke, Assembly, Delphi etc. Wrapper itself is implemented in C++. – Alex F Jan 29 '18 at 09:53
3

The solution is create C++/CLI wrapper like:

#include "DllExportClass.h"

public ref class ManagedOperationHelper
{
    public:

    double Sum(double add1, double add2)
    {
        CDllExportClass obj;
        double ret=obj.Sum(add1, add2);
        return ret;
    }

    double Mult(double mult1, double mult2)
    {
        CDllExportClass obj;
        double ret=obj.Mult(mult1, mult2);
        return ret;
    }
};

where CDllExportClass is the class exported from native code. Above is the .h of the C++/CLI. Take care to let find the lib to this dll. Put the dll and the lib in the same directory and compile the C++/CLI code.In the managed code directory put the native dll and the C++/CLI dll. In the managed project put the reference of the C++/CLI project. Instanciate in the maged code the C++/CLI class like:

ManagedOperationHelper obj = new ManagedOperationHelper();
double ret=obj.Sum(10, 20);  

It's all.

bluish
  • 26,356
  • 27
  • 122
  • 180
2

You can not use unmanged C++ code directly in C#. The interoperability can be done using PInvoke. There are a lot of issues related to this topic, especially when calling functions which have pointers as arguments.

The basic procedure goes like this:

C# part

namespace MyNamespace {
  public class Test {
    [DllImport("TheNameOfThe.dll")]
    public static extern void CreateMyClassInstance();

    public void CallIt() {
        CreateMyClassInstance(); // calls the unmanged function via PInvoke
    }
  }
}

C++ part

class MyClass {
  public: MyClass() { /** Constructor */ }
};

MyClass* staticObject;

extern "C" void CreateMyObjectInstance() {
   staticObject = new MyClass(); // constructor is called
} 
Danvil
  • 22,240
  • 19
  • 65
  • 88
  • thanks to everyone, I hated to admit it but looks like there is no other way besides writing a wrapper. – Evgeny007 Apr 14 '10 at 12:09
  • Other option is to write managed c++ using compiler /crl flag. Then you can mix unmanaged and managed code in same dll and then simple call managed methods in your C# code. It will produce sam IL code as you would wrap native methods in your code. Quick intro http://www.codeproject.com/Articles/19354/Quick-C-CLI-Learn-C-CLI-in-less-than-minutes – Milan Jaric Nov 12 '15 at 07:48
  • 1
    The link is dead – Michael Santos Dec 21 '21 at 12:48