Re: create a wrapped managed dll that can be used from pure unmanaged code



"bonk" <schwertfischtrombose@xxxxxx> wrote in message
news:%23D8wVcA1FHA.2792@xxxxxxxxxxxxxxxxxxxxxxx
> I like your answer better than the One from Atul.

We aim to please. :-)

> Thx.

You are welcome.

> I will look into it right away. Yes we can target .net 2.0 exclusively and
> yes we will use vs 2005. I am working with c++/CLI and vs 2005 beta 2
> right now.

Then you are a few steps ahead of me. I hear that the mixed-mode interop
story is significantly better with C++/CLI and .Net 2.0 but I have had no
time to experiment with it.

> there is one thing I still cannot understand. It has to do with how to
> wrap the managed stuff away in that dll. You say I would "write unmanaged
> (native) code which calls into managed code" and some of those unmanaged
> classes that call into managed code will be exposed using
> __declspec(dllexport) correct?

This is always problematic. Exporting a class based interface from a DLL
where you explicitly export the methods by name is usually only possible in
an environment where all DLL clients use the same compiler. I see that Tom
has already proposed one approach.

> If so those unmanaged wrapper classes will need to hold some private
> members to the managed classes
> (gcroot <ManagedType^> m_mythingy) and I will need to declare it as such
> in the header. When I want to use the dll (with its lib) from another
> plain unmanaged project I will need to include the header for it and it
> will now have gcroot <ManagedType^> m_mythingy; somewhere in the class
> declaration. Wich is not possible since my project does not have /clr. How
> am I supposed to wrap that away ?

Well, my MVP buds may slap me on the wrist for this, but one thing you can
do is eschew the gcroot template class, use the managed class GCHandle
(garabage collector handle) directly - which is what gcroot does - and cast
that handle to an integer. Of course, all type information is "lost" when
you do that, and later when you cast from integer back to managed type you
better cast correctly or _very_ bad things will happen. :-)

I should tell you that I started to put this reply together before Tom
posted his, had dinner, and saw Tom's reply. Feel free to ignore it. But
since it took me more than 30 minutes to test and debug, I thought I'd post
it in its entirety. :-)

First, I used this C# class to create an assemby: ClassLibrary1

//------------------------------------------------------------
using System;
using System.Runtime.InteropServices;

namespace ClassLibrary1
{
public class Class1
{
public Class1()
{
}

public void SayHello()
{
Console.WriteLine("C# says hello!");
}
}
}
//------------------------------------------------------------

Then I created a DLL which defines a unmanaged class that proxies the
managed class: ClassLibrary1Shim

Note that I took the expedient approach of exporting an unmanaged procedural
function. Exporting the shim class is left as an exercise to the interested
reader. :-) What I've done here is admittedly not very elegant, but it is
very simple. The implemention of every method in the shim class starts out
as unmanaged code and uses IJW to complete the job in managed code. Note
that the shim class stores the garbage collector's handle to the instance of
the managed class as an integer. OK, it's a hack.

Note that you must follow the rules here to build a mixed-mode DLL.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcmex/html/vcconconvertingmanagedextensionsforcprojectsfrompureintermediatelanguagetomixedmode.asp

//------------------------------------------------------------
using <mscorlib.dll>

using namespace System;
using namespace System::Runtime::InteropServices;
using namespace ClassLibrary1;

#pragma managed

int Allocator()
{
GCHandle gch;
Class1 __gc *cl1;

cl1 = new ClassLibrary1::Class1();
gch = GCHandle::Alloc(cl1);
return GCHandle::op_Explicit(gch).ToInt32();
}

void Deallocator(int h)
{
GCHandle gch;

gch = GCHandle::op_Explicit(h);
gch.Free();
}

void SayHello(int h)
{
GCHandle gch;
Class1 __gc *cl1;

gch = GCHandle::op_Explicit(h);
cl1 = dynamic_cast<Class1 *>( gch.get_Target() );

cl1->SayHello();
}

#pragma unmanaged

class NativeClassLibrary1
{
private:

int h;

public:

NativeClassLibrary1();
~NativeClassLibrary1();
void SayHello();
};

NativeClassLibrary1::NativeClassLibrary1()
{
h = ::Allocator();
}

NativeClassLibrary1::~NativeClassLibrary1()
{
::Deallocator(h);
}

void NativeClassLibrary1::SayHello()
{
::SayHello(h);
}

void __stdcall TheUmanagedExportFunction()
{
NativeClassLibrary1 ncl1;

ncl1.SayHello();
}
//------------------------------------------------------------

I used this module defintion file to build the DLL above.


//------------------------------------------------------------
LIBRARY ClassLibrary1Shim
EXPORTS

TheUmanagedExportFunction

//------------------------------------------------------------

And this is the native executable I used to test the whole mess. Note that I
load the DLL manually only because I am terminally lazy with toy samples.

//------------------------------------------------------------
#include <windows.h>

int main()
{
FARPROC fp;
HINSTANCE h;

h = LoadLibrary("ClassLibrary1Shim.dll");
fp = GetProcAddress(h, "TheUmanagedExportFunction");

(*fp)();

return 0;
}
//------------------------------------------------------------

Finally, I don't know what to make of this, but everything works well except
when I try to enable mixed-mode debugging. Then the IDE crashes. :-(

Regards,
Will












.



Relevant Pages

  • Re: Integrating with legacy code
    ... Removed nochkclr.obj as a linker input ... Extention DLL. ... access them from within the web service, ... >order to add managed code to it: ...
    (microsoft.public.dotnet.general)
  • Re: MFC DLL - ExitInstance hang on WaitForSingleObject
    ... Here is a simple pooling class implemented into a MFC DLL project. ... BOOL CPooler::StartPooling ... // Look for empty place in the array and create the Pooler ... void Enqueue(POOLER_CALLBACK_FN f, LPVOID p); ...
    (microsoft.public.vc.mfc)
  • Re: Calling a matlab dll in java
    ... you mention about putting a -nojvm option when initializing the dll ... the matlab generated library inside my jni-dll) ... all compiler and linker options in VS took me a while, ... JNIEXPORT void JNICALL ...
    (comp.soft-sys.matlab)
  • Re: Strange file not found exception
    ... Assemblies *must* reside in same directory. ... DLL on Windows Server 2003 x64 using PIA interop. ... I find creating a COM coclass object in managed code is ok, ...
    (microsoft.public.vc.language)
  • Dependency walker msvcr80d.dll missing coredll.dll and dwmapi.dll
    ... I've completed migrating one of our company's C++ Managed Code ... The dll is written in MFC with sections of C++ ... The dll exports its objects in the same manner as any VS2005 Solution Wizard ... In fact when I peer into the dll with the DepedencyWalker app, ...
    (microsoft.public.dotnet.languages.vc)

Loading