c# - Hosting managed code and garbage collection -


i have c++ out-of-process com server hosts lot of c# code support api exposed c++ com objects.

for variety of reasons, considering eliminating c++ portion of solution. however, because of constraints outside of control have retain out-of-process com server. microsoft have canonical example of here.

looking @ example there don't understand. before message loop starts, timer created call gc.collect every 5 seconds. mention of can find indicates it's ensure com objects released in reasonable timeframe. i'm little confused this...does c++ host call gc.collect automatically? i'm not doing it. , yet creating managed objects (with comvisible(true) com objects in c++ code. mean should calling gc.collect every 5 seconds now? if not, why need call in new c# out of process server. make automatic process cleans unreferenced com objects in normal c++ application? (which assume happening sometime during message loop.)

calling gc.collect every 5 seconds seems bad idea. wrong worry? there other method achieve same results?

i using .net 4.5 , visual studio 2012.

imo, easiest way create com out-of-proc server in c# use dll surrogate process.

you're still limited dual interfaces (cominterfacetype.interfaceisdual), , you'd need register generated type library (and part of deployment, too):

c:\windows\microsoft.net\framework\v4.0.30319\regasm.exe managedserver.dll /codebase /tlb

this allow utilize com type library marshaller, because don't have dedicated com proxy/stuf dll c# com objects.

make sure use correct regasm.exe binary, depending on target bit-ness of managedserver.dll assembly. above assumes x86 code.

here complete working template example. takes care of surrogate registration:

using microsoft.win32; using system; using system.runtime.interopservices;  namespace managedserver {     [comvisible(true), guid("1891cf89-1282-4ca8-b7c5-f2608af1e2f1")]     [interfacetype(cominterfacetype.interfaceisdual)]     public interface imanagedcomobject     {         string commethod(string data);     }      [comvisible(true)]     [classinterface(classinterfacetype.none)]     [comdefaultinterface(typeof(imanagedcomobject))]     [guid("989162cd-a6a6-4a7d-a7fb-c94086a4e90a")]     [progid("noseratio.managedcomobject")]      public class managedcomobject : imanagedcomobject     {         // public constructor         public managedcomobject()         {         }          // imanagedcomobject         public string commethod(string data)         {             return data;         }          // registration         [comregisterfunction()]         public static void register(type type)         {             var guid = type.guid.tostring("b");             using (var appidkey = registry.classesroot.createsubkey(@"appid\" + guid))             {                 appidkey.setvalue("dllsurrogate", string.empty);             }             using (var appidkey = registry.classesroot.createsubkey(@"clsid\" + guid))             {                 appidkey.setvalue("appid", guid);             }         }          [comunregisterfunction()]         public static void unregister(type type)         {             var guid = type.guid.tostring("b");             using (var appidkey = registry.classesroot.opensubkey(@"appid\" + guid, writable: true))             {                 if (appidkey != null)                     appidkey.deletevalue("dllsurrogate", throwonmissingvalue: false);             }             registry.classesroot.deletesubkeytree(@"clsid\" + guid, throwonmissingsubkey: false);         }     } } 

by default, objects created in mta apartment, interface methods may possibly called on thread, you'd need implement thread safety.

if need sta thread message pump inside surrogate process objects, explicitly implementing factory singleton , using comarshalinterthreadinterfaceinstream/cogetinterfaceandreleasestream export objects outside sta thread (this might related).

another point, com client code should use clsctx_local_server when creating instance of managedcomobject. not case activator.createinstance(type.gettypefromprogid("noseratio.managedcomobject")), apparently uses clsctx_all. can taken care of:

using system; using system.runtime.interopservices;  namespace client {     class program     {         static void main(string[] args)         {             // dynamic obj = activator.createinstance(type.gettypefromprogid("noseratio.managedcomobject"));              dynamic obj = comext.createinstance(                 type.gettypefromprogid("noseratio.managedcomobject").guid,                  localserver: true);              console.writeline(obj.commethod("hello"));         }     }      // com interop     public static class comext     {         const uint clsctx_local_server = 0x4;         const uint clsctx_inproc_server = 0x1;          static readonly guid iid_iunknown = new guid("00000000-0000-0000-c000-000000000046");          [dllimport("ole32.dll", exactspelling = true, preservesig = false)]         static extern void cocreateinstance(            [marshalas(unmanagedtype.lpstruct)] guid rclsid,            [marshalas(unmanagedtype.iunknown)] object punkouter,            uint dwclscontext,            [marshalas(unmanagedtype.lpstruct)] guid riid,            [marshalas(unmanagedtype.interface)] out object rreturnedcomobject);          public static object createinstance(guid clsid, bool localserver)         {             object unk;             cocreateinstance(clsid, null, localserver ? clsctx_local_server : clsctx_inproc_server, iid_iunknown, out unk);             return unk;         }     } } 

Comments

Popular posts from this blog

PHPMotion implementation - URL based videos (Hosted on separate location) -

javascript - Using Windows Media Player as video fallback for video tag -

c# - Unity IoC Lifetime per HttpRequest for UserStore -