本記事は、COM Advent Calendar 2014 – Qiitaの17日目の記事です。


前回のマーシャリングできないインタフェースの話に続いて、今回はオブジェクト自らがマーシャリングの禁止を宣言する話です。

マーシャリングできないことを表明するインタフェースINoMarshalがWindows 8で追加されました。早速サンプルコードを出します。

#include <iostream>
#include <thread>
#include <windows.h>
#include <shlwapi.h>
#include <atlbase.h>
#include <atlcom.h>
#include <atlutil.h>
 
class ATL_NO_VTABLE Hoge
  : public ATL::CComObjectRootEx<ATL::CComSingleThreadModel>
  , public ATL::CComCoClass<Hoge>
  , public ISequentialStream
{
public:
  BEGIN_COM_MAP(Hoge)
    COM_INTERFACE_ENTRY(ISequentialStream)
    COM_INTERFACE_ENTRY_IID(__uuidof (INoMarshal), ISequentialStream)
  END_COM_MAP()
 
  IFACEMETHOD(Read)(
    _Out_writes_bytes_to_(cb, *pcbRead) void* pv,
    _In_ ULONG cb,
    _Out_opt_ ULONG *pcbRead) override
  {
    if (pcbRead == nullptr)
      return E_POINTER;
    *pcbRead = 0;
    return S_OK;
  }
 
  IFACEMETHOD(Write)(
    _In_reads_bytes_(cb) const void* pv,
    _In_ ULONG cb,
    _Out_opt_ ULONG *pcbWritten) override
  {
    return E_NOTIMPL;
  }
};
 
int main()
{
  std::cout << std::hex << std::showbase;
  if (FAILED(CoInitializeEx(nullptr,
    COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE)))
  {
    return 1;
  }
 
  {
    ATL::CComObjectStackEx<Hoge> hoge;
 
    IStream* s;
    std::cout << CoMarshalInterThreadInterfaceInStream(
      IID_IUnknown, &hoge, &s) << std::endl;
  }
  CoUninitialize();
}

実行結果はこうでした。

0x80004021

CoMarshalInterThreadInterfaceInStreamで指定しているのは本来マーシャリングできるIUnknownにもかかわらず、このようにエラーコード0x80004021 (CO_E_NOT_SUPPORTED)になりました。


余談です。INoMarshalはメソッドを全く持たないため、C++クラスHogeの基底クラスに入れずに実装しました。COM_INTERFACE_ENTRY_IIDを使っています。

COM_INTERFACE_ENTRY_IID(__uuidof (INoMarshal), ISequentialStream)

こうすると、QueryInterfaceで__uuidof (INoMarshal)が来たとき、static_cast<ISequentialStream*>(this)相当を返すという意味合いになります。INoMarshalはIUnknownと全く同じ構造のvtblになるため、ISequentialStreamに限らずIUnknownから派生する任意のインタフェースを指定して構いません。


なお、INoMarshalはおそらくWinRT API (Windows Runtime)用に追加されたものですが、このようにWinRT APIと無関係に使用できます。


スポンサード リンク

この記事のカテゴリ

  • ⇒ マーシャル禁止のオブジェクト