1

C# で記述されたマネージド イベントを公開して、c++ を使用して記述された COM オブジェクトで公開および使用することができます。com と atl に精通していません。MSDN の記事に示されている例について、C++ 側がどのように見えるかを示してください。

http://msdn.microsoft.com/en-us/library/dd8bf0x3.aspx

示されている VB6 コードは、それが実行可能であることを証明しています。

4

3 に答える 3

7

C++ で最も簡単な方法は、ATLIDispEventImplIDispEventSimpleImplテンプレートを使用してイベント シンクを実装することです。サンプルプロジェクトでの説明はこちらにあります

これを行う方法については、thisthisなど、多くのオンライン リソースがありますが、必要な手順のリストは次のとおりです。

まず、マネージド側を見てみましょう。

イベントを提供するには、次のことを行う必要があります。

  • イベント インターフェイスを宣言する ( -IDispatchベース)
  • ComSourceInterfacesイベントインターフェイスをコクラスにバインドする属性でコクラスをマークします
  • コクラスに一致するイベントを実装する

マネージド コードは次のとおりです。

[ComVisible(true), 
 Guid("D6D3565F-..."), 
 InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] //! must be IDispatch
public interface IMyEvents
{
    [DispId(1)] // the dispid is used to correctly map the events
    void SomethingHappened(DateTime timestamp, string message);
}

[ComVisible(true)]
[Guid("E22E64F7-...")]
[ProgId("...")]
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(IMyEvents))] // binding the event interface
public class MyComServer : IMyComServer  
{
    // here we declare the delegate for the event
    [ComVisible(false)]
    public delegate void MyEventHandler(DateTime timestamp, string message);

    // and a public event which matches the method in IMyEvents
    // your code will raise this event when needed
    public event MyEventHandler SomethingHappened;
    ... 
}

さて、管理されていない側に戻ります。COM クライアントを記述するには ATL が最も効果的な方法だと思うので、ATL を使用しますが、MFC を試すか、「手動で」行うことができます。

次の手順が必要です。

  • シンクは継承しますIDispEventSimpleImpl(またはIDispEventImpl
  • 必要なすべてのメソッドを含むシンク マップが宣言されている
  • イベントごとにハンドラーメソッドが書かれている
  • シンクはイベントソースに登録されています
  • 最終的に、必要がなくなったら、シンクは切断されます

ATL C++ クライアントのコードは次のとおりです。

// import the typelib of your COM server
// 'named_guids' ensures friendly ID of event interface
#import "myserver.tlb" named_guids 
const UINT SINK_ID = 234231341; // we need some sink id

class MyClient : public IDispEventSimpleImpl<SINK_ID, MyClient, &MyServer::DIID_IMyEvents >
{
    public:
    // now you need to declare a sink map - a map of methods handling the events
    BEGIN_SINK_MAP(MyClient)
      SINK_ENTRY_INFO(SINK_ID, MyServer::DIID_IMyEvents, 0x1, OnSomethingHappened, &someEvent)
                                                   ^      ^      ^                   ^
      // event interface id (can be more than 1)---+      |      |                   |
      // must match dispid of your event -----------------+      |                   |
      // method which handles the event  ------------------------+                   |
      // type information for event, see below --------------------------------------+
    END_SINK_MAP()

// declare the type info object. You will need one for each method with different signature.
// it will be defined in the .cpp file, as it is a static member
static _ATL_FUNC_INFO someEvent;  // 'placeholder' object to carry event information (see below)

// method which handles the event
STDMETHOD (OnSomethingHappened)(DATE timestamp, BSTR message)
{ 
   // usually it is defined it in the .cpp file
}

... 

}

ここで、cpp ファイル (つまり、someEvent上記の例のインスタンス)で型情報メンバーを定義する必要があります。

_ATL_FUNC_INFO MyClient::traceEvent = { CC_STDCALL, VT_EMPTY, 2 , {VT_DECIMAL, VT_BSTR} };  // dispid = 1
                                               ^        ^     ^              ^
// calling convention (always stdcall) --------+        |     |              |
// type of return value (only VT_EMPTY makes sense) ----+     |              |
// number of parameters to the event -------------------------+              |
// Variant types of event arguments -----------------------------------------+

型マッピングが常に明白であるとは限らないため、これは注意が必要です (たとえば、マネージドintマップがにマップされていることは明らかですが、 にマップされVT_I4ていることはそれほど明白ではありません)。シンク マップで使用する予定の各イベントを宣言する必要があります。それらのすべてが必要でない場合は、それらをマップしないでください。DateTimeVT_DECIMAL

次に、シンクをイベント ソースに接続する必要があります。

// IUnknown* pUnk = interface to you COM server instance
pMyClient->DispEventAdvise(pUnk);
// .. from this point, events will be caught by the client
// when you are done, disconnect:
pMyClient->DispEventUnadvise(pUnk);

多かれ少なかれ、これです。IDispEventImpl代わりに使用 IDispEventSimpleImplすると、最も醜い部分である可能性のある型情報オブジェクトを提供する必要がないため、コードが少し少なくなります。ただし、次の 2 つの欠点があります。

  • typelib へのアクセスが必要です (型情報自体を提供するためにインターフェイス メタデータを読み取る必要があるため)
  • 少し遅いです(ただし、それほど大きくないと思います)
于 2012-09-29T14:03:56.060 に答える
0

C++/CLI を使用できる場合は、次のように実行できます ( source ):

// class that defines methods that will called when event occurs
ref class EventReceiver {
public:
   void OnMyClick(int i, double d) {
      Console::WriteLine("OnClick: {0}, {1}", i, d);
   }

   void OnMyDblClick(String^ str) {
      Console::WriteLine("OnDblClick: {0}", str);
   }
};

int main() {
   EventSource ^ MyEventSource = gcnew EventSource();
   EventReceiver^ MyEventReceiver = gcnew EventReceiver();

   // hook handler to event
   MyEventSource->OnClick += gcnew ClickEventHandler(MyEventReceiver, &EventReceiver::OnMyClick);
}
于 2012-09-28T22:38:41.580 に答える