2008-11-12 55 views
1

我正在编写需要连接到COM事件的C#代码。我实现了使用 的IConnectionPointContainer和的IConnectionPoint的这样:连接到C#中的COM事件 - 支持托管服务器和非托管服务器

 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对象,而不是COM对象。由于.Net对象没有实现IConnectionPointContainer接口,因此当试图将对象转换为该接口时,我会得到空值。

任何想法我该如何解决这个问题? 我当然可以在C#COM服务器上自己实现IConnectionPointContainer,但是我想要一个更简单的解决方案,我可以很容易地向需要实现COM服务器的其他开发人员解释。

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

谢谢, 因巴尔

回答

0

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

0

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

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

0

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

如果您使用Reflector(例如Redgate Reflector)挖掘UserControl类,您会看到一个'ActiveXImpl'嵌套类成员,它包含另一个名为'AdviseHelper'的嵌套静态类,它具有成员ComConnectionPointContainer和ComConnectionPoint 。它还具有帮助功能,可以根据需要连接点。

存在问题。当COM控件(事件源)将COM事件连接到连接点容器(其中包含控件事件的事件接收器)时,IQuickActivate会将事件连接起来。QuickActivate函数被调用,然后调用AdviseHelper类的'AdviseConnectionPoint'函数。

一个IUnknown接口指向事件接收器的指针,在你的客户端(即不是你的控件,包含它的东西)被传递给这个QuickActivate函数(参数'pUnkEventSink')。In reflector这个函数看起来像这样, VE强调其中不实际的事件联播:

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()函数,该函数将执行手动事件连接。而这就是我所遇到的问题 - 遗憾的是你似乎无法掌握它。

任何人有任何进一步的发展,这让我知道!

0

我知道我对此有点迟了,但是我能够使用IConnectionPoint获取水槽事件。看到我的回答here。具体查看MyAppDotNetWrapper课程以及它如何用于测试。

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