/*++ Copyright (c) 1994-1998 Microsoft Corporation Module Name : mdkeys.cpp Abstract: Metabase key wrapper class Author: Ronald Meijer (ronaldm) Project: Internet Services Manager Revision History: --*/ // // Include Files // #include "stdafx.h" #include "comprop.h" #include "idlg.h" #include "mdkeys.h" // // Constants // #define MB_TIMEOUT (15000) // Timeout in milliseconds #define MB_INIT_BUFF_SIZE ( 256) // Initial buffer size // // CMetaInterface class // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CMetaInterface::CMetaInterface( IN LPCTSTR lpszServerName OPTIONAL ) /*++ Routine Description: Construct and initialize the interface Arguments: LPCTSTR lpszServerName : Server name. NULL indicates the local computer Return Value: N/A --*/ : m_pInterface(NULL), m_iTimeOutValue(MB_TIMEOUT), m_strServerName(), m_hrInterface(S_OK) { // // Initialize the interface // m_hrInterface = Create(lpszServerName); } CMetaInterface::CMetaInterface( IN const CMetaInterface * pInterface ) /*++ Routine Description: Construct from existing interface (Copy Constructor) Arguments: CMetaInterface * pInterface : Existing interface Return Value: N/A Notes: Object will not take ownership of the interface, it will merely add to the reference count, and release it upon destruction --*/ : m_pInterface(pInterface->m_pInterface), m_iTimeOutValue(pInterface->m_iTimeOutValue), m_strServerName(pInterface->m_strServerName), m_hrInterface(pInterface->m_hrInterface) { ASSERT(m_pInterface != NULL); m_pInterface->AddRef(); } CMetaInterface::~CMetaInterface() /*++ Routine Description: Destructor -- releases the interface Arguments: N/A Return Value: N/A --*/ { SAFE_RELEASE(m_pInterface); } /* protected */ HRESULT CMetaInterface::Create( IN LPCTSTR lpszServerName OPTIONAL ) /*++ Routine Description: Create the interface with DCOM. Arguments: lpszServerName : machine name. Use the COSERVERINFO's pwszName syntax. Could be NULL, in which case the local computer is used. Return Value: HRESULT Notes: This function is smart enough to substitute NULL if the server name provided is in fact the local computer name. Presumably, that's faster. --*/ { COSERVERINFO * pcsiName = NULL; COSERVERINFO csiName; // // Be smart about the server name; optimize for local // computer name. // if (lpszServerName = ::NormalizeServerName(lpszServerName)) { // // Create the COM server info for CoCreateInstanceEx // ::ZeroMemory(&csiName, sizeof(csiName)); csiName.pwszName = (LPWSTR)lpszServerName; pcsiName = &csiName; } // // Query the MD COM interface // MULTI_QI rgmqResults[1]; rgmqResults[0].pIID = &IID_IMSAdminBase; rgmqResults[0].pItf = NULL; rgmqResults[0].hr = 0; // // Create a instance of the object and get the interface // HRESULT hr = ::CoCreateInstanceEx( GETAdminBaseCLSID(TRUE), NULL, CLSCTX_SERVER, pcsiName, 1, rgmqResults ); // // It failed, try with non-service MD // if (FAILED(hr)) { // // inetinfo.exe run as user program // TRACEEOLID("Failed to create admin interface, second attempt"); hr = ::CoCreateInstanceEx( GETAdminBaseCLSID(FALSE), NULL, CLSCTX_SERVER, pcsiName, 1, rgmqResults ); } if(SUCCEEDED(hr)) { // // Save the interface pointer // m_pInterface = (IMSAdminBase *)rgmqResults[0].pItf; ASSERT(m_pInterface != NULL); } if (lpszServerName && *lpszServerName) { m_strServerName = lpszServerName; } else { // // Use local computer name // DWORD dwSize = MAX_PATH; LPTSTR lpName = m_strServerName.GetBuffer(dwSize); GetComputerName(lpName, &dwSize); m_strServerName.ReleaseBuffer(); } return hr; } HRESULT CMetaInterface::Regenerate() /*++ Routine Description: Attempt to recreate the interface pointer. This assumes that the interface had been successfully created before, but has become invalid at some point afterwards. Arguments: None Return Value: HRESULT --*/ { ASSERT(!m_strServerName.IsEmpty()); // Must've been initialized ASSERT(m_pInterface != NULL); // As above SAFE_RELEASE(m_pInterface); m_hrInterface = Create(m_strServerName); return m_hrInterface; } /* virtual */ BOOL CMetaInterface::Succeeded() const /*++ Routine Description: Determine if object was constructed successfully. Arguments: None Return Value: TRUE for success, FALSE for failure --*/ { return SUCCEEDED(m_hrInterface); } /* virtual */ HRESULT CMetaInterface::QueryResult() const /*++ Routine Description: Return the construction error for this object. Arguments: None Return Value: HRESULT from construction errors --*/ { return m_hrInterface; } // // CWamInterface class // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CWamInterface::CWamInterface( IN LPCTSTR lpszServerName OPTIONAL ) /*++ Routine Description: Construct and initialize the interface. Arguments: LPCTSTR lpszServerName : Server name, use NULL to indicate the local computer name. Return Value: N/A --*/ : m_pInterface(NULL), m_strServerName(), m_fSupportsPooledProc(FALSE), m_hrInterface(S_OK) { // // Initialize the interface // m_hrInterface = Create(lpszServerName); } CWamInterface::CWamInterface( IN const CWamInterface * pInterface ) /*++ Routine Description: Construct from existing interface (copy constructor) Arguments: CWamInterface * pInterface : Existing interface Return Value: N/A --*/ : m_pInterface(pInterface->m_pInterface), m_strServerName(pInterface->m_strServerName), m_fSupportsPooledProc(FALSE), m_hrInterface(pInterface->m_hrInterface) { ASSERT(m_pInterface != NULL); m_pInterface->AddRef(); } CWamInterface::~CWamInterface() /*++ Routine Description: Destructor -- releases the interface. Arguments: N/A Return Value: N/A --*/ { SAFE_RELEASE(m_pInterface); } /* protected */ HRESULT CWamInterface::Create( IN LPCTSTR lpszServerName OPTIONAL ) /*++ Routine Description: Create the interface with DCOM Arguments: lpszServerName : machine name. Use the COSERVERINFO's pwszName syntax. Could be NULL, in which case the local computer is used. Return Value: HRESULT Notes: This function is smart enough to substitute NULL if the server name provided is in fact the local computer name. Presumably, that's faster. First, it will attempt to create the new interface, if it fails, it will attempt to create the downlevel interface --*/ { COSERVERINFO * pcsiName = NULL; COSERVERINFO csiName; // // Be smart about the server name; optimize for local // computer name. // if (lpszServerName = ::NormalizeServerName(lpszServerName)) { // // Create the COM server info for CoCreateInstanceEx // ::ZeroMemory(&csiName, sizeof(csiName)); csiName.pwszName = (LPWSTR)lpszServerName; pcsiName = &csiName; } // // First try to do the new interface // MULTI_QI rgmqResults[1]; rgmqResults[0].pIID = &IID_IWamAdmin2; rgmqResults[0].pItf = NULL; rgmqResults[0].hr = 0; // // Create a instance of the object and get the interface // HRESULT hr = ::CoCreateInstanceEx( CLSID_WamAdmin, NULL, CLSCTX_SERVER, pcsiName, 1, rgmqResults ); m_fSupportsPooledProc = SUCCEEDED(hr); if (hr == E_NOINTERFACE) { // // Attempt to create the downlevel version // TRACEEOLID("Attempting downlevel WAM interface"); rgmqResults[0].pIID = &IID_IWamAdmin; hr = ::CoCreateInstanceEx( CLSID_WamAdmin, NULL, CLSCTX_SERVER, pcsiName, 1, rgmqResults ); } if(SUCCEEDED(hr)) { // // Save the interface pointer // m_pInterface = (IWamAdmin *)rgmqResults[0].pItf; ASSERT(m_pInterface != NULL); } if (lpszServerName && *lpszServerName) { m_strServerName = lpszServerName; } else { // // Use local computer name // DWORD dwSize = MAX_PATH; LPTSTR lpName = m_strServerName.GetBuffer(dwSize); GetComputerName(lpName, &dwSize); m_strServerName.ReleaseBuffer(); } return hr; } /* virtual */ BOOL CWamInterface::Succeeded() const /*++ Routine Description: Determine if object was constructed successfully Arguments: None Return Value: TRUE for success, FALSE for failure --*/ { return SUCCEEDED(m_hrInterface); } /* virtual */ HRESULT CWamInterface::QueryResult() const /*++ Routine Description: Return the construction error for this object Arguments: None Return Value: HRESULT from construction errors --*/ { return m_hrInterface; } HRESULT CWamInterface::AppCreate( IN LPCTSTR szMDPath, IN DWORD dwAppProtection ) /*++ Routine Description: Create application Arguments: LPCTSTR szMDPath : Metabase path DWORD dwAppProtection : APP_INPROC to create in-proc app APP_OUTOFPROC to create out-of-proc app APP_POOLEDPROC to create a pooled-proc app Return Value: HRESULT (ERROR_INVALID_PARAMETER if unsupported protection state is requested) --*/ { if (m_fSupportsPooledProc) { // // Interface pointer is really IWamAdmin2, so call the new method // return ((IWamAdmin2 *)m_pInterface)->AppCreate2(szMDPath, dwAppProtection); } // // Call the downlevel API // if (dwAppProtection == APP_INPROC || dwAppProtection == APP_OUTOFPROC) { BOOL fInProc = (dwAppProtection == APP_INPROC); ASSERT(m_pInterface != NULL); return m_pInterface->AppCreate(szMDPath, fInProc); } return CError(ERROR_INVALID_PARAMETER); } // // CMetaback Class // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< const LPCTSTR CMetaBack::s_szMasterAppRoot =\ SZ_MBN_SEP_STR SZ_MBN_MACHINE SZ_MBN_SEP_STR SZ_MBN_WEB; CMetaBack::CMetaBack( IN LPCTSTR lpszServerName OPTIONAL ) /*++ Routine Description: Constructor for metabase backup/restore operations class. This object is both a WAM interface and a METABASE interface. Arguments: LPCTSTR lpszServerName : Server name. Use NULL to indicate the local computer name. Return Value: N/A --*/ : m_dwIndex(0), CMetaInterface(lpszServerName), CWamInterface(lpszServerName) { } /* virtual */ BOOL CMetaBack::Succeeded() const /*++ Routine Description: Determine if object was constructed successfully. Arguments: None Return Value: TRUE for success, FALSE for failure --*/ { return CMetaInterface::Succeeded() && CWamInterface::Succeeded(); } /* virtual */ HRESULT CMetaBack::QueryResult() const /*++ Routine Description: Return the construction error for this object Arguments: None Return Value: HRESULT from construction errors --*/ { // // Both interfaces must have constructed successfully // HRESULT hr = CMetaInterface::QueryResult(); if (SUCCEEDED(hr)) { hr = CWamInterface::QueryResult(); } return hr; } HRESULT CMetaBack::Restore( IN LPCTSTR lpszLocation, IN DWORD dwVersion ) /*++ Routine Description: Restore metabase Arguments: DWORD dwVersion : Backup version LPCTSTR lpszLocation : Backup location Return Value: HRESULT --*/ { // // Backup and restore the application information from a restore // CString strPath(s_szMasterAppRoot); HRESULT hr = AppDeleteRecoverable(strPath, TRUE); if (SUCCEEDED(hr)) { hr = CMetaInterface::Restore(lpszLocation, dwVersion, 0); if (SUCCEEDED(hr)) { hr = AppRecover(strPath, TRUE); } } return hr; } HRESULT CMetaBack::BackupWithPassword( IN LPCTSTR lpszLocation, IN LPCTSTR lpszPassword ) { return CMetaInterface::BackupWithPassword( lpszLocation, MD_BACKUP_NEXT_VERSION, MD_BACKUP_SAVE_FIRST, lpszPassword ); } HRESULT CMetaBack::RestoreWithPassword( IN LPCTSTR lpszLocation, IN DWORD dwVersion, IN LPCTSTR lpszPassword ) /*++ Routine Description: Restore metabase Arguments: DWORD dwVersion : Backup version LPCTSTR lpszLocation : Backup location LPCTSTR lpszPassword : Backup password Return Value: HRESULT --*/ { // // Backup and restore the application information from a restore // CString strPath(s_szMasterAppRoot); HRESULT hr = AppDeleteRecoverable(strPath, TRUE); if (SUCCEEDED(hr)) { hr = CMetaInterface::RestoreWithPassword(lpszLocation, dwVersion, 0, lpszPassword); if (SUCCEEDED(hr)) { hr = AppRecover(strPath, TRUE); } } return hr; } // // CIISSvcControl class // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CIISSvcControl::CIISSvcControl( IN LPCTSTR lpszServerName OPTIONAL ) /*++ Routine Description: Construct and initialize the interface. Arguments: LPCTSTR lpszServerName : Server name, use NULL to indicate the local computer name. Return Value: N/A --*/ : m_pInterface(NULL), m_strServerName(), m_hrInterface(S_OK) { // // Initialize the interface // m_hrInterface = Create(lpszServerName); } CIISSvcControl::CIISSvcControl( IN const CIISSvcControl * pInterface ) /*++ Routine Description: Construct from existing interface (copy constructor) Arguments: CIISSvcControl * pInterface : Existing interface Return Value: N/A --*/ : m_pInterface(pInterface->m_pInterface), m_strServerName(pInterface->m_strServerName), m_hrInterface(pInterface->m_hrInterface) { ASSERT(m_pInterface != NULL); m_pInterface->AddRef(); } CIISSvcControl::~CIISSvcControl() /*++ Routine Description: Destructor -- releases the interface. Arguments: N/A Return Value: N/A --*/ { SAFE_RELEASE(m_pInterface); } /* protected */ HRESULT CIISSvcControl::Create( IN LPCTSTR lpszServerName OPTIONAL ) /*++ Routine Description: Create the interface with DCOM Arguments: lpszServerName : machine name. Use the COSERVERINFO's pwszName syntax. Could be NULL, in which case the local computer is used. Return Value: HRESULT Notes: This function is smart enough to substitute NULL if the server name provided is in fact the local computer name. Presumably, that's faster. --*/ { COSERVERINFO * pcsiName = NULL; COSERVERINFO csiName; // // Be smart about the server name; optimize for local // computer name. // if (lpszServerName = ::NormalizeServerName(lpszServerName)) { // // Create the COM server info for CoCreateInstanceEx // ::ZeroMemory(&csiName, sizeof(csiName)); csiName.pwszName = (LPWSTR)lpszServerName; pcsiName = &csiName; } // // Query the MD COM interface // MULTI_QI rgmqResults[1]; rgmqResults[0].pIID = &IID_IIisServiceControl; rgmqResults[0].pItf = NULL; rgmqResults[0].hr = 0; // // Create a instance of the object and get the interface // HRESULT hr = ::CoCreateInstanceEx( CLSID_IisServiceControl, NULL, CLSCTX_SERVER, pcsiName, 1, rgmqResults ); if(SUCCEEDED(hr)) { // // Save the interface pointer // m_pInterface = (IIisServiceControl *)rgmqResults[0].pItf; ASSERT(m_pInterface != NULL); } if (lpszServerName && *lpszServerName) { m_strServerName = lpszServerName; } else { // // Use local computer name // DWORD dwSize = MAX_PATH; LPTSTR lpName = m_strServerName.GetBuffer(dwSize); GetComputerName(lpName, &dwSize); m_strServerName.ReleaseBuffer(); } return hr; } /* virtual */ BOOL CIISSvcControl::Succeeded() const /*++ Routine Description: Determine if object was constructed successfully Arguments: None Return Value: TRUE for success, FALSE for failure --*/ { return SUCCEEDED(m_hrInterface); } /* virtual */ HRESULT CIISSvcControl::QueryResult() const /*++ Routine Description: Return the construction error for this object Arguments: None Return Value: HRESULT from construction errors --*/ { return m_hrInterface; } // // CMetaKey class // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // // Helper macros // #define ASSURE_PROPER_INTERFACE()\ if (!HasInterface()) { ASSERT(FALSE); return MD_ERROR_NOT_INITIALIZED; } #define ASSURE_OPEN_KEY()\ if (!m_hKey && !m_fAllowRootOperations) { ASSERT(FALSE); return HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE); } #define FETCH_PROPERTY_DATA_OR_FAIL(dwID, md)\ ZeroMemory(&md, sizeof(md)); \ if (!GetMDFieldDef(dwID, md.dwMDIdentifier, md.dwMDAttributes, md.dwMDUserType, md.dwMDDataType))\ { ASSERT(FALSE); return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); } // // Static Initialization // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< const LPCTSTR CMetaKey::s_cszCompression = SZ_MBN_FILTERS SZ_MBN_SEP_STR SZ_MBN_COMPRESSION; const LPCTSTR CMetaKey::s_cszMachine = SZ_MBN_MACHINE; const LPCTSTR CMetaKey::s_cszMimeMap = SZ_MBN_MIMEMAP; const LPCTSTR CMetaKey::s_cszRoot = SZ_MBN_ROOT; const LPCTSTR CMetaKey::s_cszSep = SZ_MBN_SEP_STR; const LPCTSTR CMetaKey::s_cszInfo = SZ_MBN_INFO; const TCHAR CMetaKey::s_chSep = SZ_MBN_SEP_CHAR; // // Metabase table // const CMetaKey::MDFIELDDEF CMetaKey::s_rgMetaTable[] = { // // !!!IMPORTANT!!! This table must be sorted on dwMDIdentifier. (will // be verified in the debug version) // { MD_MAX_BANDWIDTH, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 }, { MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 }, { MD_SERVER_COMMAND, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 }, { MD_CONNECTION_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CONNECTION_TIMEOUT }, { MD_MAX_CONNECTIONS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_MAX_CONNECTIONS }, { MD_SERVER_COMMENT, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_SERVER_COMMENT }, { MD_SERVER_STATE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 }, { MD_SERVER_AUTOSTART, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 }, { MD_SERVER_SIZE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_SERVER_SIZE }, { MD_SERVER_LISTEN_BACKLOG, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_SERVER_LISTEN_BACKLOG }, { MD_SERVER_LISTEN_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_SERVER_LISTEN_TIMEOUT }, { MD_SERVER_BINDINGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, MULTISZ_METADATA, 0 }, { MD_WIN32_ERROR, METADATA_NO_ATTRIBUTES, IIS_MD_UT_FILE, DWORD_METADATA, 0 }, { MD_SECURE_BINDINGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, MULTISZ_METADATA, 0 }, { MD_FILTER_LOAD_ORDER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 }, { MD_FILTER_IMAGE_PATH, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 }, { MD_FILTER_STATE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 }, { MD_FILTER_ENABLED, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 }, { MD_FILTER_FLAGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 }, { MD_AUTH_CHANGE_URL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 }, { MD_AUTH_EXPIRED_URL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 }, { MD_AUTH_NOTIFY_PWD_EXP_URL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 }, { MD_ADV_NOTIFY_PWD_EXP_IN_DAYS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 }, { MD_ADV_CACHE_TTL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 }, { MD_NET_LOGON_WKS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 }, { MD_USE_HOST_NAME, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 }, { MD_AUTH_EXPIRED_UNSECUREURL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 }, { MD_AUTH_CHANGE_FLAGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 }, { MD_AUTH_NOTIFY_PWD_EXP_UNSECUREURL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 }, { MD_FRONTPAGE_WEB, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 }, { MD_MAPCERT, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 }, { MD_MAPNTACCT, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 }, { MD_MAPNAME, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 }, { MD_MAPENABLED, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 }, { MD_MAPREALM, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 }, { MD_MAPPWD, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 }, { MD_ITACCT, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 }, { MD_CPP_CERT11, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 }, { MD_SERIAL_CERT11, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 }, { MD_CPP_CERTW, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 }, { MD_SERIAL_CERTW, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 }, { MD_CPP_DIGEST, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 }, { MD_SERIAL_DIGEST, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 }, { MD_CPP_ITA, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 }, { MD_SERIAL_ITA, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 }, { MD_APP_FRIENDLY_NAME, METADATA_INHERIT, IIS_MD_UT_WAM, STRING_METADATA, IDS_MD_APP_FRIENDLY_NAME }, { MD_APP_ROOT, METADATA_INHERIT, IIS_MD_UT_WAM, STRING_METADATA, IDS_MD_APP_ROOT }, { MD_APP_ISOLATED, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_MD_APP_ISOLATED }, { MD_CPU_LIMITS_ENABLED, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LIMITS_ENABLED }, { MD_CPU_LIMIT_LOGEVENT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LIMIT_LOGEVENT }, { MD_CPU_LIMIT_PRIORITY, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LIMIT_PRIORITY }, { MD_CPU_LIMIT_PROCSTOP, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LIMIT_PROCSTOP }, { MD_CPU_LIMIT_PAUSE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LIMIT_PAUSE }, { MD_HC_COMPRESSION_DIRECTORY, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 }, { MD_HC_DO_DYNAMIC_COMPRESSION, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 }, { MD_HC_DO_STATIC_COMPRESSION, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 }, { MD_HC_DO_DISK_SPACE_LIMITING, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 }, { MD_HC_MAX_DISK_SPACE_USAGE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 }, { MD_VR_PATH, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_VR_PATH }, { MD_VR_USERNAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_VR_USERNAME }, { MD_VR_PASSWORD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_VR_PASSWORD }, { MD_VR_ACL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_FILE, BINARY_METADATA, 0 }, { MD_VR_UPDATE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_FILE, DWORD_METADATA, 0 }, { MD_LOG_TYPE, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOG_TYPE }, { MD_LOGFILE_DIRECTORY, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGFILE_DIRECTORY }, { MD_LOGFILE_PERIOD, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOGFILE_PERIOD }, { MD_LOGFILE_TRUNCATE_SIZE, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOGFILE_TRUNCATE_SIZE }, { MD_LOGSQL_DATA_SOURCES, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_DATA_SOURCES }, { MD_LOGSQL_TABLE_NAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_TABLE_NAME }, { MD_LOGSQL_USER_NAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_USER_NAME }, { MD_LOGSQL_PASSWORD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_PASSWORD }, { MD_LOG_PLUGIN_ORDER, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_LOG_PLUGIN_ORDER }, { MD_LOGEXT_FIELD_MASK, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOGEXT_FIELD_MASK }, { MD_LOGFILE_LOCALTIME_ROLLOVER, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOGFILE_LOCALTIME_ROLLOVER }, { MD_CPU_LOGGING_MASK, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LOGGING_MASK }, { MD_EXIT_MESSAGE, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_EXIT_MESSAGE }, { MD_GREETING_MESSAGE, METADATA_INHERIT, IIS_MD_UT_SERVER, MULTISZ_METADATA, IDS_MD_GREETING_MESSAGE }, { MD_MAX_CLIENTS_MESSAGE, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_MAX_CLIENTS_MESSAGE }, { MD_MSDOS_DIR_OUTPUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_MSDOS_DIR_OUTPUT }, { MD_ALLOW_ANONYMOUS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_ALLOW_ANONYMOUS }, { MD_ANONYMOUS_ONLY, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_ANONYMOUS_ONLY }, { MD_LOG_ANONYMOUS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOG_ANONYMOUS }, { MD_LOG_NONANONYMOUS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOG_NONANONYMOUS }, { MD_SSL_PUBLIC_KEY, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 }, { MD_SSL_PRIVATE_KEY, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 }, { MD_SSL_KEY_PASSWORD, METADATA_SECURE, IIS_MD_UT_SERVER, BINARY_METADATA, 0 }, { MD_SSL_CERT_HASH, METADATA_INHERIT, IIS_MD_UT_SERVER, BINARY_METADATA, 0 }, { MD_SSL_CERT_STORE_NAME, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, 0 }, { MD_SSL_CTL_IDENTIFIER, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, 0 }, { MD_SSL_CTL_STORE_NAME, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, 0 }, { MD_SSL_USE_DS_MAPPER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 }, { MD_AUTHORIZATION, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_AUTHORIZATION }, { MD_REALM, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_REALM }, { MD_HTTP_EXPIRES, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_HTTP_EXPIRES }, { MD_HTTP_PICS, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_HTTP_PICS }, { MD_HTTP_CUSTOM, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_HTTP_CUSTOM }, { MD_DIRECTORY_BROWSING, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_DIRECTORY_BROWSING }, { MD_DEFAULT_LOAD_FILE, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_DEFAULT_LOAD_FILE }, { MD_CONTENT_NEGOTIATION, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_CONTENT_NEGOTIATION }, { MD_CUSTOM_ERROR, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_CUSTOM_ERROR }, { MD_FOOTER_DOCUMENT, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_FOOTER_DOCUMENT }, { MD_FOOTER_ENABLED, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_FOOTER_ENABLED }, { MD_HTTP_REDIRECT, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_HTTP_REDIRECT }, { MD_DEFAULT_LOGON_DOMAIN, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_DEFAULT_LOGON_DOMAIN }, { MD_LOGON_METHOD, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOGON_METHOD }, { MD_SCRIPT_MAPS, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_SCRIPT_MAPS }, { MD_MIME_MAP, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_MIME_MAP }, { MD_ACCESS_PERM, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_ACCESS_PERM }, { MD_IP_SEC, METADATA_INHERIT | METADATA_REFERENCE, IIS_MD_UT_FILE, BINARY_METADATA, IDS_MD_IP_SEC }, { MD_ANONYMOUS_USER_NAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_ANONYMOUS_USER_NAME }, { MD_ANONYMOUS_PWD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_ANONYMOUS_PWD }, { MD_ANONYMOUS_USE_SUBAUTH, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_ANONYMOUS_USE_SUBAUTH }, { MD_DONT_LOG, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_DONT_LOG }, { MD_ADMIN_ACL, METADATA_INHERIT | METADATA_SECURE | METADATA_REFERENCE,IIS_MD_UT_SERVER, BINARY_METADATA, IDS_MD_ADMIN_ACL }, { MD_SSI_EXEC_DISABLED, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_SSI_EXEC_DISABLED }, { MD_SSL_ACCESS_PERM, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_SSL_ACCESS_PERM }, { MD_NTAUTHENTICATION_PROVIDERS, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_NTAUTHENTICATION_PROVIDERS }, { MD_SCRIPT_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_SCRIPT_TIMEOUT }, { MD_CACHE_EXTENSIONS, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_CACHE_EXTENSIONS }, { MD_CREATE_PROCESS_AS_USER, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CREATE_PROCESS_AS_USER }, { MD_CREATE_PROC_NEW_CONSOLE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CREATE_PROC_NEW_CONSOLE }, { MD_POOL_IDC_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_POOL_IDC_TIMEOUT }, { MD_ALLOW_KEEPALIVES, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_ALLOW_KEEPALIVES }, { MD_IS_CONTENT_INDEXED, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_IS_CONTENT_INDEXED }, { MD_ISM_ACCESS_CHECK, METADATA_NO_ATTRIBUTES, IIS_MD_UT_FILE, DWORD_METADATA, 0 }, { MD_ASP_BUFFERINGON, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_BUFFERINGON }, { MD_ASP_LOGERRORREQUESTS, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_LOGERRORREQUESTS }, { MD_ASP_SCRIPTERRORSSENTTOBROWSER, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_SCRIPTERRORSSENTTOBROWSER }, { MD_ASP_SCRIPTERRORMESSAGE, METADATA_INHERIT, ASP_MD_UT_APP, STRING_METADATA, IDS_ASP_SCRIPTERRORMESSAGE }, { MD_ASP_SCRIPTFILECACHESIZE, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_SCRIPTFILECACHESIZE }, { MD_ASP_SCRIPTENGINECACHEMAX, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_SCRIPTENGINECACHEMAX }, { MD_ASP_SCRIPTTIMEOUT, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_SCRIPTTIMEOUT }, { MD_ASP_SESSIONTIMEOUT, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_SESSIONTIMEOUT }, { MD_ASP_ENABLEPARENTPATHS, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ENABLEPARENTPATHS }, { MD_ASP_ALLOWSESSIONSTATE, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ALLOWSESSIONSTATE }, { MD_ASP_SCRIPTLANGUAGE, METADATA_INHERIT, ASP_MD_UT_APP, STRING_METADATA, IDS_ASP_SCRIPTLANGUAGE }, { MD_ASP_EXCEPTIONCATCHENABLE, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_EXCEPTIONCATCHENABLE }, { MD_ASP_ENABLESERVERDEBUG, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ENABLESERVERDEBUG }, { MD_ASP_ENABLECLIENTDEBUG, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ENABLECLIENTDEBUG }, }; #define NUM_ENTRIES (sizeof(CMetaKey::s_rgMetaTable) / sizeof(CMetaKey::s_rgMetaTable[0])) /* static */ int CMetaKey::MapMDIDToTableIndex( IN DWORD dwID ) /*++ Routine Description: Map MD id value to table index. Return -1 if not found Arguments: DWORD dwID : MD id value Return Value: Index into the table that coresponds to the MD id value --*/ { #ifdef _DEBUG { // // Do a quick verification that our metadata // table is sorted correctly. // static BOOL fTableChecked = FALSE; if (!fTableChecked) { for (int n = 1; n < NUM_ENTRIES; ++n) { if (s_rgMetaTable[n].dwMDIdentifier <= s_rgMetaTable[n - 1].dwMDIdentifier) { TRACEEOLID("MD ID Table is out of order: Item is " << n << " " << s_rgMetaTable[n].dwMDIdentifier ); ASSERT(FALSE); } } // // But only once. // ++fTableChecked; } } #endif // _DEBUG // // Look up the ID in the table using a binary search // int nRange = NUM_ENTRIES; int nLow = 0; int nHigh = nRange - 1; int nMid; int nHalf; while (nLow <= nHigh) { if (nHalf = nRange / 2) { nMid = nLow + (nRange & 1 ? nHalf : (nHalf - 1)); if (s_rgMetaTable[nMid].dwMDIdentifier == dwID) { return nMid; } else if (s_rgMetaTable[nMid].dwMDIdentifier > dwID) { nHigh = --nMid; nRange = nRange & 1 ? nHalf : nHalf - 1; } else { nLow = ++nMid; nRange = nHalf; } } else if (nRange) { return s_rgMetaTable[nLow].dwMDIdentifier == dwID ? nLow : -1; } else { break; } } return -1; } /* static */ BOOL CMetaKey::GetMDFieldDef( IN DWORD dwID, OUT DWORD & dwMDIdentifier, OUT DWORD & dwMDAttributes, OUT DWORD & dwMDUserType, OUT DWORD & dwMDDataType ) /*++ Routine Description: Get information about metabase property Arguments: DWORD dwID : Meta ID DWORD & dwMDIdentifier : Meta parms DWORD & dwMDAttributes : Meta parms DWORD & dwMDUserType : Meta parms DWORD & dwMDDataType : Meta parms Return Value: TRUE for success, FALSE for failure. --*/ { int nID = MapMDIDToTableIndex(dwID); if (nID == -1) { // // Unrecognized meta data ID // ASSERT(FALSE); return FALSE; } dwMDIdentifier = s_rgMetaTable[nID].dwMDIdentifier; dwMDAttributes = s_rgMetaTable[nID].dwMDAttributes; dwMDUserType = s_rgMetaTable[nID].dwMDUserType; dwMDDataType = s_rgMetaTable[nID].dwMDDataType; return TRUE; } /* static */ BOOL CMetaKey::IsPropertyInheritable( IN DWORD dwID ) /*++ Routine Description: Check to see if the given property is inheritable Arguments: DWORD dwID : Metabase ID Return Value: TRUE if the metabase ID is inheritable, FALSE otherwise. --*/ { int nID = MapMDIDToTableIndex(dwID); if (nID == -1) { // // Unrecognized meta data ID // ASSERT(FALSE); return FALSE; } return (s_rgMetaTable[nID].dwMDAttributes & METADATA_INHERIT) != 0; } /* static */ BOOL CMetaKey::GetPropertyDescription( IN DWORD dwID, OUT CString & strName ) /*++ Routine Description: Get a description for the given property Arguments: DWORD dwID : Property ID CString & strName : Returns friendly property name Return Value: TRUE for success, FALSE for failure --*/ { int nID = MapMDIDToTableIndex(dwID); if (nID == -1) { // // Unrecognized meta data ID // ASSERT(FALSE); return FALSE; } UINT uID = s_rgMetaTable[nID].uStringID; #ifndef _COMSTATIC HINSTANCE hOld = ::AfxGetResourceHandle(); ::AfxSetResourceHandle(GetModuleHandle(COMPROP_DLL_NAME)); #endif // _COMSTATIC BOOL fResult = TRUE; if (uID > 0) { fResult = (strName.LoadString(uID) != 0); } else { // // Don't have a friendly name -- fake it // CString strFmt; VERIFY(strFmt.LoadString(IDS_INHERITANCE_NO_NAME)); strName.Format(strFmt, dwID); } #ifndef _COMSTATIC ::AfxSetResourceHandle(hOld); #endif // _COMSTATIC return fResult; } /* static */ void CMetaKey::SplitMetaPath( IN LPCTSTR lpPath, OUT CString & strParent, OUT CString & strAlias ) /*++ Routine Description: Split the given path into parent metabase root and alias Arguments: LPCTSTR lpPath : Input path CString & strParent : Outputs the parent path CString & strAlias : Outputs the alias name Return Value: None. --*/ { TRACEEOLID("Source Path " << lpPath); strParent = lpPath; strAlias.Empty(); int cSlash = strParent.ReverseFind(g_chSep); ASSERT(cSlash >= 0); if (cSlash >= 0) { strAlias = strParent.Mid(++cSlash); strParent.ReleaseBuffer(--cSlash); } TRACEEOLID("Broken up into " << strParent); TRACEEOLID(" and " << strAlias); } /* static */ void CMetaKey::SplitMetaPathAtInstance( IN LPCTSTR lpPath, OUT CString & strParent, OUT CString & strAlias ) /*++ Routine Description: Split the given path into parent metabase root and alias, with the root being the instance path, and the alias everything following the instance. Arguments: LPCTSTR lpPath : Input path CString & strParent : Outputs the parent path CString & strAlias : Outputs the alias name Return Value: None. --*/ { TRACEEOLID("Source Path " << lpPath); strParent = lpPath; strAlias.Empty(); LPTSTR lp = strParent.GetBuffer(0); ASSERT(lp); int cSeparators = 0; int iChar = 0; // // Looking for "LM/sss/ddd/" <-- 3d slash: // while (*lp && cSeparators < 2) { if (*lp++ == g_chSep) { ++cSeparators; } ++iChar; } if (!*lp) { // // Bogus format // ASSERT(FALSE); return; } if (_istdigit(*lp)) { // // Not at the master instance, skip one more. // while (*lp) { ++iChar; if (*lp++ == g_chSep) { break; } } if (!*lp) { // // Bogus format // ASSERT(FALSE); return; } } strAlias = strParent.Mid(iChar); strParent.ReleaseBuffer(--iChar); TRACEEOLID("Broken up into " << strParent); TRACEEOLID(" and " << strAlias); } /* static */ LPCTSTR CMetaKey::BuildMetaPath( OUT CString & strPath, IN LPCTSTR lpSvc OPTIONAL, IN DWORD dwInstance OPTIONAL, IN LPCTSTR lpParentPath OPTIONAL, IN LPCTSTR lpAlias OPTIONAL ) /*++ Routine Description: Build a complete metapath with the given service name, instance number and optional path components. Arguments: CString & strPath : Destination path LPCTSTR lpSvc : Service (may be NULL or "") DWORD dwInstance : Instance number (may be 0 for master) LPCTSTR lpParentPath : Parent path (may be NULL or "") LPCTSTR lpAlias : Alias (may be NULL or "") Return Value: Pointer to internal buffer containing the path. --*/ { try { strPath = s_cszMachine; if (lpSvc && *lpSvc) { strPath += s_cszSep; strPath += lpSvc; } ASSERT(dwInstance >= 0); if (dwInstance != MASTER_INSTANCE) { TCHAR szInstance[] = _T("4000000000"); strPath += s_cszSep; _ltot(dwInstance, szInstance, 10); strPath += szInstance; } if (lpParentPath && *lpParentPath) { strPath += s_cszSep; strPath += lpParentPath; } if (lpAlias && *lpAlias) { // // Special case: If the alias is root, but we're // at the master instance, ignore this. // if (dwInstance != MASTER_INSTANCE || lstrcmpi(s_cszRoot, lpAlias) != 0) { strPath += s_cszSep; strPath += lpAlias; } } TRACEEOLID("Generated metapath: " << strPath); } catch(CMemoryException * e) { strPath.Empty(); e->ReportError(); e->Delete(); } return strPath; } /* static */ LPCTSTR CMetaKey::ConvertToParentPath( OUT IN CString & strMetaPath ) /*++ Routine Description: Given the path, convert it to the parent path e.g. "foo/bar/etc" returns "foo/bar" Arguments: CString & strMetaPath : Path to be converted Return value: Pointer to the converted path, or NULL in case of error --*/ { TRACEEOLID("Getting parent path of " << strMetaPath); LPTSTR lpszPath = strMetaPath.GetBuffer(1); LPTSTR lpszTail = lpszPath + lstrlen(lpszPath) - 1; LPTSTR lpszReturn = NULL; do { if (lpszTail <= lpszPath) { break; } // // Strip trailing backslash // if (*lpszTail == s_chSep) { *lpszTail-- = _T('\0'); } // // Search for parent // while (lpszTail > lpszPath && *lpszTail != s_chSep) { --lpszTail; } if (lpszTail <= lpszPath) { break; } *lpszTail = _T('\0'); lpszReturn = lpszPath; } while(FALSE); strMetaPath.ReleaseBuffer(); TRACEEOLID("Parent path should be " << strMetaPath); return lpszReturn; } /* static */ void CMetaKey::ConvertToParentPath( IN OUT CString & strService, IN OUT DWORD & dwInstance, IN OUT CString & strParent, IN OUT CString & strAlias ) /*++ Routine Description: Change the input parameters so that they are valid for the immediate parent of the path described Arguments: CString & strService : Service name DWORD & dwInstance : Instance number CString & strParent : Parent path CString & strAlias : Node name Return Value: None --*/ { if (!strAlias.IsEmpty()) { strAlias.Empty(); } else { if (!strParent.IsEmpty()) { int nSep = strParent.ReverseFind(g_chSep); if (nSep >= 0) { strParent.ReleaseBuffer(nSep); } else { strParent.Empty(); } } else { if (dwInstance != MASTER_INSTANCE) { dwInstance = MASTER_INSTANCE; } else { strService.Empty(); } } } } /* static */ BOOL CMetaKey::IsHomeDirectoryPath( IN LPCTSTR lpszMetaPath ) /*++ Routine Description: Determine if the path given describes a root directory Arguments: LPCTSTR lpszMetaPath : Metabase path Return Value: TRUE if the path describes a root directory, FALSE if it does not --*/ { ASSERT(lpszMetaPath != NULL); LPTSTR lpNode = _tcsrchr(lpszMetaPath, s_chSep); if (lpNode) { return _tcsicmp(++lpNode, g_cszRoot) == 0; } return FALSE; } /* static */ LPCTSTR CMetaKey::CleanMetaPath( IN OUT CString & strMetaRoot ) /*++ Routine Description: Clean up the metabase path to one valid for internal consumption. This removes the beginning and trailing slashes off the path Arguments: CString & strMetaRoot : Metabase path to be cleaned up. Return Value: Pointer to the metabase path --*/ { TRACEEOLID("Dirty metapath: " << strMetaRoot); if (!strMetaRoot.IsEmpty()) { if (strMetaRoot[strMetaRoot.GetLength() - 1] == SZ_MBN_SEP_CHAR) { strMetaRoot.ReleaseBuffer(strMetaRoot.GetLength() - 1); } if (strMetaRoot[0] == SZ_MBN_SEP_CHAR) { strMetaRoot = strMetaRoot.Right(strMetaRoot.GetLength() - 1); } } TRACEEOLID("Clean metapath: " << strMetaRoot); return strMetaRoot; } CMetaKey::CMetaKey( IN LPCTSTR lpszServerName OPTIONAL ) /*++ Routine Description: Constructor that creates the interface, but does not open the key. This is the ONLY constructor that allows operations from METDATA_MASTER_ROOT_HANDLE (read operations obviously) Arguments: LPCTSTR lpszServerName : If NULL, opens interface on local machine Return Value: N/A --*/ : CMetaInterface(lpszServerName), m_hKey(METADATA_MASTER_ROOT_HANDLE), m_hBase(NULL), m_hrKey(S_OK), m_dwFlags(0L), m_cbInitialBufferSize(MB_INIT_BUFF_SIZE), m_strMetaPath(), m_fAllowRootOperations(TRUE), m_fOwnKey(TRUE) { m_hrKey = CMetaInterface::QueryResult(); // // Do not open key // } CMetaKey::CMetaKey( IN const CMetaInterface * pInterface ) /*++ Routine Description: Construct with pre-existing interface. Does not open any keys Arguments: CMetaInterface * pInterface : Preexisting interface Return Value: N/A --*/ : CMetaInterface(pInterface), m_hKey(NULL), m_hBase(NULL), m_strMetaPath(), m_dwFlags(0L), m_cbInitialBufferSize(MB_INIT_BUFF_SIZE), m_fAllowRootOperations(TRUE), m_fOwnKey(TRUE) { m_hrKey = CMetaInterface::QueryResult(); } CMetaKey::CMetaKey( IN LPCTSTR lpszServerName, IN DWORD dwFlags, IN METADATA_HANDLE hkBase, IN LPCTSTR lpszMDPath ) /*++ Routine Description: Fully defined constructor that opens a key Arguments: LPCTSTR lpszServerName : Server name DWORD dwFlags : Open permissions METADATA_HANDLE hkBase : Base key LPCTSTR lpszMDPath : Path or NULL Return Value: N/A --*/ : CMetaInterface(lpszServerName), m_hKey(NULL), m_hBase(NULL), m_dwFlags(0L), m_cbInitialBufferSize(MB_INIT_BUFF_SIZE), m_fAllowRootOperations(FALSE), m_strMetaPath(), m_fOwnKey(TRUE) { m_hrKey = CMetaInterface::QueryResult(); if (SUCCEEDED(m_hrKey)) { m_hrKey = Open(dwFlags, hkBase, lpszMDPath); } } CMetaKey::CMetaKey( IN const CMetaInterface * pInterface, IN DWORD dwFlags, IN METADATA_HANDLE hkBase, IN LPCTSTR lpszMDPath ) /*++ Routine Description: Fully defined constructor that opens a key Arguments: CMetaInterface * pInterface : Existing interface DWORD dwFlags : Open permissions METADATA_HANDLE hkBase : Base key LPCTSTR lpszMDPath : Path or NULL Return Value: N/A --*/ : CMetaInterface(pInterface), m_hKey(NULL), m_hBase(NULL), m_strMetaPath(), m_dwFlags(0L), m_cbInitialBufferSize(MB_INIT_BUFF_SIZE), m_fAllowRootOperations(FALSE), m_fOwnKey(TRUE) { m_hrKey = CMetaInterface::QueryResult(); if (SUCCEEDED(m_hrKey)) { m_hrKey = Open(dwFlags, hkBase, lpszMDPath); } } CMetaKey::CMetaKey( IN LPCTSTR lpszServerName, IN DWORD dwFlags, IN LPCTSTR lpSvc, OPTIONAL IN DWORD dwInstance, OPTIONAL IN LPCTSTR lpParentPath, OPTIONAL IN LPCTSTR lpAlias OPTIONAL ) /*++ Routine Description: Constructor with path components Arguments: LPCTSTR lpszServerName : Server name DWORD dwFlags : Open permissions LPCTSTR lpSvc : Service name or NULL DWORD dwInstance, : Instance number of 0 LPCTSTR lpParentPath : Parent path or NULL LPCTSTR lpAlias : Alias name or NULL Return Value: N/A --*/ : CMetaInterface(lpszServerName), m_hKey(NULL), m_hBase(NULL), m_strMetaPath(), m_dwFlags(0L), m_cbInitialBufferSize(MB_INIT_BUFF_SIZE), m_fAllowRootOperations(FALSE), m_fOwnKey(TRUE) { m_hrKey = CMetaInterface::QueryResult(); if (SUCCEEDED(m_hrKey)) { m_hrKey = Open(dwFlags, lpSvc, dwInstance, lpParentPath, lpAlias); } } CMetaKey::CMetaKey( IN const CMetaInterface * pInterface, IN DWORD dwFlags, IN LPCTSTR lpSvc, OPTIONAL IN DWORD dwInstance, OPTIONAL IN LPCTSTR lpParentPath, OPTIONAL IN LPCTSTR lpAlias OPTIONAL ) /*++ Routine Description: Constructor with path components Arguments: CMetaInterface * pInterface : Existing interface DWORD dwFlags : Open permissions LPCTSTR lpSvc : Service name or NULL DWORD dwInstance, : Instance number of 0 LPCTSTR lpParentPath : Parent path or NULL LPCTSTR lpAlias : Alias name or NULL Return Value: N/A --*/ : CMetaInterface(pInterface), m_hKey(NULL), m_hBase(NULL), m_dwFlags(0L), m_cbInitialBufferSize(MB_INIT_BUFF_SIZE), m_fAllowRootOperations(FALSE), m_strMetaPath(), m_fOwnKey(TRUE) { m_hrKey = CMetaInterface::QueryResult(); if (SUCCEEDED(m_hrKey)) { m_hrKey = Open(dwFlags, lpSvc, dwInstance, lpParentPath, lpAlias); } } CMetaKey::CMetaKey( IN BOOL fOwnKey, IN const CMetaKey * pKey ) /*++ Routine Description: Copy constructor. Arguments: BOOL fOwnKey : TRUE to take ownership of the key const CMetaKey * pKey : Existing key Return Value: N/A --*/ : CMetaInterface(pKey), m_hKey(pKey->m_hKey), m_hBase(pKey->m_hBase), m_dwFlags(pKey->m_dwFlags), m_cbInitialBufferSize(pKey->m_cbInitialBufferSize), m_fAllowRootOperations(pKey->m_fAllowRootOperations), m_hrKey(pKey->m_hrKey), m_strMetaPath(pKey->m_strMetaPath), m_fOwnKey(fOwnKey) { // // No provisions for anything else at the moment // ASSERT(!m_fOwnKey); } CMetaKey::~CMetaKey() /*++ Routine Description: Destructor -- Close the key. Arguments: N/A Return Value: N/A --*/ { if (IsOpen() && m_fOwnKey) { Close(); } } /* virtual */ BOOL CMetaKey::Succeeded() const /*++ Routine Description: Determine if object was constructed successfully Arguments: None Return Value: TRUE for success, FALSE for failure --*/ { return SUCCEEDED(m_hrKey); } /* virtual */ HRESULT CMetaKey::QueryResult() const /*++ Routine Description: Return the construction error for this object Arguments: None Return Value: HRESULT from construction errors --*/ { return m_hrKey; } HRESULT CMetaKey::Open( IN DWORD dwFlags, IN METADATA_HANDLE hkBase, IN LPCTSTR lpszMDPath OPTIONAL ) /*++ Routine Description: Attempt to open a metabase key Arguments: METADATA_HANDLE hkBase : Base metabase key LPCTSTR lpszMDPath : Optional path DWORD dwFlags : Permission flags Return Value: HRESULT --*/ { ASSURE_PROPER_INTERFACE(); if (m_hKey != NULL) { TRACEEOLID("Attempting to open key that already has an open handle"); ASSERT(FALSE); TRACEEOLID("Closing that key"); Close(); } // // Base key is stored for reopen purposes only // m_hBase = hkBase; m_strMetaPath = lpszMDPath; m_dwFlags = dwFlags; return OpenKey(m_hBase, m_strMetaPath, m_dwFlags, &m_hKey); } HRESULT CMetaKey::Open( IN DWORD dwFlags, IN LPCTSTR lpSvc, OPTIONAL IN DWORD dwInstance, OPTIONAL IN LPCTSTR lpParentPath, OPTIONAL IN LPCTSTR lpAlias OPTIONAL ) /*++ Routine Description: Build metapath from components, and open key Arguments: Return Value: HRESULT --*/ { m_hBase = METADATA_MASTER_ROOT_HANDLE; BuildMetaPath(m_strMetaPath, lpSvc, dwInstance, lpParentPath, lpAlias); return Open(dwFlags, m_hBase, m_strMetaPath); } HRESULT CMetaKey::ConvertToParentPath( IN BOOL fImmediate ) /*++ Routine Description: Change the path to the parent path. Arguments: BOOL fImmediate : If TRUE, the immediate parent's path will be used if FALSE, the first parent that really exists Return Value: HRESULT ERROR_INVALID_PARAMETER if there is no valid path --*/ { BOOL fIsOpen = IsOpen(); if (fIsOpen) { Close(); } CError err; FOREVER { if (!ConvertToParentPath(m_strMetaPath)) { // // There is no parent path // err = ERROR_INVALID_PARAMETER; break; } err = ReOpen(); // // Path not found is the only valid error // other than success. // if (fImmediate || err.Succeeded() || err.Win32Error() != ERROR_PATH_NOT_FOUND) { break; } } // // Remember to reset the construction error // which referred to the parent path. // m_hrKey = err; return err; } HRESULT CMetaKey::CreatePathFromFailedOpen() /*++ Routine Description: If the path doesn't exist, create it. This method should be called after an Open call failed (because it will have initialized m_strMetaPath. Arguments: None Return Value: HRESULT --*/ { CString strParentPath; CString strObjectName; CString strSavePath(m_strMetaPath); SplitMetaPathAtInstance( m_strMetaPath, strParentPath, strObjectName ); CError err(Open( METADATA_PERMISSION_WRITE, METADATA_MASTER_ROOT_HANDLE, strParentPath )); if (err.Succeeded()) { // // This really should never fail, because we're opening // the path at the instance. // err = AddKey(strObjectName); } if (IsOpen()) { Close(); } // // The previous open wiped out the path... // m_strMetaPath = strSavePath; return err; } HRESULT CMetaKey::Close() /*++ Routine Description: Close the currently open key. Arguments: N/A Return Value: N/A --*/ { ASSURE_PROPER_INTERFACE(); HRESULT hr = S_OK; ASSERT(m_hKey != NULL); ASSERT(m_fOwnKey); if (m_hKey) { hr = CloseKey(m_hKey); if (SUCCEEDED(hr)) { m_hKey = NULL; } } return hr; } /* protected */ HRESULT CMetaKey::GetPropertyValue( IN DWORD dwID, OUT IN DWORD & dwSize, OPTIONAL OUT IN void *& pvData, OPTIONAL OUT IN DWORD * pdwDataType, OPTIONAL IN BOOL * pfInheritanceOverride, OPTIONAL IN LPCTSTR lpszMDPath, OPTIONAL OUT DWORD * pdwAttributes OPTIONAL ) /*++ Routine Description: Get metadata on the currently open key. Arguments: DWORD dwID : Property ID number DWORD & dwSize : Buffer size (could be 0) void *& pvData : Buffer -- will allocate if NULL DWORD * pdwDataType : NULL or on in contains valid data types, : on out contains actual data type BOOL * pfInheritanceOverride : NULL or on forces inheritance on/off LPCTSTR lpszMDPath : Optional path off the open key DWORD * pdwAttributes : Optionally returns attributes Return Value: HRESULT ERROR_INVALID_HANDLE : If the handle is not open ERROR_INVALID_PARAMETER : If the property id is not found, or the data type doesn't match requested type ERROR_OUTOFMEMORY : Out of memory --*/ { ASSURE_PROPER_INTERFACE(); ASSURE_OPEN_KEY(); METADATA_RECORD mdRecord; FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord); // // If unable to find this property ID in our table, or // if we specified a desired type, and this type doesn't // match it, give up. // if (pdwDataType && *pdwDataType != ALL_METADATA && *pdwDataType != mdRecord.dwMDDataType) { ASSERT(FALSE); return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); } // // Check to see if inheritance behaviour is overridden // if (pfInheritanceOverride) { if (*pfInheritanceOverride) { mdRecord.dwMDAttributes |= METADATA_INHERIT; } else { mdRecord.dwMDAttributes &= ~METADATA_INHERIT; } } // // This causes a bad parameter error on input otherwise // mdRecord.dwMDAttributes &= ~METADATA_REFERENCE; // // If we're looking for inheritable properties, the path // doesn't have to be completely specified. // if (mdRecord.dwMDAttributes & METADATA_INHERIT) { mdRecord.dwMDAttributes |= (METADATA_PARTIAL_PATH | METADATA_ISINHERITED); } ASSERT(dwSize > 0 || pvData == NULL); mdRecord.dwMDDataLen = dwSize; mdRecord.pbMDData = (LPBYTE)pvData; // // If no buffer provided, allocate one. // HRESULT hr = S_OK; BOOL fBufferTooSmall; BOOL fAllocatedMemory = FALSE; DWORD dwInitSize = m_cbInitialBufferSize; do { if(mdRecord.pbMDData == NULL) { mdRecord.dwMDDataLen = dwInitSize; mdRecord.pbMDData = (LPBYTE)AllocMem(dwInitSize); if(mdRecord.pbMDData == NULL && dwInitSize > 0) { hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY); break; } ++fAllocatedMemory; } // // Get the data // DWORD dwRequiredDataLen = 0; hr = GetData(m_hKey, lpszMDPath, &mdRecord, &dwRequiredDataLen); // // Re-fetch the buffer if it's too small. // fBufferTooSmall = (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER) && fAllocatedMemory; if(fBufferTooSmall) { // // Delete the old buffer, and set up for a re-fetch. // FreeMem(mdRecord.pbMDData); mdRecord.pbMDData = NULL; dwInitSize = dwRequiredDataLen; } } while(fBufferTooSmall); // // Failed // if(FAILED(hr) && fAllocatedMemory) { FreeMem(mdRecord.pbMDData); mdRecord.pbMDData = NULL; } dwSize = mdRecord.dwMDDataLen; pvData = mdRecord.pbMDData; if (pdwDataType != NULL) { // // Return actual data type // *pdwDataType = mdRecord.dwMDDataType; } if (pdwAttributes != NULL) { // // Return data attributes // *pdwAttributes = mdRecord.dwMDAttributes; } return hr; } /* protected */ HRESULT CMetaKey::GetDataPaths( OUT CStringListEx & strlDataPaths, IN DWORD dwMDIdentifier, IN DWORD dwMDDataType, IN LPCTSTR lpszMDPath OPTIONAL ) /*++ Routine Description: Get data paths Arguments: Return Value: HRESULT --*/ { ASSURE_PROPER_INTERFACE(); ASSURE_OPEN_KEY(); // // Start with a small buffer // DWORD dwMDBufferSize = 1024; LPTSTR lpszBuffer = NULL; CError err; do { if (lpszBuffer != NULL) { FreeMem(lpszBuffer); } lpszBuffer = AllocTString(dwMDBufferSize); if (lpszBuffer == NULL) { err = ERROR_NOT_ENOUGH_MEMORY; break; } err = CMetaInterface::GetDataPaths( m_hKey, lpszMDPath, dwMDIdentifier, dwMDDataType, dwMDBufferSize, lpszBuffer, &dwMDBufferSize ); } while(err.Win32Error() == ERROR_INSUFFICIENT_BUFFER); if (err.Succeeded() && (err.Win32Error() == ERROR_PATH_NOT_FOUND)) { // // That's ok... this is some sort of physical directory // that doesn't currently exist in the metabase, and // which therefore doesn't have any descendants anyway. // ZeroMemory(lpszBuffer, dwMDBufferSize); err.Reset(); } if (err.Succeeded()) { ConvertDoubleNullListToStringList(lpszBuffer, strlDataPaths); FreeMem(lpszBuffer); } return err; } HRESULT CMetaKey::CheckDescendants( IN DWORD dwID, IN LPCTSTR lpszServer, IN LPCTSTR lpszMDPath OPTIONAL ) /*++ Routine Description: Check for descendant overrides; If there are any, bring up a dialog that displays them, and give the user the opportunity the remove the overrides. Arguments: DWORD dwID : Property ID Return Value: HRESULT --*/ { ASSURE_PROPER_INTERFACE(); HRESULT hr = S_OK; METADATA_RECORD mdRecord; FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord); if (mdRecord.dwMDAttributes & METADATA_INHERIT) { CStringListEx strlDataPaths; hr = GetDataPaths( strlDataPaths, mdRecord.dwMDIdentifier, mdRecord.dwMDDataType, lpszMDPath ); if (SUCCEEDED(hr) && !strlDataPaths.IsEmpty()) { CInheritanceDlg dlg( dwID, FROM_WRITE_PROPERTY, lpszServer, lpszMDPath, strlDataPaths ); if (!dlg.IsEmpty()) { dlg.DoModal(); } } } return hr; } /* protected */ HRESULT CMetaKey::SetPropertyValue( IN DWORD dwID, IN DWORD dwSize, IN void * pvData, IN BOOL * pfInheritanceOverride, OPTIONAL IN LPCTSTR lpszMDPath OPTIONAL ) /*++ Routine Description: Set metadata on the open key. The key must have been opened with write permission. Arguments: DWORD dwID : Property ID DWORD dwSize : Size of data void * pvData : Data buffer BOOL * pfInheritanceOverride : NULL or forces inheritance on/off LPCTSTR lpszMDPath : Optional path off the open key Return Value: HRESULT ERROR_INVALID_HANDLE : If the handle is not open ERROR_INVALID_PARAMETER : If the property id is not found, or the buffer is NULL or of size 0 --*/ { ASSURE_PROPER_INTERFACE(); ASSURE_OPEN_KEY(); if (pvData == NULL && dwSize != 0) { ASSERT(FALSE); return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); } METADATA_RECORD mdRecord; FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord); if (pfInheritanceOverride) { if (*pfInheritanceOverride) { mdRecord.dwMDAttributes |= METADATA_INHERIT; } else { mdRecord.dwMDAttributes &= ~METADATA_INHERIT; } } mdRecord.dwMDDataLen = dwSize; mdRecord.pbMDData = (LPBYTE)pvData; return SetData(m_hKey, lpszMDPath, &mdRecord); } /* protected */ HRESULT CMetaKey::GetAllData( IN DWORD dwMDAttributes, IN DWORD dwMDUserType, IN DWORD dwMDDataType, OUT DWORD * pdwMDNumEntries, OUT DWORD * pdwMDDataLen, OUT PBYTE * ppbMDData, IN LPCTSTR lpszMDPath OPTIONAL ) /*++ Routine Description: Get all data off the open key. Buffer is created automatically. Arguments: DWORD dwMDAttributes : Attributes DWORD dwMDUserType : User type to fetch DWORD dwMDDataType : Data type to fetch DWORD * pdwMDNumEntries : Returns number of entries read DWORD * pdwMDDataLen : Returns size of data buffer PBYTE * ppbMDData : Returns data buffer LPCTSTR lpszMDPath : Optional data path Return Value: HRESULT --*/ { ASSURE_PROPER_INTERFACE(); ASSURE_OPEN_KEY(); // // Check for valid parameters // if(!pdwMDDataLen || !ppbMDData || !pdwMDNumEntries) { return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); } HRESULT hr = S_OK; BOOL fBufferTooSmall; DWORD dwMDDataSetNumber; DWORD dwRequiredBufferSize; DWORD dwInitSize = m_cbInitialBufferSize; *ppbMDData = NULL; do { *pdwMDDataLen = dwInitSize; *ppbMDData = (LPBYTE)AllocMem(dwInitSize); if (ppbMDData == NULL && dwInitSize > 0) { hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY); break; } hr = CMetaInterface::GetAllData( m_hKey, lpszMDPath, dwMDAttributes, dwMDUserType, dwMDDataType, pdwMDNumEntries, &dwMDDataSetNumber, *pdwMDDataLen, *ppbMDData, &dwRequiredBufferSize ); // // Re-fetch the buffer if it's too small. // fBufferTooSmall = (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER); if(fBufferTooSmall) { // // Delete the old buffer, and set up for a re-fetch. // SAFE_FREEMEM(*ppbMDData); dwInitSize = dwRequiredBufferSize; } } while (fBufferTooSmall); if (FAILED(hr)) { // // No good, be sure we don't leak anything // SAFE_FREEMEM(*ppbMDData); dwInitSize = 0L; } return hr; } HRESULT CMetaKey::QueryValue( IN DWORD dwID, IN OUT DWORD & dwValue, IN BOOL * pfInheritanceOverride, OPTIONAL IN LPCTSTR lpszMDPath, OPTIONAL OUT DWORD * pdwAttributes OPTIONAL ) /*++ Routine Description: Fetch data as a DWORD Arguments: DWORD dwID : Property ID DWORD & dwValue : Returns the value read in BOOL * pfInheritanceOverride : NULL or forces inheritance on/off LPCTSTR lpszMDPath : Optional path off the open key DWORD * pdwAttributes : Optionally returns attributes Return Value: HRESULT --*/ { DWORD dwSize = sizeof(dwValue); DWORD dwDataType = DWORD_METADATA; void * pvData = &dwValue; return GetPropertyValue( dwID, dwSize, pvData, &dwDataType, pfInheritanceOverride, lpszMDPath, pdwAttributes ); } HRESULT CMetaKey::QueryValue( IN DWORD dwID, IN OUT CString & strValue, IN BOOL * pfInheritanceOverride, OPTIONAL IN LPCTSTR lpszMDPath, OPTIONAL OUT DWORD * pdwAttributes OPTIONAL ) /*++ Routine Description: Fetch data as a string Arguments: DWORD dwID : Property ID DWORD & strValue : Returns the value read in BOOL * pfInheritanceOverride : NULL or forces inheritance on/off LPCTSTR lpszMDPath : Optional path off the open key DWORD * pdwAttributes : Optionally returns attributes Return Value: HRESULT --*/ { // // Get GetData allocate the buffer for us // DWORD dwSize = 0; DWORD dwDataType = ALL_METADATA; LPTSTR lpData = NULL; HRESULT hr = GetPropertyValue( dwID, dwSize, (void *&)lpData, &dwDataType, pfInheritanceOverride, lpszMDPath, pdwAttributes ); if (SUCCEEDED(hr)) { // // Notes: consider optional auto-expansion on EXPANDSZ_METADATA // (see registry functions), and data type conversions for DWORD // or MULTISZ_METADATA or BINARY_METADATA // if (dwDataType == EXPANDSZ_METADATA || dwDataType == STRING_METADATA) { try { strValue = lpData; } catch(CMemoryException * e) { hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); strValue.Empty(); e->Delete(); } } else { hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); } } if (lpData) { FreeMem(lpData); } return hr; } HRESULT CMetaKey::QueryValue( IN DWORD dwID, IN OUT CStringListEx & strlValue, IN BOOL * pfInheritanceOverride, OPTIONAL IN LPCTSTR lpszMDPath, OPTIONAL OUT DWORD * pdwAttributes OPTIONAL ) /*++ Routine Description: Fetch data as a stringlist Arguments: DWORD dwID : Property ID DWORD & strlValue : Returns the value read in BOOL * pfInheritanceOverride : NULL or forces inheritance on/off LPCTSTR lpszMDPath : Optional path off the open key DWORD * pdwAttributes : Optionally returns attributes Return Value: HRESULT --*/ { // // Get GetData allocate the buffer for us // DWORD dwSize = 0; DWORD dwDataType = MULTISZ_METADATA; LPTSTR lpData = NULL; HRESULT hr = GetPropertyValue( dwID, dwSize, (void *&)lpData, &dwDataType, pfInheritanceOverride, lpszMDPath, pdwAttributes ); if (SUCCEEDED(hr)) { // // Notes: Consider accepting a single STRING // ASSERT(dwDataType == MULTISZ_METADATA); DWORD err = ConvertDoubleNullListToStringList( lpData, strlValue, dwSize / sizeof(TCHAR) ); hr = HRESULT_FROM_WIN32(err); } if (lpData) { FreeMem(lpData); } return hr; } HRESULT CMetaKey::QueryValue( IN DWORD dwID, IN OUT CBlob & blValue, IN BOOL * pfInheritanceOverride, OPTIONAL IN LPCTSTR lpszMDPath, OPTIONAL OUT DWORD * pdwAttributes OPTIONAL ) /*++ Routine Description: Fetch data as a binary blob Arguments: DWORD dwID : Property ID DWORD CBlob & blValue : Returns the binary blob BOOL * pfInheritanceOverride : NULL or forces inheritance on/off LPCTSTR lpszMDPath : Optional path off the open key DWORD * pdwAttributes : Optionally returns attributes Return Value: HRESULT --*/ { // // Get GetData allocate the buffer for us // DWORD dwSize = 0; DWORD dwDataType = BINARY_METADATA; LPBYTE pbData = NULL; HRESULT hr = GetPropertyValue( dwID, dwSize, (void *&)pbData, &dwDataType, pfInheritanceOverride, lpszMDPath, pdwAttributes ); if (SUCCEEDED(hr)) { // // Blob takes ownership of the data, so don't free it... // ASSERT(pbData != NULL); blValue.SetValue(dwSize, pbData, FALSE); } return hr; } HRESULT CMetaKey::SetValue( IN DWORD dwID, IN CStringListEx & strlValue, IN BOOL * pfInheritanceOverride, OPTIONAL IN LPCTSTR lpszMDPath OPTIONAL ) /*++ Routine Description: Store data as string Arguments: DWORD dwID : Property ID CStringListEx & strlValue : Value to be written BOOL * pfInheritanceOverride : NULL or forces inheritance on/off LPCTSTR lpszMDPath : Optional path (or NULL or "") Return Value: HRESULT --*/ { DWORD cCharacters; LPTSTR lpstr = NULL; // // Flatten value // ConvertStringListToDoubleNullList( strlValue, cCharacters, lpstr ); HRESULT hr = SetPropertyValue( dwID, cCharacters * sizeof(TCHAR), (void *)lpstr, pfInheritanceOverride, lpszMDPath ); SAFE_FREEMEM(lpstr); return hr; } HRESULT CMetaKey::SetValue( IN DWORD dwID, IN CBlob & blValue, IN BOOL * pfInheritanceOverride, OPTIONAL IN LPCTSTR lpszMDPath OPTIONAL ) /*++ Routine Description: Store data as binary Arguments: DWORD dwID : Property ID CBlob & blValue : Value to be written BOOL * pfInheritanceOverride : NULL or forces inheritance on/off LPCTSTR lpszMDPath : Optional path (or NULL or "") Return Value: HRESULT --*/ { return SetPropertyValue( dwID, blValue.GetSize(), (void *)blValue.GetData(), pfInheritanceOverride, lpszMDPath ); } HRESULT CMetaKey::DeleteValue( DWORD dwID, LPCTSTR lpszMDPath OPTIONAL ) /*++ Routine Description: Delete data Arguments: DWORD dwID : Property ID of property to be deleted LPCTSTR lpszMDPath : Optional path (or NULL or "") Return Value: HRESULT --*/ { ASSURE_PROPER_INTERFACE(); ASSURE_OPEN_KEY(); METADATA_RECORD mdRecord; FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord); return DeleteData( m_hKey, lpszMDPath, mdRecord.dwMDIdentifier, mdRecord.dwMDDataType ); } HRESULT CMetaKey::DoesPathExist( IN LPCTSTR lpszMDPath ) /*++ Routine Description: Determine if the path exists Arguments: LPCTSTR lpszMDPath : Relative path off the open key Return Value: HRESULT, or S_OK if the path exists. --*/ { ASSURE_PROPER_INTERFACE(); ASSURE_OPEN_KEY(); FILETIME ft; return GetLastChangeTime(m_hKey, lpszMDPath, &ft, FALSE); } // // CMetaEnumerator Clas // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CMetaEnumerator::CMetaEnumerator( IN LPCTSTR lpszServerName, IN LPCTSTR lpSvc, OPTIONAL IN DWORD dwInstance, OPTIONAL IN LPCTSTR lpParentPath, OPTIONAL IN LPCTSTR lpAlias OPTIONAL ) /*++ Routine Description: Construct a new interface Arguments: LPCTSTR lpszServerName : Server name LPCTSTR lpSvc : Service name or NULL DWORD dwInstance, : Instance number of 0 LPCTSTR lpParentPath : Parent path or NULL LPCTSTR lpAlias : Alias name or NULL Return Value: N/A --*/ : CMetaKey( lpszServerName, METADATA_PERMISSION_READ, lpSvc, dwInstance, lpParentPath, lpAlias ), m_dwIndex(0L) { } CMetaEnumerator::CMetaEnumerator( IN CMetaInterface * pInterface, IN LPCTSTR lpSvc, OPTIONAL IN DWORD dwInstance, OPTIONAL IN LPCTSTR lpParentPath, OPTIONAL IN LPCTSTR lpAlias OPTIONAL ) /*++ Routine Description: Construct with existing interface Arguments: CMetaInterface * pInterface : Interface LPCTSTR lpSvc : Service name or NULL DWORD dwInstance, : Instance number of 0 LPCTSTR lpParentPath : Parent path or NULL LPCTSTR lpAlias : Alias name or NULL Return Value: N/A --*/ : CMetaKey( pInterface, METADATA_PERMISSION_READ, lpSvc, dwInstance, lpParentPath, lpAlias ), m_dwIndex(0L) { } HRESULT CMetaEnumerator::Next( OUT CString & strKey, IN LPCTSTR lpszMDPath OPTIONAL ) /*++ Routine Description: Get the next subkey Arguments: CString & str Returns keyname LPCTSTR lpszMDPath Optional subpath Return Value: HRESULT --*/ { ASSURE_PROPER_INTERFACE(); ASSURE_OPEN_KEY(); LPTSTR lpKey = strKey.GetBuffer(MAX_PATH); HRESULT hr = EnumKeys(m_hKey, lpszMDPath, lpKey, m_dwIndex++); strKey.ReleaseBuffer(); return hr; } HRESULT CMetaEnumerator::Next( OUT DWORD & dwKey, IN LPCTSTR lpszMDPath OPTIONAL ) /*++ Routine Description: Get the next subkey as a DWORD. This skips non-numeric keynames (including 0) until the first numeric key name Arguments: DWORD & dwKey Numeric key LPCTSTR lpszMDPath Optional subpath Return Value: HRESULT --*/ { ASSURE_PROPER_INTERFACE(); ASSURE_OPEN_KEY(); HRESULT hr; BOOL fContinue = TRUE; CString strKey; while (fContinue) { fContinue = FALSE; LPTSTR lpKey = strKey.GetBuffer(MAX_PATH); hr = EnumKeys(m_hKey, lpszMDPath, lpKey, m_dwIndex++); strKey.ReleaseBuffer(); if (SUCCEEDED(hr)) { if (!(dwKey = _ttoi((LPCTSTR)strKey))) { // // Ignore this one // fContinue = TRUE; } } } return hr; } // // CIISApplication class // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<