有了服务器管理类,我们就可以把它注册到 COM 服务器了。想要注册 COM 类,我们需要一个 Factory 工厂类来让 COM 服务器可以在通信时初始化 COM 类。首先我们需要导入 COM 相关 API,定义IClassFactory接口,其中Factory.CLSID_IRemoteThing为远程类的CLSID。
public static partial class Factory
{
public static readonly Guid CLSID_IRemoteThing = new("01153FC5-2F29-4F60-93AD-EFFB97CC9E20");
public static readonly Guid CLSID_IUnknown = new("00000000-0000-0000-C000-000000000046");
[LibraryImport("api-ms-win-core-com-l1-1-0.dll")]
internal static partial int CoRegisterClassObject(in Guid rclsid, IClassFactory pUnk, uint dwClsContext, int flags, out uint lpdwRegister);
[LibraryImport("api-ms-win-core-com-l1-1-0.dll")]
internal static partial int CoRevokeClassObject(uint dwRegister);
internal static T CreateInstance<T>(Guid rclsid, CLSCTX dwClsContext = CLSCTX.CLSCTX_INPROC_SERVER)
{
int hresult = CoCreateInstance(rclsid, 0, (uint)dwClsContext, CLSID_IUnknown, out nint result);
if (hresult < 0)
{
Marshal.ThrowExceptionForHR(hresult);
}
return Marshaler<T>.FromAbi(result);
}
internal static T CreateInstance<T>(Guid rclsid, CLSCTX dwClsContext, TimeSpan period) where T : ISetMonitor
{
T results = CreateInstance<T>(rclsid, dwClsContext);
results.SetMonitor(IsAlive, period);
return results;
}
[LibraryImport("api-ms-win-core-com-l1-1-0.dll")]
private static partial int CoCreateInstance(in Guid rclsid, nint pUnkOuter, uint dwClsContext, in Guid riid, out nint ppv);
}
复制代码
如今我们只需要执行IRemoteThing remote = Factory.CreateRemoteThing();就能获取远程类了。
到这里我们已经完成了 OOP COM 的全部流程,我们想要实现什么内容就可以按照构建服务器管理类的方法来制作 COM 远程类,然后通过在服务器管理类添加一个构造方法来获取这个远程类,如许我们就不需要单独分配 CLSID 和注册 COM 类了。
比如我们可以给Process套个壳:
/// <inheritdoc cref="Process"/>
public partial class RemoteProcess(Process inner) : IProcess
{
/// <inheritdoc cref="Process.ProcessName"/>
public string ProcessName => inner.ProcessName;
/// <inheritdoc cref="Process.StandardError"/>
public ITextReader StandardError => new RemoteTextReader(inner.StandardError);
/// <inheritdoc cref="Process.ProcessName"/>
public ITextWriter StandardInput => new RemoteTextWriter(inner.StandardInput);
/// <inheritdoc cref="Process.StandardOutput"/>
public ITextReader StandardOutput => new RemoteTextReader(inner.StandardOutput);
/// <inheritdoc cref="Process.StartInfo"/>
public IProcessStartInfo StartInfo
{
get => new RemoteProcessStartInfo(inner.StartInfo);