少し前に書いたATL::CAxWindowでWebBrowserコントロールを使ってみるの続きです。ATL::CAxWindowでWebBrowserコントロールを使っている場合に、JavaScriptなどを禁止する方法です。まずはIInternetSecurityManagerなどを使う方法その1です。

IInternetSecurityManagerおよびそこから派生するインタフェースは、インターネットオプションのセキュリティゾーンの設定を表現するインタフェースです。セキュリティゾーンの設定を見たことがないなら、IE のセキュリティ ゾーンについて – Japan IE Support Team Blogなどを読んでみてください。

IInternetSecurityManagerを自分で実装すると、インターネットオプションの設定より優先して、URLごとに、ゾーンやゾーン内の個々の項目について選択できます。

WebBrowserコンポーネントにIInternetSecurityManagerを渡すには、IServiceProviderを使います。そのIServiceProviderを渡すやり方は2つあります。

  • サイトオブジェクトに対してQueryInterfaceしてくるので、そこでオブジェクトを返す。
  • IProfferServiceでIServiceProviderを提供する。

今回は、1つ目の方法です。さて、そのQueryInterfaceを受け付けるのは誰かというと、ATL::CAxWindowの内部で作成されるATL::CAxHostWindowクラスのオブジェクトです。そこに手を入れられないか調べたところ、ATL::CAxHostWindowはIObjectWithSiteを実装しており、ここにIServiceProviderを実装したオブジェクトへのポインタを渡せば良いということが分かりました。

#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 <atlbase.h>
#include <atltypes.h>
#include <atlwin.h>
 
#include <atlapp.h>
#include <atlcrack.h>
 
class Module : public ATL::CAtlExeModuleT<Module>
{
};
 
Module module;
 
