Click here to visit our sponsor

Collection の作成


ATL でコレクションの実装をする


目次


ウィザードでプロジェクトの作成

[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_EntriesIDR_Entry をリソースから削除します。
Entires.rgsEntiry.rgs もリソースファイルから削除します。
 リソースファイル


cEntries.hcEntriy.h
DECLARE_REGISTRY_RESOURCEID(IDR_EntrXX)
の宣言を
DECLARE_NO_REGISTRY()
に変更します。


プロパティの実装

トップレベルオブジェクトにコレクションを返すプロパティを実装します。

IDLファイル

interface IHyonWinObj : IDispatch
{
    [propget, id(0x40020002)]
        HRESULT Entries([out, retval] IHyonWinObjEntries **ppEntries);
};

読み込み専用プロパティなので、取得関数のみです。


cWinObj.hファイル

コレクションのクラスをインクルードし、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 をインクルードします。


ATL テンプレートの用意

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 はまだです。


おわりに

このページの満足度は・・・

素晴らしい!
まあまあ、良いかも
自己満足感がよくわかるページですね
まったくもって説明不足


Visual C++ページトップ

HOME

兄弟ページ 姉妹ページ
Click here to visit our sponsor