클라이언트는 루트 개체가 제공하는 읽기 전용의 속성을 통하여 컬렉션 개체에 접근하게 된다.
클래스 팩토리 관련 내용은 제거한다.
.Count
.Item[]
._NewEnum
[.Add()]
[.Remove()]
클래스 팩토리 관련 내용은 제거한다.
다른 컬렉션 개체를 제공할 수 있다.
class ATL_NO_VTABLE CCompany :
...
public IDispatchImpl<ICompany, &IID_ICompany, &LIBID_COMPANYLib>
{
// {
CComObject<CEmployees>* m_pEmployees;
// }
public:
CCompany()
{
m_pEmployees = new CComObject<CEmployees>;
m_pEmployees->Init();
}
...
BEGIN_COM_MAP(CCompany)
COM_INTERFACE_ENTRY(ICompany)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(ISupportErrorInfo)
END_COM_MAP()
// ISupportsErrorInfo
STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);
// ICompany
public:
STDMETHOD(get_Employees)(/*[out, retval]*/ VARIANT *pVal);
};
STDMETHODIMP CCompany::get_Employees(VARIANT *pVal)
{
// TODO: Add your implementation code here
// {
VariantInit(pVal);
IDispatch* pDisp;
m_pEmployees->QueryInterface(IID_IDispatch, (LPVOID*)&pDisp);
pVal->vt = VT_DISPATCH;
pVal->pdispVal = pDisp;
// }
return S_OK;
}
class CEmployees :
...
public CComObjectRoot
{
// {
long m_Count;
CComVariant* m_pEmployees;
// }
public:
// {
void Init();
// }
CEmployees() {
m_pEmployees = NULL;
m_Count = 0;
}
~CEmployees() {
delete [] m_pEmployees;
}
BEGIN_COM_MAP(CEmployees)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IEmployees)
COM_INTERFACE_ENTRY(ISupportErrorInfo)
END_COM_MAP()
...
// IEmployees
public:
STDMETHOD(get__NewEnum)(/*[out, retval]*/ LPUNKNOWN *pVal);
STDMETHOD(get_Item)(/*[in]*/ long index, /*[out, retval]*/ VARIANT *pVal);
STDMETHOD(get_Count)(/*[out, retval]*/ long *pVal);
};
void CEmployees::Init()
{
...
if (m_pEmployees != NULL)
delete [] m_pEmployees;
m_Count = 10;
m_pEmployees = new CComVariant[m_Count];
CComObject<CEmployee>* pEmployee;
LPDISPATCH lpDisp = NULL;
for (int i = 0; i < m_Count; i++) {
HRESULT hr = CComObject<CEmployee>::CreateInstance(&pEmployee);
if(FAILED(hr)) {
MessageBox(NULL, "Can't create Employe object", NULL, MB_OK);
return;
}
pEmployee->m_Name = names[i];
...
pEmployee->QueryInterface(IID_IDispatch, (void**)&lpDisp);
CComVariant& var = m_pEmployees[i];
var.vt = VT_DISPATCH;
var.pdispVal = lpDisp;
}
}
STDMETHODIMP CEmployees::get_Count(long *pVal)
{
// TODO: Add your implementation code here
// {
*pVal = m_Count;
// }
return S_OK;
}
STDMETHODIMP CEmployees::get_Item(long index, VARIANT *pVal)
{
// TODO: Add your implementation code here
// {
if (NULL == pVal)
return E_POINTER;
// 인덱스는 1에서 시작(VB용)
if ((index < 1) || (index > m_Count))
return E_INVALIDARG;
VariantInit(pVal);
pVal->vt = VT_UNKNOWN;
pVal->punkVal = NULL;
// 0 에서 시작하는 인덱스로 변경
HRESULT hr = VariantCopy(pVal, &m_pEmployees[index-1]);
if(FAILED(hr))
MessageBox(NULL, "Can't get the Item.", NULL, MB_OK);
return hr;
// }
// return S_OK;
}
STDMETHODIMP CEmployees::get__NewEnum(LPUNKNOWN *pVal)
{
// TODO: Add your implementation code here
// {
if (NULL == pVal)
return E_POINTER;
*pVal = NULL;
typedef CComObject<
CComEnum<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT,
_Copy<VARIANT> > > EnumVar;
EnumVar* p = new EnumVar;
HRESULT hr = p->Init(&m_pEmployees[0],
&m_pEmployees[m_Count],
NULL, AtlFlagCopy);
if (SUCCEEDED(hr))
hr = p->QueryInterface(IID_IEnumVARIANT, (LPVOID*)pVal);
if (FAILED(hr))
delete p;
return hr;
// }
// return S_OK;
}