IThumbCtl (CThumbCtl) のBUG

IE4,IE5のShell(Explorer)で使われている縮小版表示用のOCXコントロールです。IE4以降のインストールされたマシンにはこれがついていると考えてよく、プログラマとしてはこれを利用するのも手です。

ダイアログなどへActiveXコントロールの貼り付けとして簡単に貼り付けられます。ラップしたクラスも生成してくれます。が、このコントロールをMFCから利用する場合、イベントシンクがただしく初期化されないという問題があります。これによって、コントロールが縮小版を作成後、Readyになったというイベントを受け取ることができません。

これは、IThumbCtl 内部で実装されている IQuickActivateを通してコントロールが初期化されたときに起こります。IConnectionPoint を使ってイベントシンクに接続したときは正しくイベント機構に接続できます。一方でMFCではIQuickActivateが取得できた場合、こちらを使うようにかかれているため、 MFCのAPPからうまくIThumbCtlのイベントを利用できません。

ウィザードが吐き出す、class CThumbCtl : public CWnd に次のメンバを追加して、コントロールの作成後呼び出します。これでイベントが動き出します。ただし、MFCのソースファイルがインストールされていることが肝心です。

#include <../src/occimpl.h>

public:
   DWORD ConnectSink()
   {
   COleControlSite* pSite = m_pCtrlSite;
   REFIID iid = pSite->m_iidEvents;
   LPUNKNOWN punkSink = (IDispatch*) ( &pSite->m_xEventSink ) - 1;
   // なぜここで1ずれる(4バイトずれる)のかは不明。なぞ。
   LPOLEOBJECT m_pObject = pSite->m_pObject ;
   ASSERT(m_pObject != NULL);
 LPCONNECTIONPOINTCONTAINER pConnPtCont;
 if ((m_pObject != NULL) &&
   SUCCEEDED(m_pObject->QueryInterface(IID_IConnectionPointContainer,
   (LPVOID*)&pConnPtCont)))
   {
   ASSERT(pConnPtCont != NULL);
   LPCONNECTIONPOINT pConnPt = NULL;
   DWORD dwCookie = 0;
 if (SUCCEEDED(pConnPtCont->FindConnectionPoint(iid, &pConnPt)))
   {
   ASSERT(pConnPt != NULL);
   pConnPt->Advise(punkSink, &dwCookie);
   pConnPt->Release();
   }
 pConnPtCont->Release();
   if( dwCookie )
   pSite->m_dwEventSink = dwCookie;
   return dwCookie;
   }
 return 0;
}