mirror of https://github.com/tongzx/nt5src
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.
1439 lines
35 KiB
1439 lines
35 KiB
/*===================================================================
|
|
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;
|
|
}
|