![]()
今回から数回に分けてフォーカス関連のバグ修正をする。現状ではドロップダウンリストが正常に選択できなくなったり、アドレスバーにフォーカスを置いたままだとIEコントロールの描画が更新されないなどなどの不具合が多い。これらをなんとか治す。
これまで、ビューウインドウはATL/WTLアプリケーションウイザードの生成したCAxWindow派生のものを利用していた。このままだと修正が大変なので、派生元をCAxHostWindowに変更する。
CAxWindowはIEコントロールなどのActiveXコントロールをホストするための簡単な仕組みが備わっているのみだが、CAxHostWindowはかなり多くの実装がされていて便利なためだ。
class CTabBrowser100View : public CComObject<CAxHostWindow> //■変更
,public IDispEventImpl<SINKID_EVENTS, CTabBrowser100View, &DIID_DWebBrowserEvents2>
,public CIEUtility
{
//■追加
//CAxHostWindowの場合、メッセージハンドラが使えなくなるので
//このウインドウをサブクラス化してメッセージハンドラが使えるようにする
class CReflectWnd : public CWindowImpl<CReflectWnd>
{
CTabBrowser100View* _pView;
public:
CReflectWnd(CTabBrowser100View* pView)
{
_pView = pView;
}
BEGIN_MSG_MAP(CReflectWnd)
CHAIN_MSG_MAP_MEMBER((*_pView))
END_MSG_MAP()
};
CReflectWnd _wndReflect; //■追加
public:
DECLARE_WND_SUPERCLASS(NULL, CAxWindow::GetWndClassName()) //CAxHostWindow::ではなくCAxWindow::のままなことに注意
CTabBrowser100View(CTabView* pTabView)
: _wndReflect(this) //■追加
{
_pTabView = pTabView;
_bPageError = false;
}
BEGIN_SINK_MAP(CTabBrowser100View)
SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_NEWWINDOW2, OnNewWindow2)
SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_DOCUMENTCOMPLETE, OnDocumentComplete)
SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_STATUSTEXTCHANGE, OnStatusTextChange)
SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_DOWNLOADCOMPLETE, OnDownloadComplete)
SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_COMMANDSTATECHANGE, OnCommandStateChange)
SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_DOWNLOADBEGIN, OnDownloadBegin)
SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_PROGRESSCHANGE, OnProgressChange)
SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_PROPERTYCHANGE, OnPropertyChange)
SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_TITLECHANGE, OnTitleChange)
SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_NAVIGATECOMPLETE2, OnNavigateComplete2)
SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_NAVIGATEERROR, OnNavigateError)
SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_PRIVACYIMPACTEDSTATECHANGE, OnPrivacyImpactedStateChange)
SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_NEWWINDOW3, OnNewWindow3)
SINK_ENTRY_EX(SINKID_EVENTS, DIID_DWebBrowserEvents2, DISPID_SETSECURELOCKICON, OnSetSecureLockIcon)
END_SINK_MAP()
BEGIN_MSG_MAP(CTabBrowser100View)
MESSAGE_HANDLER(WM_DNP_SCRIPTERROR, OnDnpScriptError)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
MESSAGE_HANDLER(WM_DNP_SHOWSCRIPTERROR, OnShowScriptError)
MESSAGE_HANDLER(WM_DNP_SHOWPRIVACYREPORT, OnShowPrivacyReport)
MESSAGE_HANDLER(WM_DNP_SHOWPSECURITYREPORT, OnShowSecurityReport)
MESSAGE_HANDLER(WM_DNP_SHOWZONECONFIGURE, OnShowZoneConfigure)
CHAIN_MSG_MAP(CAxHostWindow) //■追加
END_MSG_MAP()
![]()
そしてCreate()の処理を変更する。CAxHostWindow::Create()は使わずに、CWindow::Createを、CAxWindow(CAxHostWindowではない)のクラス名を使って呼び出してウインドウ生成をする。
//■変更
//Create関数のオーバーライド。内部でIEの取得、接続などを行う
HWND Create(HWND hWndParent, _U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
DWORD dwStyle = 0, DWORD dwExStyle = 0,
_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
{
HWND hWnd;
//__super::ではなく、CWindow::のCreateをCAxWindow::GetWndClassName()指定で利用
hWnd = CWindow::Create(CAxWindow::GetWndClassName(), hWndParent, rect, szWindowName, dwStyle, dwExStyle, MenuOrID, lpCreateParam);
if(hWnd == NULL)
return NULL; //Create失敗
_wndReflect.SubclassWindow(m_hWnd); //メッセージマップが使えるようにこのウインドウをサブクラス化
//CWindow::Createで作れたコントロールをこのウインドウにアタッチ
{
CComPtr<IUnknown> pIUnknown;
AtlAxGetControl(m_hWnd,&pIUnknown);
if(pIUnknown)
AttachControl(pIUnknown,m_hWnd);
QueryControl(IID_IWebBrowser2,(void**)&_pIWebBrowser2); //_pIWebBrowser2にこのビューに関連づいているIEをセットする
if(_pIWebBrowser2 == NULL)
return hWnd; //WebBrowser取得失敗
//サイトも設定
pIUnknown = NULL;
QueryHost(&pIUnknown);
SetSite(pIUnknown);
}
Advise(_pIWebBrowser2); //IEとの接続
//jacascriptや画像ダウンロードのコントロール設定
{
CComPtr<IOleObject> pIOleObject;
CComObject<CAmbientControl>* pCAmbientControl;
CComPtr<IAxWinAmbientDispatchEx> pIAxWinAmbientDispatchEx;
//ダウンロードコントロールの準備
CComObject<CAmbientControl>::CreateInstance(&pCAmbientControl);
if(pCAmbientControl)
pCAmbientControl->QueryInterface(&_pIAmbientControl);
//■削除CAxHostWindowを使うのでセットしない
// //IEコントロールへのセット
// _pIWebBrowser2->QueryInterface(&pIOleObject);
// if(pIOleObject && pCAmbientControl)
// pIOleObject->SetClientSite(pCAmbientControl);
//デフォルトのダウンロードコントロールを設定
//本来ならゾーン変化をチェックしてゾーンに応じて決定すべき?
SetAmbientDownloadControl(DLCTL_DLIMAGES | DLCTL_VIDEOS | DLCTL_BGSOUNDS);
}
return hWnd;
}
//■追加
//CAxWindowのソースからコピー。ホスト取得用関数
template <class Q>
HRESULT QueryHost(Q** ppUnk)
{
return QueryHost(__uuidof(Q), (void**)ppUnk);
}
HRESULT QueryHost(REFIID iid, void** ppUnk)
{
ATLASSERT(ppUnk != NULL);
if (ppUnk == NULL)
return E_POINTER;
HRESULT hr;
*ppUnk = NULL;
CComPtr<IUnknown> spUnk;
hr = AtlAxGetHost(m_hWnd, &spUnk);
if (SUCCEEDED(hr))
hr = spUnk->QueryInterface(iid, ppUnk);
return hr;
}
![]()
これでとりあえず今回は終了だ。まだCAxWindowからCAxHostWindowに切り替えただけでバグは修正されていない。
次回はバグ修正のためにフォーカスがIEコントロールにあるのか、それともそれ以外にあるのかを検出する処理を実装する。
