Mixed mode dll, intellecutal exercise

R

Robert Ginsburg

I have a DLL that is "mixed mode" in that it is both an ATL com server and a
reference managed C++ class. For the most part it works, however the problem
I have (which may simply not be solvable) is that I want to call managed
code from the unmanaged (ATL classes). It is quite easy to go the other way
from managed to unmanaged, but is there any way I can expose the managed
class to the unmanaged caller.

I came into this while upgrading a ATL project, I do realize that it will be
"better" to simply recreate the class as a managed class and expose the COM
server using interop, but the question remains. Can you call from unmanaged
to managed in a mixed mode dll ?

-Robert
 
W

William DePalo [MVP VC++ ]

Robert Ginsburg said:
I have a DLL that is "mixed mode" in that it is both an ATL com server and
a reference managed C++ class. For the most part it works, however the
problem I have (which may simply not be solvable) is that I want to call
managed code from the unmanaged (ATL classes). It is quite easy to go the
other way from managed to unmanaged, but is there any way I can expose the
managed class to the unmanaged caller.

Yes, of course.

With Managed C++ (VS2003) or C++/CLI (VS2005) it is possible to include
modules that call on both the Win32 API and .Net's base class library.

One way to do what you want is to use what used to be called "it just works"
and which is now called "C++ interop". You compile the modules that contain
the managed functions with the /clr switch (which shows up as "use managed
extensions") The compiler does most of the grunt work.

Take a look at these articles to get started:

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

http://msdn.microsoft.com/msdnmag/issues/04/05/VisualC2005/

If any of it is not clear post again with more detail.

Regards,
Will
 
R

Robert Ginsburg

Hopefully I am not being overly dense, but I cant seem to make it work. Here
is a specific example,
1) Create a new ATL project, make it a DLL, add an ATL class to it add a
method to it, it all works fine.
2) Now add CLR support and recompile it, still works fine
3) Now add a .NET class and a method, still works
4) Now how do you call the .net Method class from the COM component module ?

If I include the .NET class definition header, the compiler complains about
the format of it, and wont compile
If I dont include the header, the compiler complains that it is not defined
If I try to use the gcroot template, it does not know the name of the .NET
class.


Thanks in advance

-Robert
 
W

William DePalo [MVP VC++ ]

Robert Ginsburg said:
If I include the .NET class definition header, the compiler complains
about the format of it, and wont compile
If I dont include the header, the compiler complains that it is not
defined
If I try to use the gcroot template, it does not know the name of the .NET
class.

There are some here who are good at answering questions in the abstract. I'm
not among them.

In the concrete, I'd need to know why the compiler "complaining" about the
header? Is the module that includes it compiled with the /clr switch?

In the abstract, I'm not sure how much this will help, but it is my story
....

In an application of mine where there is an unmanaged function which needs
to create an instance of a managed class, I have a module which has both
managed and unmanaged sections. I delimit the sections with

#pragma managed

...

#pragma unmanaged

In the unmanaged function I call a managed helper function which creates an
instance of the managed class. I use the Alloc member function of the
GCHandle class to get a handle to the object. I convert that to an integer
with

GCHandle::blush:p_Explicit( /* handle goes here */).ToInt32();

It is that integer which I hold on the native side of my application to
refer to the managed object. Of course, it has no meaning except in managed
code. There I use

GCHandle::blush:p_explicit( /* integer goes here */) ;

to convert the integer to a GC handle. That handle can be used to get an
object with the get_target() function of the GCHandle class.

Note that I am not claiming this is a "best practice". It was simply the
most expedient way to add support for .Net plugins to an application of mine
two years ago. You may find it easier and more elegant to use the gcroot
template.

Regards,
Will
 
R

Robert Ginsburg

Will,
If my managed header includes a #using <mscorlib.dll>, then the compiler
breaks on the unmanaged class with a
Error 1 fatal error C1190: managed targeted code requires a '/clr' option
c:\my code\ijwtest\ijwtest\managedkaboom.h 2

If I dont have that, of course it cant understand the module syntax and
reports the following
When I include the managed header in the unmanaged module the compiler
reports the following errors
Error 2 error C2871: 'System' : a namespace with this name does not exist
c:\my code\ijwtest\ijwtest\ManagedKaboom.h 4
Error 3 error C2059: syntax error : 'public' c:\my
code\ijwtest\ijwtest\ManagedKaboom.h 11
Error 4 error C2143: syntax error : missing ';' before '{' c:\my
code\ijwtest\ijwtest\ManagedKaboom.h 12
Error 5 error C2447: '{' : missing function header (old-style formal list?)
c:\my code\ijwtest\ijwtest\ManagedKaboom.h 12

ManagedKaboom.H
#pragma once
//#using <mscorlib.dll>
using namespace System;
namespace IJWTest {

public ref class ManagedKaboom
{
public:
ManagedKaboom(void)
{
}
~ManagedKaboom()
{
}
String^ HelloWorld();
};
}

the module is marked with /clr , here it is
#pragma managed
#include "ManagedKaboom.h"


String^ IJWTest::ManagedKaboom::HelloWorld()
{
return "Managed Howdy";
}

So using your technique what would a simple module look like that called
this from unmanaged code (my current prototype is below)
STDMETHOD(HelloWorld)(BSTR* pVal);

Thanks Again
robert
 
R

Robert Ginsburg

So while just poking aroud I added this to the header of my unmanaged class:
#include "stdafx.h"
#include "Kaboom.h"

#using < mscorlib.dll >
#include < vcclr.h >
#include "ManagedKaboom.h"
#pragma unmanaged

and this in the actual function call
STDMETHODIMP CKaboom::HelloWorld(BSTR* pVal)
{
gcroot<IJWTest::ManagedKaboom^> mKaboom = gcnew IJWTest::ManagedKaboom();
return S_OK;
}


And the compiler says

Error 1 error C3821: 'IJWTest::ManagedKaboom': managed type or function
cannot be used in an unmanaged function c:\My
Code\IJWTest\IJWTest\Kaboom.cpp 16

-Robert
 
W

William DePalo [MVP VC++ ]

Robert Ginsburg said:
If my managed header includes a #using <mscorlib.dll>, then the compiler
breaks on the unmanaged class with a
Error 1 fatal error C1190: managed targeted code requires a '/clr' option
c:\my code\ijwtest\ijwtest\managedkaboom.h 2

Right. As they might say in Brooklyn - C++ doesn't know from pound sign
using. It is a Microsoft extension.

You need to tell the compiler that it is not ISO standard C++ that you
target. From the IDE's menu choose Project->Properties. In the left pane
"open" the "Configuration" folder.Select "General". In the right pane find
the box labelled "Use managed extensions" and set its value to "Yes".
Thanks Again

You are welcome.

Regards,
Will
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top