2008-11-12 90 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