class ATL_NO_VTABLE UntrustedSecurityManager :
  public ATL::CComObjectRootEx<ATL::CComSingleThreadModel>,
  public IInternetSecurityManagerEx2
{
public:
  BEGIN_COM_MAP(UntrustedSecurityManager)
    COM_INTERFACE_ENTRY(IInternetSecurityManager)
    COM_INTERFACE_ENTRY(IInternetSecurityManagerEx)
    COM_INTERFACE_ENTRY(IInternetSecurityManagerEx2)
  END_COM_MAP()
 
  IFACEMETHOD(SetSecuritySite)(
    _In_opt_ IInternetSecurityMgrSite* /*pSite*/) override
  {
    return INET_E_DEFAULT_ACTION;
  }
 
  IFACEMETHOD(GetSecuritySite)(
    _Out_ IInternetSecurityMgrSite** /*ppSite*/) override
  {
    return INET_E_DEFAULT_ACTION;
  }
 
  IFACEMETHOD(MapUrlToZone)(
    _In_ LPCWSTR /*pwszUrl*/,
    _Out_ DWORD* pdwZone,
    DWORD /*dwFlags*/) override
  {
    *pdwZone = URLZONE_UNTRUSTED;
    return S_OK;
  }
 
  IFACEMETHOD(GetSecurityId)(
    _In_ LPCWSTR /*pwszUrl*/,
    _Out_writes_bytes_to_(MAX_SIZE_SECURITY_ID, *pcbSecurityId) BYTE* /*pbSecurityId*/,
    _Inout_ _At_(*pcbSecurityId, _In_range_(>= , MAX_SIZE_SECURITY_ID) _Out_range_(0, MAX_SIZE_SECURITY_ID)) DWORD* /*pcbSecurityId*/,
    _In_ DWORD_PTR /*dwReserved*/) override
  {
    return INET_E_DEFAULT_ACTION;
  }
 
  IFACEMETHOD(ProcessUrlAction)(
    _In_ LPCWSTR pwszUrl,
    DWORD dwAction,
    _Out_writes_(cbPolicy) BYTE* pPolicy,
    DWORD cbPolicy,
    _In_opt_ BYTE* pContext,
    DWORD cbContext,
    DWORD dwFlags,
    DWORD dwReserved) override
  {
    DWORD flags;
    return ProcessUrlActionEx(pwszUrl, dwAction, pPolicy, cbPolicy, pContext, cbContext, dwFlags, dwReserved, &flags);
  }
 
  IFACEMETHOD(QueryCustomPolicy)(
    _In_ LPCWSTR /*pwszUrl*/,
    _In_ REFGUID /*guidKey*/,
    /*__RPC__deref_out_ecount_full_opt(*pcbPolicy)*/ BYTE** /*ppPolicy*/,
    _Out_ DWORD* /*pcbPolicy*/,
    _In_ BYTE* /*pContext*/,
    DWORD /*cbContext*/,
    DWORD /*dwReserved*/) override
  {
    return INET_E_DEFAULT_ACTION;
  }
 
  IFACEMETHOD(SetZoneMapping)(
    DWORD /*dwZone*/,
    _In_ LPCWSTR /*lpszPattern*/,
    DWORD /*dwFlags*/) override
  {
    return INET_E_DEFAULT_ACTION;
  }
 
  IFACEMETHOD(GetZoneMappings)(
    DWORD /*dwZone*/,
    __RPC__deref_out_opt IEnumString** /*ppenumString*/,
    DWORD /*dwFlags*/) override
  {
    return INET_E_DEFAULT_ACTION;
  }
 
  IFACEMETHOD(ProcessUrlActionEx)(
    _In_ LPCWSTR /*pwszUrl*/,
    DWORD /*dwAction*/,
    __RPC__out_ecount_full(cbPolicy) BYTE* pPolicy,
    DWORD cbPolicy,
    _In_ BYTE* /*pContext*/,
    DWORD /*cbContext*/,
    DWORD /*dwFlags*/,
    DWORD /*dwReserved*/,
    _Out_ DWORD* pdwOutFlags) override
  {
    if (pdwOutFlags != nullptr)
    {
      *pdwOutFlags = PUAFOUT_DEFAULT;
    }
    if (cbPolicy == sizeof(DWORD))
    {
      *reinterpret_cast<DWORD*>(pPolicy) = URLPOLICY_DISALLOW;
      return S_FALSE;
    }
    return INET_E_DEFAULT_ACTION;
  }
 
  IFACEMETHOD(MapUrlToZoneEx2)(
    _In_ IUri* /*pUri*/,
    _Out_ DWORD* pdwZone,
    DWORD /*dwFlags*/,
    _Outptr_opt_ LPWSTR* ppwszMappedUrl,
    _Out_opt_ DWORD* pdwOutFlags) override
  {
    if (ppwszMappedUrl != nullptr)
    {
      *ppwszMappedUrl = nullptr;
    }
    if (pdwOutFlags != nullptr)
    {
      *pdwOutFlags = 0;
    }
    if (pdwZone != nullptr)
    {
      *pdwZone = URLZONE_UNTRUSTED;
    }
    return S_OK;
  }
 
  IFACEMETHOD(ProcessUrlActionEx2)(
    _In_ IUri* /*pUri*/,
    DWORD dwAction,
    __RPC__out_ecount_full(cbPolicy) BYTE* pPolicy,
    DWORD cbPolicy,
    _In_opt_ BYTE* pContext,
    DWORD cbContext,
    DWORD dwFlags,
    DWORD_PTR dwReserved,
    _Out_ DWORD* pdwOutFlags) override
  {
    return ProcessUrlActionEx(L"", dwAction, pPolicy, cbPolicy, pContext, cbContext, dwFlags, dwReserved, pdwOutFlags);
  }
 
  IFACEMETHOD(GetSecurityIdEx2)(
    _In_ IUri* /*pUri*/,
    /*_Out_writes_bytes_to_(MAX_SIZE_SECURITY_ID, *pcbSecurityId)*/ BYTE* /*pbSecurityId*/,
    /*_Inout_ _At_(*pcbSecurityId, _In_range_(>= , MAX_SIZE_SECURITY_ID) _Out_range_(0, MAX_SIZE_SECURITY_ID))*/ DWORD* /*pcbSecurityId*/,
    _In_ DWORD_PTR /*dwReserved*/) override
  {
    return INET_E_DEFAULT_ACTION;
  }
 
  IFACEMETHOD(QueryCustomPolicyEx2)(
    _In_ IUri* /*pUri*/,
    _In_ REFGUID /*guidKey*/,
    __RPC__deref_out_ecount_full_opt(*pcbPolicy) BYTE** /*ppPolicy*/,
    _Out_ DWORD* /*pcbPolicy*/,
    _In_ BYTE* /*pContext*/,
    DWORD /*cbContext*/,
    DWORD_PTR /*dwReserved*/) override
  {
    return INET_E_DEFAULT_ACTION;
  }
};
 
