ATL が用意している コンテナクラス(CAxHostWindow) を利用します。
ウイザードで SDK プロジェクト を作ってください。
次に StdAfx.h にヘッダーのインクルードをします。
次にウインドウクラスを作ります。
(CMainWindow という名前にします / エラー処理は記述してません)
class CMainWindow : public CWindowImpl<CMainWindow, CWindow, CFrameWinTraits>
{
CAxWindow m_ax;
CComPtr<IUnknown> m_spUnknown;
public:
CMainWindow() {}
virtual ~CMainWindow() {}
BEGIN_MSG_MAP(CMainWindow)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
MESSAGE_HANDLER(WM_SIZE, OnSize)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
MESSAGE_HANDLER(WM_CLOSE, OnClose)
END_MSG_MAP()
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
RECT rect;
GetClientRect(&rect);
AtlAxWinInit();
m_ax.Create(m_hWnd, rect,
_T("{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"),
WS_CHILD|WS_VISIBLE);
m_ax.QueryControl(&m_spUnknown);
return 1;
}
LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
RECT rect = { 0, 0, LOWORD(lParam), HIWORD(lParam) };
return m_ax.MoveWindow(&rect);
}
LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
DestroyWindow();
return 0;
}
LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
m_spUnknown.Release();
::PostQuitMessage(0);
return 0;
}
};
Create() の 3番目の引数は、CLSID または ProgID の文字列です。m_spUnknown は、コントロールのインターフェイスを得るためのもの。OnDestroy() でm_spUnknown.Release() を明示的に行っているのは、WinMain() の::CoUninitialize() より先に実行させるためです。
あとは、WinMain()
CComModule _Module;
int APIENTRY WinMain(
HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
::CoInitialize(NULL); // STA
_Module.Init(0, hInstance);
CMainWindow wndMain;
wndMain.Create(0, CWindow::rcDefault, _T("Main"), 0, 0, NULL);
wndMain.ShowWindow(nCmdShow);
wndMain.UpdateWindow();
MSG msg;
while (::GetMessage(&msg, NULL, 0, 0)) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
_Module.Term();
::CoUninitialize();
return 0;
}
これで、おしまい。
IDispEventImpl をクラスに追加し、イベントハンドラの実装します。
#define UNIT_ID 1
class CMainWindow :
public CWindowImpl<CMainWindow, CWindow, CFrameWinTraits>,
public IDispEventImpl<UNIT_ID, CMainWindow, &DIID_DxxxxEvents>
{
BEGIN_SINK_MAP(CMainWindow)
SINK_ENTRY(UNIT_ID, DIID_DxxxxEvents, DISPID, OnXxxxEvent)
END_SINK_MAP()
void __stdcall OnXxxxEvent() { ... }
};
あとは、接続と切り離しを見合った場所で実行させます。
AtlAdviseSinkMap(this, TRUE or FALSE);
ただし、この方法は実装するクラスが CWindow の派生クラスである場合です。
CWindow を使わない場合、
| IDispEventImpl | → | IDispEventSimpleImpl |
| SINK_ENTRY | → | SINK_ENTRY_EX 又は SINK_ENTRY_INFO |
| AtlAdviseSinkMap() | → | DispEventAdvise(), DispEventUnadvise() |
を使います。