[ATL COM AppWizard] で ダイナミックライブラリ(DLL) のプロジェクトを新規作成します。
ここではプロジェクト名を WinObjにしています。
まずトップレベルのオブジェクトの生成をします。
これは外部に公開するオブジェクトになります。
[挿入(I)] メニュー → [ATLオブジェクトの新規作成]。
ここではクラス名を cWinObjにします。
オブジェクトショートネーム WinObj CoClass名 HyonWinObj タイプ名 HyonWinObj Class タイプID(ProgID) Hyon.WinObj インターフェイス IHyonWinObj
(Hyon という部分は適当に替えてください)
次にオブジェクトを2つ作ります。
このオブジェクトはコレクションにします。
クラス名: cEntries
オブジェクトショートネーム Entries CoClass名 HyonWinObjEntries タイプ名 HyonWinObjEntries Class タイプID(ProgID) Hyon.WinObjEntries インターフェイス IHyonWinObjEntries
コレクションが生成する子オブジェクトになります。
クラス名: cEntry
オブジェクトショートネーム Entry CoClass名 HyonWinObjEntry タイプ名 HyonWinObjEntry Class タイプID(ProgID) Hyon.WinObjEntry インターフェイス IHyonWinObjEntry
WinObj
└ Entries (コレクション)
└ Entry
コレクションとその子オブジェクトは、外部から生成しないので、noncreatable なオブジェクトにします。
IDLファイルを開いて、タイプライブラリ部分の coclass に noncreatable を追加します。
library WINOBJLib
{
[
noncreatable,
uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx),
helpstring("Entry Class")
]
coclass HyonWinObjEntry
{
[default] interface IHyonWinObjEntry;
};
[
noncreatable,
uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx),
helpstring("Entries Class")
]
coclass HyonWinObjEntries
{
[default] interface IHyonWinObjEntries;
};
......
}
レジストリの登録も不要なので、IDR_Entries と IDR_Entry をリソースから削除します。
Entires.rgs、Entiry.rgs もリソースファイルから削除します。
cEntries.h と cEntriy.h の
DECLARE_REGISTRY_RESOURCEID(IDR_EntrXX)
の宣言を
DECLARE_NO_REGISTRY()
に変更します。
トップレベルオブジェクトにコレクションを返すプロパティを実装します。
interface IHyonWinObj : IDispatch
{
[propget, id(0x40020002)]
HRESULT Entries([out, retval] IHyonWinObjEntries **ppEntries);
};
読み込み専用プロパティなので、取得関数のみです。
コレクションのクラスをインクルードし、CComObject 型として定義します。
#include"cEntries.h"
typedef CComObject<cEntries> cEntriesImpl;
コレクションの実体を保持しておく変数を実装します。
cEntriesImpl* m_spEntries;
cWinObj() :
m_spEntries(NULL)
{
}
コレクションのインスタンスの生成と破棄するコードを追加します。
FinalConstruct() と FinalRelease() をオーバーライドさせます。
HRESULT FinalConstruct()
{
HRESULT hr = cEntriesImpl::CreateInstance(&m_spEntries);
if (FAILED(hr))
{
return hr;
}
m_spEntries->AddRef();
return S_OK;
}
void FinalRelease()
{
m_spEntries->Release();
}
プロパティを実装します。
STDMETHODIMP get_Entries(/*[out, retval]*/ IHyonWinObjEntries **ppInterface)
{
if (!ppInterface)
{
return E_POINTER;
}
*ppInterface = NULL;
return
m_spEntries->QueryInterface(
IID_IHyonWinObjEntries,
(void**)ppInterface
);
}
STL を使用するので、[プロジェクト]メニュー → [設定(S)]ダイアログ
[すべての構成] に対して [C/C++]タブ → カテゴリ [C++言語] → 例外処理を有効にする(E) を有効にします。
StdAfx.h に list.h をインクルードします。
cEntries.h の変更
生成させるための子オブジェクトのクラスをインクルードします。
#include"cEntry.h"
ATL のコレクション用テンプレートを利用します。
typedef std::list< CAdapt< CComPtr<IHyonWinObjEntry> > > EntryList;
template <typename T>
struct _CopyVariantFromAdaptItf
{
static HRESULT copy(VARIANT* p1, CAdapt< CComPtr<T> >* p2)
{
HRESULT hr =
p2->m_T->QueryInterface(IID_IDispatch, (void**)&p1->pdispVal);
if( SUCCEEDED(hr) )
{
p1->vt = VT_DISPATCH;
}
else
{
hr = p2->m_T->QueryInterface(IID_IUnknown, (void**)&p1->punkVal);
if( SUCCEEDED(hr) )
{
p1->vt = VT_UNKNOWN;
}
}
return hr;
}
static void init(VARIANT* p) { VariantInit(p); }
static void destroy(VARIANT* p) { VariantClear(p); }
};
typedef CComEnumOnSTL<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT,
_CopyVariantFromAdaptItf<IHyonWinObjEntry>,
EntryList >
CComEnumVariantOnListOfEntries;
template <typename T>
struct _CopyItfFromAdaptItf
{
static HRESULT copy(T** p1, CAdapt< CComPtr<T> >* p2)
{
if ( *p1 = p2->m_T )
{
return (*p1)->AddRef(), S_OK;
}
return E_POINTER;
}
static void init(T** p) {}
static void destroy(T** p) { if( *p ) (*p)->Release(); }
};
typedef
ICollectionOnSTLImpl<IDispatchImpl<IHyonWinObjEntries, &IID_IHyonWinObjEntries>,
EntryList,
IHyonWinObjEntry*,
_CopyItfFromAdaptItf<IHyonWinObjEntry>,
CComEnumVariantOnListOfEntries>
EntriesCollImpl;
public IDispatchImpl<IHyonWinObjEntries, &IID_IHyonWinObjEntries, &LIBID_WINOBJLib>
↓↓↓↓
public EntriesCollImpl
public CComCoClass<cEntries, &CLSID_HyonWinObjEntries>
↓↓↓↓
public CComCoClass<cEntries>
IDL の変更
import "oaidl.idl";
import "ocidl.idl";
#include "olectl.h"
interface IHyonWinObjEntries : IDispatch
{
[propget, id(DISPID_VALUE) ]
HRESULT Item([in]long nIndex, [out,retval]IHyonWinObjEntry **ppEntry);
[propget, id(DISPID_NEWENUM)]
HRESULT _NewEnum([out, retval]IUnknown** ppEnum);
[propget, id(0x40020001)]
HRESULT Count([out, retval]long* pnCount);
[id(DISPID_ADDITEM)]
HRESULT Add([out, retval]IHyonWinObjEntry **ppEntry);
[id(DISPID_REMOVEITEM)]
HRESULT Remove([in]VARIANT Index);
[id(DISPID_CLEAR)]
HRESULT RemoveAll();
};
Item, _NewEnum がコレクションの必須メソッドです。
cEntries.h の変更
public:
STDMETHODIMP Add(/*[out, retval]*/IHyonWinObjEntry **ppEntry);
STDMETHODIMP Remove(/*[in]*/VARIANT Index);
STDMETHODIMP RemoveAll()
{
m_coll.clear();
return S_OK;
}
cEntries.cpp の変更
STDMETHODIMP cEntries::Add(/*[out, retval]*/IHyonWinObjEntry **ppEntry)
{
if (!ppEntry)
{
return E_POINTER;
}
CComObject<cEntry> *pEntry = NULL;
HRESULT hr = CComObject<cEntry>::CreateInstance(&pEntry);
if (SUCCEEDED(hr))
{
hr = pEntry->QueryInterface(ppEntry);
if (SUCCEEDED(hr))
{
CComPtr<IHyonWinObjEntry> spEntry = *ppEntry;
m_coll.push_back(spEntry);
}
}
return hr;
}
STDMETHODIMP cEntries::Remove(/*[in]*/VARIANT Index)
{
return E_NOTIMPL;
}
Remove はまだです。