简体   繁体   中英

Call C++ native/unmanaged member functions from C# when member functions were not exported

I have an unmanaged DLL that exports only a C style factory method that returns a new instance of a class (simplified here to look simple).

hello.h

#if defined(HWLIBRARY_EXPORT) // inside DLL
#   define HWAPI   __declspec(dllexport)
#else // outside DLL
#   define HWAPI   __declspec(dllimport)
#endif

struct HelloWorld{
   public:
    virtual void sayHello() = 0;
    virtual void release() = 0;
};
extern "C" HWAPI HelloWorld* GetHW();

hello.cpp

#include "hello.h"

struct HelloWorldImpl : HelloWorld
{
    void sayHello(){
    int triv;
    std::cout<<"Hello World!";
    std::cin>>triv;
};
void release(){
    this->HelloWorldImpl::~HelloWorldImpl();
};
HelloWorld* GetHW(){
HelloWorld* ptr = new HelloWorldImpl();
return ptr;
};

Now, I can use dllimport to access GetHW() but is there a way to access the member functions of the returned 'struct'... ie, sayHello and release?

I was also stuck with the same problem. This question was asked a while before. I commented to it for any better solution but didn't get any reply yet. So, reposting it.

When i googled, able to find out two solutions.

Solution1: Expose all the member functions in the C-style for the existing dll. Which i cant do, as it is a 3rd party dll.

Solution2: Write a managed C++ dll exposing the functionality of native C++ dll, which later can be used in your C# dll. Here many classes/functions are present. So, creating would take most of the time.

i got the above solutions from the link below. How To Marshall

Please let me know if there is any better solution other than the above two solutions?

i have the source code for C++ solution. But what i though was not to touch C++ dll. If there is any possibility to do it in C#, it would be great.

If there is no alternative, i need to follow any one of the specified two solutions.

The C++ code is using the way abstract classes are implemented by the Visual C++ compiler. http://blogs.msdn.com/b/oldnewthing/archive/2004/02/05/68017.aspx . This memory layout is "fixed" because it is used for implementing COM interfaces. The first member of the struct in memory will be a pointer to a vtable containing the function pointers of your methods. So for a

struct HelloWorldImpl : public HelloWorld
{
   public:
    int value1;
    int value2;
}

the "real" layout in memory would be:

struct HelloWorldImpl
{
    HelloWorldVtbl *vtbl;
    int value1;
    int value2;
}

where vtbl would be:

struct HelloWorldVtbl
{
    void *sayHello;
    void *release;
}

Just for the sake of doing a complete response, I'm writing the example for this signatures:

struct HelloWorld {
   public:
    virtual int sayHello(int v1, int v2, int v3) = 0;
    virtual void release() = 0;
};

C# code:

[DllImport("NativeLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr GetHW();

[StructLayout(LayoutKind.Sequential)]
struct HelloWorldVtbl
{
    public IntPtr sayHello;
    public IntPtr release;
}

Your functions are void Func(void) or int Func(int, int, int) , but in truth they have a hidden parameter, this , so you can write them as:

int sayHello(HelloWorld*, int, int, int);
void release(HelloWorld*);

so in C# the delegate is

[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
public delegate int Int32MethodInt32Int32Int32(IntPtr ptr, int v1, int v2, int v3);

[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
public delegate void VoidMethodVoid(IntPtr ptr);

Then you can use

IntPtr ptr = GetHW();
IntPtr vtbl = Marshal.ReadIntPtr(ptr, 0);

HelloWorldVtblhw = (HelloWorldVtbl)Marshal.PtrToStructure(vtbl, typeof(HelloWorldVtbl));

Int32MethodInt32Int32Int32 sayHello = (Int32MethodInt32Int32Int32)Marshal.GetDelegateForFunctionPointer(hw.sayHello, typeof(Int32MethodInt32Int32Int32));
int res = sayHello(ptr, 1, 2, 3);
Console.WriteLine(res);

VoidMethodVoid release = (VoidMethodVoid)Marshal.GetDelegateForFunctionPointer(hw.release, typeof(VoidMethodVoid));
release(ptr);

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