问题描述
我有一个C ++托管了大量的C#代码来支持由C ++ COM对象公开的API外的进程COM服务器。
I have a C++ out-of-process COM server that hosts a lot of C# code to support the API exposed by the C++ COM objects.
由于各种原因,我正在考虑消除我的解决方案的C ++部分。但是,因为我的控制范围之外的限制我的有无的保留进程外的COM服务器。微软确实有这里此。
IMO, the easiest way to create a COM out-of-proc server in C# is to use a DLL surrogate process.
您还在局限于双接口( ComInterfaceType.InterfaceIsDual
),然后你需要注册生成的类型库(并做到这一点作为部署的一部分,太):
You're still limited to dual interfaces (ComInterfaceType.InterfaceIsDual
), and you'd need to register the generated type library (and do it as part of deployment, too):
ç :\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe ManagedServer.dll /代码库/ TLB
这将允许您利用COM类型库编组,因为你没有为你的C#的COM对象专用的COM代理/ STUF DLL。
This will allow you to utilize the COM type library marshaller, because you don't have a dedicated COM proxy/stuf DLL for your C# COM objects.
请务必使用正确的 RegAsm.exe
二进制文件,这取决于你的 ManagedServer.dll
装配的目标位岬。以上假设x86代码。
Make sure to use the correct RegAsm.exe
binary, depending on the target bit-ness of your ManagedServer.dll
assembly. The above assumes x86 code.
下面是一个完整的工作模板的例子。它采用代理注册护理:
Here is a complete working template example. It takes care of the 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);
}
}
}
默认情况下,对象将在MTA的公寓中创建的,所以接口方法有可能在任何线程调用,你需要实现线程安全。
By default, the objects will be created in MTA apartment, so the interface methods may possibly be called on any thread, you'd need to implement thread safety.
如果你需要为你的对象的替代进程内消息泵STA线程,你可以做到这一点明确实施工厂单,并使用 CoMarshalInterThreadInterfaceInStream对该
/ CoGetInterfaceAndReleaseStream对
导出STA线程之外的对象(的可能是相关的)。
If you need an STA thread with message pump inside the surrogate process for your objects, you could do that explicitly by implementing a factory singleton and using CoMarshalInterThreadInterfaceInStream
/CoGetInterfaceAndReleaseStream
to export objects outside the STA thread (this might be related).
还有一点,你的COM客户端代码应该使用 CLSCTX_LOCAL_SERVER
时创建 ManagedComObject
这样的一个实例。这是不是与 Activator.CreateInstance的情况下(Type.GetTypeFromProgID(Noseratio.ManagedComObject))
,这显然使用了 CLSCTX_ALL
。这可以很容易地照顾:
Another point, your COM client code should use CLSCTX_LOCAL_SERVER
when creating this an instance of ManagedComObject
. This is not the case with Activator.CreateInstance(Type.GetTypeFromProgID("Noseratio.ManagedComObject"))
, which apparently uses CLSCTX_ALL
. This can be easily 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;
}
}
}
这篇关于主机托管代码和垃圾回收的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!