イベントの受信これまでオブジェクトを操作する方法について説明してきましたが、今回はオブジェクトからイベントを受信する方法について説明します。オブジェクトの現在の状態を把握した場合は便利な存在といえます。COMにおけるイベント受信の標準的なインターフェースは、IConnectionPointです。自身とシンクを接続するためのAdviseというメソッドを提供しています。シンクとは、クライアントが作成するイベント受信用のオブジェクトのことです。コネクションポイントを取得するには、それを探すためのオブジェクトが別途必要になります。IConnectionPointContainerを実装することになっています。指定されたIIDで識別されるコネクションポイントを取得することができます。**ppCP);riidは、取得したいコネクションポイントのIIDを指定します。ppCPは、コネクションポイントを受け取る変数のアドレスを指定します。コネクションポイントを取得したら、Adviseを呼び出してクライアントのシンクと接続させます。*pdwCookie);pUnkSinkは、クライアントが作成したシンクのアドレスを指定します。pdwCookieは、確立された接続を識別する値を受け取る変数のアドレスを指定します。この値は、Unadviseで接続を解除する際に必要です。コネクションポイントは、シンクのメソッドを呼び出すことでイベントが発生したことを通知します。これは一体に何になるのでしょうか。Wordの場合は、IDispatchになります。その第1引数にイベントの種類を表す値を指定します。シンクは、この第1引数を参照することで発生したイベントを特定できることになります。コネクションポイントから通知されるイベントにはどれだけの量が存在するのでしょうか。WordのようなOfficeアプリケーションならば、MSDNやタイプライブラリから確認することができます。IApplicationEvents2以下に列挙されているのが通知されるイベントの総数です。上図ではNewDocumentを選択しており、そのidは9になっています。ドキュメントが作成されたこと示す通知であると判断できます。インターフェースのIIDを確認しておく必要があります。uuidキーワードに指定されている値がIApplicationEvents2のIIDになります。クライアントは、これをサポートするコネクションポイントを探す必要があります。今回のプログラムは、Wordを起動して表示します。これを受信したシンクはその旨をWordのドキュメントに記述しています。TEXT("終了します。Documentイベントを検出しました。S_OK;}グローバルに定義されているIID_IApplicationEvents2は、IApplicationEvents2のIIDを格納しています。CEventSinkというクラスは、コネクションポイントと接続するシンクの型です。CEventSinkはIDispatchを継承している必要があります。オブジェクトを実装する際の基本的な事項はCOMサーバーの章を参照してください。WordにおけるApplicationオブジェクトはこの役割も兼ねています。ApplicationオブジェクトをIConnectionPointContainerで識別することができます。&pConnectionPoint);pConnectionPointContainer->Release();pConnectionPointContainerの型がIConnectionPointContainerであれば、QueryInterfaceは成功します。IID_IApplicationEvents2を指定してFindConnectionPointを呼び出すことになります。IConnectionPointContainerは、不要になったら直ぐに開放しても構いません。コネクションポイントを取得したら、それに接続するためのシンクを作成することになります。&dwCookie);シンクの型はCEventSinkで表すことになっていますから、この型のインスタンスを作成することになります。IConnectionPoint::Adviseが成功すれば、コネクションポイントとシンクは接続されたことになります。IApplicationEvents2のメソッドのIDを基に通知が行われるようになります。アプリケーションを終了する際には、必ずUnadviseを呼び出すようにしてください。CEventSinkは、IUnknownのメソッドとIDispatchメソッドを持っています。IUnknown関連で注意しなければならないのは、QueryInterfaceの実装です。S_OK;}QueryInterfaceでは、オブジェクトが実装しているインターフェースを明確にしておかなければなりません。これらのIIDが指定された場合はオブジェクトのアドレスを返すようにします。オブジェクトのアドレスを返すという点です。このIIDには応答しなければならないようです。今回はこれをサポートしていないので、アドレスに0を格納してS_OKを返せば問題ありません。GetTypeInfoとGetIDsOfNamesについては、そもそも実装しないということでE_NOTIMPLを返します。これを意味のある形で実装することになります。Documentイベントを検出しました。S_OK;}既に述べたように、Invokeの第1引数にはイベントの種類を表す値が格納されます。Documentイベントを意味しますから、このif文は新しいドキュメントが作成された際に実行されることになります。pDispParams->rgvarg[0]にはそれが格納されていることになります。rgvargはVARIANT構造体であり、オブジェクトのポインタを格納する場合はvtメンバにVT_DISPATCHを格納しています。これを使用してDocumentオブジェクトを操作することができます。Textプロパティに文字列を指定しています。