Managed C++ "wrapper classes" deployment problem 
Author Message
 Managed C++ "wrapper classes" deployment problem

I'm facing a bit of a problem wrapping some old unmanaged code in
managed C++ classes. The Visual C++ .NET Migration docs have some good
examples of how to do this in the simple case, but I want to
distribute the managed wrappers with little or no source code (as part
of an SDK). The unmanaged code being wrapped is legacy code that has
been written by several different customers, all of whom compile this
code to static libraries. These .libs contain classes that all
implement the same set of interfaces (which I want to wrap). The
essential problem is that I can't build my managed wrappers to an
assembly, because the end-user of the SDK needs to statically link
their unmanaged .lib with the wrappers. But I can't seem to compile
the managed wrappers to a .lib either, at least not without losing all
the metadata when I finally link that .lib with the unmanaged .lib to
form an assembly.

I've tried separating the wrappers into their own assembly that
accepts an unmanaged pointer to the interface implemented by the
unmanaged .lib, but the compiler didn't like that (for reasons that
should probably be obvious to me, but aren't because I don't
understand managed/unmanaged interoperability well enough). I tried
the same thing using IntPtr and ugly casting instead, but that seemed
to cause lots of heap errors when destroying STL strings and the like
(again, for reasons that I want to better understand). The solution I
finally settled on goes something like this...

I have a managed interface, call it IFoo, written in C# in the
assembly IFoo.dll. I have an unmanaged C++ interface, IOldFoo, defined
in a header file. The SDK user supplies OldFoo.lib, which contains an
unmanaged class that implements IOldFoo. I want to write a Managed C++
wrapper for IOldFoo that implements IFoo, but I want to distribute as
little source as possible. What I ended up doing was implementing the
wrapper, Foo, and compiling it to a .lib (Foo.lib). This .lib also
contains an unmanaged class, UnmanagedFooFactory, that returns an IFoo
reference (that actually refers to an instance of Foo). Then I have
one source file (FooFactory.h) that defines the FooFactory managed C++
class that calls UnmanagedFooFactory to return an instance of IFoo.
This gets around the problem of the metadata of Foo being lost when it
gets compiled to a .lib, as well as the problem of the SDK user
requiring the source for Foo. Now all they need is the source for
FooFactory. This way, the SDK user gets FooFactory.h/.cpp, Foo.lib,
and IFoo.dll, and supplies OldFoo.lib to build the final assembly.
Pretty complicated!

This solution seems to work, but I'm not very comfortable with it
because I still don't really understand *why* it works. Does anybody
know if this solution will cause me problems in the future?



Wed, 29 Sep 2004 09:19:21 GMT  
 Managed C++ "wrapper classes" deployment problem


Quote:
> the managed wrappers to a .lib either, at least not without losing all
> the metadata when I finally link that .lib with the unmanaged .lib to
> form an assembly.

Remember, each object in a library will only be linked into the resultant
image if a symbol from that object is referenced from something else already
being linked into the image.

It sounds like nothing else being linked into the image references the
objects in this library.

If you want to force an object to be linked into the image, then don't put
that object into a library (as the entire purpose of a library is to allow
the linker to selectively pick objects without bringing unnecessary ones
into the image.)

Quote:
> I've tried separating the wrappers into their own assembly that
> accepts an unmanaged pointer to the interface implemented by the
> unmanaged .lib, but the compiler didn't like that (for reasons that
> should probably be obvious to me, but aren't because I don't
> understand managed/unmanaged interoperability well enough). I tried
> the same thing using IntPtr and ugly casting instead, but that seemed
> to cause lots of heap errors when destroying STL strings and the like
> (again, for reasons that I want to better understand). The solution I
> finally settled on goes something like this...

Are you statically linking to the CRT?  If so, then you need to remember
each DLL has it's own CRT (with a separate heap) and if you allocate from
one heap you cannot free into another heap.  This can make passing a
std::string that uses the default allocator a problem.