class ATL_NO_VTABLE WebBrowserServiceProvider :
  public ATL::CComObjectRootEx<ATL::CComSingleThreadModel>,
  public IServiceProvider
{
public:
  BEGIN_COM_MAP(WebBrowserServiceProvider)
    COM_INTERFACE_ENTRY(IServiceProvider)
  END_COM_MAP()
 
public:
  IFACEMETHOD(QueryService)(
    _In_ REFGUID guidService,
    _In_ REFIID riid,
    _COM_Outptr_ void** ppv) override
  {
    if (guidService == SID_SInternetSecurityManager
      || guidService == SID_SInternetSecurityManagerEx
      || guidService == SID_SInternetSecurityManagerEx2)
    {
      return m_untrustedSecurityManager.QueryInterface(riid, ppv);
    }
    return E_NOINTERFACE;
  }
 
private:
  ATL::CComObjectStackEx<UntrustedSecurityManager> m_untrustedSecurityManager;
};
 
ATL::CComObjectStackEx<WebBrowserServiceProvider> g_webBrowserServiceProvider;
 
class TestWindow :
  public ATL::CWindowImpl<TestWindow>,
  public WTL::CMessageFilter
{
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()
 
private:
  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"",
      WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP | WS_GROUP | WS_VSCROLL | WS_HSCROLL, 0,
      IDC_WEBBROWSER_CONTROL);
 
    ATL::CComPtr<IObjectWithSite> host;
    if (SUCCEEDED(m_webBrowser.QueryHost(&host)))
    {
      ATLENSURE_RETURN_VAL(SUCCEEDED(
        host->SetSite(&g_webBrowserServiceProvider)), -1);
    }
 
    ATLENSURE_RETURN_VAL(SUCCEEDED(
      m_webBrowser.CreateControl(L"http://enable-javascript.com/ja/")), -1);
 
    return 0;
  }
 
  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));
}

IServiceProviderはTestWindowクラスに実装しても良かったのですが、その理解しやすいかと思い、今回は分けてみました。

特徴的な点は以下のところです。

  • セキュリティゾーンの実装(UntrustedSecurityManagerクラス)。
    • IInternetSecurityManagerのMapUrlToZoneとProcessUrlAction
    • IInternetSecurityManagerExのProcessUrlActionEx
    • IInternetSecurityManagerEx2のMapUrlToZoneEx2とProcessUrlActionEx2

    MapUrlToZoneなどでは「制限付きサイト」ゾーンのURLZONE_UNTRUSTEDを返しています。また、念のため、ProcessUrlActionのほうではURLPOLICY_DISALLOWを返し、あらゆる機能を禁止する指定としています。

  • UntrustedSecurityManagerを提供するIServiceProvider実装(WebBrowserServiceProviderクラス。
  • WebBrowserコントロールからのQueryServiceにWebBrowserServiceProviderを使ってもらうよう、ATL::CAxHostWindowに設定する処理。
    ATL::CComPtr<IObjectWithSite> host;
    if (SUCCEEDED(m_webBrowser.QueryHost(&host)))
    {
      ATLENSURE_RETURN_VAL(SUCCEEDED(
        host->SetSite(&g_webBrowserServiceProvider)), -1);
    }

実はこのサンプル、IInternetSecurityManagerExやIInternetSecurityManagerEx2の機能を使っていないので、その2つのインタフェースの実装を削除(SID_SInternetSecurityManagerExとSID_SInternetSecurityManagerEx2も削除)しても動作します。サンプルコードとして、一応含めることにしました。

IProfferServiceを使う方法は次回にします。

MSDNライブラリやサポート情報へのリンク:


スポンサード リンク

この記事のカテゴリ

  • ⇒ WebBrowserコントロールでJavaScriptほか色々禁止する (1)
  • ⇒ WebBrowserコントロールでJavaScriptほか色々禁止する (1)
  • ⇒ WebBrowserコントロールでJavaScriptほか色々禁止する (1)