1

我正在编写需要连接到 COM 事件的 C# 代码。我因此实现了 IConnectionPointContainer 和 IConnectionPoint 的使用:

      IConnectionPointContainer connectionPointContainer = internalGenerator as IConnectionPointContainer;
      if (connectionPointContainer == null)
      {
        Debug.Fail("The script generator doesn't support the required interface - IConnectionPointContainer");
        throw new InvalidCastException("The script generator doesn't support the required interface - IConnectionPointContainer");
      }
      Guid IID_IScriptGeneratorEvents = typeof(IScriptGeneratorCallback).GUID;
      connectionPointContainer.FindConnectionPoint(ref IID_IScriptGeneratorEvents, out m_connectionPoint);
      m_connectionPoint.Advise(this, out m_cookie);

问题是,当 COM 服务器实际上是在 .Net(例如 C#)中实现时,在 .Net 创建它之后,它会将其作为 .Net 对象而不是 COM 对象来处理。由于 .Net 对象没有实现 IConnectionPointContainer 接口,因此在尝试将对象强制转换为该接口时,我得到了 null。

知道如何解决这个问题吗?我当然可以在 C# COM 服务器中自己实现 IConnectionPointContainer,但是我想要一个更简单的解决方案,我可以轻松地向其他需要实现 COM 服务器的开发人员解释。

PS 我必须使用 IConnectionPointContainer,因为 COM 服务器可能在非 .Net(C++、Java)中实现。

谢谢, 因巴尔

4

5 回答 5

1

IConnectionPointContainer 在 CCW(COM 可调用包装器)上实现,当将您的 .NET 对象作为外部 COM 对象公开时,.NET 会自动生成该 CCW。

尝试在 .NET 对象上调用Marshal.GetComInterfaceForObject以获取 IConnectionPointContainer 的 COM 接口,而不仅仅是强制转换它。

更新......如果这不起作用Marshal.GetIUnknownForObject必须返回一些东西,也许这将支持Marshal.QueryInterface调用。

于 2008-11-12T02:11:56.757 回答
0

我没有找到办法做到这一点。最终,我将在 .Net 中定义另一个接口,并编写 2 个代码路径,一个用于 .Net 对象,一个用于真正的 COM 对象。

于 2008-11-12T17:30:24.907 回答
0

问题是执行 GetIUnknownForObject 调用会返回一个指针,然后您可以使用其 GUID 成功调用该指针以获取对象的 IConnectionPointContainer。但是,对 QueryInterface 的调用只返回原始的 .NET 对象,而不是 IConnectionPointContainer 接口。

我也坚持这一点,如果有人有任何进一步的见解,请分享。我的场景是我使用 COM 互操作将 .NET 控件公开为 ActiveX。我为事件接收器定义了一个 ComSourceInterface,但在 VB6 主机中,事件没有按预期连接。因此,我试图为暴露的 .NET 控件获取 IConnectionPointContainer 接口,以便手动连接事件,但如果确实实现了该接口,则无法访问该接口 - 或者我只是在查看错误的对象?

于 2009-08-25T10:01:45.710 回答
0

我更进一步,因为在使用 COM 互操作将 .NET 控件公开为 ActiveX 时,手动连接事件时遇到了同样的问题。

如果您使用 Reflector(例如 Redgate Reflector)深入了解 UserControl 类,您会看到一个“ActiveXImpl”嵌套类成员,其中包含另一个名为“AdviseHelper”的嵌套静态类,它具有成员 ComConnectionPointContainer 和 ComConnectionPoint。它还具有根据需要连接点的辅助功能。

有问题。当 COM 互操作将事件从控件(事件源)连接到连接点容器(其中包含控件事件的事件接收器)时,将调用 IQuickActivate.QuickActivate 函数,然后调用 AdviseHelper 类''AdviseConnectionPoint ' 功能。

一个指向事件接收器的 IUnknown 接口指针,在您的客户端(即不是您的控件,包含它的东西)被传递给这个 QuickActivate 函数(参数'pUnkEventSink'。在反射器中,这个函数看起来像这样,我已经突出显示它的位置做实际的事件连接:

internal void QuickActivate(UnsafeNativeMethods.tagQACONTAINER pQaContainer, UnsafeNativeMethods.tagQACONTROL pQaControl)
{
    int num;
    this.LookupAmbient(-701).Value = ColorTranslator.FromOle((int) pQaContainer.colorBack);
    this.LookupAmbient(-704).Value = ColorTranslator.FromOle((int) pQaContainer.colorFore);
    if (pQaContainer.pFont != null)
    {
        Control.AmbientProperty ambient = this.LookupAmbient(-703);
        IntSecurity.UnmanagedCode.Assert();
        try
        {
            Font font2 = Font.FromHfont(((UnsafeNativeMethods.IFont) pQaContainer.pFont).GetHFont());
            ambient.Value = font2;
        }
        catch (Exception exception)
        {
            if (ClientUtils.IsSecurityOrCriticalException(exception))
            {
                throw;
            }
            ambient.Value = null;
        }
        finally
        {
            CodeAccessPermission.RevertAssert();
        }
    }
    pQaControl.cbSize = UnsafeNativeMethods.SizeOf(typeof(UnsafeNativeMethods.tagQACONTROL));
    this.SetClientSite(pQaContainer.pClientSite);
    if (pQaContainer.pAdviseSink != null)
    {
        this.SetAdvise(1, 0, (IAdviseSink) pQaContainer.pAdviseSink);
    }
    IntSecurity.UnmanagedCode.Assert();
    try
    {
        ((UnsafeNativeMethods.IOleObject) this.control).GetMiscStatus(1, out num);
    }
    finally
    {
        CodeAccessPermission.RevertAssert();
    }
    pQaControl.dwMiscStatus = num;
    if ((pQaContainer.pUnkEventSink != null) && (this.control is UserControl))
    {
        Type defaultEventsInterface = GetDefaultEventsInterface(this.control.GetType());
        if (defaultEventsInterface != null)
        {
            IntSecurity.UnmanagedCode.Assert();
            try
            {
                **AdviseHelper.AdviseConnectionPoint(this.control, pQaContainer.pUnkEventSink, defaultEventsInterface, out pQaControl.dwEventCookie);**
            }
            catch (Exception exception2)
            {
                if (ClientUtils.IsSecurityOrCriticalException(exception2))
                {
                    throw;
                }
            }
            finally
            {
                CodeAccessPermission.RevertAssert();
            }
        }
    }
    if ((pQaContainer.pPropertyNotifySink != null) && UnsafeNativeMethods.IsComObject(pQaContainer.pPropertyNotifySink))
    {
        UnsafeNativeMethods.ReleaseComObject(pQaContainer.pPropertyNotifySink);
    }
    if ((pQaContainer.pUnkEventSink != null) && UnsafeNativeMethods.IsComObject(pQaContainer.pUnkEventSink))
    {
        UnsafeNativeMethods.ReleaseComObject(pQaContainer.pUnkEventSink);
    }
}

'pUnkEventSink' 变量通过 tagQACONTROL 结构传递给此函数,但正如您所见,与 IAdviseSink、控件容器、字体样式等不同,此变量未设置为 'ActiveXImpl' 类的任何成员,并且因此,在框架最初调用此函数后,您将无法访问它。

您需要获取此 IUnknown pUnkEventSink 变量来调用 AdviseHelper.AdviseConnectionPoint() 函数,该函数将执行手动事件连接。这就是我遇到的问题 - 遗憾的是,您似乎根本无法掌握它。

任何其他人对此有任何进一步的发展,请告诉我!

于 2009-08-26T08:31:07.203 回答
0

我知道我对此有点晚了,但我能够使用 IConnectionPoint 让接收器事件工作。在这里查看我的答案。具体检查MyAppDotNetWrapper课程以及如何使用测试。

最终我认为你的m_connectionPoint.Advise(this, out m_cookie);失败是因为this必须[ComVisible(true)][ClassInterface(ClassInterfaceType.None)]public

于 2013-05-02T16:04:33.987 回答