delphi - How to Consume COM Server (ATL, DLL Surrogate) in .NET C# WinService? -
i have dll com server, used 1 old delphi exe-application.
com server written many years ago (not me) in c++ atl. implements callbacks (event - same?) - using outgoing interface iconnectionpointimpl
. class factory singleton (marked declare_classfactory_singleton
)
now required com server have shared between more 1 clients: both delphi , c# (.net 2.0, vs2008). put dllsurrogate
, can use multiple delphi clients, using class inherited toleserver
, overriding getserver
method use cocreateinstance
(because getactiveobject
fails) , it's working.
now need consume c# winservice , don't know start. wrote little c# hello-world use winapi cocreateinstance
, dllimport("ole32.dll")
- able connect existing instance com server cannot subscribe events.
here dll meta-data imported vs:
i don't know if correct way. here aproximative code:
using system; using system.collections.generic; using system.text; using swlmlib; using system.runtime.interopservices; using system.runtime.interopservices.comtypes; namespace testswlm { [flags] enum clsctx : uint { //... defines here clsctx } class program { [dllimport("ole32.dll", entrypoint = "cocreateinstance", callingconvention = callingconvention.stdcall)] static extern uint32 cocreateinstance([in, marshalas(unmanagedtype.lpstruct)] guid rclsid, intptr punkouter, uint32 dwclscontext, [in, marshalas(unmanagedtype.lpstruct)] guid riid, [marshalas(unmanagedtype.iunknown)] out object rreturnedcomobject); public static void aboutexpirehandler(ifeature pfeature, int hoursremained) { console.writeline("aboutexpirehandler, pfeature = {0}", pfeature.code); } static void main(string[] args) { try { swlmlib.iswmgr lintfswlmgr = null; object instance = null; uint32 dwres = cocreateinstance(new guid("8eaafad7-73f8-403b-a53b-4400e16d8edf"), intptr.zero, (uint)clsctx.clsctx_local_server, new guid("00000000-0000-0000-c000-000000000046"), out instance); swlmlib.swmgrclass lswlmgr = null; unsafe { lintfswlmgr = (instance swlmlib.iswmgr); type litype = instance.gettype(); } if (lintfswlmgr != null) { intptr iuknw = marshal.getiunknownforobject(lintfswlmgr); intptr ipointer = intptr.zero; guid licpcguid = typeof(iconnectionpointcontainer).guid; guid licpguid = typeof(iconnectionpoint).guid; guid liev = new guid("{c13a9d38-4bb0-465b-bf4a-487f371a5538}"); iconnectionpoint lcp = null; iconnectionpointcontainer lcpc = null; int32 r = marshal.queryinterface(iuknw, ref licpcguid, out ipointer); lcpc = (iconnectionpointcontainer)marshal.getobjectforiunknown(ipointer); lcpc.findconnectionpoint(ref liev, out lcp); int32 outid; lcp.advise(???, out outid); // here don't know further lievev.featureabouttoexpire += aboutexpirehandler; } } catch (exception e) { console.writeline(e.message); throw; } console.readline(); } } }
any advices, links , know-hows welcome.
it seems succeeded connect to- , handle events of dll (in-proc) com server.
- i put com server dll surrogate (howto here).
- delphi client side - form com wrapper class, inheriting toleserver class overridden getserver method:
function tswmgr.getserver: iunknown; begin olecheck(cocreateinstance(serverdata^.classid, nil, clsctx_local_server, iunknown, result)); end;
- c# (hello-world client) side (after consulting howtos this):
//using swlmlib; //using system.runtime.interopservices; //using system.runtime.interopservices.comtypes;
[flags] enum returncode : uint { s_ok = 0, s_false = 1, regdb_e_classnotreg = 0x80040154, class_e_noaggregation = 0x80040110, e_nointerface = 0x80004002, e_pointer = 0x80004003 } [flags] enum clsctx : uint { clsctx_inproc_server = 0x1, clsctx_inproc_handler = 0x2, clsctx_local_server = 0x4, //... //others clsctx_all = clsctx_server | clsctx_inproc_handler } /// <summary> /// sink class implementig com server outgoing interface swlmlib.iswmgrevents /// </summary> [classinterface(classinterfacetype.none)] class mysink : swlmlib.iswmgrevents { public void featureabouttoexpire(swlmlib.ifeature pfeature, int hoursremained) { console.writeline("{0} featureabouttoexpire: feature {1} hours={2}", datetime.now, pfeature.code, hoursremained); marshal.releasecomobject(pfeature); //wtf??? without line com server object not released! } public void featureexpired(swlmlib.ifeature pfeature) { console.writeline("featureexpired: feature {0}", pfeature.code); marshal.releasecomobject(pfeature); //without line com server object not released! } } class program { //import "cocreateinstance" play run context of created com-object (3rd parameter) [dllimport("ole32.dll", entrypoint = "cocreateinstance", callingconvention = callingconvention.stdcall)] static extern uint32 cocreateinstance([in, marshalas(unmanagedtype.lpstruct)] guid rclsid, intptr punkouter, uint32 dwclscontext, [in, marshalas(unmanagedtype.lpstruct)] guid riid, [marshalas(unmanagedtype.iunknown)] out object rreturnedcomobject); static void main(string[] args) { try { guid swmgrclassobjectguid = typeof(swlmlib.swmgrclass).guid; //{8eaafad7-73f8-403b-a53b-4400e16d8edf} guid iunknownguid = new guid("00000000-0000-0000-c000-000000000046"); //can written in more pretty style? swlmlib.iswmgr lintfswlmgr = null; /* create in-proc server because, seems cocreateinstance invoked clsctx_inproc_server flag settled type type = type.gettypefromclsid(swmgrclassobjectguid), true); object instance0 = activator.createinstance(type); lintfswlmgr = (instance0 swlmlib.iswmgr); */ guid ev1 = typeof(iswmgrevents).guid; object instance = null; unsafe { uint32 dwres = cocreateinstance(swmgrclassobjectguid, intptr.zero, (uint)(clsctx.clsctx_local_server), //if or clsctx_inproc_server inproc server created, because of dll com server iunknownguid, out instance); if (dwres != 0) { int ierror = marshal.getlastwin32error(); console.writeline("cocreateinstance error = {0}, lastwin32error = {1}", dwres, ierror); return; } lintfswlmgr = (instance swlmlib.iswmgr); } if (lintfswlmgr != null) { //lintfswlmgr.initializemethod(...); //initialize object //find connection point events guid iswmgreventsguid = typeof(swlmlib.iswmgrevents).guid; //{c13a9d38-4bb0-465b-bf4a-487f371a5538} interface evenets handling iconnectionpoint lcp = null; iconnectionpointcontainer lcpc = (instance iconnectionpointcontainer); lcpc.findconnectionpoint(ref iswmgreventsguid, out lcp); mysink lsink = new mysink(); int32 dweventscookie; lcp.advise(lsink, out dweventscookie); console.writeline("waiting events handling..."); console.writeline("press enter exit..."); console.readline(); // until eneter not hit, events arrive //here starting unsubscribe events , com objects cleanup lcp.unadvise(dweventscookie); marshal.releasecomobject(lcp); marshal.releasecomobject(lintfswlmgr); } } catch (exception e) { console.writeline(e.message); throw; } } }
maybe not best way (like tblimp.exe , or com wrappers) raw way works.
Comments
Post a Comment