windows-nt/Source/XPSP1/NT/inetsrv/iis/utils/metautil/mutilobj.cpp
2020-09-26 16:20:57 +08:00

1440 lines
35 KiB
C++

/*===================================================================
Microsoft Denali
Microsoft Confidential.
Copyright 1997 Microsoft Corporation. All Rights Reserved.
Component: MetaUtil object
File: MUtilObj.cpp
Owner: t-BrianM
This file contains implementation of the main MetaUtil class.
Except CheckSchema is in ChkSchm.cpp and CheckKey is in ChkKey.cpp
===================================================================*/
#include "stdafx.h"
#include "MetaUtil.h"
#include "MUtilObj.h"
#include "keycol.h"
/*------------------------------------------------------------------
* C M e t a U t i l (edit and general portions)
*/
/*===================================================================
CMetaUtil::CMetaUtil
Constructor
Parameters:
None
Returns:
Nothing
===================================================================*/
CMetaUtil::CMetaUtil() : m_dwMaxPropSize(10 * 1024), // 10k
m_dwMaxKeySize(100 * 1024), // 100k
m_dwMaxNumErrors(100)
{
}
/*===================================================================
CMetaUtil::FinalConstruct
Constructor
Parameters:
None
Returns:
Nothing
===================================================================*/
HRESULT CMetaUtil::FinalConstruct()
{
HRESULT hr;
// Create the metabase admin base object
hr = ::CoCreateInstance(CLSID_MSAdminBase,
NULL,
CLSCTX_ALL,
IID_IMSAdminBase,
(void **)&m_pIMeta);
if (FAILED(hr)) {
return ::ReportError(hr);
}
// Create a schema table
m_pCSchemaTable = new CMetaSchemaTable;
if (m_pCSchemaTable == NULL) {
return ::ReportError(E_OUTOFMEMORY);
}
return S_OK;
}
/*===================================================================
CMetaUtil::FinalRelease
Destructor
Parameters:
None
Returns:
Nothing
===================================================================*/
void CMetaUtil::FinalRelease()
{
m_pIMeta = NULL;
if (m_pCSchemaTable != NULL)
m_pCSchemaTable->Release();
}
/*===================================================================
CMetaUtil::InterfaceSupportsErrorInfo
Standard ATL implementation
===================================================================*/
STDMETHODIMP CMetaUtil::InterfaceSupportsErrorInfo(REFIID riid)
{
static const IID* arr[] =
{
&IID_IMetaUtil,
};
for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
{
if (InlineIsEqualGUID(*arr[i],riid))
return S_OK;
}
return S_FALSE;
}
/*===================================================================
CMetaUtil::EnumKeys
Do a flat (non-recursive) enumeration of subkeys
Parameters:
bstrBaseKey [in] Key to enumerate the subkeys of
ppIReturn [out, retval] interface for the ouput key collection
Returns:
E_OUTOFMEMORY if allocation fails.
E_INVALIDARG if ppIReturn == NULL
S_OK on success
===================================================================*/
STDMETHODIMP CMetaUtil::EnumKeys(BSTR bstrBaseKey,
IKeyCollection ** ppIReturn)
{
TRACE0("MetaUtil: CMetaUtil::EnumKeys\n");
ASSERT_NULL_OR_POINTER(bstrBaseKey, OLECHAR);
ASSERT_NULL_OR_POINTER(ppIReturn, IKeyCollection *);
if (ppIReturn == NULL) {
return ::ReportError(E_INVALIDARG);
}
USES_CONVERSION;
HRESULT hr;
// Create the Flat Keys Collection
CComObject<CFlatKeyCollection> *pObj = NULL;
ATLTRY(pObj = new CComObject<CFlatKeyCollection>);
if (pObj == NULL) {
return ::ReportError(E_OUTOFMEMORY);
}
hr = pObj->Init(m_pIMeta, OLE2T(bstrBaseKey));
if (FAILED(hr)) {
return ::ReportError(hr);
}
// Set the interface to IKeyCollection
hr = pObj->QueryInterface(IID_IKeyCollection, (void **) ppIReturn);
if (FAILED(hr)) {
return ::ReportError(hr);
}
ASSERT(ppIReturn != NULL);
return S_OK;
}
/*===================================================================
CMetaUtil::EnumAllKeys
Do a deep (recursive) enumeration of subkeys
Parameters:
bstrBaseKey [in] Key to enumerate the subkeys of
ppIReturn [out, retval] interface for the ouput key collection
Returns:
E_OUTOFMEMORY if allocation fails.
E_INVALIDARG if ppIReturn == NULL
S_OK on success
===================================================================*/
STDMETHODIMP CMetaUtil::EnumAllKeys(BSTR bstrBaseKey,
IKeyCollection ** ppIReturn)
{
TRACE0("MetaUtil: CMetaUtil::EnumAllKeys\n");
ASSERT_NULL_OR_POINTER(bstrBaseKey, OLECHAR);
ASSERT_NULL_OR_POINTER(ppIReturn, IKeyCollection *);
if (ppIReturn == NULL) {
return ::ReportError(E_INVALIDARG);
}
USES_CONVERSION;
HRESULT hr;
// Create the Flat Keys Collection
CComObject<CDeepKeyCollection> *pObj = NULL;
ATLTRY(pObj = new CComObject<CDeepKeyCollection>);
if (pObj == NULL) {
return ::ReportError(E_OUTOFMEMORY);
}
hr = pObj->Init(m_pIMeta, OLE2T(bstrBaseKey));
if (FAILED(hr)) {
return ::ReportError(hr);
}
// Set the interface to IKeyCollection
hr = pObj->QueryInterface(IID_IKeyCollection, (void **) ppIReturn);
if (FAILED(hr)) {
return ::ReportError(hr);
}
ASSERT(ppIReturn != NULL);
return S_OK;
}
/*===================================================================
CMetaUtil::EnumProperties
Do an enumeration of properties
Parameters:
bstrBaseKey [in] Key to enumerate the properties of
ppIReturn [out, retval] interface for the ouput property collection
Returns:
E_OUTOFMEMORY if allocation fails.
E_INVALIDARG if ppIReturn == NULL
S_OK on success
===================================================================*/
STDMETHODIMP CMetaUtil::EnumProperties(BSTR bstrKey,
IPropertyCollection **ppIReturn)
{
TRACE0("MetaUtil: CMetaUtil::EnumProperties\n");
ASSERT_NULL_OR_POINTER(bstrKey, OLECHAR);
ASSERT_NULL_OR_POINTER(ppIReturn, IKeyCollection *);
if (ppIReturn == NULL) {
return ::ReportError(E_INVALIDARG);
}
USES_CONVERSION;
HRESULT hr;
// Create the Flat Keys Collection
CComObject<CPropertyCollection> *pObj = NULL;
ATLTRY(pObj = new CComObject<CPropertyCollection>);
if (pObj == NULL) {
return ::ReportError(E_OUTOFMEMORY);
}
hr = pObj->Init(m_pIMeta, m_pCSchemaTable, OLE2T(bstrKey));
if (FAILED(hr)) {
return ::ReportError(hr);
}
// Set the interface to IPropertyCollection
hr = pObj->QueryInterface(IID_IPropertyCollection, (void **) ppIReturn);
if (FAILED(hr)) {
return ::ReportError(hr);
}
ASSERT(ppIReturn != NULL);
return S_OK;
}
/*===================================================================
CMetaUtil::CreateKey
Create a new key
Parameters:
bstrKey [in] Key to create
Returns:
E_INVALIDARG if bstrKey == NULL
S_OK on success
===================================================================*/
STDMETHODIMP CMetaUtil::CreateKey(BSTR bstrKey)
{
TRACE0("MetaUtil: CMetaUtil::CreateKey\n");
ASSERT_NULL_OR_POINTER(bstrKey, OLECHAR);
if (bstrKey == NULL) {
return ::ReportError(E_INVALIDARG);
}
USES_CONVERSION;
TCHAR tszKey[ADMINDATA_MAX_NAME_LEN];
_tcscpy(tszKey,OLE2T(bstrKey));
CannonizeKey(tszKey);
return ::CreateKey(m_pIMeta, tszKey);
}
/*===================================================================
CMetaUtil::DeleteKey
Delete a key
Parameters:
bstrKey [in] Key to delete
Returns:
E_INVALIDARG if bstrKey == NULL
S_OK on success
===================================================================*/
STDMETHODIMP CMetaUtil::DeleteKey(BSTR bstrKey)
{
TRACE0("MetaUtil: CMetaUtil::DeleteKey\n");
ASSERT_NULL_OR_POINTER(bstrKey, OLECHAR);
if (bstrKey == NULL) {
return ::ReportError(E_INVALIDARG);
}
USES_CONVERSION;
TCHAR tszKey[ADMINDATA_MAX_NAME_LEN];
_tcscpy(tszKey,OLE2T(bstrKey));
CannonizeKey(tszKey);
return ::DeleteKey(m_pIMeta, tszKey);
}
/*===================================================================
CMetaUtil::RenameKey
Rename a key
Parameters:
bstrOldName [in] Original Key Name
bstrNewName [in] New key name
Returns:
E_INVALIDARG if bstrOldName == NULL OR bstrNewName == NULL
S_OK on success
===================================================================*/
STDMETHODIMP CMetaUtil::RenameKey(BSTR bstrOldName, BSTR bstrNewName)
{
TRACE0("MetaUtil: CMetaUtil::RenameKey\n");
ASSERT_NULL_OR_POINTER(bstrOldName, OLECHAR);
ASSERT_NULL_OR_POINTER(bstrNewName, OLECHAR);
if ((bstrOldName == NULL) || (bstrNewName == NULL)) {
return ::ReportError(E_INVALIDARG);
}
USES_CONVERSION;
HRESULT hr;
TCHAR tszOldName[ADMINDATA_MAX_NAME_LEN];
TCHAR tszNewName[ADMINDATA_MAX_NAME_LEN];
_tcscpy(tszOldName, OLE2T(bstrOldName));
CannonizeKey(tszOldName);
_tcscpy(tszNewName, OLE2T(bstrNewName));
CannonizeKey(tszNewName);
// Figure out the key's common root
TCHAR tszParent[ADMINDATA_MAX_NAME_LEN];
int i;
i = 0;
while ((tszOldName[i] != _T('\0')) && (tszNewName[i] != _T('\0')) &&
(tszOldName[i] == tszNewName[i])) {
tszParent[i] = tszOldName[i];
i++;
}
if (i == 0) {
// Nothing in common
tszParent[i] = _T('\0');
}
else {
// Back up to the first slash
while ((i > 0) && (tszParent[i] != _T('/'))) {
i--;
}
// Cut it off at the slash
tszParent[i] = _T('\0');
}
int iParentKeyLen;
iParentKeyLen = _tcslen(tszParent);
LPTSTR tszRelOldName;
LPTSTR tszRelNewName;
// Figure out the relative new and old names
tszRelOldName = tszOldName + iParentKeyLen;
if (*tszRelOldName == _T('/')) {
tszRelOldName++;
}
tszRelNewName = tszNewName + iParentKeyLen;
if (*tszRelNewName == _T('/')) {
tszRelNewName++;
}
// Open the parent
METADATA_HANDLE hMDParentKey;
hr = m_pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
T2W(tszParent),
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
MUTIL_OPEN_KEY_TIMEOUT,
&hMDParentKey);
if (FAILED(hr)) {
return ::ReportError(hr);
}
// Rename the key
hr = m_pIMeta->RenameKey(hMDParentKey,
T2W(tszRelOldName),
T2W(tszRelNewName));
if (FAILED(hr)) {
m_pIMeta->CloseKey(hMDParentKey);
return ::ReportError(hr);
}
// Close the parent
m_pIMeta->CloseKey(hMDParentKey);
return S_OK;
}
/*===================================================================
CMetaUtil::CopyKey
Copy a key
Parameters:
bstrSrcKey [in] Source Key Name
bstrDestKey [in] Destination key name
fOverwrite [in] If true then already existing properties
at destination are overwritten.
Returns:
E_INVALIDARG if bstrSrcKey == NULL OR bstrDestKey == NULL
S_OK on success
===================================================================*/
STDMETHODIMP CMetaUtil::CopyKey(BSTR bstrSrcKey, BSTR bstrDestKey, BOOL fOverwrite)
{
TRACE0("MetaUtil: CMetaUtil::CopyKey\n");
ASSERT_NULL_OR_POINTER(bstrSrcKey, OLECHAR);
ASSERT_NULL_OR_POINTER(bstrDestKey, OLECHAR);
if ((bstrSrcKey == NULL) || (bstrDestKey == NULL)) {
return ::ReportError(E_INVALIDARG);
}
USES_CONVERSION;
TCHAR tszSrcKey[ADMINDATA_MAX_NAME_LEN];
TCHAR tszDestKey[ADMINDATA_MAX_NAME_LEN];
_tcscpy(tszSrcKey, OLE2T(bstrSrcKey));
CannonizeKey(tszSrcKey);
_tcscpy(tszDestKey, OLE2T(bstrDestKey));
CannonizeKey(tszDestKey);
return ::CopyKey(m_pIMeta, tszSrcKey, tszDestKey, fOverwrite, TRUE);
}
/*===================================================================
CMetaUtil::MoveKey
Move a key
Parameters:
bstrSrcKey [in] Source Key Name
bstrDestKey [in] Destination key name
fOverwrite [in] If true then already existing properties
at destination are overwritten.
Returns:
E_INVALIDARG if bstrSrcKey == NULL OR bstrDestKey == NULL
S_OK on success
===================================================================*/
STDMETHODIMP CMetaUtil::MoveKey(BSTR bstrSrcKey, BSTR bstrDestKey, BOOL fOverwrite)
{
TRACE0("MetaUtil: CMetaUtil::MoveKey\n");
ASSERT_NULL_OR_POINTER(bstrSrcKey, OLECHAR);
ASSERT_NULL_OR_POINTER(bstrDestKey, OLECHAR);
if ((bstrSrcKey == NULL) || (bstrDestKey == NULL)) {
return ::ReportError(E_INVALIDARG);
}
USES_CONVERSION;
TCHAR tszSrcKey[ADMINDATA_MAX_NAME_LEN];
TCHAR tszDestKey[ADMINDATA_MAX_NAME_LEN];
_tcscpy(tszSrcKey, OLE2T(bstrSrcKey));
CannonizeKey(tszSrcKey);
_tcscpy(tszDestKey, OLE2T(bstrDestKey));
CannonizeKey(tszDestKey);
return ::CopyKey(m_pIMeta, tszSrcKey, tszDestKey, fOverwrite, FALSE);
}
/*===================================================================
CMetaUtil::GetProperty
Gets a property object from the metabase.
Parameters:
bstrKey [in] Key containing property to get
varId [in] Identifier of property to get. Either the
Id (number) or Name (string).
ppIReturn [out, retval] Interface for retreived property.
Returns:
E_INVALIDARG if bstrKey == NULL or ppIReturn == NULL
S_OK on success
===================================================================*/
STDMETHODIMP CMetaUtil::GetProperty(BSTR bstrKey,
VARIANT varId,
IProperty **ppIReturn)
{
TRACE0("MetaUtil: CMetaUtil::GetProperty\n");
ASSERT_NULL_OR_POINTER(bstrKey, OLECHAR);
ASSERT_NULL_OR_POINTER(ppIReturn, IProperty *);
if ((bstrKey == NULL) || (ppIReturn == NULL)) {
return ::ReportError(E_INVALIDARG);
}
USES_CONVERSION;
TCHAR tszKey[ADMINDATA_MAX_NAME_LEN];
_tcscpy(tszKey,OLE2T(bstrKey));
CannonizeKey(tszKey);
return ::GetProperty(m_pIMeta, m_pCSchemaTable, tszKey, varId, ppIReturn);
}
/*===================================================================
CMetaUtil::CreateProperty
Creates a property object that can be written to the Metbase or
retreives the property if it already exists.
Parameters:
bstrKey [in] Key containing property to get
varId [in] Identifier of property to get. Either the
Id (number) or Name (string).
ppIReturn [out, retval] Interface for retreived property.
Returns:
E_INVALIDARG if bstrKey == NULL or ppIReturn == NULL
S_OK on success
===================================================================*/
STDMETHODIMP CMetaUtil::CreateProperty(BSTR bstrKey,
VARIANT varId,
IProperty **ppIReturn)
{
TRACE0("MetaUtil: CMetaUtil::CreateProperty\n");
ASSERT_NULL_OR_POINTER(bstrKey, OLECHAR);
ASSERT_NULL_OR_POINTER(ppIReturn, IProperty *);
if ((bstrKey == NULL) || (ppIReturn == NULL)) {
return ::ReportError(E_INVALIDARG);
}
USES_CONVERSION;
TCHAR tszKey[ADMINDATA_MAX_NAME_LEN];
_tcscpy(tszKey,OLE2T(bstrKey));
CannonizeKey(tszKey);
return ::CreateProperty(m_pIMeta, m_pCSchemaTable, tszKey, varId, ppIReturn);
}
/*===================================================================
CMetaUtil::DeleteProperty
Deletes a property from the metabase.
Parameters:
bstrKey [in] Key containing property to get
varId [in] Identifier of property to get. Either the
Id (number) or Name (string).
Returns:
E_INVALIDARG if bstrKey == NULL
S_OK on success
===================================================================*/
STDMETHODIMP CMetaUtil::DeleteProperty(BSTR bstrKey, VARIANT varId)
{
TRACE0("MetaUtil: CMetaUtil::DeleteProperty\n");
ASSERT_NULL_OR_POINTER(bstrKey, OLECHAR);
if (bstrKey == NULL) {
return ::ReportError(E_INVALIDARG);
}
USES_CONVERSION;
TCHAR tszKey[ADMINDATA_MAX_NAME_LEN];
_tcscpy(tszKey,OLE2T(bstrKey));
CannonizeKey(tszKey);
return ::DeleteProperty(m_pIMeta, m_pCSchemaTable, tszKey, varId);
}
/*===================================================================
CMetaUtil::ExpandString
Expands a string with environment variables. Maximum output is 1024
bytes.
Parameters:
bstrIn [in] String to expand
pbstrRet [out, retval] Expanded string
Returns:
E_INVALIDARG if bstrIn == NULL or pbstrRet == NULL
S_OK on success
===================================================================*/
STDMETHODIMP CMetaUtil::ExpandString(BSTR bstrIn, BSTR *pbstrRet)
{
ASSERT_POINTER(bstrIn, OLECHAR);
ASSERT_NULL_OR_POINTER(pbstrRet, BSTR);
if ((bstrIn == NULL) || (pbstrRet == NULL)) {
return ::ReportError(E_INVALIDARG);
}
USES_CONVERSION;
TCHAR tszRet[1024];
int iRet;
iRet = ExpandEnvironmentStrings(OLE2T(bstrIn), tszRet, 1024);
if (iRet == 0) {
::ReportError(GetLastError());
}
*pbstrRet = T2BSTR(tszRet);
return S_OK;
}
/*===================================================================
MetaUtil::PropIdToName
Converts a property Id to its name, as listed in
_Machine_/Schema/Properties/Names
Parameters:
bstrKey [in] Approximate key where property is located,
needed to determine what schema to use.
lId [in] Id of property
pbstrName [out, retval] Output name of property
Returns:
E_INVALIDARG if bstrKey == NULL or pbstrName == NULL
S_OK on success
===================================================================*/
STDMETHODIMP CMetaUtil::PropIdToName(BSTR bstrKey, long lId, BSTR *pbstrName)
{
ASSERT_NULL_OR_POINTER(bstrKey, OLECHAR);
ASSERT_NULL_OR_POINTER(pbstrName, BSTR);
if ((bstrKey == NULL) || (pbstrName == NULL)) {
return ::ReportError(E_INVALIDARG);
}
USES_CONVERSION;
TCHAR tszKey[ADMINDATA_MAX_NAME_LEN];
CPropInfo *pCPropInfo;
// Convert the base key to cannonical form
_tcscpy(tszKey, OLE2T(bstrKey));
CannonizeKey(tszKey);
// Get the property info from the Schema Table
pCPropInfo = m_pCSchemaTable->GetPropInfo(tszKey, lId);
// 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;
}
/*===================================================================
MetaUtil::PropNameToId
Converts a property name to its id, as listed in
_Machine_/Schema/Properties/Names
Parameters:
bstrKey [in] Approximate key where property is located,
needed to determine what schema to use.
pbstrName [in] Name of property
lId [out, retval] Output id of property
Returns:
E_INVALIDARG if bstrKey == NULL OR bstrName == NULL OR plId == NULL
S_OK on success
===================================================================*/
STDMETHODIMP CMetaUtil::PropNameToId(BSTR bstrKey, BSTR bstrName, long *plId)
{
ASSERT_NULL_OR_POINTER(bstrKey, OLECHAR);
ASSERT_NULL_OR_POINTER(bstrName, OLECHAR);
ASSERT_NULL_OR_POINTER(plId, long);
if ((bstrKey == NULL) || (bstrName == NULL) || (plId == NULL)) {
return ::ReportError(E_INVALIDARG);
}
USES_CONVERSION;
TCHAR tszKey[ADMINDATA_MAX_NAME_LEN];
CPropInfo *pCPropInfo;
// Convert the base key to cannonical form
_tcscpy(tszKey, OLE2T(bstrKey));
CannonizeKey(tszKey);
// Get the property info from the Schema Table
pCPropInfo = m_pCSchemaTable->GetPropInfo(tszKey, OLE2T(bstrName));
// Did we find it?
if (pCPropInfo == NULL) {
// No, return 0
*plId = 0;
}
else {
// Yes, return the id
*plId = pCPropInfo->GetId();
}
return S_OK;
}
/*===================================================================
MetaUtil::get_Config
Gets the value of a configuration setting.
Valid Settings:
MaxPropertySize
MaxKeySize
MaxNumberOfErrors
Parameters:
bstrSetting [in] Name of the setting
pvarValue [out, retval] Value of the setting
Returns:
E_INVALIDARG if bstrSettting doesn't match any known settings
S_OK on success
===================================================================*/
STDMETHODIMP CMetaUtil::get_Config(BSTR bstrSetting, VARIANT *pvarValue)
{
ASSERT_POINTER(bstrSetting, OLECHAR);
ASSERT_POINTER(pvarValue, VARIANT);
USES_CONVERSION;
LPTSTR tszSetting;
if( !bstrSetting )
{
return ::ReportError(E_INVALIDARG);
}
VariantInit(pvarValue);
tszSetting = OLE2T(bstrSetting);
if (_tcsicmp(tszSetting, _T("MaxPropertySize")) == 0) {
V_VT(pvarValue) = VT_I4;
V_I4(pvarValue) = m_dwMaxPropSize;
}
else if (_tcsicmp(tszSetting, _T("MaxKeySize")) == 0) {
V_VT(pvarValue) = VT_I4;
V_I4(pvarValue) = m_dwMaxKeySize;
}
else if (_tcsicmp(tszSetting, _T("MaxNumberOfErrors")) == 0) {
V_VT(pvarValue) = VT_I4;
V_I4(pvarValue) = m_dwMaxNumErrors;
}
else {
return ::ReportError(E_INVALIDARG);
}
return S_OK;
}
/*===================================================================
MetaUtil::put_Config
Sets the value of a configuration setting.
Valid Settings:
MaxPropertySize
MaxKeySize
MaxNumberOfErrors
Parameters:
bstrSetting [in] Name of the setting
varValue [out, retval] New value of the setting
Returns:
E_INVALIDARG if bstrSettting doesn't match any known settings or
if varValue is of an unexpected subtype.
S_OK on success
===================================================================*/
STDMETHODIMP CMetaUtil::put_Config(BSTR bstrSetting, VARIANT varValue)
{
ASSERT_POINTER(bstrSetting, OLECHAR);
USES_CONVERSION;
HRESULT hr;
LPTSTR tszSetting;
tszSetting = OLE2T(bstrSetting);
// Cleanup any IDispatch or byref stuff
CComVariant varValue2;
hr = VariantResolveDispatch(&varValue, &varValue2);
if (FAILED(hr)) {
return hr;
}
if (_tcsicmp(tszSetting, _T("MaxPropertySize")) == 0) {
// Set Maximum Property Size
switch (V_VT(&varValue2)) {
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
if (FAILED(hr = VariantChangeType(&varValue2, &varValue2, 0, VT_UI4))) {
return ::ReportError(hr);
}
// fallthru to VT_UI4
case VT_UI4:
m_dwMaxPropSize = V_UI4(&varValue2);
break;
default:
// Unexpected data type
return ::ReportError(E_INVALIDARG);
}
}
else if (_tcsicmp(tszSetting, _T("MaxKeySize")) == 0) {
// Set Maximum Key Size
switch (V_VT(&varValue2)) {
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
if (FAILED(hr = VariantChangeType(&varValue2, &varValue2, 0, VT_UI4))) {
return ::ReportError(hr);
}
// fallthru to VT_UI4
case VT_UI4:
m_dwMaxKeySize = V_UI4(&varValue2);
break;
default:
// Unexpected data type
return ::ReportError(E_INVALIDARG);
}
}
else if (_tcsicmp(tszSetting, _T("MaxNumberOfErrors")) == 0) {
// Set Maximum Number of Errors
switch (V_VT(&varValue2)) {
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
if (FAILED(hr = VariantChangeType(&varValue2, &varValue2, 0, VT_UI4))) {
return ::ReportError(hr);
}
// fallthru to VT_UI4
case VT_UI4:
m_dwMaxNumErrors = V_UI4(&varValue2);
break;
default:
// Unexpected data type
return ::ReportError(E_INVALIDARG);
}
}
else {
return ::ReportError(E_INVALIDARG);
}
return S_OK;
}
/*------------------------------------------------------------------
* Methods also supported by the collections
*
* Actual implementation here to avoid redundant code
*/
/*===================================================================
CreateKey
Create a new key
Parameters:
pIMeta [in] Smart pointer to metabase, passed by reference
to avoid the copy and unneeded AddRef/Release.
Would have used const, however the '->' operator
would not work.
tszKey [in] Key to create
Returns:
E_INVALIDARG if bstrKey == NULL
S_OK on success
===================================================================*/
HRESULT CreateKey(CComPtr<IMSAdminBase> &pIMeta,
LPCTSTR tszKey)
{
ASSERT(pIMeta.p != NULL);
ASSERT_STRING(tszKey);
USES_CONVERSION;
HRESULT hr;
TCHAR tszParent[ADMINDATA_MAX_NAME_LEN];
TCHAR tszChild[ADMINDATA_MAX_NAME_LEN];
::SplitKey(tszKey, tszParent, tszChild);
// Open the parent key
METADATA_HANDLE hMDParent;
hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
T2W(tszParent),
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
MUTIL_OPEN_KEY_TIMEOUT,
&hMDParent);
if (FAILED(hr)) {
return ::ReportError(hr);
}
// Create the child
hr = pIMeta->AddKey(hMDParent, T2W(tszChild));
if (FAILED(hr)) {
pIMeta->CloseKey(hMDParent);
return ::ReportError(hr);
}
// Close the parent key
pIMeta->CloseKey(hMDParent);
return S_OK;
}
/*===================================================================
DeleteKey
Delete a key
Parameters:
pIMeta [in] Smart pointer to metabase, passed by reference
to avoid the copy and unneeded AddRef/Release.
Would have used const, however the '->' operator
would not work.
tszKey [in] Key to delete
Returns:
E_INVALIDARG if pbSuccess == NULL
S_OK on success
===================================================================*/
HRESULT DeleteKey(CComPtr<IMSAdminBase> &pIMeta,
LPCTSTR tszKey)
{
ASSERT(pIMeta.p != NULL);
ASSERT_STRING(tszKey);
USES_CONVERSION;
HRESULT hr;
TCHAR tszParent[ADMINDATA_MAX_NAME_LEN];
TCHAR tszChild[ADMINDATA_MAX_NAME_LEN];
::SplitKey(tszKey, tszParent, tszChild);
// Open the parent key
METADATA_HANDLE hMDParent;
hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
T2W(tszParent),
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
MUTIL_OPEN_KEY_TIMEOUT,
&hMDParent);
if (FAILED(hr)) {
return ::ReportError(hr);
}
// Delete the child
hr = pIMeta->DeleteKey(hMDParent, T2W(tszChild));
if (FAILED(hr)) {
pIMeta->CloseKey(hMDParent);
return ::ReportError(hr);
}
// Close the parent key
pIMeta->CloseKey(hMDParent);
return S_OK;
}
/*===================================================================
CMetaUtil::CopyKey
Copy or move a key
Parameters:
bstrSrcKey [in] Source Key Name
bstrDestKey [in] Destination key name
fOverwrite [in] If true then already existing properties
at destination are overwritten.
fCopy [in] If true than copy the key, else move it
Returns:
S_OK on success
===================================================================*/
HRESULT CopyKey(CComPtr<IMSAdminBase> &pIMeta,
LPTSTR tszSrcKey,
LPTSTR tszDestKey,
BOOL fOverwrite,
BOOL fCopy)
{
ASSERT(pIMeta.p != NULL);
ASSERT_STRING(tszSrcKey);
ASSERT_STRING(tszDestKey);
USES_CONVERSION;
HRESULT hr;
// Check for overlap
TCHAR tszParent[ADMINDATA_MAX_NAME_LEN];
int i;
i = 0;
while ((tszSrcKey[i] != _T('\0')) && (tszDestKey[i] != _T('\0')) &&
(tszSrcKey[i] == tszDestKey[i])) {
tszParent[i] = tszSrcKey[i];
i++;
}
// Terminate tszParent
tszParent[i] = _T('\0');
if (i == 0) {
// Nothing in common
TCHAR tszSrcParent[ADMINDATA_MAX_NAME_LEN];
TCHAR tszSrcChild[ADMINDATA_MAX_NAME_LEN];
TCHAR tszDestParent[ADMINDATA_MAX_NAME_LEN];
TCHAR tszDestChild[ADMINDATA_MAX_NAME_LEN];
::SplitKey(tszSrcKey, tszSrcParent, tszSrcChild);
::SplitKey(tszDestKey, tszDestParent, tszDestChild);
// Open the parent source key
METADATA_HANDLE hMDSrcParent;
hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
T2W(tszSrcParent),
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
MUTIL_OPEN_KEY_TIMEOUT,
&hMDSrcParent);
if (FAILED(hr)) {
return ::ReportError(hr);
}
// Open the parent dest key
METADATA_HANDLE hMDDestParent;
hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
T2W(tszDestParent),
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
MUTIL_OPEN_KEY_TIMEOUT,
&hMDDestParent);
if (FAILED(hr)) {
return ::ReportError(hr);
}
// Copy the children
hr = pIMeta->CopyKey(hMDSrcParent, T2W(tszSrcChild),
hMDDestParent, T2W(tszDestChild),
fOverwrite, fCopy);
if (FAILED(hr)) {
pIMeta->CloseKey(hMDSrcParent);
pIMeta->CloseKey(hMDDestParent);
return ::ReportError(hr);
}
// Close the parents
pIMeta->CloseKey(hMDSrcParent);
pIMeta->CloseKey(hMDDestParent);
}
else {
// Something in common
// Back up to the first slash
while ((i > 0) && (tszParent[i] != _T('/'))) {
i--;
}
// Cut it off at the slash
tszParent[i] = _T('\0');
int iParentKeyLen;
iParentKeyLen = _tcslen(tszParent);
LPTSTR tszSrcChild;
LPTSTR tszDestChild;
// Figure out the relative new and old names
tszSrcChild = tszSrcKey + iParentKeyLen;
if (*tszSrcChild == _T('/')) {
tszSrcChild++;
}
tszDestChild = tszDestKey + iParentKeyLen;
if (*tszDestChild == _T('/')) {
tszDestChild++;
}
// Open the parent key
METADATA_HANDLE hMDParent;
hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
T2W(tszParent),
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
MUTIL_OPEN_KEY_TIMEOUT,
&hMDParent);
if (FAILED(hr)) {
return ::ReportError(hr);
}
// Copy the children
hr = pIMeta->CopyKey(hMDParent, T2W(tszSrcChild),
hMDParent, T2W(tszDestChild),
fOverwrite, fCopy);
if (FAILED(hr)) {
pIMeta->CloseKey(hMDParent);
return ::ReportError(hr);
}
// Close the parent
pIMeta->CloseKey(hMDParent);
}
return S_OK;
}
/*===================================================================
GetProperty
Gets a property object from the metabase.
Parameters:
pIMeta [in] Smart pointer to metabase, passed by
reference to avoid the copy and unneeded
AddRef/Release. Would have used const, however
the '->' operator would not work.
pCSchemaTable [in] Metabase schema table to use to look up
property names
tszKey [in] Key containing property to get
varId [in] Identifier of property to get. Either the
Id (number) or Name (string).
ppIReturn [out, retval] Interface for retreived property.
Returns:
S_OK on success
===================================================================*/
HRESULT GetProperty(CComPtr<IMSAdminBase> &pIMeta,
CMetaSchemaTable *pCSchemaTable,
LPCTSTR tszKey,
VARIANT varId,
IProperty **ppIReturn)
{
ASSERT(pIMeta != NULL);
ASSERT_STRING(tszKey);
ASSERT_POINTER(ppIReturn, IProperty *);
HRESULT hr;
DWORD dwId;
// Figure out the property id
hr = ::VarToMetaId(pCSchemaTable, tszKey, varId, &dwId);
if (FAILED(hr)) {
return ::ReportError(hr);
}
// Create the property object
CComObject<CProperty> *pObj = NULL;
ATLTRY(pObj = new CComObject<CProperty>);
if (pObj == NULL) {
return ::ReportError(E_OUTOFMEMORY);
}
hr = pObj->Init(pIMeta, pCSchemaTable, tszKey, dwId, FALSE);
if (FAILED(hr)) {
return ::ReportError(hr);
}
// Set the interface to IProperty
hr = pObj->QueryInterface(IID_IProperty, (void **) ppIReturn);
if (FAILED(hr)) {
return ::ReportError(hr);
}
ASSERT(*ppIReturn != NULL);
return S_OK;
}
/*===================================================================
CreateProperty
Creates a property object that can be written to the Metbase or
retreives the property if it already exists.
Parameters:
pIMeta [in] Smart pointer to metabase, passed by
reference to avoid the copy and unneeded
AddRef/Release. Would have used const, however
the '->' operator would not work.
pCSchemaTable [in] Metabase schema table to use to look up
property names
tszKey [in] Key containing property to get
varId [in] Identifier of property to get. Either the
Id (number) or Name (string).
ppIReturn [out, retval] Interface for retreived property.
Returns:
S_OK on success
===================================================================*/
HRESULT CreateProperty(CComPtr<IMSAdminBase> &pIMeta,
CMetaSchemaTable *pCSchemaTable,
LPCTSTR tszKey,
VARIANT varId,
IProperty **ppIReturn)
{
ASSERT(pIMeta.p != NULL);
ASSERT_STRING(tszKey);
ASSERT_POINTER(ppIReturn, IProperty *);
HRESULT hr;
DWORD dwId;
// Figure out the property id
hr = ::VarToMetaId(pCSchemaTable, tszKey, varId, &dwId);
if (FAILED(hr)) {
return ::ReportError(hr);
}
// Create the property object
CComObject<CProperty> *pObj = NULL;
ATLTRY(pObj = new CComObject<CProperty>);
if (pObj == NULL) {
return ::ReportError(E_OUTOFMEMORY);
}
hr = pObj->Init(pIMeta, pCSchemaTable, tszKey, dwId, TRUE);
if (FAILED(hr)) {
return ::ReportError(hr);
}
// Set the interface to IProperty
hr = pObj->QueryInterface(IID_IProperty, (void **) ppIReturn);
if (FAILED(hr)) {
return ::ReportError(hr);
}
ASSERT(*ppIReturn != NULL);
return S_OK;
}
/*===================================================================
DeleteProperty
Deletes a property from the metabase.
Parameters:
pIMeta [in] Smart pointer to metabase, passed by
reference to avoid the copy and unneeded
AddRef/Release. Would have used const, however
the '->' operator would not work.
pCSchemaTable [in] Metabase schema table to use to look up
property names
tszKey [in] Key containing property to get
varId [in] Identifier of property to get. Either the
Id (number) or Name (string).
Returns:
S_OK on success
===================================================================*/
HRESULT DeleteProperty(CComPtr<IMSAdminBase> &pIMeta,
CMetaSchemaTable *pCSchemaTable,
LPTSTR tszKey,
VARIANT varId)
{
ASSERT(pIMeta.p != NULL);
ASSERT_STRING(tszKey);
USES_CONVERSION;
HRESULT hr;
DWORD dwId;
hr = ::VarToMetaId(pCSchemaTable, tszKey, varId, &dwId);
if (FAILED(hr)) {
return ::ReportError(hr);
}
// Open the key
METADATA_HANDLE hMDKey;
hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
T2W(tszKey),
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
MUTIL_OPEN_KEY_TIMEOUT,
&hMDKey);
if (FAILED(hr)) {
return ::ReportError(hr);
}
// Delete the property
hr = pIMeta->DeleteData(hMDKey, NULL, dwId, ALL_METADATA);
if (FAILED(hr)) {
pIMeta->CloseKey(hMDKey);
return ::ReportError(hr);
}
// Close the key
pIMeta->CloseKey(hMDKey);
return S_OK;
}
/*===================================================================
VarToMetaId
Converts a variant to a metabase property id. IDispatch is resolved,
strings are looked up in the schema property list and integers are
converted to a DWORD.
Parameters:
pCSchemaTable [in] Metabase schema table to use to look up
property names
tszKey [in] Key the property is under (needed to get the
right schema)
varId [in] Variant to resolve
pdwId [out] Metabase property Id that varId resolved to
Returns:
E_INVALIDARG if varId subtype isn't an integer or string
ERROR_FILE_NOT_FOUND if varId is a BSTR that doesn't match any
property names.
S_OK on success
===================================================================*/
HRESULT VarToMetaId(CMetaSchemaTable *pCSchemaTable,
LPCTSTR tszKey,
VARIANT varId,
DWORD *pdwId)
{
ASSERT_STRING(tszKey);
ASSERT_POINTER(pdwId, DWORD);
USES_CONVERSION;
HRESULT hr;
CComVariant varId2;
CPropInfo *pCPropInfo;
// VBScript can call us with a VARIANT that isn't a simple type,
// such as VT_VARIANT|VT_BYREF. This resolves it to a simple type.
if (FAILED(hr = VariantResolveDispatch(&varId, &varId2)))
return hr;
switch (V_VT(&varId2)) {
case VT_BSTR:
// Look up the property name
pCPropInfo = pCSchemaTable->GetPropInfo(tszKey, OLE2T(V_BSTR(&varId2)));
if (pCPropInfo == NULL) {
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
*pdwId = pCPropInfo->GetId();
return S_OK;
break;
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 REG_DWORD
if (FAILED(hr = VariantChangeType(&varId2, &varId2, 0, VT_UI4)))
return hr;
// fallthru to VT_UI4
case VT_UI4:
*pdwId = V_UI4(&varId2);
break;
default:
return E_INVALIDARG; // Cannot handle this data type
}
return S_OK;
}