gpt4 book ai didi

c# - 如何在单线程客户端中将 ComVisible 类实例化到自己的 AppDomain 中?

转载 作者:行者123 更新时间:2023-11-30 21:43:35 26 4
gpt4 key购买 nike

问题

在同一个单线程 COM 客户端中实例化两个独立的 .NET COM 可见类时,.NET 将它们加载到同一个 AppDomain 中。

我猜这是因为它们被加载到同一个线程/进程中。

此行为的示例显示在 this GitHub repository 中。 .

本质上,演示如下:

  1. 实例化一个 COM 类
  2. 为第一个 COM 对象设置一个属性,该对象在后端调用 CurrentDomain 上的 SetData
  3. 实例化第二个独立的 COM 类(不同的接口(interface)名称、GUID 等)
  4. 读取 AppDomain 属性
  5. 证明它看起来是一样的
  6. 此外,从两个 AppDomain 中获取哈希码,注意它也是相同的

为什么这是个问题?

当两个类都实现了 AppDomain.CurrentDomain.AssemblyResolve 事件(或任何其他 AppDomain 事件)时,这些事件可能会相互干扰。这至少是一个并发症;我猜可能还有其他人。

一个想法

我认为处理此问题的最佳方法是为每个 COM 对象创建一个新的 AppDomain。因为我找不到(或谷歌)以托管方式执行此操作的方法,所以我认为可能有必要在非托管代码中执行此操作。

我做了一点侦探工作。在 OleView 中,.NET COM 可见类的 InprocServer32 属性是 mscoree.dll。因此,我创建了一个“垫片”DLL,它将其所有 EXPORTS 转发到 mscoree.dll。通过消除过程(消除导出直到 COM 不再加载),我发现 DllGetClassObjectmscoree 中负责启动 .NET 运行时,并返回实例化的 COM 对象。

所以,我能做的就是实现我自己的 DllGetClassObject,如下所示:

  1. 使用 CLRCreateInstance 在非托管程序集中托管 .NET 运行时
  2. 在新的 AppDomain 中创建对象,并返回它

(不过我猜这并不像听起来那么简单)

问题

在开始这个可能困难且漫长的过程之前,我想知道:

  1. 是否有一种管理方式让 .NET COM 可见类在其自己的 AppDomain 中运行?
  2. 如果不是,这是“正确”的做法吗,还是我错过了一个明显的解决方案?

最佳答案

如果代码不必在同一进程中运行,进程外服务器将是最简单的修复方法。将 CLSCTX_LOCAL_SERVER 传递给 CoCreateInstance,每个类都将在 dllhost 托管进程中创建。

例如在客户端:

public static object CreateLocalServer(Guid clsid)
{
return CoCreateInstance(clsid, null, CLSCTX.LOCAL_SERVER, IID_IUnknown);
}

public static object CreateLocalServer(string progid)
{
Contract.Requires(!string.IsNullOrEmpty(progid));

Guid clsid;
CLSIDFromProgID(progid, out clsid);
return CreateLocalServer(clsid);
}

enum CLSCTX : uint
{
INPROC_SERVER = 0x1,
INPROC_HANDLER = 0x2,
LOCAL_SERVER = 0x4,
INPROC_SERVER16 = 0x8,
REMOTE_SERVER = 0x10,
INPROC_HANDLER16 = 0x20,
RESERVED1 = 0x40,
RESERVED2 = 0x80,
RESERVED3 = 0x100,
RESERVED4 = 0x200,
NO_CODE_DOWNLOAD = 0x400,
RESERVED5 = 0x800,
NO_CUSTOM_MARSHAL = 0x1000,
ENABLE_CODE_DOWNLOAD = 0x2000,
NO_FAILURE_LOG = 0x4000,
DISABLE_AAA = 0x8000,
ENABLE_AAA = 0x10000,
FROM_DEFAULT_CONTEXT = 0x20000,
ACTIVATE_32_BIT_SERVER = 0x40000,
ACTIVATE_64_BIT_SERVER = 0x80000
}

[DllImport(Ole32, ExactSpelling = true, PreserveSig = false)]
[return: MarshalAs(UnmanagedType.Interface)]
public static extern object CoCreateInstance(
[In, MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
[MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter,
CLSCTX dwClsContext,
[In, MarshalAs(UnmanagedType.LPStruct)] Guid riid);

[DllImport(Ole32, CharSet = CharSet.Unicode, PreserveSig = false)]
public static extern void CLSIDFromProgID(string progId, out Guid rclsid);

您还可以注册自定义主机,并将标准 InProcServer32 替换为 LocalServer32。对于示例服务器

// StandardOleMarshalObject keeps us single-threaded on the UI thread
// https://msdn.microsoft.com/en-us/library/74169f59(v=vs.110).aspx
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ProgId(IpcConstants.CoordinatorProgID)]
public sealed class Coordinator : StandardOleMarshalObject, ICoordinator
{
public Coordinator()
{
// required for regasm
}

#region Registration

[ComRegisterFunction]
internal static void RegasmRegisterLocalServer(string path)
{
// path is HKEY_CLASSES_ROOT\\CLSID\\{clsid}", we only want CLSID...
path = path.Substring("HKEY_CLASSES_ROOT\\".Length);
using (RegistryKey keyCLSID = Registry.ClassesRoot.OpenSubKey(path, writable: true))
{
// Remove the auto-generated InprocServer32 key after registration
// (REGASM puts it there but we are going out-of-proc).
keyCLSID.DeleteSubKeyTree("InprocServer32");

// Create "LocalServer32" under the CLSID key
using (RegistryKey subkey = keyCLSID.CreateSubKey("LocalServer32"))
{
subkey.SetValue("", Assembly.GetExecutingAssembly().Location, RegistryValueKind.String);
}
}
}

[ComUnregisterFunction]
internal static void RegasmUnregisterLocalServer(string path)
{
// path is HKEY_CLASSES_ROOT\\CLSID\\{clsid}", we only want CLSID...
path = path.Substring("HKEY_CLASSES_ROOT\\".Length);
Registry.ClassesRoot.DeleteSubKeyTree(path, throwOnMissingSubKey: false);
}

#endregion
}

关于c# - 如何在单线程客户端中将 ComVisible 类实例化到自己的 AppDomain 中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41616334/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com