【问题标题】:Cross process .net COM IPC throws E_NOINTERFACE跨进程 .net COM IPC 抛出 E_NOINTERFACE
【发布时间】:2016-09-27 06:28:10
【问题描述】:

我正在尝试使用IRunningObjectTable 来允许客户端调用者访问另一个进程中的对象以实现 UI 自动化。

+----------------+                 +-----------+
| Client Process |---------------->| UI server |
| .Net WPF       |                 | .Net WPF  |
+----------------+                 +-----------+

我已经实现了一个示例接口,实现如下,我在运行对象表中看到了注册对象,但是在转换为类型化接口时得到E_NOINTERFACE

服务器

Interface.cs:

[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(IChatTarget))]
[ComVisible(true), Guid("FEF67638-6654-47DB-A40D-F11FE72795A9")]
public class ChatInterface : IChatTarget
{
    public void PrintString(string text)
    {
        Console.WriteLine(text);
    }
}

[ComVisible(true)]
[Guid("9A3164C9-F800-4B7D-9AB0-29E9F5D325B2")]
public interface IChatTarget
{
    void PrintString(string text);
}

程序.cs:

class Program
{
    static void Main(string[] args)
    {
        var ct = new ChatInterface();

        var rot = NativeMethods.GetRunningObjectTable(0);
        IMoniker moniker = NativeMethods.CreateItemMoniker("!", "TestMoniker");

        var hRotEntry = rot.Register(NativeMethods.ROTFLAGS_REGISTRATIONKEEPSALIVE, (IChatTarget)ct, moniker);

        MSG msg;
        while (NativeMethod.GetMessage(out msg, IntPtr.Zero, 0, 0))
        {
            NativeMethod.TranslateMessage(ref msg);
            NativeMethod.DispatchMessage(ref msg);
        }

        rot.Revoke(hRotEntry);
    }
}

客户

Proxy.cs:

public class ChatProxy : IChatTarget
{
    IChatTarget target;

    public ChatProxy()
    {
        var rot = NativeMethods.GetRunningObjectTable(0);
        var moniker = NativeMethods.CreateItemMoniker("!", "TestMoniker");

        object utobj;
        if (rot.GetObject(moniker, out utobj) != 0 /* S_OK */)
        {
            throw new InvalidOperationException("Moniker not in table");
        }
        // This throws ComException(E_NOINTERFACE)
        target = (IChatTarget)utobj;
    }

    public void PrintString(string text)
    {
        target.PrintString(text);
    }
}

程序.cs:

class Program
{
    static void Main(string[] args)
    {
        var cp = new ChatProxy();
        while (true)
            cp.PrintString(Console.ReadLine());
    }
}

我正在使用 regasm 注册服务器程序集。

【问题讨论】:

    标签: c# com


    【解决方案1】:

    为了获得类型化代理,包含接口的程序集必须是强命名的。

    使用强名称密钥对程序集进行签名,一切都会好起来的。

    其他陷阱:

    • 必须使用/tlb 标志调用regasm 才能注册OLE 编组,否则您可以获得E_NOINTERFACE。您可以通过查找ProxyStubClsid32 key 进行检查。完整的命令应该是regasm assembly.dll /tlbregasm assembly.dll /tlb /u 以取消注册。
    • 对于进程内服务器,程序集必须在 GAC 中,或者必须将 /codebase 标志传递给 regasm
    • 注册应使用与客户端相同的位数 (Wow6432Node)
    • 对于标有 Any CPU 的程序集,您必须同时注册 regasm 的 32 位和 64 位版本

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-13
      • 2010-11-18
      • 2014-07-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多