Asim Patnaik

Hi,

I have a Win32 dll that has a class (say C) which has a method (say M). What I want is to instantiate the class C and invoke the method M on that instance.

I know how to call functions using DllImport but dont know how to instantiate a class and invoke method on that.

Please guide me.

Regards,

Asim.



Re: Visual C# Language Using P/Invoke to create instance of class

Frank Boyne

I don't think you can use P/Invoke to do what you describe. The DllImportAttribute is decorated with the value AttributeUsageAttribute (AttributeTargets.Method) meaning it can only be applied to a method, not to a class or any of the orther possible AttributeTargets.

You could implement a CFactoryMethod in your Win32 DLL that returned a pointer to class C instance as a result and could invoke that factory method using P/Invoke. That would allow you to instantiate a C object as an IntPtr but by itself that IntPtr isn't much use.

You could also have your Win32 DLL implement an MWrapper method that took all the same parameters as the method M's parameters plus an extra pointer to C parameter. You could call MWrapper using P/Invoke and could pass the IntPtr returned by the factory method as the "pointer to C" parameter.

Of course all that only works if you can modify your Win32 DLL.

Update: The first paragraph above is just wrong.

The CallingConvention enumeration contains a value "ThisCall" specifically to allow calls to exported Class methods. You are still limited to only calling methods on the class, you can't (for example) directly access public member fields. The whole exercise looks somewhat non-trivial. I haven't tried this myself yet, but this code-project article seems to offer some guidance:

http://www.codeproject.com/useritems/usingcppdll.asp





Re: Visual C# Language Using P/Invoke to create instance of class

SThotakura2

May be you can think of converting your Win32 dll into a COM dll, with a design like interface-implementation. Then you can use it in your C# code just by addina reference to that COM dll.

Or

You can develop a COM wrapper dll with a COM wrapper class to your win32 dll calss C - with proxy methods to actual win32 dll Class methods.





Re: Visual C# Language Using P/Invoke to create instance of class

Frank Boyne

I used Visual Studio 2005 to create a C++ Win32 project and set the Application Type to DLL and checked the Export symbols box to get a quick an dirty DLL that exports a C++ Class. I then added a private member variable of type int and added two public methods - one to set the int and one to retrieve the int value. The class looks like this...

Code Snippet

// This class is exported from the NativeClassExport.dll

class NATIVECLASSEXPORT_API CNativeClassExport {

private:

int mMyInt;

public:

CNativeClassExport(void);

// TODO: add your methods here.

int get_MyInt (void);

void put_MyInt (int val);

};

To keep things simple (and because haven't figured out how to construct a C++ class from C# yet) I also created a factory function in the native DLL that looks like this...

Code Snippet

extern "C" {

NATIVECLASSEXPORT_API CNativeClassExport * NativeClassExportFactory (void);

}

The implementation of the factory function looks like this

Code Snippet

extern "C" {

NATIVECLASSEXPORT_API CNativeClassExport * NativeClassExportFactory (void)

{

return new CNativeClassExport ();

}

}

The C# description of the factory object looks like this

Code Snippet

[DllImport("NativeClassExport.dll",

CallingConvention = CallingConvention.Cdecl)]

static extern IntPtr NativeClassExportFactory();

The C# description of the two Class methods look like this...

Code Snippet

[DllImport ("NativeClassExport.dll",

EntryPoint = " put_MyInt@CNativeClassExport@@QAEXH@Z",

CallingConvention=CallingConvention.ThisCall)]

static extern void put_MyInt(IntPtr thisPtr, int val);

[DllImport ("NativeClassExport.dll",

EntryPoint = " get_MyInt@CNativeClassExport@@QAEHXZ",

CallingConvention = CallingConvention.ThisCall)]

static extern int get_MyInt(IntPtr thisPtr);

To get the Entrypoint values for the methods I ran Depends against the NativeClassExport.dll file and examined the actual names of the methods. I could also have used the DumpBin utility.

One downside to this approach is that the C++ decorated name of the methods can change when you recompile the DLL. If they do, then you have to re-run Depends or DumpBin and then change the EntryPoint values to match the new decorated names. You could use Ordinal rather than name to identify the entry point but Ordinals can suffer from the same problem of changing aftera recompile.

With all the above a C# program can create an instance of the exported class and can call the public methods of that class...

Code Snippet

IntPtr theClass;

// construct the class pointer

theClass = NativeClassExportFactory();

int i = 42;

put_MyInt(theClass, i);

int j = 0;

j = get_MyInt(theClass);

Console.WriteLine(j);





Re: Visual C# Language Using P/Invoke to create instance of class

Asim Patnaik

Hi Frank,

Thanks a lot for the answer. I did use the approach which you have given in your mail. As you have mentioned, the only problem is name mangling.

Is it possible to convert the Win32 dll to COM dll. I think by converting to COM dll, the name mangling issue would be resolved.

Regards,

Asim.





Re: Visual C# Language Using P/Invoke to create instance of class

Frank Boyne

Asim Patnaik wrote:
Is it possible to convert the Win32 dll to COM dll. I think by converting to COM dll, the name mangling issue would be resolved.

Oh absolutely. If you are familiar with COM, you could create a COM object that created and stored a private class pointer and which provided wrapper methods that called the real class methods via that private member. Of course COM has its own challenges!

Yet another option is to use Managed C++ to create a managed class which wraps the unmanaged class. In some ways that may be the best way forward. Paul DiLascia explains how in this column. http://msdn.microsoft.com/msdnmag/issues/05/09/CAtWork/

Be careful though. Paul's column was written before Visual studio 2005 was released so he uses the old __gc class syntax rather than the newer ref class syntax





Re: Visual C# Language Using P/Invoke to create instance of class

Asim Patnaik

Thanks a tonne again Frank.





Re: Visual C# Language Using P/Invoke to create instance of class

Lê Khánh Thành

Hello Frank,

Pls tell me how to use CNativeClassExport in Visual Basic application

Could you send me your CNativeClassExport project

Thank you so much !






Re: Visual C# Language Using P/Invoke to create instance of class

Frank Boyne

Le Khanh Thanh wrote:
Pls tell me how to use CNativeClassExport in Visual Basic application

It is pretty much exactly as I described above only Visual Basic uses '<' and '>' to enclose attributes instead of '[' and ']', uses := instead of = to assign named parameters and uses empty function bodies instead of the 'extern' keyword so the code looks like this (translated free-hand and not actually tested I'm afraid).

Code Block

<DllImport("NativeClassExport.dll", _

CallingConvention:=CallingConvention.Cdecl)> _

Function NativeClassExportFactory() As IntPtr

End Function

Code Block

<DllImport("NativeClassExport.dll", _

EntryPoint:=" put_MyInt@CNativeClassExport@@QAEXH@Z", _

CallingConvention:=CallingConvention.ThisCall)> _

Sub put_MyInt(ByVal thisPtr As IntPtr, ByVal val As Int32)

End Sub

<DllImport("NativeClassExport.dll", _

EntryPoint:=" get_MyInt@CNativeClassExport@@QAEHXZ", _

CallingConvention:=CallingConvention.ThisCall)> _

Function get_MyInt(ByVal thisPtr As IntPtr) As Int32

End Function