Wed, 29 Sep 2004 12:12:20 GMT  
 Managed C++ "wrapper classes" deployment problem

Quote:


> > the managed wrappers to a .lib either, at least not without losing all
> > the metadata when I finally link that .lib with the unmanaged .lib to
> > form an assembly.

> Remember, each object in a library will only be linked into the resultant
> image if a symbol from that object is referenced from something else already
> being linked into the image.

Does this apply to IL as well? Most of the classes in the wrapper .lib
are managed.

Quote:
> It sounds like nothing else being linked into the image references the
> objects in this library.

There is a chain of dependencies that ultimately does refer to the
classes in the wrapper .lib. Specifically, FooFactory (managed class
that builds as part of the final assembly) refers to
UnmanagedFooFactory (unmanaged class implemented in the wrapper .lib).
UnmanagedFooFactory refers to its product, FooWrapper (managed class
in wrapper .lib that wraps IOldFoo and implements IFoo). All three
parties involved (FooFactory, UnmanagedFooFactory, and FooWrapper) all
refer to IFoo, a managed interface that is imported from another
assembly.

I don't actually need FooWrapper to be publicly visible, since it is
accessible to the outside world via IFoo. The real issues here are
twofold: Firstly, I couldn't make FooWrapper publicly visible even if
I wanted to because its metadata (the CLR variety, in case it was
unclear from my original post) seems to vanish after building the
wrapper .lib (or possibly when linking it with the image). Secondly, I
need to introduce this unmanaged intermediary, UnmanagedFooFactory, in
order to give the final image something to link to in the wrapper
.lib.

All of this actually does work -- I can call IFoo, and I can see that
the methods implemented in FooWrapper are in fact being called, so I
know that it must be linking properly. But the two issues I mentioned
above worry me -- I'm not sure how reliable this solution is in
general. Is there a better way to do this?

Quote:
> If you want to force an object to be linked into the image, then don't put
> that object into a library (as the entire purpose of a library is to allow
> the linker to selectively pick objects without bringing unnecessary ones
> into the image.)

The problem isn't about forcing objects to link into the image, it's
about making sure their metadata is still visible somehow. After
linking the wrapper.lib into the image, I view the image with ILDASM
and see none of the metadata for the managed classes implemented in
the .lib, even though I *know* they're there, because I can trace into
their methods with the de{*filter*}.

Quote:
> > I've tried separating the wrappers into their own assembly that
> > accepts an unmanaged pointer to the interface implemented by the
> > unmanaged .lib, but the compiler didn't like that (for reasons that
> > should probably be obvious to me, but aren't because I don't
> > understand managed/unmanaged interoperability well enough). I tried
> > the same thing using IntPtr and ugly casting instead, but that seemed
> > to cause lots of heap errors when destroying STL strings and the like
> > (again, for reasons that I want to better understand). The solution I
> > finally settled on goes something like this...

> Are you statically linking to the CRT?  If so, then you need to remember
> each DLL has it's own CRT (with a separate heap) and if you allocate from
> one heap you cannot free into another heap.  This can make passing a
> std::string that uses the default allocator a problem.

Aha! I forgot about that. Thanks for the tip.


Sat, 02 Oct 2004 01:36:20 GMT  
 
 [ 3 post ] 

 Relevant Pages 

1. managed C++ wrapper around unmanaged C++ classes: causing StackOverflow exception

2. Managed C++ wrappers for unmanaged C++ classes

3. Referencing data from unmanaged code to managed code in C++ Wrapper class

4. Tutorial wanted for using a managed C++ class wrapper

5. Creating a managed C++ class wrapper

6. C "wrapper" around int 21,9

7. HOWTO: throw "managed excpetions"

8. "Class Not Registered" ON aggregated class

9. "New Class: Base Class" (Classwizard)

10. Classes disappear from "class view"

11. New class: "MFC class" gone

12. Making managed wrapper for legacy unmanaged classes.

 

 
Powered by phpBB® Forum Software