最近工作需要,正在研究ATL/COM方面的东东。今天正好看到了集合(Collection)和枚举器(Enumerater),这个两个东东个人觉得不是很好理解,反正我是看了好几遍书,然后又在网上找了些资料,才算勉强有些入门,然后写了几个小练习。
练习一: 使用CComEnum实现,使用的IEnumVARIANT枚举接口
1.IDL文件
[
object,
uuid(FBCAD1D2-9148-4DD4-8FAC-EB41420E27F8),
dual,
nonextensible,
helpstring("INumbers 接口"),
pointer_default(unique)
]
interface INumbers : IDispatch{
[propget, id(1), helpstring("属性 Count")] HRESULT Count([out, retval] LONG* pVal);
[propget, id(DISPID_VALUE), helpstring("属性 Item")] HRESULT Item([in] LONG n, [out, retval] LONG* pVal);
[propget, id(DISPID_NEWENUM), helpstring("属性 _NewEnum")] HRESULT _NewEnum([out, retval] IUnknown** pVal);
};
[
uuid(03DE570D-D020-4A6C-B21F-AC92963C1D42),
version(1.0),
helpstring("MyNumbers 1.0 类型库")
]
library MyNumbersLib
{
importlib("stdole2.tlb");
[
uuid(C3A5B58A-F764-43FF-82B9-A7CBB0D1F867),
helpstring("Numbers Class")
]
coclass Numbers
{
[default] interface INumbers;
};
};
2.Numbers.h实现
#include "MyNumbers.h"
#include <vector>
#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
#error "Windows CE 平台(如不提供完全 DCOM 支持的 Windows Mobile 平台)上无法正确支持单线程 COM 对象。定义 _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA 可强制 ATL 支持创建单线程 COM 对象实现并允许使用其单线程 COM 对象实现。rgs 文件中的线程模型已被设置为“Free”,原因是该模型是非 DCOM Windows CE 平台支持的唯一线程模型。"
#endif
typedef CComEnum<IEnumVARIANT,&IID_IEnumVARIANT,VARIANT,_Copy<VARIANT>> MyNumbersEnum;
// CNumbers
class ATL_NO_VTABLE CNumbers :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CNumbers, &CLSID_Numbers>,
public IDispatchImpl<INumbers, &IID_INumbers, &LIBID_MyNumbersLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
CNumbers()
{
m_Num.push_back(10);
m_Num.push_back(11);
m_Num.push_back(12);
m_Num.push_back(13);
m_Num.push_back(14);
m_Num.push_back(15);
}
DECLARE_REGISTRY_RESOURCEID(IDR_NUMBERS)
BEGIN_COM_MAP(CNumbers)
COM_INTERFACE_ENTRY(INumbers)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct()
{
return S_OK;
}
void FinalRelease()
{
}
public:
public:
STDMETHOD(get_Count)(LONG* pVal);
public:
STDMETHOD(get_Item)(LONG n, LONG* pVal);
public:
STDMETHOD(get__NewEnum)(IUnknown** pVal);
protected:
std::vector<long> m_Num;
};
OBJECT_ENTRY_AUTO(__uuidof(Numbers), CNumbers)
3.Numbers.cpp实现
#include "stdafx.h"
#include "Numbers.h"
// CNumbers
STDMETHODIMP CNumbers::get_Count(LONG* pVal)
{
// TODO: 在此添加实现代码
*pVal = (long)m_Num.size();
return S_OK;
}
STDMETHODIMP CNumbers::get_Item(LONG n, LONG* pVal)
{
// TODO: 在此添加实现代码
long Max = (long)m_Num.size();
if (n >= Max)
{
return E_OUTOFMEMORY;
}
*pVal = m_Num[n];
return S_OK;
}
STDMETHODIMP CNumbers::get__NewEnum(IUnknown** pVal)
{
// TODO: 在此添加实现代码
CComObject<MyNumbersEnum>* pNumbersEnum = NULL ;
HRESULT hr = CComObject<MyNumbersEnum>::CreateInstance(&pNumbersEnum);
if (SUCCEEDED(hr))
{
pNumbersEnum->AddRef();
long lSize = (long)m_Num.size();
VARIANT* pVARIANT = new VARIANT[lSize];
if (pVARIANT)
{
ZeroMemory(pVARIANT,sizeof(VARIANT)*lSize);
VARIANT* pTemp = pVARIANT;
std::vector<long>::iterator it = m_Num.begin();
for (;it != m_Num.end();it++,pTemp++)
{
pTemp->vt = VT_I4;
pTemp->lVal = *it;
}
hr = pNumbersEnum->Init(&pVARIANT[0],&pVARIANT[lSize],0,AtlFlagTakeOwnership);
if (SUCCEEDED(hr))
{
hr = pNumbersEnum->QueryInterface(IID_IUnknown,(void**)pVal);
}
else
{
hr = E_OUTOFMEMORY;
}
}
pNumbersEnum->Release();
}
return hr;
}
4.测试Client
#include "../MyNumbers/MyNumbers.h"
#include "../MyNumbers/MyNumbers_i.c"
using namespace std;
int main()
{
CoInitialize(NULL);
try
{
CComPtr<INumbers> pNum = NULL;
HRESULT hr;
hr = CoCreateInstance(CLSID_Numbers,NULL,CLSCTX_INPROC,IID_INumbers,(void**)&pNum);
if (FAILED(hr))
{
cout << "CoCrateInstance error." << endl;
CoUninitialize();
return -1;
}
long lSize = 0;
pNum->get_Count(&lSize);
cout << "Size: " << lSize << endl;
CComPtr<IEnumVARIANT> pEnum = NULL;
CComPtr<IUnknown> pUnknown = NULL;
pNum->get__NewEnum(&pUnknown);
pUnknown->QueryInterface(IID_IEnumVARIANT,(void**)&pEnum);
for (int i=1;i<=lSize;i++)
{
VARIANT varTemp[1];
ULONG lFetched = 0;
hr = pEnum->Next(1,&varTemp[0],&lFetched);
if (SUCCEEDED(hr))
{
CComVariant comvar;
comvar.Attach(&varTemp[0]);
wcout << "Number " << i << " is " << comvar.lVal << endl;
}
}
}
catch (...)
{
cout << "an expection occur......" << endl;
}
CoUninitialize();
system("pause");
return 0;
}