Csharp/C#教程:在C#/ .Net中创建进程外COM?分享


在C#/ .Net中创建进程外COM?

我需要在C#中创建一个进程外COM服务器(.exe),它将被同一个盒子上的多个其他进程访问。 组件必须是单个进程,因为它会将其提供的信息缓存到内存中的使用者。

注意:访问我的COM服务器的进程主要是Matlab进程,因此需要 COM接口。

我已经看到有关在.Net上创建进程内COM组件的线程溢出( 创建COM … )和Web上的线程,但我很难找到一种方法来创建.Net的进程外组件。

这怎么可以实现? 任何建议的参考?

谢谢。

一个选项是服务组件 – 即将它作为shell exe托管在COM +中。 另见这里的方法 。

多年前我们也遇到了一些问题,包括regasm并将COM类作为本地EXE服务器运行。

这是一个黑客,我欢迎任何建议,使其更优雅。 它是在.NET 1.0天后的一个项目中实现的,从那时起就没有被触及过!

基本上,每次应用程序启动时它都会执行一种regasm注册方式(在COM容器应用程序中实例化COM对象之前,需要运行一次以生成注册表项)。

我从我们的实现中复制了以下重要部分,并重命名了几个类来说明这个例子。

从Form Loaded事件调用以下方法来注册COM类(在此示例中重命名为MyCOMClass

 private void InitialiseCOM() { System.Runtime.InteropServices.RegistrationServices services = new System.Runtime.InteropServices.RegistrationServices(); try { System.Reflection.Assembly ass = Assembly.GetExecutingAssembly(); services.RegisterAssembly(ass, System.Runtime.InteropServices.AssemblyRegistrationFlags.SetCodeBase); Type t = typeof(MyCOMClass); try { Registry.ClassesRoot.DeleteSubKeyTree("CLSID\{" + t.GUID.ToString() + "}\InprocServer32"); } catch(Exception E) { Log.WriteLine(E.Message); } System.Guid GUID = t.GUID; services.RegisterTypeForComClients(t, ref GUID ); } catch ( Exception e ) { throw new Exception( "Failed to initialise COM Server", e ); } } 

对于有问题的类型, MyCOMObject需要一些特殊属性才能与COM兼容。 一个重要的属性是指定一个固定的GUID,否则每次编译注册表都会填满孤立的COM GUID。 您可以使用VisualStudio中的“工具”菜单为您创建唯一的GUID。

  [GuidAttribute("D26278EA-A7D0-4580-A48F-353D1E455E50"), ProgIdAttribute("My PROGID"), ComVisible(true), Serializable] public class MyCOMClass : IAlreadyRegisteredCOMInterface { public void MyMethod() { } [ComRegisterFunction] public static void RegisterFunction(Type t) { AttributeCollection attributes = TypeDescriptor.GetAttributes(t); ProgIdAttribute ProgIdAttr = attributes[typeof(ProgIdAttribute)] as ProgIdAttribute; string ProgId = ProgIdAttr != null ? ProgIdAttr.Value : t.FullName; GuidAttribute GUIDAttr = attributes[typeof(GuidAttribute)] as GuidAttribute; string GUID = "{" + GUIDAttr.Value + "}"; RegistryKey localServer32 = Registry.ClassesRoot.CreateSubKey(String.Format("CLSID\{0}\LocalServer32", GUID)); localServer32.SetValue(null, t.Module.FullyQualifiedName); RegistryKey CLSIDProgID = Registry.ClassesRoot.CreateSubKey(String.Format("CLSID\{0}\ProgId", GUID)); CLSIDProgID.SetValue(null, ProgId); RegistryKey ProgIDCLSID = Registry.ClassesRoot.CreateSubKey(String.Format("CLSID\{0}", ProgId)); ProgIDCLSID.SetValue(null, GUID); //Registry.ClassesRoot.CreateSubKey(String.Format("CLSID\{0}\Implemented Categories\{{63D5F432-CFE4-11D1-B2C8-0060083BA1FB}}", GUID)); //Registry.ClassesRoot.CreateSubKey(String.Format("CLSID\{0}\Implemented Categories\{{63D5F430-CFE4-11d1-B2C8-0060083BA1FB}}", GUID)); //Registry.ClassesRoot.CreateSubKey(String.Format("CLSID\{0}\Implemented Categories\{{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}}", GUID)); } [ComUnregisterFunction] public static void UnregisterFunction(Type t) { AttributeCollection attributes = TypeDescriptor.GetAttributes(t); ProgIdAttribute ProgIdAttr = attributes[typeof(ProgIdAttribute)] as ProgIdAttribute; string ProgId = ProgIdAttr != null ? ProgIdAttr.Value : t.FullName; Registry.ClassesRoot.DeleteSubKeyTree("CLSID\{" + t.GUID + "}"); Registry.ClassesRoot.DeleteSubKeyTree("CLSID\" + ProgId); } } 

主窗体中的InitialiseCOM方法使用RegistrationServices来注册类型。 然后,框架使用reflection来查找使用ComRegisterFunction属性标记的方法,并使用要注册的类型调用该函数。

ComRegisterFunction标记方法,hand为本地EXE服务器COM对象创建注册表设置,如果您使用REGEDIT并找到有问题的密钥,可以将其与regasm进行比较。

我已经注释掉了三个\Registry.ClassesRoot.CreateSubKey方法调用,因为这是我们自己注册类型的另一个原因,因为这是OPC服务器,第三方OPC客户端使用这些实现的类别来扫描兼容的OPC服务器。 除非我们自己完成工作,否则REGASM不会为我们添加这些内容。

如果在函数启动时对函数设置断点,则可以轻松查看其工作原理。

我们的实现使用了已经向COM注册的接口。 对于您的应用,您将需要: –

  1. 扩展上面列出的注册方法以向COM注册接口
  2. 或者使用接口定义创建一个单独的DLL,然后将该接口定义导出到类型库,并按照您在问题中添加的StackOverflow链接中的说明进行注册。

官方答案在KB文章中如何使用Visual C ++,Visual C#或Visual Basic .NET开发进程外COM组件 。

IMO,其中一种方法是按照你在链接中提到的方法创建一个普通的COM Dll,然后在注册你的COM dll后,将它改为代理DLL。 这可以通过OLEView实用程序轻松完成,尽管您也可以通过更改注册表项以及https://msdn.microsoft.com/en-us/library/ms686606(VS.85)中提到的方法手动完成此操作。 ).aspx 。

通过使它成为代理DLL,它将在它自己的dllhost.exe中运行,因此将是进程外的。

ActiveX.NET是C#.NET中真正的Out-Of-Proc(EXE)COM服务器实现。 与在Code.MSDN中发布的原始CSExeCOMServer相比,这个实现更清晰。

ActiveX.NET具有使用.NET消息泵(而不是本机)并使用MEF插件模型的function,因此EXE服务器可以解耦,并且可以在多个COM插件之间共享,这些插件可以独立开发

您可以使用RegistrationServices.RegisterTypeForComClients,它是CoRegisterClassObject的托管等价物 – 用于示例代码,请参阅https://www.andymcm.com/blog/2009/10/managed-dcom-server.html

它可以使用非托管ATL框架并使用托管代码进行管理(通过将结果项目属性更改为/ clr来简化)。

以下是说明性摘要:

 .H-part: #include < vcclr.h > #using < MyCSharpModule.dll > using namespace System; class ATL_NO_VTABLE MyCSharpProxyServer : public CComObjectRootEx< CComMultiThreadModel >, ..... { HRESULT FinalConstruct(); STDMETHODIMP LoadMyFile(BSTR FileName); ..... gcroot m_CSClass; } .CPP-part: using namespace System::Collections; using namespace MyCSNamespace; HRESULT MyCSharpProxyServer::FinalConstruct() { m_CSClass = gcnew MyCSharpClass(); } STDMETHODIMP MyCSharpProxyServer::LoadMyFile(BSTR FileName) { try { int hr = m_CSClass->LoadFile(gcnew String( FileName)); return hr; } catch( Exception^ e ) { return E_FAIL; } } 

C#部分(MyCSharpClass类)位于具有输出类型Class Library的单独项目中。

使用标志REGCLS_MULTIPLEUSE和CoRegisterClassObject()使coclass成为一个多用途类。 这是更多信息: http : //support.microsoft.com/kb/169321 。

你可以在这里找到的视觉工作室项目“CSExeCOMServer”(All-in-One)给出了一个完整的例子。

上述就是C#学习教程:在C#/ .Net中创建进程外COM?分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/cdevelopment/1002407.html

(0)
上一篇 2021年12月28日
下一篇 2021年12月28日

精彩推荐