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.
1715 lines
41 KiB
1715 lines
41 KiB
/*===================================================================
|
|
Microsoft Denali
|
|
|
|
Microsoft Confidential.
|
|
Copyright 1997 Microsoft Corporation. All Rights Reserved.
|
|
|
|
Component: MetaUtil object
|
|
|
|
File: PropCol.cpp
|
|
|
|
Owner: t-BrianM
|
|
|
|
This file contains implementation of the property collection and
|
|
property object.
|
|
===================================================================*/
|
|
|
|
#include "stdafx.h"
|
|
#include "MetaUtil.h"
|
|
#include "MUtilObj.h"
|
|
#include "PropCol.h"
|
|
|
|
|
|
/*------------------------------------------------------------------
|
|
* C P r o p e r t y C o l l e c t i o n
|
|
*/
|
|
|
|
/*===================================================================
|
|
CPropertyCollection::CPropertyCollection
|
|
|
|
Constructor
|
|
|
|
Parameters:
|
|
None
|
|
|
|
Returns:
|
|
Nothing
|
|
===================================================================*/
|
|
CPropertyCollection::CPropertyCollection() : m_pCSchemaTable(NULL),
|
|
m_tszKey(NULL)
|
|
{
|
|
}
|
|
|
|
/*===================================================================
|
|
CPropertyCollection::Init
|
|
|
|
Constructor
|
|
|
|
Parameters:
|
|
pIMeta ATL Smart pointer to the metabase
|
|
tszKey Name of key to enumerate properties of
|
|
|
|
Returns:
|
|
E_OUTOFMEMORY if allocation fails
|
|
S_OK on success
|
|
===================================================================*/
|
|
HRESULT CPropertyCollection::Init(const CComPtr<IMSAdminBase> &pIMeta,
|
|
CMetaSchemaTable *pCSchemaTable,
|
|
LPTSTR tszKey)
|
|
{
|
|
ASSERT(pIMeta.p != NULL);
|
|
ASSERT_NULL_OR_STRING(tszKey);
|
|
|
|
USES_CONVERSION;
|
|
HRESULT hr;
|
|
|
|
m_pIMeta = pIMeta;
|
|
m_pCSchemaTable = pCSchemaTable;
|
|
m_pCSchemaTable->AddRef();
|
|
|
|
// Copy tszKey to m_tszKey
|
|
if (tszKey == NULL) {
|
|
// Key is root
|
|
m_tszKey = NULL;
|
|
}
|
|
else {
|
|
// Allocate and copy the passed string to the member string
|
|
m_tszKey = new TCHAR[_tcslen(tszKey) + 1];
|
|
if (m_tszKey == NULL) {
|
|
return ::ReportError(E_OUTOFMEMORY);
|
|
}
|
|
_tcscpy(m_tszKey, tszKey);
|
|
CannonizeKey(m_tszKey);
|
|
|
|
// Make sure the key exists by opening and closing it
|
|
METADATA_HANDLE hMDKey;
|
|
|
|
hr = m_pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
|
|
T2W(m_tszKey),
|
|
METADATA_PERMISSION_READ,
|
|
MUTIL_OPEN_KEY_TIMEOUT,
|
|
&hMDKey);
|
|
if (FAILED(hr)) {
|
|
return ::ReportError(hr);
|
|
}
|
|
|
|
m_pIMeta->CloseKey(hMDKey);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CPropertyCollection::~CPropertyCollection
|
|
|
|
Destructor
|
|
|
|
Parameters:
|
|
None
|
|
|
|
Returns:
|
|
Nothing
|
|
===================================================================*/
|
|
CPropertyCollection::~CPropertyCollection()
|
|
{
|
|
m_pCSchemaTable->Release();
|
|
|
|
if (m_tszKey != NULL) {
|
|
delete m_tszKey;
|
|
}
|
|
}
|
|
|
|
/*===================================================================
|
|
CPropertyCollection::InterfaceSupportsErrorInfo
|
|
|
|
Standard ATL implementation
|
|
|
|
===================================================================*/
|
|
STDMETHODIMP CPropertyCollection::InterfaceSupportsErrorInfo(REFIID riid)
|
|
{
|
|
static const IID* arr[] =
|
|
{
|
|
&IID_IPropertyCollection,
|
|
};
|
|
|
|
for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
|
|
{
|
|
if (InlineIsEqualGUID(*arr[i],riid))
|
|
return S_OK;
|
|
}
|
|
return S_FALSE;
|
|
}
|
|
|
|
/*===================================================================
|
|
CPropertyCollection::get_Count
|
|
|
|
Get method for Count property. Counts the number of properties for
|
|
this key.
|
|
|
|
Parameters:
|
|
plReturn [out, retval] Value to return to client.
|
|
|
|
Returns:
|
|
E_INVALIDARG if plReturn == NULL
|
|
S_OK on success
|
|
|
|
Notes:
|
|
Actually counts all of the properties. Do not call in a loop!
|
|
===================================================================*/
|
|
STDMETHODIMP CPropertyCollection::get_Count(long * plReturn)
|
|
{
|
|
TRACE0("MetaUtil: CPropertyCollection::get_Count\n");
|
|
|
|
ASSERT_NULL_OR_POINTER(plReturn, long);
|
|
|
|
if (plReturn == NULL) {
|
|
return ::ReportError(E_INVALIDARG);
|
|
}
|
|
|
|
USES_CONVERSION;
|
|
HRESULT hr;
|
|
|
|
METADATA_RECORD mdr;
|
|
BYTE *pbData;
|
|
DWORD dwDataLen;
|
|
DWORD dwReqDataLen;
|
|
|
|
dwDataLen = 1024;
|
|
pbData = new BYTE[dwDataLen];
|
|
if (pbData == NULL) {
|
|
return ::ReportError(E_OUTOFMEMORY);
|
|
}
|
|
|
|
*plReturn = 0;
|
|
for(;;) { // FOREVER, will return out of loop
|
|
// Get a property
|
|
mdr.dwMDIdentifier = 0;
|
|
mdr.dwMDAttributes = 0;
|
|
mdr.dwMDUserType = ALL_METADATA;
|
|
mdr.dwMDDataType = ALL_METADATA;
|
|
mdr.pbMDData = pbData;
|
|
mdr.dwMDDataLen = dwDataLen;
|
|
mdr.dwMDDataTag = 0;
|
|
hr = m_pIMeta->EnumData(METADATA_MASTER_ROOT_HANDLE,
|
|
T2W(m_tszKey),
|
|
&mdr,
|
|
*plReturn,
|
|
&dwReqDataLen);
|
|
|
|
if (FAILED(hr)) {
|
|
if (HRESULT_CODE(hr) == ERROR_NO_MORE_ITEMS) {
|
|
// Done, cleanup and return the result
|
|
delete pbData;
|
|
return S_OK;
|
|
}
|
|
else if (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER) {
|
|
// Make a bigger buffer and try again
|
|
delete pbData;
|
|
dwDataLen = dwReqDataLen;
|
|
pbData = new BYTE[dwDataLen];
|
|
if (pbData == NULL) {
|
|
return ::ReportError(E_OUTOFMEMORY);
|
|
}
|
|
}
|
|
else {
|
|
delete pbData;
|
|
return ::ReportError(hr);
|
|
}
|
|
}
|
|
else { // SUCCEEDED(hr)
|
|
// Count it
|
|
(*plReturn)++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*===================================================================
|
|
CPropertyCollection::get_Item
|
|
|
|
Get method for Item property. Returns a key given its index.
|
|
|
|
Parameters:
|
|
varId [in] 1 based index or Name of the property to get
|
|
ppIReturn [out, retval] Interface for the property object
|
|
|
|
Returns:
|
|
E_INVALIDARG if ppIReturn == NULL or lIndex <= 0
|
|
E_OUTOFMEMORY if allocation fails
|
|
S_OK on success
|
|
===================================================================*/
|
|
STDMETHODIMP CPropertyCollection::get_Item(long lIndex,
|
|
LPDISPATCH * ppIReturn)
|
|
{
|
|
TRACE0("MetaUtil: CPropertyCollection::get_Item\n");
|
|
|
|
ASSERT_NULL_OR_POINTER(ppIReturn, LPDISPATCH);
|
|
|
|
if ((ppIReturn == NULL) || (lIndex <= 0)) {
|
|
return ::ReportError(E_INVALIDARG);
|
|
}
|
|
|
|
USES_CONVERSION;
|
|
HRESULT hr;
|
|
|
|
// Get the requested property
|
|
METADATA_RECORD mdr;
|
|
BYTE *pbData;
|
|
DWORD dwReqDataLen;
|
|
|
|
pbData = new BYTE[1024];
|
|
if (pbData == NULL) {
|
|
return ::ReportError(E_OUTOFMEMORY);
|
|
}
|
|
|
|
mdr.dwMDIdentifier = 0;
|
|
mdr.dwMDAttributes = 0;
|
|
mdr.dwMDUserType = ALL_METADATA;
|
|
mdr.dwMDDataType = ALL_METADATA;
|
|
mdr.pbMDData = pbData;
|
|
mdr.dwMDDataLen = 1024;
|
|
mdr.dwMDDataTag = 0;
|
|
hr = m_pIMeta->EnumData(METADATA_MASTER_ROOT_HANDLE,
|
|
T2W(m_tszKey),
|
|
&mdr,
|
|
lIndex - 1,
|
|
&dwReqDataLen);
|
|
|
|
// If the buffer was too small, try again with a bigger one
|
|
if (FAILED(hr) && (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER)) {
|
|
delete pbData;
|
|
pbData = new BYTE[dwReqDataLen];
|
|
if (pbData == NULL) {
|
|
return ::ReportError(hr);
|
|
}
|
|
|
|
mdr.dwMDIdentifier = 0;
|
|
mdr.dwMDAttributes = 0;
|
|
mdr.dwMDUserType = ALL_METADATA;
|
|
mdr.dwMDDataType = ALL_METADATA;
|
|
mdr.pbMDData = pbData;
|
|
mdr.dwMDDataLen = dwReqDataLen;
|
|
mdr.dwMDDataTag = 0;
|
|
|
|
hr = m_pIMeta->EnumData(METADATA_MASTER_ROOT_HANDLE,
|
|
T2W(m_tszKey),
|
|
&mdr,
|
|
lIndex - 1,
|
|
&dwReqDataLen);
|
|
}
|
|
|
|
// If we got it create a properties object
|
|
if (SUCCEEDED(hr)) {
|
|
// Create the property object
|
|
CComObject<CProperty> *pObj = NULL;
|
|
ATLTRY(pObj = new CComObject<CProperty>);
|
|
if (pObj == NULL) {
|
|
delete pbData;
|
|
return ::ReportError(E_OUTOFMEMORY);
|
|
}
|
|
hr = pObj->Init(m_pIMeta, m_pCSchemaTable, m_tszKey, &mdr);
|
|
if (FAILED(hr)) {
|
|
delete pbData;
|
|
return ::ReportError(hr);
|
|
}
|
|
|
|
// Set the interface to IDispatch
|
|
hr = pObj->QueryInterface(IID_IDispatch, (void **) ppIReturn);
|
|
if (FAILED(hr)) {
|
|
delete pbData;
|
|
return ::ReportError(hr);
|
|
}
|
|
ASSERT(*ppIReturn != NULL);
|
|
}
|
|
else { // FAILED(hr)
|
|
delete pbData;
|
|
return ::ReportError(hr);
|
|
}
|
|
|
|
delete pbData;
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CPropertyCollection::get__NewEnum
|
|
|
|
Get method for _NewEnum property. Returns an enumeration object for
|
|
the properties.
|
|
|
|
Parameters:
|
|
ppIReturn [out, retval] Interface for the enumeration object
|
|
|
|
Returns:
|
|
E_INVALIDARG if ppIReturn == NULL
|
|
E_OUTOFMEMORY if allocation failed
|
|
S_OK on success
|
|
===================================================================*/
|
|
STDMETHODIMP CPropertyCollection::get__NewEnum(LPUNKNOWN * ppIReturn)
|
|
{
|
|
TRACE0("MetaUtil: CPropertyCollection::get__NewEnum\n");
|
|
|
|
ASSERT_NULL_OR_POINTER(ppIReturn, LPUNKNOWN);
|
|
|
|
if (ppIReturn == NULL) {
|
|
return ::ReportError(E_INVALIDARG);
|
|
}
|
|
|
|
HRESULT hr;
|
|
|
|
// Create the property enumeration
|
|
CComObject<CPropertyEnum> *pObj = NULL;
|
|
ATLTRY(pObj = new CComObject<CPropertyEnum>);
|
|
if (pObj == NULL) {
|
|
return ::ReportError(E_OUTOFMEMORY);
|
|
}
|
|
hr = pObj->Init(m_pIMeta, m_pCSchemaTable, m_tszKey, 0);
|
|
if (FAILED(hr)) {
|
|
return ::ReportError(hr);
|
|
}
|
|
|
|
// Set the interface to IUnknown
|
|
hr = pObj->QueryInterface(IID_IUnknown, (void **) ppIReturn);
|
|
if (FAILED(hr)) {
|
|
return ::ReportError(hr);
|
|
}
|
|
ASSERT(*ppIReturn != NULL);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CPropertyCollection::Get
|
|
|
|
Get a property object from the base key of the collection.
|
|
|
|
Parameters:
|
|
varId [in] Identifier of property to get. Either the
|
|
Id (number) or Name (string).
|
|
ppIReturn [out, retval] Interface for the property object
|
|
|
|
Returns:
|
|
E_INVALIDARG if ppIReturn == NULL
|
|
S_OK on success
|
|
===================================================================*/
|
|
STDMETHODIMP CPropertyCollection::Get(VARIANT varId, IProperty **ppIReturn)
|
|
{
|
|
TRACE0("MetaUtil: CPropertyCollection::Get\n");
|
|
|
|
ASSERT_NULL_OR_POINTER(ppIReturn, IProperty *);
|
|
|
|
if (ppIReturn == NULL) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
return ::GetProperty(m_pIMeta, m_pCSchemaTable, m_tszKey, varId, ppIReturn);
|
|
}
|
|
|
|
/*===================================================================
|
|
CPropertyCollection::Add
|
|
|
|
Add a property object to the base key of the collection.
|
|
|
|
Parameters:
|
|
varId [in] Identifier of property to get. Either the
|
|
Id (number) or Name (string).
|
|
ppIReturn [out, retval] Interface for the property object
|
|
|
|
Returns:
|
|
E_INVALIDARG if ppIReturn == NULL
|
|
S_OK on success
|
|
===================================================================*/
|
|
STDMETHODIMP CPropertyCollection::Add(VARIANT varId, IProperty **ppIReturn)
|
|
{
|
|
TRACE0("MetaUtil: CPropertyCollection::Add\n");
|
|
|
|
ASSERT_NULL_OR_POINTER(ppIReturn, IProperty *);
|
|
|
|
if (ppIReturn == NULL) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
return ::CreateProperty(m_pIMeta, m_pCSchemaTable, m_tszKey, varId, ppIReturn);
|
|
}
|
|
|
|
/*===================================================================
|
|
CPropertyCollection::Remove
|
|
|
|
Remove a property from the base key of the collection.
|
|
|
|
Parameters:
|
|
varId [in] Identifier of property to remove. Either the
|
|
Id (number) or Name (string).
|
|
|
|
Returns:
|
|
S_OK on success
|
|
===================================================================*/
|
|
STDMETHODIMP CPropertyCollection::Remove(VARIANT varId)
|
|
{
|
|
TRACE0("MetaUtil: CPropertyCollection::Remove\n");
|
|
|
|
return ::DeleteProperty(m_pIMeta, m_pCSchemaTable, m_tszKey, varId);
|
|
}
|
|
|
|
|
|
/*------------------------------------------------------------------
|
|
* C P r o p e r t y E n u m
|
|
*/
|
|
|
|
/*===================================================================
|
|
CPropertyEnum::CPropertyEnum
|
|
|
|
Constructor
|
|
|
|
Parameters:
|
|
None
|
|
|
|
Returns:
|
|
Nothing
|
|
===================================================================*/
|
|
CPropertyEnum::CPropertyEnum() : m_pCSchemaTable(NULL),
|
|
m_tszKey(NULL),
|
|
m_iIndex(0)
|
|
{
|
|
}
|
|
|
|
/*===================================================================
|
|
CPropertyEnum::Init
|
|
|
|
Constructor
|
|
|
|
Parameters:
|
|
pIMeta ATL Smart pointer to the metabase
|
|
tszKey Name of key to enumerate properties of
|
|
iIndex Index of next element in enumeration
|
|
|
|
Returns:
|
|
E_OUTOFMEMORY if allocation fails
|
|
S_OK on success
|
|
===================================================================*/
|
|
HRESULT CPropertyEnum::Init(const CComPtr<IMSAdminBase> &pIMeta,
|
|
CMetaSchemaTable *pCSchemaTable,
|
|
LPCTSTR tszKey,
|
|
int iIndex)
|
|
{
|
|
ASSERT(pIMeta.p != NULL);
|
|
ASSERT_NULL_OR_STRING(tszKey);
|
|
ASSERT(iIndex >= 0);
|
|
|
|
m_pIMeta = pIMeta;
|
|
m_pCSchemaTable = pCSchemaTable;
|
|
m_pCSchemaTable->AddRef();
|
|
|
|
// Copy m_tszKey
|
|
if (tszKey == NULL) {
|
|
// Key is root
|
|
m_tszKey = NULL;
|
|
}
|
|
else {
|
|
// Allocate and copy the passed string to the member string
|
|
m_tszKey = new TCHAR[_tcslen(tszKey) + 1];
|
|
if (m_tszKey == NULL) {
|
|
return ::ReportError(E_OUTOFMEMORY);
|
|
}
|
|
_tcscpy(m_tszKey, tszKey);
|
|
CannonizeKey(m_tszKey);
|
|
}
|
|
|
|
m_iIndex = iIndex;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CPropertyEnum::~CPropertyEnum
|
|
|
|
Destructor
|
|
|
|
Parameters:
|
|
None
|
|
|
|
Returns:
|
|
Nothing
|
|
===================================================================*/
|
|
CPropertyEnum::~CPropertyEnum()
|
|
{
|
|
m_pCSchemaTable->Release();
|
|
|
|
if (m_tszKey != NULL) {
|
|
delete m_tszKey;
|
|
}
|
|
}
|
|
|
|
/*===================================================================
|
|
CPropertyEnum::Next
|
|
|
|
Gets the next n items from the enumberation.
|
|
|
|
Parameters:
|
|
ulNumToGet [in] Number of elements to get
|
|
rgvarDest [out] Array to put them in
|
|
pulNumGot [out] If not NULL, number of elements rgvarDest got
|
|
|
|
Returns:
|
|
E_INVALIDARG if rgvarDest == NULL
|
|
E_OUTOFMEMORY if allocation failed
|
|
S_OK if outputs ulNumToGet items
|
|
S_FALSE if outputs less than ulNumToGet items
|
|
===================================================================*/
|
|
STDMETHODIMP CPropertyEnum::Next(unsigned long ulNumToGet,
|
|
VARIANT FAR* rgvarDest,
|
|
unsigned long FAR* pulNumGot)
|
|
{
|
|
TRACE0("MetaUtil: CPropertyEnum::Next\n");
|
|
|
|
ASSERT_NULL_OR_POINTER(pulNumGot, unsigned long);
|
|
// Make sure the array is big enough and we can write to it
|
|
ASSERT((rgvarDest == NULL) || IsValidAddress(rgvarDest, ulNumToGet * sizeof(VARIANT), TRUE));
|
|
|
|
if (rgvarDest == NULL) {
|
|
return ::ReportError(E_INVALIDARG);
|
|
}
|
|
|
|
USES_CONVERSION;
|
|
HRESULT hr;
|
|
|
|
METADATA_RECORD mdr;
|
|
BYTE *pbData;
|
|
DWORD dwDataLen;
|
|
DWORD dwReqDataLen;
|
|
unsigned int uiDestIndex;
|
|
IDispatch *pIDispatch;
|
|
|
|
dwDataLen = 1024;
|
|
pbData = new BYTE[dwDataLen];
|
|
if (pbData == NULL) {
|
|
return ::ReportError(E_OUTOFMEMORY);
|
|
}
|
|
|
|
// For each property to get
|
|
uiDestIndex = 0;
|
|
while (uiDestIndex < ulNumToGet) {
|
|
// Get a property
|
|
mdr.dwMDIdentifier = 0;
|
|
mdr.dwMDAttributes = 0;
|
|
mdr.dwMDUserType = ALL_METADATA;
|
|
mdr.dwMDDataType = ALL_METADATA;
|
|
mdr.pbMDData = pbData;
|
|
mdr.dwMDDataLen = dwDataLen;
|
|
mdr.dwMDDataTag = 0;
|
|
hr = m_pIMeta->EnumData(METADATA_MASTER_ROOT_HANDLE,
|
|
T2W(m_tszKey),
|
|
&mdr,
|
|
m_iIndex,
|
|
&dwReqDataLen);
|
|
|
|
if (FAILED(hr)) {
|
|
if (HRESULT_CODE(hr) == ERROR_NO_MORE_ITEMS) {
|
|
// Done, cleanup and return the result
|
|
if (pulNumGot != NULL) {
|
|
*pulNumGot = uiDestIndex;
|
|
}
|
|
delete pbData;
|
|
return S_FALSE;
|
|
}
|
|
else if (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER) {
|
|
// Try again with a bigger buffer
|
|
delete pbData;
|
|
dwDataLen = dwReqDataLen;
|
|
pbData = new BYTE[dwDataLen];
|
|
if (pbData == NULL) {
|
|
return ::ReportError(E_OUTOFMEMORY);
|
|
}
|
|
}
|
|
else {
|
|
delete pbData;
|
|
return ::ReportError(hr);
|
|
}
|
|
}
|
|
else { // SUCCEEDED(hr)
|
|
// Create the property object
|
|
CComObject<CProperty> *pObj = NULL;
|
|
ATLTRY(pObj = new CComObject<CProperty>);
|
|
if (pObj == NULL) {
|
|
delete pbData;
|
|
return ::ReportError(E_OUTOFMEMORY);
|
|
}
|
|
hr = pObj->Init(m_pIMeta, m_pCSchemaTable, m_tszKey, &mdr);
|
|
if (FAILED(hr)) {
|
|
delete pbData;
|
|
return ::ReportError(hr);
|
|
}
|
|
|
|
// Set the interface to IDispatch
|
|
hr = pObj->QueryInterface(IID_IDispatch, (void **) &pIDispatch);
|
|
if (FAILED(hr)) {
|
|
delete pbData;
|
|
return ::ReportError(hr);
|
|
}
|
|
ASSERT(pIDispatch != NULL);
|
|
|
|
// Put it in the output array
|
|
VariantInit(&(rgvarDest[uiDestIndex]));
|
|
rgvarDest[uiDestIndex].vt = VT_DISPATCH;
|
|
rgvarDest[uiDestIndex].pdispVal = pIDispatch;
|
|
|
|
// Next element
|
|
m_iIndex++;
|
|
uiDestIndex++;
|
|
}
|
|
}
|
|
|
|
delete pbData;
|
|
|
|
if (pulNumGot != NULL) {
|
|
*pulNumGot = uiDestIndex;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CPropertyEnum::Skip
|
|
|
|
Skips the next n items in an enumeration
|
|
|
|
Parameters:
|
|
ulNumToSkip [in] Number of elements to skip
|
|
|
|
Returns:
|
|
S_OK always
|
|
===================================================================*/
|
|
STDMETHODIMP CPropertyEnum::Skip(unsigned long ulNumToSkip)
|
|
{
|
|
TRACE0("MetaUtil: CPropertyEnum::Skip\n");
|
|
|
|
m_iIndex += ulNumToSkip;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CPropertyEnum::Reset
|
|
|
|
Rests the enumeration to the first item
|
|
|
|
Parameters:
|
|
None
|
|
|
|
Returns:
|
|
S_OK always
|
|
===================================================================*/
|
|
STDMETHODIMP CPropertyEnum::Reset()
|
|
{
|
|
TRACE0("MetaUtil: CPropertyEnum::Reset\n");
|
|
|
|
m_iIndex = 0;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CPropertyEnum::Clone
|
|
|
|
Gets an interface pointer to a copy of the enumeration at its
|
|
current state.
|
|
|
|
Parameters:
|
|
ppIReturn [out] Pointer to interface for copy
|
|
|
|
Returns:
|
|
E_INVALIDARG if ppIReturn == NULL
|
|
E_OUTOFMEMORY if not enough memory to create clone
|
|
S_OK on success
|
|
===================================================================*/
|
|
STDMETHODIMP CPropertyEnum::Clone(IEnumVARIANT FAR* FAR* ppIReturn)
|
|
{
|
|
TRACE0("MetaUtil: CPropertyEnum::Clone\n");
|
|
|
|
ASSERT_NULL_OR_POINTER(ppIReturn, LPUNKNOWN);
|
|
|
|
if (ppIReturn == NULL) {
|
|
return ::ReportError(E_INVALIDARG);
|
|
}
|
|
|
|
HRESULT hr;
|
|
|
|
// Create a copy of the enumeration
|
|
CComObject<CPropertyEnum> *pObj = NULL;
|
|
ATLTRY(pObj = new CComObject<CPropertyEnum>);
|
|
if (pObj == NULL) {
|
|
return ::ReportError(E_OUTOFMEMORY);
|
|
}
|
|
hr = pObj->Init(m_pIMeta, m_pCSchemaTable, m_tszKey, m_iIndex);
|
|
if (FAILED(hr)) {
|
|
return ::ReportError(hr);
|
|
}
|
|
|
|
// Set the interface to IEnumVARIANT
|
|
hr = pObj->QueryInterface(IID_IEnumVARIANT, (void **) ppIReturn);
|
|
if (FAILED(hr)) {
|
|
return ::ReportError(hr);
|
|
}
|
|
ASSERT(*ppIReturn != NULL);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
/*------------------------------------------------------------------
|
|
* C P r o p e r t y
|
|
*/
|
|
|
|
/*===================================================================
|
|
CProperty::CProperty
|
|
|
|
Constructor
|
|
|
|
Parameters:
|
|
None
|
|
|
|
Returns:
|
|
Nothing
|
|
===================================================================*/
|
|
CProperty::CProperty() : m_pCSchemaTable(NULL),
|
|
m_tszKey(NULL),
|
|
m_dwId(0),
|
|
m_dwAttributes(0),
|
|
m_dwUserType(0),
|
|
m_dwDataType(0)
|
|
{
|
|
VariantInit(&m_varData);
|
|
}
|
|
|
|
/*===================================================================
|
|
CProperty::Init
|
|
|
|
Constructor
|
|
|
|
Parameters:
|
|
tszKey Name of key where the property is located
|
|
dwId Id of property
|
|
bCreate TRUE if this property can be created (does not have to exist)
|
|
|
|
Returns:
|
|
E_OUTOFMEMORY if allocation fails
|
|
S_OK on success
|
|
===================================================================*/
|
|
HRESULT CProperty::Init(const CComPtr<IMSAdminBase> &pIMeta,
|
|
CMetaSchemaTable *pCSchemaTable,
|
|
LPCTSTR tszKey,
|
|
DWORD dwId,
|
|
BOOL bCreate)
|
|
{
|
|
ASSERT(pIMeta.p != NULL);
|
|
ASSERT_NULL_OR_STRING(tszKey);
|
|
|
|
USES_CONVERSION;
|
|
HRESULT hr;
|
|
|
|
m_pIMeta = pIMeta;
|
|
m_pCSchemaTable = pCSchemaTable;
|
|
m_pCSchemaTable->AddRef();
|
|
|
|
// Set the Key and Id members
|
|
if (tszKey == NULL) {
|
|
m_tszKey = NULL;
|
|
}
|
|
else {
|
|
m_tszKey = new TCHAR[_tcslen(tszKey) + 1];
|
|
if (m_tszKey == NULL) {
|
|
return ::ReportError(E_OUTOFMEMORY);
|
|
}
|
|
_tcscpy(m_tszKey, tszKey);
|
|
CannonizeKey(m_tszKey);
|
|
}
|
|
|
|
m_dwId = dwId;
|
|
|
|
// Open the key (to be sure it exists)
|
|
METADATA_HANDLE hMDKey;
|
|
|
|
hr = m_pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
|
|
T2W(m_tszKey),
|
|
METADATA_PERMISSION_READ,
|
|
MUTIL_OPEN_KEY_TIMEOUT,
|
|
&hMDKey);
|
|
if (FAILED(hr)) {
|
|
return ::ReportError(hr);
|
|
}
|
|
|
|
// Get the property
|
|
METADATA_RECORD mdr;
|
|
BYTE *pbData;
|
|
DWORD dwReqLen;
|
|
|
|
pbData = new BYTE[1024];
|
|
if (pbData == NULL) {
|
|
m_pIMeta->CloseKey(hMDKey);
|
|
return ::ReportError(hr);
|
|
}
|
|
|
|
mdr.dwMDIdentifier = m_dwId;
|
|
mdr.dwMDAttributes = 0;
|
|
mdr.dwMDUserType = ALL_METADATA;
|
|
mdr.dwMDDataType = ALL_METADATA;
|
|
mdr.pbMDData = pbData;
|
|
mdr.dwMDDataLen = 1024;
|
|
mdr.dwMDDataTag = 0;
|
|
|
|
hr = m_pIMeta->GetData(hMDKey,
|
|
NULL,
|
|
&mdr,
|
|
&dwReqLen);
|
|
|
|
// If the buffer was too small, try again with a bigger one
|
|
if (FAILED(hr) && (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER)) {
|
|
delete pbData;
|
|
pbData = new BYTE[dwReqLen];
|
|
if (pbData == NULL) {
|
|
m_pIMeta->CloseKey(hMDKey);
|
|
return ::ReportError(hr);
|
|
}
|
|
|
|
mdr.dwMDIdentifier = m_dwId;
|
|
mdr.dwMDAttributes = 0;
|
|
mdr.dwMDUserType = ALL_METADATA;
|
|
mdr.dwMDDataType = ALL_METADATA;
|
|
mdr.pbMDData = pbData;
|
|
mdr.dwMDDataLen = dwReqLen;
|
|
mdr.dwMDDataTag = 0;
|
|
|
|
hr = m_pIMeta->GetData(hMDKey,
|
|
NULL,
|
|
&mdr,
|
|
&dwReqLen);
|
|
}
|
|
|
|
// If we got it fill in the fields
|
|
if (SUCCEEDED(hr)) {
|
|
m_dwAttributes = mdr.dwMDAttributes;
|
|
m_dwUserType = mdr.dwMDUserType;
|
|
m_dwDataType = mdr.dwMDDataType;
|
|
SetDataToVar(mdr.pbMDData, mdr.dwMDDataLen);
|
|
}
|
|
// If the property doesn't exist and we're creating, set defaults
|
|
else if ((bCreate) && (hr == MD_ERROR_DATA_NOT_FOUND)) {
|
|
m_dwAttributes = 0;
|
|
m_dwUserType = 0;
|
|
m_dwDataType = 0;
|
|
VariantClear(&m_varData);
|
|
}
|
|
else { //(FAILED(hr))
|
|
delete pbData;
|
|
m_pIMeta->CloseKey(hMDKey);
|
|
return ::ReportError(hr);
|
|
}
|
|
|
|
delete pbData;
|
|
|
|
// Close the key
|
|
m_pIMeta->CloseKey(hMDKey);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CProperty::Init
|
|
|
|
Constructor
|
|
|
|
Parameters:
|
|
tszKey Name of key where property is located
|
|
mdr METADATA_RECORD containing the current property info
|
|
|
|
Returns:
|
|
E_OUTOFMEMORY if allocation fails
|
|
S_OK on success
|
|
===================================================================*/
|
|
HRESULT CProperty::Init(const CComPtr<IMSAdminBase> &pIMeta,
|
|
CMetaSchemaTable *pCSchemaTable,
|
|
LPCTSTR tszKey,
|
|
METADATA_RECORD *mdr)
|
|
{
|
|
ASSERT(pIMeta.p != NULL);
|
|
ASSERT_NULL_OR_STRING(tszKey);
|
|
|
|
HRESULT hr;
|
|
|
|
m_pIMeta = pIMeta;
|
|
m_pCSchemaTable = pCSchemaTable;
|
|
m_pCSchemaTable->AddRef();
|
|
|
|
// Set the Key member
|
|
if (tszKey == NULL) {
|
|
m_tszKey = NULL;
|
|
}
|
|
else {
|
|
m_tszKey = new TCHAR[_tcslen(tszKey) + 1];
|
|
if (m_tszKey == NULL) {
|
|
return ::ReportError(E_OUTOFMEMORY);
|
|
}
|
|
_tcscpy(m_tszKey, tszKey);
|
|
}
|
|
|
|
// Use mdr to set the rest
|
|
m_dwId = mdr->dwMDIdentifier;
|
|
m_dwAttributes = mdr->dwMDAttributes;
|
|
m_dwUserType = mdr->dwMDUserType;
|
|
m_dwDataType = mdr->dwMDDataType;
|
|
hr = SetDataToVar(mdr->pbMDData, mdr->dwMDDataLen);
|
|
if (FAILED(hr)) {
|
|
::ReportError(hr);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CProperty::~CProperty
|
|
|
|
Destructor
|
|
|
|
Parameters:
|
|
None
|
|
|
|
Returns:
|
|
Nothing
|
|
===================================================================*/
|
|
CProperty::~CProperty()
|
|
{
|
|
m_pCSchemaTable->Release();
|
|
|
|
if (m_tszKey != NULL) {
|
|
delete m_tszKey;
|
|
}
|
|
|
|
VariantClear(&m_varData);
|
|
}
|
|
|
|
/*===================================================================
|
|
CProperty::InterfaceSupportsErrorInfo
|
|
|
|
Standard ATL implementation
|
|
|
|
===================================================================*/
|
|
STDMETHODIMP CProperty::InterfaceSupportsErrorInfo(REFIID riid)
|
|
{
|
|
static const IID* arr[] =
|
|
{
|
|
&IID_IProperty,
|
|
};
|
|
|
|
for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
|
|
{
|
|
if (InlineIsEqualGUID(*arr[i],riid))
|
|
return S_OK;
|
|
}
|
|
return S_FALSE;
|
|
}
|
|
|
|
/*===================================================================
|
|
CProperty::get_Id
|
|
|
|
Get method for Id property. Identifier for this metabase property.
|
|
|
|
Parameters:
|
|
plId [out, retval] Value to return to client.
|
|
|
|
Returns:
|
|
E_INVALIDARG if pulId == NULL
|
|
S_OK on success
|
|
===================================================================*/
|
|
STDMETHODIMP CProperty::get_Id(long *plId)
|
|
{
|
|
//TRACE0("MetaUtil: CProperty::get_Id\n");
|
|
ASSERT_NULL_OR_POINTER(plId, long);
|
|
|
|
if (plId == NULL) {
|
|
return ::ReportError(E_INVALIDARG);
|
|
}
|
|
|
|
*plId = (long) m_dwId;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CProperty::get_Name
|
|
|
|
Get method for Name property. Name of this metabase property.
|
|
|
|
Parameters:
|
|
pbstrName [out, retval] Value to return to client. If property
|
|
has no name "" is returned
|
|
|
|
Returns:
|
|
E_INVALIDARG if pbstrName == NULL
|
|
S_OK on success
|
|
===================================================================*/
|
|
STDMETHODIMP CProperty::get_Name(BSTR *pbstrName)
|
|
{
|
|
TRACE0("MetaUtil: CProperty::get_Name\n");
|
|
ASSERT_NULL_OR_POINTER(pbstrName, BSTR);
|
|
|
|
if (pbstrName == NULL) {
|
|
return ::ReportError(E_INVALIDARG);
|
|
}
|
|
|
|
CPropInfo *pCPropInfo;
|
|
|
|
// Get the property info from the Schema Table
|
|
pCPropInfo = m_pCSchemaTable->GetPropInfo(m_tszKey, m_dwId);
|
|
|
|
// Did we find it? Is there a name entry
|
|
if ((pCPropInfo == NULL) || (pCPropInfo->GetName() == NULL)) {
|
|
// No, return ""
|
|
*pbstrName = T2BSTR(_T(""));
|
|
}
|
|
else {
|
|
// Yes, return the name
|
|
*pbstrName = T2BSTR(pCPropInfo->GetName());
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CProperty::get_Attributes
|
|
|
|
Get method for Attributes property. Gets the attribute flags for
|
|
this property.
|
|
|
|
Parameters:
|
|
plAttributes [out, retval] Value to return to client.
|
|
|
|
Returns:
|
|
E_INVALIDARG if pulAttributes == NULL
|
|
S_OK on success
|
|
===================================================================*/
|
|
STDMETHODIMP CProperty::get_Attributes(long *plAttributes)
|
|
{
|
|
//TRACE0("MetaUtil: CProperty::get_Attributes\n");
|
|
ASSERT_NULL_OR_POINTER(plAttributes, long);
|
|
|
|
if (plAttributes == NULL) {
|
|
return ::ReportError(E_INVALIDARG);
|
|
}
|
|
|
|
*plAttributes = (long) m_dwAttributes;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CProperty::put_Attributes
|
|
|
|
Put method for Attributes property. Sets the attribute flags for
|
|
this property.
|
|
|
|
Parameters:
|
|
lAttributes [in] New value for attributes.
|
|
|
|
Returns:
|
|
S_OK always
|
|
===================================================================*/
|
|
STDMETHODIMP CProperty::put_Attributes(long lAttributes)
|
|
{
|
|
TRACE0("MetaUtil: CProperty::put_Attributes\n");
|
|
|
|
m_dwAttributes = (DWORD) lAttributes;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CProperty::get_UserType
|
|
|
|
Get method for UserType property. Gets the User Type for this
|
|
metabase property.
|
|
|
|
Parameters:
|
|
plUserType [out, retval] Value to return to client.
|
|
|
|
Returns:
|
|
E_INVALIDARG if pulUserType == NULL
|
|
S_OK on success
|
|
===================================================================*/
|
|
STDMETHODIMP CProperty::get_UserType(long *plUserType)
|
|
{
|
|
//TRACE0("MetaUtil: CProperty::get_UserType\n");
|
|
ASSERT_NULL_OR_POINTER(plUserType, long);
|
|
|
|
if (plUserType == NULL) {
|
|
return ::ReportError(E_INVALIDARG);
|
|
}
|
|
|
|
*plUserType = (long) m_dwUserType;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CProperty::put_UserType
|
|
|
|
Put method for UserType property. Sets the user type
|
|
|
|
Parameters:
|
|
lUserType [in] New value for user type.
|
|
|
|
Returns:
|
|
S_OK always
|
|
===================================================================*/
|
|
STDMETHODIMP CProperty::put_UserType(long lUserType)
|
|
{
|
|
TRACE0("MetaUtil: CProperty::put_UserType\n");
|
|
|
|
m_dwUserType = (DWORD) lUserType;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CProperty::get_DataType
|
|
|
|
Get method for DataType property. Gets the type of data stored in
|
|
the metabase property.
|
|
|
|
Parameters:
|
|
plDataType [out, retval] Value to return to client.
|
|
|
|
Returns:
|
|
E_INVALIDARG if pulDataType == NULL
|
|
S_OK on success
|
|
===================================================================*/
|
|
STDMETHODIMP CProperty::get_DataType(long *plDataType)
|
|
{
|
|
//TRACE0("MetaUtil: CProperty::get_DataType\n");
|
|
ASSERT_NULL_OR_POINTER(plDataType, long);
|
|
|
|
if (plDataType == NULL) {
|
|
return ::ReportError(E_INVALIDARG);
|
|
}
|
|
|
|
*plDataType = (long) m_dwDataType;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CProperty::put_DataType
|
|
|
|
Put method for DataType property. Sets the data type
|
|
|
|
Parameters:
|
|
lDataType [in] New value for data type.
|
|
|
|
Returns:
|
|
S_OK always
|
|
===================================================================*/
|
|
STDMETHODIMP CProperty::put_DataType(long lDataType)
|
|
{
|
|
TRACE0("MetaUtil: CProperty::put_DataType\n");
|
|
|
|
m_dwDataType = (DWORD) lDataType;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CProperty::get_Data
|
|
|
|
Get method for Data property. Gets the data for this metabase
|
|
property.
|
|
|
|
Parameters:
|
|
pvarData [out, retval] Value to return to client.
|
|
|
|
Returns:
|
|
E_INVALIDARG if pvarData == NULL
|
|
S_OK on success
|
|
===================================================================*/
|
|
STDMETHODIMP CProperty::get_Data(VARIANT *pvarData)
|
|
{
|
|
//TRACE0("MetaUtil: CProperty::get_Data\n");
|
|
ASSERT_NULL_OR_POINTER(pvarData, VARIANT);
|
|
|
|
if (pvarData == NULL) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
HRESULT hr;
|
|
|
|
hr = VariantCopy(pvarData, &m_varData);
|
|
if (FAILED(hr)) {
|
|
return ::ReportError(hr);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CProperty::put_Data
|
|
|
|
Put method for Data property. Sets the data
|
|
|
|
Parameters:
|
|
varData [in] New value for data
|
|
===================================================================*/
|
|
STDMETHODIMP CProperty::put_Data(VARIANT varData)
|
|
{
|
|
TRACE0("MetaUtil: CProperty::put_Data\n");
|
|
|
|
HRESULT hr;
|
|
|
|
hr = VariantCopy(&m_varData, &varData);
|
|
if (FAILED(hr)) {
|
|
return ::ReportError(hr);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CProperty::Write
|
|
|
|
Writes changes made to this object to the metabase
|
|
|
|
Parameters:
|
|
None
|
|
|
|
Returns:
|
|
S_OK on success
|
|
===================================================================*/
|
|
STDMETHODIMP CProperty::Write()
|
|
{
|
|
USES_CONVERSION;
|
|
|
|
TRACE0("MetaUtil: CProperty::Write\n");
|
|
|
|
HRESULT hr;
|
|
|
|
// Open the key for write access
|
|
METADATA_HANDLE hMDKey;
|
|
|
|
hr = m_pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
|
|
T2W(m_tszKey),
|
|
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
|
|
MUTIL_OPEN_KEY_TIMEOUT,
|
|
&hMDKey);
|
|
if (FAILED(hr)) {
|
|
return ::ReportError(hr);
|
|
}
|
|
|
|
// Create the data record
|
|
METADATA_RECORD mdr;
|
|
|
|
mdr.dwMDIdentifier = m_dwId;
|
|
mdr.dwMDAttributes = m_dwAttributes;
|
|
mdr.dwMDUserType = m_dwUserType;
|
|
mdr.dwMDDataType = m_dwDataType;
|
|
hr = GetDataFromVar(mdr.pbMDData, mdr.dwMDDataLen);
|
|
if (FAILED(hr)) {
|
|
m_pIMeta->CloseKey(hMDKey);
|
|
return ::ReportError(hr);
|
|
}
|
|
mdr.dwMDDataTag = 0;
|
|
|
|
// Set the data
|
|
hr = m_pIMeta->SetData(hMDKey,
|
|
L"",
|
|
&mdr);
|
|
if (FAILED(hr)) {
|
|
m_pIMeta->CloseKey(hMDKey);
|
|
delete mdr.pbMDData;
|
|
return ::ReportError(hr);
|
|
}
|
|
|
|
// Close the key
|
|
m_pIMeta->CloseKey(hMDKey);
|
|
delete mdr.pbMDData;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CProperty::SetDataToVar
|
|
|
|
Private function to save property data from its raw form to the
|
|
variant data member.
|
|
|
|
Parameters:
|
|
pbData Raw property data to convert to variant
|
|
dwDataLen Length of property data
|
|
|
|
Returns:
|
|
ERROR_INVALID_DATA if m_dwDataType is not recognized
|
|
E_OUTOFMEMORY if allocation failed
|
|
S_OK on success
|
|
===================================================================*/
|
|
HRESULT CProperty::SetDataToVar(BYTE *pbData, DWORD dwDataLen)
|
|
{
|
|
ASSERT((pbData == NULL) || IsValidAddress(pbData, dwDataLen, FALSE));
|
|
|
|
HRESULT hr;
|
|
|
|
hr = VariantClear(&m_varData);
|
|
if (FAILED(hr)) {
|
|
return ::ReportError(hr);
|
|
}
|
|
|
|
switch(m_dwDataType) {
|
|
|
|
case DWORD_METADATA:
|
|
// I4 subtype
|
|
V_VT(&m_varData) = VT_I4;
|
|
V_I4(&m_varData) = *(reinterpret_cast<long *> (pbData));
|
|
break;
|
|
|
|
case STRING_METADATA:
|
|
case EXPANDSZ_METADATA:
|
|
// BSTR subtype
|
|
V_VT(&m_varData) = VT_BSTR;
|
|
V_BSTR(&m_varData) = W2BSTR(reinterpret_cast<LPCWSTR> (pbData));
|
|
break;
|
|
|
|
case MULTISZ_METADATA: {
|
|
ULONG cStrings = 0;
|
|
// Metabase string are Unicode
|
|
LPCWSTR pwsz = reinterpret_cast<LPCWSTR> (pbData);
|
|
LPCWSTR pwszEnd = reinterpret_cast<LPCWSTR> (pbData + dwDataLen);
|
|
|
|
// Data is a series of null-terminated strings terminated by two nulls.
|
|
// Figure out how many values we have
|
|
while ((*pwsz != L'\0') && (pwsz < pwszEnd))
|
|
{
|
|
cStrings++;
|
|
pwsz += wcslen(pwsz) + 1; // skip string and trailing \0
|
|
}
|
|
|
|
// Create a SAFEARRAY to hold the return result. The array
|
|
// has to be of VARIANTs, not BSTRs, as you might expect, because
|
|
// VBScript will not accept an array of BSTRs (although VB5 will).
|
|
SAFEARRAYBOUND rgsabound[1] = {{cStrings, 0L}};
|
|
SAFEARRAY* psa = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
|
|
|
|
if (psa == NULL)
|
|
return ::ReportError(E_OUTOFMEMORY);
|
|
|
|
// now stuff the values into the array
|
|
LONG i = 0;
|
|
pwsz = reinterpret_cast<LPCWSTR> (pbData);
|
|
|
|
while ((*pwsz != L'\0') && (pwsz < pwszEnd))
|
|
{
|
|
// Stuff the string into a BSTR VARIANT
|
|
CComVariant vt = W2BSTR(pwsz);
|
|
ASSERT(V_VT(&vt) == VT_BSTR);
|
|
HRESULT hr = SafeArrayPutElement(psa, &i, (void*) &vt);
|
|
if (FAILED(hr))
|
|
::ReportError(hr);
|
|
i++;
|
|
pwsz += wcslen(pwsz) + 1; // skip string and trailing \0
|
|
}
|
|
|
|
V_VT(&m_varData) = VT_ARRAY | VT_VARIANT;
|
|
V_ARRAY(&m_varData) = psa;
|
|
|
|
break;
|
|
}
|
|
|
|
case BINARY_METADATA:
|
|
// BSTR of byte data subtype
|
|
V_VT(&m_varData) = VT_BSTR;
|
|
V_BSTR(&m_varData) = SysAllocStringByteLen((char *) pbData, dwDataLen);
|
|
break;
|
|
|
|
default:
|
|
// Unknown data type
|
|
return ::ReportError(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*===================================================================
|
|
CProperty::GetDataFromVar
|
|
|
|
Private function to get data from the variant data member to its
|
|
raw form.
|
|
|
|
Supported SubTypes:
|
|
|
|
DWORD_METADATA:
|
|
I1, I2, I4, I8, UI1, UI2, UI4, UI8
|
|
|
|
STRING_METADATA and EXPANDSZ_METADATA:
|
|
BSTR
|
|
|
|
MULTISZ_METADATA
|
|
VT_ARRAY | VT_VARIANT (1 Dimension, stops on NULL or EMPTY)
|
|
VT_ARRAY | VT_BSTR (1 Dimension)
|
|
|
|
BINARY_METADATA
|
|
BSTR
|
|
|
|
Parameters:
|
|
pbData Pointer to output buffer (allocated by this function)
|
|
dwDataLen Length of data in output buffer
|
|
|
|
Returns:
|
|
ERROR_INVALID_DATA if m_dwDataType is not recognized or does not
|
|
match the expected variant subtype.
|
|
E_OUTOFMEMORY on allocation failure
|
|
S_OK on succes
|
|
|
|
Notes:
|
|
Case statements are used for each dwMDDataType value to facilitate
|
|
adding support for additional VariantSubType to Data conversions.
|
|
|
|
MULTISZ_METADATA with VT_ARRAY | VT_VARIANT stops at a NULL or
|
|
EMPTY entry because it is easy to allocate an array one bigger
|
|
than you need in VBScript. Instead of erroring in this case, I
|
|
stop when I hit such an entry. This also allows a larger array
|
|
to be allocated that is terminated by NULL or EMPTY.
|
|
===================================================================*/
|
|
HRESULT CProperty::GetDataFromVar(BYTE * &pbData, DWORD &dwDataLen)
|
|
{
|
|
USES_CONVERSION;
|
|
HRESULT hr;
|
|
|
|
// Cleanup any IDispatch or byref stuff
|
|
CComVariant varData;
|
|
|
|
hr = VariantResolveDispatch(&m_varData, &varData);
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
switch(m_dwDataType) {
|
|
|
|
case DWORD_METADATA:
|
|
// I4 subtype
|
|
|
|
switch (V_VT(&varData)) {
|
|
|
|
case VT_I1: case VT_I2: case VT_I4: case VT_I8:
|
|
case VT_UI1: case VT_UI2: case VT_UI8:
|
|
|
|
// Coerce all integral types to VT_UI4, which is the same as DWORD_METADATA
|
|
if (FAILED(hr = VariantChangeType(&varData, &varData, 0, VT_UI4)))
|
|
return ::ReportError(hr);
|
|
|
|
// fallthru to VT_UI4
|
|
|
|
case VT_UI4:
|
|
|
|
dwDataLen = sizeof(DWORD);
|
|
pbData = reinterpret_cast<BYTE *> (new DWORD);
|
|
if (pbData == NULL) {
|
|
return ::ReportError(E_OUTOFMEMORY);
|
|
}
|
|
|
|
*(reinterpret_cast<DWORD *> (pbData)) = V_UI4(&varData);
|
|
break;
|
|
|
|
default:
|
|
// Unexpected data type
|
|
return ::ReportError(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
break;
|
|
|
|
case STRING_METADATA:
|
|
case EXPANDSZ_METADATA:
|
|
// BSTR subtype
|
|
|
|
switch (V_VT(&varData)) {
|
|
|
|
case VT_BSTR:
|
|
// Ignores the length field, terminate at the first NULL
|
|
dwDataLen = (wcslen(OLE2W(V_BSTR(&varData))) + 1) * sizeof(wchar_t);
|
|
|
|
pbData = new BYTE[dwDataLen];
|
|
if( pbData == NULL )
|
|
{
|
|
return ::ReportError(E_OUTOFMEMORY);
|
|
}
|
|
memcpy(pbData, OLE2W(V_BSTR(&varData)), dwDataLen);
|
|
|
|
default:
|
|
// Unexpected data type
|
|
return ::ReportError(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
break;
|
|
|
|
case MULTISZ_METADATA:
|
|
// ARRAY of BSTR subtype
|
|
|
|
// if it's a 1 Dimentional Array subtype
|
|
if (((V_VT(&varData) & VT_ARRAY) == VT_ARRAY) &&
|
|
(SafeArrayGetDim(V_ARRAY(&varData)) == 1) ) {
|
|
|
|
// Get Array Bounds
|
|
long lLBound;
|
|
long lUBound;
|
|
long lNumElements;
|
|
hr = SafeArrayGetLBound(V_ARRAY(&varData), 1, &lLBound);
|
|
if (FAILED(hr)) {
|
|
return ::ReportError(hr);
|
|
}
|
|
hr = SafeArrayGetUBound(V_ARRAY(&varData), 1, &lUBound);
|
|
if (FAILED(hr)) {
|
|
return ::ReportError(hr);
|
|
}
|
|
|
|
lNumElements = lUBound - lLBound + 1;
|
|
|
|
// Process the element types
|
|
switch (V_VT(&varData)) {
|
|
|
|
case VT_ARRAY | VT_VARIANT : {
|
|
|
|
VARIANT *rgvarRaw; // Before resolveIDispatch
|
|
CComVariant *rgvar; // After resolveIDispatch
|
|
LPWSTR wszIndex;
|
|
int i;
|
|
int iStrLen;
|
|
|
|
rgvar = new CComVariant[lUBound - lLBound + 1];
|
|
if (rgvar == NULL) {
|
|
return ::ReportError(E_OUTOFMEMORY);
|
|
}
|
|
|
|
hr = SafeArrayAccessData(V_ARRAY(&varData), (void **) &rgvarRaw);
|
|
if (FAILED(hr)) {
|
|
return ::ReportError(hr);
|
|
}
|
|
|
|
// Pass 1, resolve IDispatch, check types and figure out how much memory is needed
|
|
dwDataLen = 0;
|
|
for (i = 0; i < lNumElements; i++) {
|
|
hr = VariantResolveDispatch(&(rgvarRaw[i]), &(rgvar[i]));
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
if (V_VT(&(rgvar[i])) != VT_BSTR) {
|
|
if ((V_VT(&(rgvar[i])) == VT_EMPTY) ||
|
|
(V_VT(&(rgvar[i])) == VT_NULL)) {
|
|
// NULL or EMPTY, Stop Here
|
|
lNumElements = i;
|
|
break;
|
|
}
|
|
else {
|
|
SafeArrayUnaccessData(V_ARRAY(&varData));
|
|
return ::ReportError(ERROR_INVALID_DATA);
|
|
}
|
|
}
|
|
|
|
dwDataLen += (wcslen(OLE2W(V_BSTR(&(rgvar[i])))) + 1) * sizeof(wchar_t);
|
|
}
|
|
dwDataLen += sizeof(wchar_t);
|
|
|
|
// Allocate
|
|
pbData = new BYTE[dwDataLen];
|
|
if (pbData == NULL) {
|
|
SafeArrayUnaccessData(V_ARRAY(&varData));
|
|
return ::ReportError(E_OUTOFMEMORY);
|
|
}
|
|
|
|
// Pass 2, copy to desination
|
|
wszIndex = reinterpret_cast<LPWSTR> (pbData);
|
|
for (i = 0; i < lNumElements; i++) {
|
|
iStrLen = (wcslen(OLE2W(V_BSTR(&(rgvar[i])))) + 1);
|
|
memcpy(wszIndex, OLE2W(V_BSTR(&(rgvar[i]))), iStrLen * sizeof(wchar_t));
|
|
wszIndex += iStrLen;
|
|
}
|
|
*wszIndex = L'\0';
|
|
|
|
SafeArrayUnaccessData(V_ARRAY(&varData));
|
|
|
|
break;
|
|
}
|
|
|
|
case VT_ARRAY | VT_BSTR : {
|
|
|
|
BSTR *rgbstr;
|
|
LPWSTR wszIndex;
|
|
int i;
|
|
int iStrLen;
|
|
|
|
hr = SafeArrayAccessData(V_ARRAY(&varData), (void **) &rgbstr);
|
|
if (FAILED(hr)) {
|
|
return ::ReportError(hr);
|
|
}
|
|
|
|
// Pass 1, figure out how much memory is needed
|
|
dwDataLen = 0;
|
|
for (i = 0; i < lNumElements; i++) {
|
|
dwDataLen += (wcslen(OLE2W(rgbstr[i])) + 1) * sizeof(wchar_t);
|
|
}
|
|
dwDataLen += sizeof(wchar_t);
|
|
|
|
// Allocate
|
|
pbData = new BYTE[dwDataLen];
|
|
if (pbData == NULL) {
|
|
SafeArrayUnaccessData(V_ARRAY(&varData));
|
|
return ::ReportError(E_OUTOFMEMORY);
|
|
}
|
|
|
|
// Pass 2, copy to desination
|
|
wszIndex = reinterpret_cast<LPWSTR> (pbData);
|
|
for (i = 0; i < lNumElements; i++) {
|
|
iStrLen = (wcslen(OLE2W(rgbstr[i])) + 1);
|
|
memcpy(wszIndex, OLE2W(rgbstr[i]), iStrLen * sizeof(wchar_t));
|
|
wszIndex += iStrLen;
|
|
}
|
|
*wszIndex = L'\0';
|
|
|
|
SafeArrayUnaccessData(V_ARRAY(&varData));
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
// Unexpected data type
|
|
return ::ReportError(ERROR_INVALID_DATA);
|
|
}
|
|
}
|
|
else { // Array is not one dimensional
|
|
// Unexpected data type
|
|
return ::ReportError(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
break;
|
|
|
|
case BINARY_METADATA:
|
|
// BSTR of bytes subtype
|
|
switch (V_VT(&varData)) {
|
|
|
|
case VT_BSTR:
|
|
// Use the length field, since NULL values are allowed
|
|
dwDataLen = SysStringByteLen(V_BSTR(&varData));
|
|
|
|
pbData = new BYTE[dwDataLen];
|
|
if( pbData == NULL )
|
|
{
|
|
return ::ReportError(E_OUTOFMEMORY);
|
|
}
|
|
memcpy(pbData, V_BSTR(&varData), dwDataLen);
|
|
|
|
default:
|
|
// Unexpected data type
|
|
return ::ReportError(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
// Unknown metabase data type
|
|
return ::ReportError(ERROR_INVALID_DATA);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|