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 がそれを作成した後、それを COM オブジェクトではなく .Net オブジェクトとして処理することです。.Net オブジェクトは IConnectionPointContainer インターフェイスを実装していないため、オブジェクトをそのインターフェイスにキャストしようとすると null が返されます。

どうすればこれを回避できますか?もちろん、IConnectionPointContainer を自分で C# COM サーバーに実装することもできますが、COM サーバーを実装する必要がある他の開発者に簡単に説明できる、より単純なソリューションが必要です。

PS COM サーバーは非 .Net (C++、Java) で実装される可能性があるため、IConnectionPointContainer を使用する必要があります。

ありがとう、インバー

4

5 に答える 5

1

IConnectionPointContainer は、.NET オブジェクトを COM オブジェクトとして外部に公開するときに .NET が自動的に生成する CCW (COM 呼び出し可能ラッパー) に実装されます。

単にキャストするのではなく、.NET オブジェクトでMarshal.GetComInterfaceForObjectを呼び出して、IConnectionPointContainer の COM インターフェイスを取得してみてください。

更新...そしてそれが機能しない場合、Marshal.GetIUnknownForObjectは何かを返す必要があり、おそらくそれがMarshal.QueryInterface呼び出しをサポートします。

于 2008-11-12T02:11:56.757 に答える
0

COM 相互運用機能を使用して .NET コントロールを ActiveX として公開するときに、イベントを手動で接続するという同じ問題が発生していたため、もう少し先に進みました。

Reflector (Redgate Reflector など) を使用して UserControl クラスを少し掘り下げると、ComConnectionPointContainer および ComConnectionPoint メンバーを持つ「AdviseHelper」と呼ばれる別のネストされた静的クラスを含む「ActiveXImpl」ネストされたクラス メンバーが表示されます。また、必要に応じてポイントを接続するためのヘルパー機能もあります。

問題があります。コントロール (イベント ソース) からコネクション ポイント コンテナー (コントロールのイベントのイベント シンクを含む) にイベントが COM 相互運用によってフックされると、IQuickActivate.QuickActivate 関数が呼び出され、AdviseHelper クラスが呼び出されます。 ' 関数。

クライアント上のイベント シンクへの 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

問題は、GetIUnknownForObject 呼び出しを実行するとポインターが返されることです。このポインターを呼び出して、GUID を使用してオブジェクトの IConnectionPointContainer を取得することができます。ただし、その QueryInterface への呼び出しは、IConnectionPointContainer インターフェイスではなく、元の .NET オブジェクトを返すだけです。

私もこれにこだわっています。誰かがさらに洞察を持っている場合は、共有してください。私のシナリオは、COM 相互運用機能を使用して .NET コントロールを ActiveX として公開しているというものです。イベント シンク用に ComSourceInterface を定義しましたが、VB6 ホストでは、イベントが期待どおりに接続されていません。したがって、イベントを手動でフックするために、公開された .NET コントロールの IConnectionPointContainer インターフェイスを取得しようとしていますが、実際に実装されている場合、このインターフェイスにアクセスできません。または、単に間違ったオブジェクトを見ているだけですか?

于 2009-08-25T10:01:45.710 に答える
0

これを行う方法が見つかりませんでした。最終的には、.Net で別のインターフェイスを定義し、.Net オブジェクト用と実際の COM オブジェクト用の 2 つのコード パスを記述します。

于 2008-11-12T17:30:24.907 に答える
0

私はこれに少し遅れていることを知っていますが、IConnectionPoint を使用してシンク イベントを機能させることができました。ここで私の答えを見てください。具体的MyAppDotNetWrapperには、クラスとその使用方法をテストで確認してください。

最終的には、 、および でなければならないm_connectionPoint.Advise(this, out m_cookie);ため、失敗すると思います。 this[ComVisible(true)][ClassInterface(ClassInterfaceType.None)]public

于 2013-05-02T16:04:33.987 に答える