[Mono-dev] managed code wrappers (exceptions & garbage collection across pinvoke barriers)

Sebastian Good sebastian at palladiumconsulting.com
Sat Aug 25 16:37:47 EDT 2007


Thanks, I've read (and now-reread!) this fairly carefully, but my case is
about  C code calling CLI code, not the other way around, so I do not see
explicit instructions about things like, for instance, how to treat the
char* returned from the managed delegate. I would have expected the copy of
the char* I pass to the CLI ("hello", below) to be magically handled by the
CLI, but the document doesn't make 100% clear how to free the char* copy
that comes back from the managed delegate. It seems clear to me that the CLI
can't collect it for me (its lifetime must be managed by C), but it also
seems that I suffer a memory leak even if I try to g_free it. The equivalent
explicit marshaling
(mono_string_to_utf8(reinterpret_cast<MonoString*>(answer)) works like a
charm and leaks nothing.

On 8/25/07, Zoltan Varga <vargaz at gmail.com> wrote:
>
> Hi,
>
> Try our interop tutorial. It has some answers to your questions.
>
> http://www.mono-project.com/Interop_with_Native_Libraries
>
>             Zoltan
>
> On 8/25/07, Sebastian Good <sebastian at palladiumconsulting.com> wrote:
> >  Thanks to help on this list I've come a long way in embedding mono into
> my
> > C++ application. During the transition of a very large application (25+
> yrs
> > of C, Fortran, & C++) towards managed code, we will be adding new code
> in
> > .NET languages, but needing to access these objects from C++ fairly
> > intimately. Therefore I'm looking at writing wrappers which expose CLR
> > classes as C++ classes -- without resorting to (XP)COM or CORBA. I
> figure
> > most of these can be auto-generated. I believe it will make sense to
> emit
> > mono-embedding wrappers for Linux and Managed C++ wrappers for Windows.
> If
> > anyone else is interested (or has already undertaken!) such an effort,
> let
> > me know. However I'm still looking at some marshalling issues.
> >
> >  If I call .NET functions exclusively via the embedding reflection API,
> e.g.
> > mono_runtime_invoke, and carefully call g_free on returned copies of
> things
> > like strings, everything works fine, including managed exceptions. It
> seems
> > that  by caching the reflected objects, e.g. MonoMethod*, performance is
> > good.
> >
> >  However I am having problems with delegates invoked across the barrier.
> > They execute properly, but appear to leak memory, and I am not sure how
> to
> > catch exceptions they might throw. For the majority of our interop, we
> can
> > avoid attempting this scenario, but we'd like to investigate it so that
> we
> > can provide managed callbacks for unmanaged code to call.
> >
> >  In our C++, we define (using MSVC syntax for this prototype)
> >
> > // function: string->string
> >  typedef char* (__stdcall * action_string)(char*);
> >
> >  // managed code will stash a delegate here for use by unmanaged code
> >  action_string _f_string;
> >  extern "C" _declspec(dllexport) void __stdcall
> init_string(action_string f)
> >  {  _f_string =f ; }
> >
> >  // the unmanged code actually calls this code, e.g. do_string("hello")
> >  extern "C" _declspec(dllexport) char* __stdcall do_string(char* s);
> >  {  return _f_string(s); }
> >  then in C# we write
> >
> > // function: string->string, equivalent to action_string above
> >  public delegate string ActionString(string _);
> >
> >  // the managed code we'll be calling from unmanaged code
> >  public static string Echo(string s) { return s+s; }
> >
> >  // and the bootstrapper
> >  [DllImport("libhost")] public static extern void
> init_string(ActionString
> > s);
> >  public static void Boot { init_string(Echo); }
> >  and again in C++, we can actually call the managed code like so
> >
> > // find_method is just a shortcut using debug-helpers
> >  MonoMethod *bootMethod = find_method("Hello.World:Boot", image);
> >   mono_runtime_invoke(bootMethod, NULL, NULL, NULL);
> >  // now we have a function pointer we can call
> >  char *result = do_string("hello");
> >  g_free(result);
> >  Everything works. However, there appears to be a memory leak. I am not
> sure
> > whether it is the input that is leaking (i.e. a copy of  char*"hello"
> turned
> > into utf16"hello"), or if I am improperly freeing the output (which I
> must
> > assume is a copied string) or something else in the internals. What is
> > encouraging is that all the marshalling is correct, just leaky. Also, if
> the
> > managed code throws an exception, the program prints an error message
> > ("uncaught exception") and hangs. I am not sure what I would have
> expected
> > on the C++ side, perhaps a C++ exception, perhaps silence.
> >
> >  >From the fact that the function pointers work at all, I can tell a lot
> of
> > thought has already gone into this PInvoke stuff. What am I missing on
> the
> > garbage collection side? (And as soon as the strings work, I need to
> worry
> > about making sure that managed delegate doesn't move or get garbage
> > collected!)
> >
> >  Thanks
> >
> >  Sebastian
> > _______________________________________________
> > Mono-devel-list mailing list
> > Mono-devel-list at lists.ximian.com
> > http://lists.ximian.com/mailman/listinfo/mono-devel-list
> >
> >
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.ximian.com/pipermail/mono-devel-list/attachments/20070825/be54adaa/attachment.html 


More information about the Mono-devel-list mailing list