今回は、前回予告した、IProfferServiceを使い、WebBrowserコントロールにIInternetSecurityManagerを提供する方法の話です。

WebBrowserコントロールでのIProfferServiceの使い方はこんな感じでした。

  1. WebBrowserコントロールのオブジェクトに対し、IServiceProvider.QueryServiceでSID_SProfferServiceを問い合わせ、IProfferServiceへのポインタを得る。
  2. IProfferService.ProfferServiceで、サービスのGUIDと自分が作成したIServiceProviderへのポインタを登録する。

その部分のコードです。

// class TestWindow内
 
LRESULT OnCreate(const CREATESTRUCT*)
{
  constexpr DWORD IDC_WEBBROWSER_CONTROL = 1;
  RECT empty{};
  m_webBrowser.Create(m_hWnd, empty,
    L"{8856F961-340A-11D0-A96B-00C04FD705A2}",
    WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP | WS_GROUP, 0,
    IDC_WEBBROWSER_CONTROL);
 
  ATL::CComPtr<IServiceProvider> sp;
  if (SUCCEEDED(m_webBrowser.QueryControl(&sp)))
  {
    ATL::CComPtr<IProfferService> ps;
    if (SUCCEEDED(sp->QueryService(SID_SProfferService, &ps)))
    {
      DWORD cookie;
      ATLENSURE_RETURN_VAL(
        SUCCEEDED(ps->ProfferService(
          SID_SInternetSecurityManagerEx2,
          &g_webBrowserServiceProvider,
          &cookie)),
        -1);
      m_webBrowserServiceCookie.push_back(cookie);
      ATLENSURE_RETURN_VAL(
        SUCCEEDED(ps->ProfferService(
          SID_SInternetSecurityManagerEx,
          &g_webBrowserServiceProvider,
          &cookie)),
        -1);
      m_webBrowserServiceCookie.push_back(cookie);
      ATLENSURE_RETURN_VAL(
        SUCCEEDED(ps->ProfferService(
          SID_SInternetSecurityManager,
          &g_webBrowserServiceProvider,
          &cookie)),
        -1);
      m_webBrowserServiceCookie.push_back(cookie);
    }
  }
 
  ATL::CComQIPtr<IWebBrowser2> wb = sp;
  ATL::CComVariant url(L"http://enable-javascript.com/ja/");
  wb->Navigate2(&url, nullptr, nullptr, nullptr, nullptr);
 
  return 0;
}
 
void OnDestroy()
{
  ATL::CComPtr<IServiceProvider> sp;
  if (SUCCEEDED(m_webBrowser.QueryControl(&sp)))
  {
    ATL::CComPtr<IProfferService> ps;
    if (SUCCEEDED(sp->QueryService(SID_SProfferService, &ps)))
    {
      for (auto cookie : m_webBrowserServiceCookie)
      {
        ps->RevokeService(cookie);
      }
    }
  }
  PostQuitMessage(0);
}
 
ATL::CAxWindow m_webBrowser;
// boostを使いたくないなら、std::vector<DWORD>に変更する。
boost::container::static_vector<DWORD, 3> m_webBrowserServiceCookie;

ここ以外は、前回と全く同じコードです。そのコード全部を次に載せます。

#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 <shobjidl.h>
 
#include <atlbase.h>
#include <atltypes.h>
#include <atlwin.h>
 
#include <atlapp.h>
#include <atlcrack.h>
 
// boostを使いたくないなら、#include <vector>に変更する。
#include <boost/container/static_vector.hpp>
 
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"{8856F961-340A-11D0-A96B-00C04FD705A2}",
      WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP | WS_GROUP, 0,
      IDC_WEBBROWSER_CONTROL);
 
    ATL::CComPtr<IServiceProvider> sp;
    if (SUCCEEDED(m_webBrowser.QueryControl(&sp)))
    {
      ATL::CComPtr<IProfferService> ps;
      if (SUCCEEDED(sp->QueryService(SID_SProfferService, &ps)))
      {
        DWORD cookie;
        ATLENSURE_RETURN_VAL(
          SUCCEEDED(ps->ProfferService(
            SID_SInternetSecurityManagerEx2,
            &g_webBrowserServiceProvider,
            &cookie)),
          -1);
        m_webBrowserServiceCookie.push_back(cookie);
        ATLENSURE_RETURN_VAL(
          SUCCEEDED(ps->ProfferService(
            SID_SInternetSecurityManagerEx,
            &g_webBrowserServiceProvider,
            &cookie)),
          -1);
        m_webBrowserServiceCookie.push_back(cookie);
        ATLENSURE_RETURN_VAL(
          SUCCEEDED(ps->ProfferService(
            SID_SInternetSecurityManager,
            &g_webBrowserServiceProvider,
            &cookie)),
          -1);
        m_webBrowserServiceCookie.push_back(cookie);
      }
    }
 
    ATL::CComQIPtr<IWebBrowser2> wb = sp;
    ATL::CComVariant url(L"http://enable-javascript.com/ja/");
    wb->Navigate2(&url, nullptr, nullptr, nullptr, nullptr);
 
    return 0;
  }
 
  void OnDestroy()
  {
    ATL::CComPtr<IServiceProvider> sp;
    if (SUCCEEDED(m_webBrowser.QueryControl(&sp)))
    {
      ATL::CComPtr<IProfferService> ps;
      if (SUCCEEDED(sp->QueryService(SID_SProfferService, &ps)))
      {
        for (auto cookie : m_webBrowserServiceCookie)
        {
          ps->RevokeService(cookie);
        }
      }
    }
    PostQuitMessage(0);
  }
 
  ATL::CAxWindow m_webBrowser;
  // boostを使いたくないなら、std::vector<DWORD>に変更する。
  boost::container::static_vector<DWORD, 3> m_webBrowserServiceCookie;
};
 
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));
}

前回より少し手順が複雑です。その代わり、ATL::CAxWindowやATL::CAxHostWindowなどの内部実装を知る必要が無いのが利点です。

今回のIProfferServiceを使う方法は、C# Tips -AxWebBrowserのIInternetSecurityManager-で知りました。この方法をC++でやってみたということになります。

MSDNライブラリの項目へのリンクです: IProfferService interface


スポンサード リンク

この記事のカテゴリ

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