bonk said:
I like your answer better than the One from Atul.
We aim to please.
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/d...tsfrompureintermediatelanguagetomixedmode.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:
p_Explicit(gch).ToInt32();
}
void Deallocator(int h)
{
GCHandle gch;
gch = GCHandle:
p_Explicit(h);
gch.Free();
}
void SayHello(int h)
{
GCHandle gch;
Class1 __gc *cl1;
gch = GCHandle:
p_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()
{
:
eallocator(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