WebBrowserコントロールの機能を制限する話、これで最後です。
今回は、これまでやっていなかったこと、まとめてコードを書きました。
- ページ遷移の禁止: DWebBrowserEvents2のBeforeNavigate2イベントを受信しての処理
- コンテキストメニュー(右クリックなど)の禁止: IAxWinAmbientDispatchのput_AllowContextMenu
- その他: IAxWinAmbientDispatchのput_AllowShowUI、IWebBrowser2のput_RegisterAsBrowserとput_RegisterAsDropTargetとput_Silent
ソースコードを載せます。
#define UNICODE #define _UNICODE #define WINVER 0x0501 #define _ATL_XP_TARGETING #define _ATL_NO_AUTOMATIC_NAMESPACE #define _WTL_NO_AUTOMATIC_NAMESPACE #include <cstdlib> #include <windows.h> #include <exdisp.h> #include <exdispid.h> #include <atlbase.h> #include <atltypes.h> #include <atlwin.h> #include <atlapp.h> #include <atlcrack.h> class Module : public ATL::CAtlExeModuleT<Module> { }; Module module; constexpr UINT ID_WEBBROWSER_EVENTS = 1; class TestWindow : public ATL::CWindowImpl<TestWindow>, public WTL::CMessageFilter, public ATL::IDispEventImpl<ID_WEBBROWSER_EVENTS, TestWindow, &__uuidof(DWebBrowserEvents2), &LIBID_SHDocVw, 1, 1> { public: int Run(int cmdShow, _Inout_ WTL::CMessageLoop& msgLoop) { if (!Create(nullptr, ATL::CWindow::rcDefault, TEXT("Hello, world"), WS_OVERLAPPEDWINDOW)) { return -1; } ShowWindow(cmdShow); UpdateWindow(); msgLoop.AddMessageFilter(this); return msgLoop.Run(); } BOOL PreTranslateMessage(_In_ MSG* pmsg) override { if (m_webBrowser.IsWindow() && m_webBrowser.SendMessage( WM_FORWARDMSG, 0, reinterpret_cast<LPARAM>(pmsg))) { return TRUE; } return IsDialogMessage(pmsg); } DECLARE_WND_CLASS(TEXT("Test Window Class")); BEGIN_MSG_MAP(TestWindow) MSG_WM_SIZE(OnSize) MSG_WM_SETFOCUS(OnSetFocus) MSG_WM_CREATE(OnCreate) MSG_WM_DESTROY(OnDestroy) END_MSG_MAP() BEGIN_SINK_MAP(TestWindow) SINK_ENTRY_EX(ID_WEBBROWSER_EVENTS, __uuidof(DWebBrowserEvents2), DISPID_BEFORENAVIGATE2, &TestWindow::BeforeNavigate2) END_SINK_MAP() private: void __stdcall BeforeNavigate2( _In_ IDispatch* /*disp*/, _In_ VARIANT* /*url*/, _In_ VARIANT* /*flags*/, _In_ VARIANT* /*targetFrameName*/, _In_ VARIANT* /*postData*/, _In_ VARIANT* /*headers*/, _Inout_ VARIANT_BOOL* cancel) { if (cancel != nullptr) { *cancel = VARIANT_TRUE; } } void OnSize(UINT, SIZE size) { m_webBrowser.ResizeClient(size.cx, size.cy); } void OnSetFocus(HWND) { m_webBrowser.SetFocus(); } LRESULT OnCreate(const CREATESTRUCT*) { constexpr DWORD IDC_WEBBROWSER_CONTROL = 1; RECT empty{}; m_webBrowser.Create(m_hWnd, empty, L"https://www.google.co.jp/", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP | WS_GROUP | WS_VSCROLL | WS_HSCROLL, 0, IDC_WEBBROWSER_CONTROL); ATL::CComPtr<IAxWinAmbientDispatch> ambient; m_webBrowser.QueryHost(&ambient); ATLENSURE_RETURN_VAL( SUCCEEDED(ambient->put_AllowContextMenu(VARIANT_FALSE)), -1); ATLENSURE_RETURN_VAL( SUCCEEDED(ambient->put_AllowShowUI(VARIANT_FALSE)), -1); ATLENSURE_RETURN_VAL( SUCCEEDED(InitializeWebBrowserControl()), -1); ATLENSURE_RETURN_VAL( SUCCEEDED(ATL::AtlAdviseSinkMap(this, true)), -1); return 0; } HRESULT InitializeWebBrowserControl() { ATL::CComPtr<IWebBrowser2> wb; if (SUCCEEDED(m_webBrowser.QueryControl(&wb))) { auto hrRB = wb->put_RegisterAsBrowser(VARIANT_FALSE); ATLENSURE_RETURN_HR(SUCCEEDED(hrRB), hrRB); auto hrRDT = wb->put_RegisterAsDropTarget(VARIANT_TRUE); ATLENSURE_RETURN_HR(SUCCEEDED(hrRDT), hrRDT); auto hrSl = wb->put_Silent(VARIANT_TRUE); ATLENSURE_RETURN_HR(SUCCEEDED(hrSl), hrSl); } return S_OK; } void OnDestroy() { PostQuitMessage(0); } ATL::CAxWindow m_webBrowser; }; int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int cmdShow) { if (FAILED(OleInitialize(nullptr))) { std::quick_exit(-1); } WTL::CMessageLoop msgLoop; TestWindow wnd; std::quick_exit(wnd.Run(cmdShow, msgLoop)); } |
コンテキストメニュー(いわゆる右クリックメニュー)の禁止は、本来IDocHostUIHandlerのShowContextMenuで制御します。ところが、ATL::CAxHostWindowがIDocHostUIHandlerを実装していて、ATL::CAxWindowを使う側ではAllowContextMenuプロパティで簡単に制御できるようになっています。AllowShowUIも同じです。
DWebBrowserEvents2のイベントの受信のコードは、BEGIN_SINK_MAPやAtlAdviseSinkMap関数などをオーソドックスに使って書き上げています。BeforeNavigate2で、cancelにVARIANT_TRUEを書き込むことで、リンクをクリックしてもページ遷移を実行させないようにしています。
ここまで、単なるHTMLビューアーとしてWebBroserコントロールを使いたいと思って、いろいろ試してきました。これでだいたいやり尽くしたのではないかと考えています。
スポンサード リンク |
もはや廃れたWebブラウザのIE。
基本的に そのIE専用の拡張機能であるActiveXコントロールの技術的説明を 今更 積極的に公開する意義って何でしょう?
私は大変助かりました
現在はedgeエンジンのWebViewコントロールが利用できますが、まだまだ残存しているWin7では利用不可なので、WebBowserコントロールを使用せざるをえない状況はまだ十分に考えられます。