You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
558 lines
18 KiB
558 lines
18 KiB
//----------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 2001.
|
|
//
|
|
// File: Dataobj.h
|
|
//
|
|
// Contents: Wifi Policy management Snapin
|
|
//
|
|
//
|
|
// History: TaroonM
|
|
// 10/30/01
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#ifndef _DATAOBJ_H
|
|
#define _DATAOBJ_H
|
|
|
|
#define ByteOffset(base, offset) (((LPBYTE)base)+offset)
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// class CSnapInClipboardFormats - contains the clipboard formats supported
|
|
// by the WIRELESS snap-in
|
|
class CSnapInClipboardFormats
|
|
{
|
|
public:
|
|
|
|
// Clipboard formats that are required by the console
|
|
static unsigned int m_cfNodeType; // Required by the console
|
|
static unsigned int m_cfNodeTypeString; // Required by the console
|
|
static unsigned int m_cfDisplayName; // Required by the console
|
|
static unsigned int m_cfCoClass; // Required by the console
|
|
|
|
// static unsigned int m_cfInternal; // Step 3
|
|
static unsigned int m_cfWorkstation; // Published information
|
|
|
|
static unsigned int m_cfDSObjectNames; // Published information
|
|
static unsigned int m_cfPolicyObject;
|
|
};
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Template class to extract the TYPE format from the data object
|
|
template <class TYPE>
|
|
TYPE* Extract(LPDATAOBJECT lpDataObject, unsigned int cf)
|
|
{
|
|
ASSERT(lpDataObject != NULL);
|
|
|
|
TYPE* p = NULL;
|
|
|
|
STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL };
|
|
FORMATETC formatetc = { (CLIPFORMAT)cf, NULL,
|
|
DVASPECT_CONTENT, -1, TYMED_HGLOBAL
|
|
};
|
|
|
|
// Allocate memory for the stream
|
|
int len = (int)((cf == CDataObject::m_cfWorkstation) ?
|
|
((MAX_COMPUTERNAME_LENGTH+1) * sizeof(TYPE)) : sizeof(TYPE));
|
|
|
|
stgmedium.hGlobal = GlobalAlloc(GMEM_SHARE, len);
|
|
|
|
// Get the workstation name from the data object
|
|
do
|
|
{
|
|
if (stgmedium.hGlobal == NULL)
|
|
{
|
|
TRACE(_T("Extract - stgmedium.hGlobal == NULL\n"));
|
|
break;
|
|
}
|
|
|
|
if (lpDataObject->GetDataHere(&formatetc, &stgmedium) != S_OK)
|
|
{
|
|
TRACE(_T("Extract - GetDataHere FAILED\n"));
|
|
break;
|
|
}
|
|
|
|
p = reinterpret_cast<TYPE*>(stgmedium.hGlobal);
|
|
|
|
if (p == NULL)
|
|
{
|
|
TRACE(_T("Extract - stgmedium.hGlobal cast to NULL\n"));
|
|
break;
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
return p;
|
|
}
|
|
|
|
// helper methods extracting data from data object
|
|
// INTERNAL * ExtractInternalFormat(LPDATAOBJECT lpDataObject);
|
|
wchar_t * ExtractWorkstation(LPDATAOBJECT lpDataObject);
|
|
GUID * ExtractNodeType(LPDATAOBJECT lpDataObject);
|
|
CLSID * ExtractClassID(LPDATAOBJECT lpDataObject);
|
|
|
|
#define FREE_DATA(pData) \
|
|
ASSERT(pData != NULL); \
|
|
do { if (pData != NULL) \
|
|
GlobalFree(pData); } \
|
|
while(0);
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Template class implementing IDataObject for the WIRELESS snap-in
|
|
template <class T>
|
|
class ATL_NO_VTABLE CDataObjectImpl :
|
|
public IDataObject,
|
|
public CSnapInClipboardFormats
|
|
{
|
|
friend class CComponentImpl;
|
|
|
|
// Construction/Destruction
|
|
public:
|
|
CDataObjectImpl()
|
|
#ifdef _DEBUG
|
|
: m_ComponentData( NULL )
|
|
#endif
|
|
{
|
|
DSOBJECTObjectNamesPtr (NULL);
|
|
POLICYOBJECTPtr (NULL);
|
|
// INTERNALCookie (0);
|
|
};
|
|
~CDataObjectImpl()
|
|
{
|
|
#ifdef _DEBUG
|
|
SetComponentData( NULL );
|
|
#endif
|
|
if (DSOBJECTObjectNamesPtr() != NULL)
|
|
{
|
|
// TODO: we need to free the memory associated with this
|
|
ASSERT (0);
|
|
// and null the member ptr
|
|
DSOBJECTObjectNamesPtr(NULL);
|
|
}
|
|
if (POLICYOBJECTPtr() != NULL)
|
|
{
|
|
delete POLICYOBJECTPtr();
|
|
POLICYOBJECTPtr (NULL);
|
|
}
|
|
};
|
|
|
|
// Standard IDataObject methods
|
|
public:
|
|
// Implemented
|
|
STDMETHOD(GetData)(LPFORMATETC lpFormatetcIn, LPSTGMEDIUM lpMedium);
|
|
STDMETHOD(GetDataHere)(LPFORMATETC lpFormatetc, LPSTGMEDIUM lpMedium);
|
|
STDMETHOD(SetData)(LPFORMATETC lpFormatetc, LPSTGMEDIUM lpMedium, BOOL bRelease);
|
|
|
|
|
|
// Not Implemented
|
|
private:
|
|
STDMETHOD(QueryGetData)(LPFORMATETC lpFormatetc)
|
|
{ return E_NOTIMPL; };
|
|
|
|
STDMETHOD(GetCanonicalFormatEtc)(LPFORMATETC lpFormatetcIn, LPFORMATETC lpFormatetcOut)
|
|
{ return E_NOTIMPL; };
|
|
|
|
STDMETHOD(DAdvise)(LPFORMATETC lpFormatetc, DWORD advf,
|
|
LPADVISESINK pAdvSink, LPDWORD pdwConnection)
|
|
{ return E_NOTIMPL; };
|
|
|
|
STDMETHOD(DUnadvise)(DWORD dwConnection)
|
|
{ return E_NOTIMPL; };
|
|
|
|
STDMETHOD(EnumDAdvise)(LPENUMSTATDATA* ppEnumAdvise)
|
|
{ return E_NOTIMPL; };
|
|
|
|
STDMETHOD(EnumFormatEtc)(DWORD dwDirection, LPENUMFORMATETC* ppEnumFormatEtc)
|
|
{ return E_NOTIMPL; };
|
|
|
|
|
|
// Implementation
|
|
public:
|
|
STDMETHOD_(const GUID*, GetDataObjectTypeGuid)() { return &cNodeTypeWirelessMan; }
|
|
STDMETHOD_(const wchar_t*, GetDataStringObjectTypeGuid)() { return cszNodeTypeWirelessMan; }
|
|
|
|
// This is used only as a diagnostic in debug builds to track if
|
|
// anyone is hanging on to any data objects that's have been handed out
|
|
// Snapin's should view context data objects as ephemeral.
|
|
#ifdef _DEBUG
|
|
public:
|
|
void SetComponentData(CComponentDataImpl* pCCD)
|
|
{
|
|
ASSERT((m_ComponentData == NULL && pCCD != NULL) || pCCD == NULL);
|
|
m_ComponentData = pCCD;
|
|
} ;
|
|
private:
|
|
CComponentDataImpl* m_ComponentData;
|
|
#endif
|
|
|
|
public:
|
|
// access functions for IDataObject hglobal data in its raw form(s)
|
|
// void INTERNALCookie(long cookie) { m_internalData.cookie( cookie );}
|
|
// long INTERNALCookie() {return m_internalData.cookie();}
|
|
|
|
// void INTERNALType(DATA_OBJECT_TYPES type) {ASSERT(m_internalData.type() == CCT_UNINITIALIZED); m_internalData.type(type);}
|
|
// DATA_OBJECT_TYPES INTERNALType() {return m_internalData.type();}
|
|
|
|
//void INTERNALclsid(const CLSID& clsid) {m_internalData.clsid( clsid );}
|
|
//CLSID INTERNALclsid () {return m_internalData.clsid();}
|
|
|
|
void clsid(const CLSID& clsid) {m_clsid = clsid;}
|
|
CLSID clsid () {return m_clsid;}
|
|
|
|
void DSOBJECTObjectNamesPtr (DSOBJECTNAMES* pDSObjectNames) {m_pDSObjectNamesPtr = pDSObjectNames;}
|
|
DSOBJECTNAMES* DSOBJECTObjectNamesPtr () {return m_pDSObjectNamesPtr;}
|
|
|
|
void POLICYOBJECTPtr (POLICYOBJECT* pPolicyObjPtr) {m_pPolicyObjPtr = pPolicyObjPtr;}
|
|
POLICYOBJECT* POLICYOBJECTPtr () {return m_pPolicyObjPtr;}
|
|
|
|
void NodeName (CString &strNodeName) {m_strNodeName = strNodeName;};
|
|
CString NodeName () {return m_strNodeName;};
|
|
|
|
protected:
|
|
// allocate hglobal helpers
|
|
HRESULT CreateNodeTypeData(LPSTGMEDIUM lpMedium);
|
|
HRESULT CreateNodeTypeStringData(LPSTGMEDIUM lpMedium);
|
|
HRESULT CreateDisplayName(LPSTGMEDIUM lpMedium);
|
|
HRESULT CreateInternal(LPSTGMEDIUM lpMedium);
|
|
HRESULT CreateWorkstationName(LPSTGMEDIUM lpMedium);
|
|
HRESULT CreateCoClassID(LPSTGMEDIUM lpMedium);
|
|
HRESULT CreateDSObjectNames(LPSTGMEDIUM lpMedium);
|
|
HRESULT CreatePolicyObject(LPSTGMEDIUM lpMedium);
|
|
HRESULT Create(const void* pBuffer, int len, LPSTGMEDIUM lpMedium);
|
|
int DataGlobalAllocLen (CLIPFORMAT cf);
|
|
|
|
// data associated with this IDataObject
|
|
// INTERNAL m_internalData;
|
|
POLICYOBJECT* m_pPolicyObjPtr;
|
|
DSOBJECTNAMES* m_pDSObjectNamesPtr;
|
|
CString m_strNodeName;
|
|
|
|
// Class ID of who created this data object
|
|
CLSID m_clsid;
|
|
};
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// template CDataObjectImpl - IDataObject interface
|
|
|
|
template <class T>
|
|
STDMETHODIMP CDataObjectImpl<T>::GetData(LPFORMATETC lpFormatetcIn, LPSTGMEDIUM lpMedium)
|
|
{
|
|
OPT_TRACE(_T("CDataObjectImpl<T>::GetData this-%p\n"), this);
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
T* pThis = (T*)this;
|
|
|
|
// allocate the memory
|
|
int iLen = DataGlobalAllocLen (lpFormatetcIn->cfFormat);
|
|
if (iLen != -1)
|
|
{
|
|
// allocate the required amount of memory
|
|
lpMedium->hGlobal = GlobalAlloc(GMEM_SHARE, iLen);
|
|
|
|
// make sure they know they need to free this memory
|
|
lpMedium->pUnkForRelease = NULL;
|
|
|
|
// put the data in it
|
|
if (lpMedium->hGlobal != NULL)
|
|
{
|
|
// make use of
|
|
return pThis->GetDataHere(lpFormatetcIn, lpMedium);
|
|
|
|
}
|
|
}
|
|
|
|
OPT_TRACE(_T("CDataObjectImpl<T>::GetData format-%i return E_UNEXPECTED\n"), lpFormatetcIn->cfFormat);
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
template <class T>
|
|
STDMETHODIMP CDataObjectImpl<T>::GetDataHere(LPFORMATETC lpFormatetc, LPSTGMEDIUM lpMedium)
|
|
{
|
|
OPT_TRACE(_T("CDataObjectImpl<T>::GetDataHere this-%p\n"), this);
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
#ifdef DO_TRACE
|
|
{
|
|
CLIPFORMAT cfDebug = lpFormatetc->cfFormat;
|
|
if (cfDebug == m_cfNodeType)
|
|
{
|
|
OPT_TRACE(_T(" Format: NodeTypeData\n"));
|
|
} else if (cfDebug == m_cfCoClass)
|
|
{
|
|
OPT_TRACE(_T(" Format: CoClassID\n"));
|
|
} else if(cfDebug == m_cfNodeTypeString)
|
|
{
|
|
OPT_TRACE(_T(" Format: NodeTypeString\n"));
|
|
} else if (cfDebug == m_cfDisplayName)
|
|
{
|
|
OPT_TRACE(_T(" Format: DisplayName\n"));
|
|
//} else if (cfDebug == m_cfInternal)
|
|
//{
|
|
// OPT_TRACE(_T(" Format: INTERNAL\n"));
|
|
} else if (cfDebug == m_cfWorkstation)
|
|
{
|
|
OPT_TRACE(_T(" Format: Workstation\n"));
|
|
} else if (cfDebug == m_cfDSObjectNames)
|
|
{
|
|
OPT_TRACE(_T(" Format: DSObjectNames\n"));
|
|
} else if (cfDebug == m_cfPolicyObject)
|
|
{
|
|
OPT_TRACE(_T(" Format: PolicyObject\n"));
|
|
} else
|
|
{
|
|
OPT_TRACE(_T(" ERROR, Unknown format\n"));
|
|
}
|
|
}
|
|
#endif //#ifdef DO_TRACE
|
|
|
|
HRESULT hr = DV_E_CLIPFORMAT;
|
|
|
|
T* pThis = (T*)this;
|
|
|
|
// Based on the CLIPFORMAT create the alloc the correct amount
|
|
// of memory and write the data to it
|
|
const CLIPFORMAT cf = lpFormatetc->cfFormat;
|
|
|
|
if (cf == m_cfNodeType)
|
|
{
|
|
hr = pThis->CreateNodeTypeData(lpMedium);
|
|
} else if (cf == m_cfCoClass)
|
|
{
|
|
hr = pThis->CreateCoClassID(lpMedium);
|
|
} else if(cf == m_cfNodeTypeString)
|
|
{
|
|
hr = pThis->CreateNodeTypeStringData(lpMedium);
|
|
} else if (cf == m_cfDisplayName)
|
|
{
|
|
hr = pThis->CreateDisplayName(lpMedium);
|
|
//} else if (cf == m_cfInternal)
|
|
//{
|
|
// hr = pThis->CreateInternal(lpMedium);
|
|
} else if (cf == m_cfWorkstation)
|
|
{
|
|
hr = pThis->CreateWorkstationName(lpMedium);
|
|
} else if (cf == m_cfDSObjectNames)
|
|
{
|
|
hr = pThis->CreateDSObjectNames(lpMedium);
|
|
} else if (cf == m_cfPolicyObject)
|
|
{
|
|
hr = pThis->CreatePolicyObject (lpMedium);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
template <class T>
|
|
STDMETHODIMP CDataObjectImpl<T>::SetData(LPFORMATETC lpFormatetc, LPSTGMEDIUM lpMedium, BOOL bRelease)
|
|
{
|
|
OPT_TRACE(_T("CDataObjectImpl<T>::SetData this-%p\n"), this);
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
HRESULT hr = E_NOTIMPL;
|
|
|
|
// only implemeneted for cf == m_cfPolicyObject
|
|
const CLIPFORMAT cf = lpFormatetc->cfFormat;
|
|
if (cf == m_cfPolicyObject)
|
|
{
|
|
// let our POLICYOBJECT pull its data out of the ObjMedium
|
|
if (POLICYOBJECTPtr() != NULL)
|
|
{
|
|
hr = POLICYOBJECTPtr()->FromObjMedium (lpMedium);
|
|
|
|
// did the user OK or Apply some settings?
|
|
if (POLICYOBJECTPtr()->dwInterfaceFlags() == POFLAG_APPLY)
|
|
{
|
|
// well then...
|
|
ASSERT (0);
|
|
::MMCPropertyChangeNotify(POLICYOBJECTPtr()->lMMCUpdateHandle(), NULL /*INTERNALCookie()*/);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// template CDataObjectImpl - protected members
|
|
|
|
template <class T>
|
|
HRESULT CDataObjectImpl<T>::CreateNodeTypeData(LPSTGMEDIUM lpMedium)
|
|
{
|
|
// Create the node type object in GUID format
|
|
const GUID* pcObjectType = NULL;
|
|
T* pThis = (T*)this;
|
|
|
|
// get correct object type
|
|
pcObjectType = pThis->GetDataObjectTypeGuid ();
|
|
|
|
return Create(reinterpret_cast<const void*>(pcObjectType), sizeof(GUID), lpMedium);
|
|
}
|
|
|
|
template <class T>
|
|
HRESULT CDataObjectImpl<T>::CreateNodeTypeStringData(LPSTGMEDIUM lpMedium)
|
|
{
|
|
// Create the node type object in GUID string format
|
|
const wchar_t* cszObjectType = NULL;
|
|
T* pThis = (T*)this;
|
|
|
|
// get correct object type string
|
|
cszObjectType = pThis->GetDataStringObjectTypeGuid ();
|
|
|
|
return Create(cszObjectType, ((wcslen(cszObjectType)+1) * sizeof(wchar_t)), lpMedium);
|
|
}
|
|
|
|
template <class T>
|
|
HRESULT CDataObjectImpl<T>::CreateDisplayName(LPSTGMEDIUM lpMedium)
|
|
{
|
|
// This is the display named used in the scope pane and snap-in manager
|
|
return Create(NodeName(), ((NodeName().GetLength()+1) * sizeof(wchar_t)), lpMedium);
|
|
}
|
|
|
|
|
|
template <class T>
|
|
HRESULT CDataObjectImpl<T>::CreateWorkstationName(LPSTGMEDIUM lpMedium)
|
|
{
|
|
wchar_t pzName[MAX_COMPUTERNAME_LENGTH+1] = {0};
|
|
DWORD len = MAX_COMPUTERNAME_LENGTH+1;
|
|
|
|
if (GetComputerName(pzName, &len) == FALSE)
|
|
{
|
|
TRACE(_T("CDataObjectImpl<T>::CreateWorkstationName returning E_FAIL\n"));
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Add 1 for the NULL and calculate the bytes for the stream
|
|
return Create(pzName, ((len+1)* sizeof(wchar_t)), lpMedium);
|
|
}
|
|
|
|
template <class T>
|
|
HRESULT CDataObjectImpl<T>::CreateCoClassID(LPSTGMEDIUM lpMedium)
|
|
{
|
|
// Create the CoClass information
|
|
return Create(reinterpret_cast<const void*>(&clsid()), sizeof(CLSID), lpMedium);
|
|
}
|
|
|
|
template <class T>
|
|
HRESULT CDataObjectImpl<T>::CreateDSObjectNames(LPSTGMEDIUM lpMedium)
|
|
{
|
|
int len = 0;
|
|
HRESULT hr = S_OK;
|
|
|
|
len = DataGlobalAllocLen((CLIPFORMAT)m_cfDSObjectNames);
|
|
|
|
hr = Create(DSOBJECTObjectNamesPtr(), len, lpMedium);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
template <class T>
|
|
HRESULT CDataObjectImpl<T>::CreatePolicyObject(LPSTGMEDIUM lpMedium)
|
|
{
|
|
HRESULT hr = E_UNEXPECTED;
|
|
|
|
// can only do this if there is a POLICYOBJECTPtr
|
|
if (POLICYOBJECTPtr() != NULL)
|
|
{
|
|
// allocate a POLICYOBJECTSTRUCT of the correct length
|
|
int iLen = POLICYOBJECTPtr()->DataGlobalAllocLen();
|
|
POLICYOBJECTSTRUCT* pPolicyStruct = (POLICYOBJECTSTRUCT* ) malloc (iLen);
|
|
|
|
if (POLICYOBJECTPtr()->ToPolicyStruct (pPolicyStruct) == S_OK)
|
|
{
|
|
return Create (reinterpret_cast<const void*>(pPolicyStruct), iLen, lpMedium);
|
|
};
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
template <class T>
|
|
HRESULT CDataObjectImpl<T>::Create(const void* pBuffer, int len, LPSTGMEDIUM lpMedium)
|
|
{
|
|
HRESULT hr = DV_E_TYMED;
|
|
|
|
// Do some simple validation
|
|
if (pBuffer == NULL || lpMedium == NULL)
|
|
return E_POINTER;
|
|
|
|
// Make sure the type medium is HGLOBAL
|
|
if (lpMedium->tymed == TYMED_HGLOBAL)
|
|
{
|
|
// Create the stream on the hGlobal passed in
|
|
LPSTREAM lpStream;
|
|
hr = CreateStreamOnHGlobal(lpMedium->hGlobal, FALSE, &lpStream);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
// Write to the stream the number of bytes
|
|
unsigned long written;
|
|
hr = lpStream->Write(pBuffer, len, &written);
|
|
|
|
// Because we told CreateStreamOnHGlobal with 'FALSE',
|
|
// only the stream is released here.
|
|
// Note - the caller (i.e. snap-in, object) will free the HGLOBAL
|
|
// at the correct time. This is according to the IDataObject specification.
|
|
lpStream->Release();
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
template <class T>
|
|
int CDataObjectImpl<T>::DataGlobalAllocLen (CLIPFORMAT cf)
|
|
{
|
|
int iLen = -1;
|
|
|
|
// need to determine the correct amount of space depending on the time
|
|
if (cf == CSnapInClipboardFormats::m_cfCoClass)
|
|
{
|
|
iLen = sizeof (CLSID);
|
|
} else if (cf == m_cfNodeType)
|
|
{
|
|
iLen = sizeof (GUID);
|
|
} else if (cf == m_cfWorkstation)
|
|
{
|
|
iLen = ((MAX_COMPUTERNAME_LENGTH+1) * sizeof(wchar_t));
|
|
} else if (cf == m_cfDSObjectNames)
|
|
{
|
|
// compute size of the DSOBJECTNAMES structure
|
|
if (DSOBJECTObjectNamesPtr() != NULL)
|
|
{
|
|
CString strName = (LPWSTR)ByteOffset(DSOBJECTObjectNamesPtr(), DSOBJECTObjectNamesPtr()->aObjects[0].offsetName);;
|
|
CString strClass = (LPWSTR)ByteOffset(DSOBJECTObjectNamesPtr(), DSOBJECTObjectNamesPtr()->aObjects[0].offsetClass);;
|
|
iLen = sizeof(DSOBJECTNAMES) + sizeof(DSOBJECT);
|
|
iLen += strName.GetLength()*sizeof(wchar_t)+1 + strClass.GetLength()*sizeof(wchar_t)+1;
|
|
}
|
|
} else if (cf == m_cfPolicyObject)
|
|
{
|
|
// compute size of the needed POLICYSTORAGE structure
|
|
iLen = POLICYOBJECTPtr()->DataGlobalAllocLen();
|
|
} else
|
|
{
|
|
// unknown type!!
|
|
}
|
|
|
|
return iLen;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// class CDataObject - standalone instantiation of IDataObject implementation
|
|
class CDataObject :
|
|
public CDataObjectImpl <CDataObject>,
|
|
public CComObjectRoot
|
|
{
|
|
friend class CComponentImpl;
|
|
public:
|
|
CDataObject() {};
|
|
virtual ~CDataObject() {};
|
|
|
|
// ATL Maps
|
|
DECLARE_NOT_AGGREGATABLE(CDataObject)
|
|
BEGIN_COM_MAP(CDataObject)
|
|
COM_INTERFACE_ENTRY(IDataObject)
|
|
END_COM_MAP()
|
|
|
|
// Standard IDataObject methods implemented in CDataObjectImpl
|
|
};
|
|
#endif
|