/*++ Copyright (c) 1994-2001 Microsoft Corporation Module Name : mdkeys.cpp Abstract: Metabase key wrapper class Author: Ronald Meijer (ronaldm) Sergei Antonov (sergeia) Project: Internet Services Manager Revision History: --*/ #include "stdafx.h" #include "common.h" #include "idlg.h" #include "mdkeys.h" #include "iisdebug.h" #include "SiteCreator.h" #ifdef _DEBUG #undef THIS_FILE static char BASED_CODE THIS_FILE[] = __FILE__; #endif #define new DEBUG_NEW extern HINSTANCE hDLLInstance; // // Constants // #define MB_TIMEOUT (15000) // Timeout in milliseconds #define MB_INIT_BUFF_SIZE ( 256) // Initial buffer size // // CComAuthInfo implementation // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< /* static */ BOOL CComAuthInfo::SplitUserNameAndDomain( IN OUT CString & strUserName, IN CString & strDomainName ) /*++ Routine Description: Split the user name and domain from the given username, which is in the format "domain\user". Return TRUE if the user name contained a domain FALSE if it did not Arguments: CString & strUserName : User name which may contain a domain name CString & strDomainName : Output domain name ("." if local) Return Value: TRUE if a domain is split off --*/ { // // Assume local // strDomainName = _T("."); int nSlash = strUserName.Find(_T("\\")); if (nSlash >= 0) { strDomainName = strUserName.Left(nSlash); strUserName = strUserName.Mid(nSlash + 1); return TRUE; } return FALSE; } /* static */ DWORD CComAuthInfo::VerifyUserPassword( IN LPCTSTR lpstrUserName, IN LPCTSTR lpstrPassword ) /*++ Routine Description: Verify the usernamer password combo checks out Arguments: LPCTSTR lpstrUserName : Domain/username combo LPCTSTR lpstrPassword : Password Return Value: ERROR_SUCCESS if the password checks out, an error code otherwise. --*/ { CString strDomain; CString strUser(lpstrUserName); CString strPassword(lpstrPassword); SplitUserNameAndDomain(strUser, strDomain); // // In order to look up an account name, this process // must first be granted the privilege of doing so. // CError err; #if 0 { HANDLE hToken; LUID AccountLookupValue; TOKEN_PRIVILEGES tkp; do { // sounds like it doesn't required for Whistler if (!::OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken) ) { err.GetLastWinError(); break; } if (!::LookupPrivilegeValue(NULL, SE_TCB_NAME, &AccountLookupValue)) { err.GetLastWinError(); break; } tkp.PrivilegeCount = 1; tkp.Privileges[0].Luid = AccountLookupValue; tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; ::AdjustTokenPrivileges( hToken, FALSE, &tkp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL ); err.GetLastWinError(); if (err.Failed()) { break; } HANDLE hUser = NULL; if (::LogonUser( strUser.GetBuffer(0), strDomain.GetBuffer(0), strPassword.GetBuffer(0), LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &hUser )) { // // Success! // CloseHandle(hUser); } else { err.GetLastWinError(); } // // Remove the privilege // } while(FALSE); } #endif HANDLE hUser = NULL; if (::LogonUser( strUser.GetBuffer(0), strDomain.GetBuffer(0), strPassword.GetBuffer(0), LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &hUser)) { // // Success! // CloseHandle(hUser); } else { err.GetLastWinError(); } return err; } CComAuthInfo::CComAuthInfo( IN LPCOLESTR lpszServerName OPTIONAL, IN LPCOLESTR lpszUserName OPTIONAL, IN LPCOLESTR lpszPassword OPTIONAL ) /*++ Routine Description: Construct CIIServer object Argument: LPCOLESTR lpszServerName : Server name or NULL for local computer LPCOLESTR lpszUserName : User name of blank for no impersonation LPCOLESTR lpszPassword : Password (might be blank or NULL) Return Value: N/A --*/ : m_bstrServerName(), m_bstrUserName(lpszUserName), m_bstrPassword(lpszPassword), m_fLocal(FALSE) { SetComputerName(lpszServerName); } CComAuthInfo::CComAuthInfo( IN CComAuthInfo & auth ) /*++ Routine Description: Copy constructor Arguments: CComAuthInfo & auth : Source object to copy from Return Value: N/A --*/ : m_bstrServerName(auth.m_bstrServerName), m_bstrUserName(auth.m_bstrUserName), m_bstrPassword(auth.m_bstrPassword), m_fLocal(auth.m_fLocal) { } CComAuthInfo::CComAuthInfo( IN CComAuthInfo * pAuthInfo OPTIONAL ) /*++ Routine Description: Copy constructor Arguments: CComAuthInfo * pAuthInfo : Source object to copy from (or NULL) Return Value: N/A --*/ : m_bstrServerName(), m_bstrUserName(), m_bstrPassword(), m_fLocal(FALSE) { if (pAuthInfo) { // // Full authentication information available // m_bstrUserName = pAuthInfo->m_bstrUserName; m_bstrPassword = pAuthInfo->m_bstrPassword; m_bstrServerName = pAuthInfo->m_bstrServerName; m_fLocal = pAuthInfo->m_fLocal; } else { // // Local computer w/o impersonation // SetComputerName(NULL); } } CComAuthInfo & CComAuthInfo::operator =( IN CComAuthInfo & auth ) /*++ Routine Description: Assignment operator Arguments: CComAuthInfo & auth : Source object to copy from Return Value: Reference to current object --*/ { m_bstrServerName = auth.m_bstrServerName; m_bstrUserName = auth.m_bstrUserName; m_bstrPassword = auth.m_bstrPassword; m_fLocal = auth.m_fLocal; return *this; } CComAuthInfo & CComAuthInfo::operator =( IN CComAuthInfo * pAuthInfo OPTIONAL ) /*++ Routine Description: Assignment operator Arguments: CComAuthInfo * pAuthInfo : Source object to copy from (or NULL) Return Value: Reference to current object --*/ { if (pAuthInfo) { m_bstrUserName = pAuthInfo->m_bstrUserName; m_bstrPassword = pAuthInfo->m_bstrPassword; SetComputerName(pAuthInfo->m_bstrServerName); } else { // // Local computer w/o impersonation // m_bstrUserName.Empty(); m_bstrPassword.Empty(); SetComputerName(NULL); } return *this; } CComAuthInfo & CComAuthInfo::operator =( IN LPCTSTR lpszServerName ) /*++ Routine Description: Assignment operator. Assign computer name w/o impersonation Arguments: LPCTSTR lpszServerName : Source server name Return Value: Reference to current object --*/ { RemoveImpersonation(); SetComputerName(lpszServerName); return *this; } void CComAuthInfo::SetComputerName( IN LPCOLESTR lpszServerName OPTIONAL ) /*++ Routine Description: Store the computer name. Determine if its local. Arguments: LPCOLESTR lpszServername : Server name. NULL indicates the local computer Return Value: None --*/ { if (lpszServerName && *lpszServerName) { // // Specific computer name specified // m_bstrServerName = lpszServerName; m_fLocal = ::IsServerLocal(lpszServerName); } else { // // Use local computer name // // CODEWORK: Cache static version of computername maybe? // TCHAR szLocalServer[MAX_PATH + 1]; DWORD dwSize = MAX_PATH; VERIFY(::GetComputerName(szLocalServer, &dwSize)); m_bstrServerName = szLocalServer; m_fLocal = TRUE; } } void CComAuthInfo::SetImpersonation( IN LPCOLESTR lpszUser, IN LPCOLESTR lpszPassword ) /*++ Routine Description: Set impersonation parameters Arguments: LPCOLESTR lpszUser : User name LPCOLESTR lpszPassword : Password Return Value: None --*/ { m_bstrUserName = lpszUser; StorePassword(lpszPassword); } void CComAuthInfo::RemoveImpersonation() /*++ Routine Description: Remove impersonation parameters Arguments: None Return Value: None --*/ { m_bstrUserName.Empty(); m_bstrPassword.Empty(); } COSERVERINFO * CComAuthInfo::CreateServerInfoStruct() const { return (CComAuthInfo::CreateServerInfoStruct(RPC_C_AUTHN_LEVEL_DEFAULT)); } COSERVERINFO * CComAuthInfo::CreateServerInfoStruct(DWORD dwAuthnLevel) const /*++ Routine Description: Create the server info structure. Might return NULL for the no frills case. Arguments: NULL Return Value: A COSERVERINFO structure, or NULL if the computer is local, and no impersonation is required. Notes: Caller must call FreeServerInfoStruct() to prevent memory leaks --*/ { // // Be smart about the server name; optimize for local // computer name. // if (m_fLocal && !UsesImpersonation()) { // // Special, no-frills case. // return NULL; } // // Create the COM server info for CoCreateInstanceEx // COSERVERINFO * pcsiName = NULL; do { pcsiName = (COSERVERINFO *)AllocMem(sizeof(COSERVERINFO)); if (!pcsiName) { break; } pcsiName->pwszName = m_bstrServerName; // // Set impersonation // if (UsesImpersonation()) { COAUTHINFO * pAuthInfo = (COAUTHINFO *)AllocMem(sizeof(COAUTHINFO)); if (!pAuthInfo) { break; } COAUTHIDENTITY * pAuthIdentityData = (COAUTHIDENTITY *)AllocMem(sizeof(COAUTHIDENTITY)); if (!pAuthIdentityData) { break; } CString strUserName(m_bstrUserName); CString strPassword(m_bstrPassword); CString strDomain; // // Break up domain\username combo // SplitUserNameAndDomain(strUserName, strDomain); pAuthIdentityData->UserLength = strUserName.GetLength(); if (pAuthIdentityData->UserLength) { pAuthIdentityData->User = AllocString( strUserName, strUserName.GetLength() ); } pAuthIdentityData->DomainLength = strDomain.GetLength(); if (pAuthIdentityData->DomainLength) { pAuthIdentityData->Domain = AllocString( strDomain, strDomain.GetLength() ); } pAuthIdentityData->PasswordLength = strPassword.GetLength(); if (pAuthIdentityData->PasswordLength) { pAuthIdentityData->Password = AllocString( strPassword, strPassword.GetLength() ); } // RPC_C_AUTHN_LEVEL_DEFAULT 0 // RPC_C_AUTHN_LEVEL_NONE 1 // RPC_C_AUTHN_LEVEL_CONNECT 2 // RPC_C_AUTHN_LEVEL_CALL 3 // RPC_C_AUTHN_LEVEL_PKT 4 // RPC_C_AUTHN_LEVEL_PKT_INTEGRITY 5 // RPC_C_AUTHN_LEVEL_PKT_PRIVACY 6 if (RPC_C_AUTHN_LEVEL_DEFAULT != dwAuthnLevel) { // you can only specify stuff stronger than RPC_C_AUTHN_LEVEL_CONNECT if (dwAuthnLevel >= RPC_C_AUTHN_LEVEL_CONNECT && dwAuthnLevel <= RPC_C_AUTHN_LEVEL_PKT_PRIVACY) { pAuthInfo->dwAuthnLevel = dwAuthnLevel; } else { pAuthInfo->dwAuthnLevel = RPC_C_AUTHN_LEVEL_CONNECT; } } else { pAuthInfo->dwAuthnLevel = RPC_C_AUTHN_LEVEL_DEFAULT; } pAuthIdentityData->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; pAuthInfo->dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE; pAuthInfo->dwAuthnSvc = RPC_C_AUTHN_WINNT; pAuthInfo->dwAuthzSvc = RPC_C_AUTHZ_NONE; pAuthInfo->pwszServerPrincName = NULL; pAuthInfo->dwCapabilities = EOAC_NONE; pAuthInfo->pAuthIdentityData = pAuthIdentityData; pcsiName->pAuthInfo = pAuthInfo; } } while(FALSE); return pcsiName; } void CComAuthInfo::FreeServerInfoStruct( IN COSERVERINFO * pServerInfo ) const /*++ Routine Description: As mentioned above -- free the server info structure Arguments: COSERVERINFO * pServerInfo : Server info structure Return Value: None --*/ { if (pServerInfo) { if (pServerInfo->pAuthInfo) { if (pServerInfo->pAuthInfo->pAuthIdentityData) { if (pServerInfo->pAuthInfo->pAuthIdentityData) { SAFE_FREEMEM(pServerInfo->pAuthInfo->pAuthIdentityData->User); SAFE_FREEMEM(pServerInfo->pAuthInfo->pAuthIdentityData->Domain); SAFE_FREEMEM(pServerInfo->pAuthInfo->pAuthIdentityData->Password); FreeMem(pServerInfo->pAuthInfo->pAuthIdentityData); } } FreeMem(pServerInfo->pAuthInfo); } FreeMem(pServerInfo); } } HRESULT CComAuthInfo::ApplyProxyBlanket( IN OUT IUnknown * pInterface ) /*++ Routine Description: Set security information on the interface. The user name is of the form domain\username. Arguments: IUnknown * pInterface : Interface Return Value: HRESULT --*/ { HRESULT hr = S_OK; COSERVERINFO * pcsiName = CreateServerInfoStruct(); // // This method should only be called if we're using impersonation. // so the pcsiName returned should never be NULL. // // ASSERT(pcsiName && pcsiName->pAuthInfo); if (pcsiName && pcsiName->pAuthInfo) { hr = ::CoSetProxyBlanket( pInterface, pcsiName->pAuthInfo->dwAuthnSvc, pcsiName->pAuthInfo->dwAuthzSvc, pcsiName->pAuthInfo->pwszServerPrincName, pcsiName->pAuthInfo->dwAuthnLevel, pcsiName->pAuthInfo->dwImpersonationLevel, pcsiName->pAuthInfo->pAuthIdentityData, pcsiName->pAuthInfo->dwCapabilities ); FreeServerInfoStruct(pcsiName); } return hr; } HRESULT CComAuthInfo::ApplyProxyBlanket( IN OUT IUnknown * pInterface, IN DWORD dwAuthnLevel ) /*++ Routine Description: Set security information on the interface. The user name is of the form domain\username. Arguments: IUnknown * pInterface : Interface Return Value: HRESULT --*/ { HRESULT hr = S_OK; COSERVERINFO * pcsiName = CreateServerInfoStruct(dwAuthnLevel); // // This method should only be called if we're using impersonation. // so the pcsiName returned should never be NULL. // // ASSERT(pcsiName && pcsiName->pAuthInfo); if (pcsiName && pcsiName->pAuthInfo) { hr = ::CoSetProxyBlanket( pInterface, pcsiName->pAuthInfo->dwAuthnSvc, pcsiName->pAuthInfo->dwAuthzSvc, pcsiName->pAuthInfo->pwszServerPrincName, pcsiName->pAuthInfo->dwAuthnLevel, pcsiName->pAuthInfo->dwImpersonationLevel, pcsiName->pAuthInfo->pAuthIdentityData, pcsiName->pAuthInfo->dwCapabilities ); FreeServerInfoStruct(pcsiName); } return hr; } // // CMetabasePath implemention // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< const LPCTSTR CMetabasePath::_cszMachine = SZ_MBN_MACHINE; const LPCTSTR CMetabasePath::_cszRoot = SZ_MBN_ROOT; const LPCTSTR CMetabasePath::_cszSep = SZ_MBN_SEP_STR; const TCHAR CMetabasePath::_chSep = SZ_MBN_SEP_CHAR; /* static */ LPCTSTR CMetabasePath::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 --*/ { LPTSTR lpszPath = strMetaPath.GetBuffer(1); LPTSTR lpszTail = lpszPath + lstrlen(lpszPath) - 1; LPTSTR lpszReturn = NULL; do { if (lpszTail <= lpszPath) { break; } // // Strip trailing backslash // if (*lpszTail == _chSep) { *lpszTail-- = _T('\0'); } // // Search for parent // while (lpszTail > lpszPath && *lpszTail != _chSep) { --lpszTail; } if (lpszTail <= lpszPath) { break; } *lpszTail = _T('\0'); lpszReturn = lpszPath; } while(FALSE); strMetaPath.ReleaseBuffer(); return lpszReturn; } /* static */ LPCTSTR CMetabasePath::TruncatePath( IN int nLevel, IN LPCTSTR lpszMDPath, OUT CString & strNewPath, OUT CString * pstrRemainder OPTIONAL ) /*++ Routine Description: Truncate the given metabase path at the given level, that is, the nLevel'th separator in the path, starting at 0, where 0 will always give lpszPath back whether it started with a separator or not. Examples: "/lm/w3svc/1/foo" at level 2 returns "/lm/w3svc" as does "lm/w3svc/1/foo". Arguments: int nLevel 0-based separator count to truncate at. LPTSTR lpszMDPath Fully-qualified metabase path CString & strNewPath Returns truncated path CString * pstrRemainder Optionally returns the remainder past the nLevel'th separator. Return Value: The truncated path at the level requested. See examples above. *pstrRemainder returns the remainder of the path. If the path does not contain nLevel worth of separators, the entire path is returned, and the remainder will be blank. --*/ { ASSERT_PTR(lpszMDPath); ASSERT(nLevel >= 0); if (!lpszMDPath || nLevel < 0) { return NULL; } // // Skip the first sep whether it exists or not // LPCTSTR lp = *lpszMDPath == _chSep ? lpszMDPath + 1 : lpszMDPath; LPCTSTR lpRem = NULL; int cSeparators = 0; if (nLevel) { // // Advance to the requested separator level // while (*lp) { if (*lp == _chSep) { if (++cSeparators == nLevel) { break; } } ++lp; } if (!*lp) { // // End of path is considered a separator // ++cSeparators; } ASSERT(cSeparators <= nLevel); if (cSeparators == nLevel) { // // Break up the strings // strNewPath = lpszMDPath; strNewPath.ReleaseBuffer((int)(lp - lpszMDPath)); if (*lp) { lpRem = ++lp; } } } // // Return remainder // if (pstrRemainder && lpRem) { ASSERT_WRITE_PTR(pstrRemainder); *pstrRemainder = lpRem; } return strNewPath; } /* static */ DWORD CMetabasePath::GetInstanceNumber( IN LPCTSTR lpszMDPath ) /*++ Routine Description: Get the number of the instance referred to in the given metabase path. Examples: "lm/w3svc/1/foo/bar" will return 1 "lm/w3svc/" will return 0 (master instance) "lm/bogus/path/" will return 0xffffffff (error) Arguments: LPCTSTR lpszMDPath : A metabase path. Return Value: Instance number (0 indicates master instance) or 0xffffffff if the path is in error. --*/ { DWORD dwInstance = 0xffffffff; CString strService, strInst; if (GetServicePath(lpszMDPath, strService, &strInst)) { if (strInst.IsEmpty()) { dwInstance = MASTER_INSTANCE; } else { if (_istdigit(strInst.GetAt(0))) { dwInstance = _ttol(strInst); } } } return dwInstance; } /* static */ LPCTSTR CMetabasePath::GetLastNodeName( IN LPCTSTR lpszMDPath, OUT CString & strNodeName ) /*++ Routine Description: Get the last nodename off the metabase path Example: "/lm/foo/bar/" returns "bar" Arguments: LPCTSTR lpszMDPath : Metabase path Return Value: Pointer to the node name or NULL in case of a malformed path. --*/ { ASSERT_PTR(lpszMDPath); if (!lpszMDPath || !*lpszMDPath) { return NULL; } LPCTSTR lp; LPCTSTR lpTail; lp = lpTail = lpszMDPath + lstrlen(lpszMDPath) - 1; // // Skip trailing separator // if (*lp == _chSep) { --lpTail; --lp; } strNodeName.Empty(); while (*lp && *lp != _chSep) { strNodeName += *(lp--); } strNodeName.MakeReverse(); return strNodeName; } /* static */ void CMetabasePath::SplitMetaPathAtInstance( IN LPCTSTR lpszMDPath, 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 lpszMDPath : Input path CString & strParent : Outputs the parent path CString & strAlias : Outputs the alias name Return Value: None. --*/ { ASSERT_PTR(lpszMDPath); strParent = lpszMDPath; strAlias.Empty(); LPTSTR lp = strParent.GetBuffer(0); ASSERT_PTR(lp); if (!lp) { // // This is just about impossible // return; } int cSeparators = 0; int iChar = 0; // // Looking for "LM/sss/ddd/" <-- 3d slash: // while (*lp && cSeparators < 2) { if (*lp++ == _chSep) { ++cSeparators; } ++iChar; } if (!*lp) { // // Bogus format // ASSERT_MSG("Bogus Format"); return; } if (_istdigit(*lp)) { // // Not at the master instance, skip one more. // while (*lp) { ++iChar; if (*lp++ == _chSep) { break; } } if (!*lp) { // // Bogus format // ASSERT_MSG("Bogus Format"); return; } } strAlias = strParent.Mid(iChar); strParent.ReleaseBuffer(--iChar); } /* static */ BOOL CMetabasePath::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_READ_PTR(lpszMetaPath); LPTSTR lpNode = lpszMetaPath ? _tcsrchr(lpszMetaPath, _chSep) : NULL; if (lpNode) { return _tcsicmp(++lpNode, _cszRoot) == 0; } return FALSE; } /* static */ BOOL CMetabasePath::IsMasterInstance( IN LPCTSTR lpszMDPath ) /*++ Routine Description: Determine if the given metabase path points to the master instance (site). This is essentially the service path. Arguments: LPCTSTR lpszMDPath : Metabase path. Return Value: TRUE if the path is the master instance, FALSE otherwise. --*/ { ASSERT_READ_PTR(lpszMDPath); if (!lpszMDPath || !*lpszMDPath) { return FALSE; } CString strService; CString strRemainder; LPCTSTR lpPath = TruncatePath(2, lpszMDPath, strService, &strRemainder); return lpPath && !strService.IsEmpty() && strRemainder.IsEmpty(); } /* static */ LPCTSTR CMetabasePath::GetServiceInfoPath( IN LPCTSTR lpszMDPath, OUT CString & strInfoPath, IN LPCTSTR lpszDefService OPTIONAL ) /*++ Routine Description: Generate the appropriate metabase service info path for the given metabase path. For example: "lm/w3svc/1/foo/bar" Generates "lm/w3svc/info" Arguments: LPCTSTR lpszMDPath : Input metabase path CString & strInfoPath : Returns the info path LPCTSTR lpszDefService : Optionally specifies the default service to use (e.g "w3svc") if no service could be found in the path. Return Value: The info metabase path or NULL if one could not be generated. --*/ { // // Capability info stored off the service path ("lm/w3svc"). // CString strService; CString strRem; // // Strip off everything past the service // if (!TruncatePath(2, lpszMDPath, strService, &strRem) || strService.IsEmpty()) { if (!lpszDefService) { TRACEEOLID("Unable to generate info path"); return NULL; } // // Machine path (no service). Use web as default service to // look for capability and version info. // strService = CMetabasePath(TRUE, lpszDefService); } strInfoPath = CMetabasePath(FALSE, strService, SZ_MBN_INFO); return strInfoPath; } /* static */ LPCTSTR CMetabasePath::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 --*/ { if (!strMetaRoot.IsEmpty()) { if (strMetaRoot[strMetaRoot.GetLength() - 1] == _chSep) { strMetaRoot.ReleaseBuffer(strMetaRoot.GetLength() - 1); } if (!strMetaRoot.IsEmpty() && strMetaRoot[0] == _chSep) { strMetaRoot = strMetaRoot.Right(strMetaRoot.GetLength() - 1); } } return strMetaRoot; } CMetabasePath::CMetabasePath( IN BOOL fAddBasePath, IN LPCTSTR lpszMDPath, IN LPCTSTR lpszMDPath2 OPTIONAL, IN LPCTSTR lpszMDPath3 OPTIONAL, IN LPCTSTR lpszMDPath4 OPTIONAL ) /*++ Routine Description: Constructor. Arguments: BOOL fAddBasePath : TRUE to prepend base path ("LM") FALSE if the path is complete LPCTSTR lpszMDPath : Metabase path LPCTSTR lpszMDPath2 : Optional child path LPCTSTR lpszMDPath3 : Optional child path LPCTSTR lpszMDPath4 : Optional child path Return Value: N/A --*/ : m_strMetaPath() { ASSERT_READ_PTR(lpszMDPath); if (fAddBasePath) { m_strMetaPath = _cszMachine; AppendPath(lpszMDPath); } else { m_strMetaPath = lpszMDPath; } // // Add optional path components // AppendPath(lpszMDPath2); AppendPath(lpszMDPath3); AppendPath(lpszMDPath4); } CMetabasePath::CMetabasePath( IN LPCTSTR lpszSvc, OPTIONAL IN DWORD dwInstance, OPTIONAL IN LPCTSTR lpszParentPath, OPTIONAL IN LPCTSTR lpszAlias OPTIONAL ) /*++ Routine Description: Constructor. Construct with path components. Arguments: LPCTSTR lpszSvc : Service (may be NULL or "") DWORD dwInstance : Instance number (may be 0 for master) LPCTSTR lpszParentPath : Parent path (may be NULL or "") LPCTSTR lpszAlias : Alias (may be NULL or "") Return Value: N/A --*/ : m_strMetaPath() { BuildMetaPath(lpszSvc, dwInstance, lpszParentPath, lpszAlias); } void CMetabasePath::AppendPath( IN LPCTSTR lpszPath ) /*++ Routine Description: Append path to current metabase path Arguments: LPCTSTR lpszPath : Metabase path Return Value: None --*/ { if (lpszPath && *lpszPath) { m_strMetaPath += _cszSep; m_strMetaPath += lpszPath; } } void CMetabasePath::AppendPath( IN DWORD dwInstance ) /*++ Routine Description: Append path to current metabase path Arguments: DWORD dwInstance : Instance path Return Value: None --*/ { if (!IS_MASTER_INSTANCE(dwInstance)) { TCHAR szInstance[] = _T("4000000000"); _ltot(dwInstance, szInstance, 10); m_strMetaPath += _cszSep; m_strMetaPath += szInstance; } } void CMetabasePath::BuildMetaPath( IN LPCTSTR lpszSvc OPTIONAL, IN LPCTSTR lpszInstance OPTIONAL, IN LPCTSTR lpszParentPath OPTIONAL, IN LPCTSTR lpszAlias OPTIONAL ) /*++ Routine Description: Build a complete metapath with the given service name, instance number and optional path components. Arguments: LPCTSTR lpszSvc : Service (may be NULL or "") LPCTSTR lpszInstance : Instance (may be NULL or "") LPCTSTR lpszParentPath : Parent path (may be NULL or "") LPCTSTR lpszAlias : Alias (may be NULL or "") Return Value: Pointer to internal buffer containing the path. --*/ { m_strMetaPath = _cszMachine; AppendPath(lpszSvc); AppendPath(lpszInstance); AppendPath(lpszParentPath); if (lpszAlias && *lpszAlias) { // // Special case: If the alias is root, but we're // at the master instance, ignore this. // if (lpszInstance || ::lstrcmpi(_cszRoot, lpszAlias)) { m_strMetaPath += _cszSep; m_strMetaPath += lpszAlias; } } } void CMetabasePath::BuildMetaPath( IN LPCTSTR lpszSvc OPTIONAL, IN DWORD dwInstance OPTIONAL, IN LPCTSTR lpszParentPath OPTIONAL, IN LPCTSTR lpszAlias OPTIONAL ) /*++ Routine Description: Build a complete metapath with the given service name, instance number and optional path components. Arguments: LPCTSTR lpszSvc : Service (may be NULL or "") DWORD dwInstance : Instance number (may be 0 for master) LPCTSTR lpszParentPath : Parent path (may be NULL or "") LPCTSTR lpszAlias : Alias (may be NULL or "") Return Value: Pointer to internal buffer containing the path. --*/ { m_strMetaPath = _cszMachine; AppendPath(lpszSvc); AppendPath(dwInstance); AppendPath(lpszParentPath); if (lpszAlias && *lpszAlias) { // // Special case: If the alias is root, but we're // at the master instance, ignore this. // if (!IS_MASTER_INSTANCE(dwInstance) || ::lstrcmpi(_cszRoot, lpszAlias)) { m_strMetaPath += _cszSep; m_strMetaPath += lpszAlias; } } } // // CIISInterface class // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CIISInterface::CIISInterface( IN CComAuthInfo * pAuthInfo, OPTIONAL IN HRESULT hrInterface OPTIONAL ) /*++ Routine Description: Base class constructor. Arguments: CComAuthInfo * pAuthInfo : Auth info or NULL for local computer HRESULT hrInterface : Initial error code. S_OK by default. Return Value: N/A --*/ : m_auth(pAuthInfo), m_hrInterface(hrInterface) { } HRESULT CIISInterface::Create( IN int cInterfaces, IN const IID rgIID[], IN const GUID rgCLSID[], OUT int * pnInterface, OPTIONAL OUT IUnknown ** ppInterface ) /*++ Routine Description: Create interface. This will try a range of interfaces in order of priority. Arguments: int cInterfaces : Number of interfaces in array. const IID * rgIID : Array if IIDs const GUID * rgCLSID : Array of CLSIDs int * pnInterface : Returns the interface index that was successful. or NULL if not interested. IUnknown ** ppInterface : Returns pointer to the interface. Return Value: HRESULT Notes: This will attempt to create an interface, in order of declaration in the IID and CLSIS arrays. The first successful interface to be created will have its index returned in *pnInterfaces. --*/ { ASSERT(cInterfaces > 0); ASSERT(rgIID && rgCLSID && ppInterface); COSERVERINFO * pcsiName = m_auth.CreateServerInfoStruct(); MULTI_QI rgmqResults; CError err; int nInterface; ZeroMemory(&rgmqResults, sizeof(rgmqResults)); // // Try to create the interface in order // for (nInterface = 0; nInterface < cInterfaces; ++nInterface) { rgmqResults.pIID = &rgIID[nInterface]; err = ::CoCreateInstanceEx( rgCLSID[nInterface], NULL, CLSCTX_SERVER, pcsiName, 1, &rgmqResults ); if (err.Succeeded() || err.Win32Error() == ERROR_ACCESS_DENIED) { break; } ZeroMemory(&rgmqResults, sizeof(rgmqResults)); } if(err.Succeeded()) { // // Save the interface pointer // ASSERT_PTR(rgmqResults.pItf); *ppInterface = rgmqResults.pItf; if (pnInterface) { // // Store successful interface index // *pnInterface = nInterface; } // // Strangely enough, I now have still have to apply // the proxy blanket. Apparently this is by design. // if (m_auth.UsesImpersonation()) { ApplyProxyBlanket(); } } // // Clean up // m_auth.FreeServerInfoStruct(pcsiName); return err; } // // CMetaInterface class // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CMetaInterface::CMetaInterface( IN CComAuthInfo * pAuthInfo OPTIONAL ) /*++ Routine Description: Construct and initialize the interface Arguments: CComAuthInfo * pAuthInfo : Authentication info. NULL indicates the local computer. Return Value: N/A --*/ : CIISInterface(pAuthInfo), m_pInterface(NULL), m_iTimeOutValue(MB_TIMEOUT) { // // Initialize the interface // m_hrInterface = Create(); } CMetaInterface::CMetaInterface( IN 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 BUGBUG: if pInterface is NULL, this will AV. --*/ : CIISInterface(&pInterface->m_auth, pInterface->m_hrInterface), m_pInterface(pInterface->m_pInterface), m_iTimeOutValue(pInterface->m_iTimeOutValue) { ASSERT_READ_PTR(m_pInterface); m_pInterface->AddRef(); } CMetaInterface::~CMetaInterface() /*++ Routine Description: Destructor -- releases the interface --*/ { SAFE_RELEASE(m_pInterface); } HRESULT CMetaInterface::CreateSite( LPCTSTR service, LPCTSTR comment, LPCTSTR binding, LPCTSTR home_path, DWORD * pinst, DWORD * pRequestedSiteInst ) { CError err; BOOL bHonorRequestedSiteId = FALSE; CSiteCreator sc(m_pInterface); if (pRequestedSiteInst) { if (*pRequestedSiteInst != 0) { bHonorRequestedSiteId = TRUE; } } if (bHonorRequestedSiteId) { err = sc.CreateNewSite2( _tcsicmp(service, SZ_MBN_WEB) == 0 ? SC_W3SVC : SC_MSFTPSVC, comment, binding, home_path, NULL, pinst, pRequestedSiteInst); } else { err = sc.CreateNewSite2( _tcsicmp(service, SZ_MBN_WEB) == 0 ? SC_W3SVC : SC_MSFTPSVC, comment, binding, home_path, NULL, pinst); } return err; } // // CMetaKey class // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // // Helper macros // #define ASSURE_OPEN_KEY()\ if (!m_hKey && !m_fAllowRootOperations) { ASSERT_MSG("No open key"); 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_MSG("Bad property ID"); return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); } // // Static Initialization // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< #define MD_SERVER_PLATFORM (IIS_MD_SERVER_BASE+100 ) #define MD_SERVER_VERSION_MAJOR (IIS_MD_SERVER_BASE+101 ) #define MD_SERVER_VERSION_MINOR (IIS_MD_SERVER_BASE+102 ) #define MD_SERVER_CAPABILITIES (IIS_MD_SERVER_BASE+103 ) #if 0 // // Metabase table // const CMetaKey::MDFIELDDEF CMetaKey::s_rgMetaTable[] = { /////////////////////////////////////////////////////////////////////////// // // !!!IMPORTANT!!! This table must be sorted on dwMDIdentifier. (Will // ASSERT if not not sorted) // { 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_DOWNLEVEL_ADMIN_INSTANCE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_DOWNLEVEL_ADMIN_INSTANCE }, { MD_SERVER_BINDINGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, MULTISZ_METADATA, 0 }, { MD_WIN32_ERROR, METADATA_VOLATILE, IIS_MD_UT_FILE, DWORD_METADATA, 0 }, { MD_SERVER_PLATFORM, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 }, { MD_SERVER_VERSION_MAJOR, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 }, { MD_SERVER_VERSION_MINOR, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 }, { MD_SERVER_CAPABILITIES, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, 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_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_IN_PROCESS_ISAPI_APPS, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_IN_PROCESS_ISAPI_APPS }, { 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_FRONTPAGE_WEB, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_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_RESET_INTERVAL, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_RESET_INTERVAL }, { 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, EXPANDSZ_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_LOG_PLUGIN_MOD_ID, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_LOG_PLUGIN_MOD_ID }, { MD_LOG_PLUGIN_UI_ID, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_LOG_PLUGIN_UI_ID }, { 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_LOG_PLUGINS_AVAILABLE, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_LOG_PLUGINS_AVAILABLE }, { 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_LOGCUSTOM_PROPERTY_ID, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOGCUSTOM_PROPERTY_ID }, { MD_LOGCUSTOM_PROPERTY_MASK, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOGCUSTOM_PROPERTY_MASK }, { MD_LOGCUSTOM_SERVICES_STRING, METADATA_INHERIT, IIS_MD_UT_SERVER, MULTISZ_METADATA, IDS_MD_LOGCUSTOM_SERVICES_STRING }, { MD_LOGCUSTOM_PROPERTY_NODE_ID, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOGCUSTOM_PROPERTY_NODE_ID }, { 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_BANNER_MESSAGE, METADATA_INHERIT, IIS_MD_UT_SERVER, MULTISZ_METADATA, IDS_MD_BANNER_MESSAGE }, { 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_INHERIT, 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 }, { MD_WAM_USER_NAME, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_WAM_USER_NAME }, { MD_WAM_PWD, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_WAM_PWD }, // // IIS6 Application Pools // { MD_APPPOOL_PERIODIC_RESTART_TIME, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_PERIODIC_RESTART_TIME }, { MD_APPPOOL_PERIODIC_RESTART_REQUEST_COUNT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_PERIODIC_RESTART_REQUEST_COUNT }, { MD_APPPOOL_MAX_PROCESS_COUNT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_MAX_PROCESS_COUNT }, { MD_APPPOOL_PINGING_ENABLED, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_PINGING_ENABLED }, { MD_APPPOOL_IDLE_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_IDLE_TIMEOUT }, { MD_APPPOOL_RAPID_FAIL_PROTECTION_ENABLED, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_RAPID_FAIL_PROTECTION_ENABLED }, { MD_APPPOOL_ORPHAN_PROCESSES_FOR_DEBUGGING, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_ORPHAN_PROCESSES_FOR_DEBUGGING }, { MD_APPPOOL_STARTUP_TIMELIMIT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_STARTUP_TIMELIMIT }, { MD_APPPOOL_SHUTDOWN_TIMELIMIT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_SHUTDOWN_TIMELIMIT }, { MD_APPPOOL_PING_INTERVAL, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_PING_INTERVAL }, { MD_APPPOOL_UL_APPPOOL_QUEUE_LENGTH, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_UL_APPPOOL_QUEUE_LENGTH }, { MD_APPPOOL_PERIODIC_RESTART_SCHEDULE, METADATA_INHERIT, IIS_MD_UT_SERVER, MULTISZ_METADATA, IDS_MD_APPPOOL_PERIODIC_RESTART_SCHEDULE }, { MD_APPPOOL_IDENTITY_TYPE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_IDENTITY_TYPE }, { MD_CPU_ACTION, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_ACTION }, { MD_CPU_LIMIT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LIMIT }, { MD_APPPOOL_PERIODIC_RESTART_MEMORY, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_PERIODIC_RESTART_MEMORY }, { MD_APPPOOL_COMMAND, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_COMMAND }, { MD_APPPOOL_STATE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_STATE }, { MD_RAPID_FAIL_PROTECTION_INTERVAL, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_RAPID_FAIL_PROTECTION_INTERVAL}, { MD_RAPID_FAIL_PROTECTION_MAX_CRASHES, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_RAPID_FAIL_PROTECTION_MAX_CRASHES}, { MD_APPPOOL_ORPHAN_ACTION_EXE, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_APPPOOL_ORPHAN_ACTION_EXE }, { MD_APPPOOL_ORPHAN_ACTION_PARAMS, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_APPPOOL_ORPHAN_ACTION_PARAMS}, { MD_APP_APPPOOL_ID, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_APP_APPPOOL_ID }, // Global parameters { MD_MAX_GLOBAL_BANDWIDTH, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_MAX_GLOBAL_BANDWIDTH }, { MD_GLOBAL_STANDARD_APP_MODE_ENABLED,METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_GLOBAL_STANDARD_APP_MODE_ENABLED }, { MD_GLOBAL_LOG_IN_UTF_8, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_GLOBAL_LOG_IN_UTF_8 }, { MD_ROOT_ENABLE_EDIT_WHILE_RUNNING, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 }, }; #endif /* 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 --*/ { #if defined(_DEBUG) //|| DBG { // // Do a quick verification that our metadata // table is sorted correctly. // static BOOL fTableChecked = FALSE; if (!fTableChecked) { for (int n = 1; n < s_MetaTableSize; ++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_MSG("MD ID Table out of order"); } } // // But only once. // ++fTableChecked; } } #endif // _DEBUG // // Look up the ID in the table using a binary search // int nRange = s_MetaTableSize; int nLow = 0; int nHigh = nRange - 1; int nMid; int nHalf; while (nLow <= nHigh) { if (0 != (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 CMap g_metaid_map; const CMetaKey::MDFIELDDEF * CMetaKey::GetMetaProp(DWORD id) { MDFIELDDEF * p = NULL; if (g_metaid_map.GetCount() == 0) { for (int i = 0; i < s_MetaTableSize; i++) { DWORD id2 = CMetaKey::s_rgMetaTable[i].dwMDIdentifier; MDFIELDDEF * pt = (MDFIELDDEF *)&CMetaKey::s_rgMetaTable[i]; g_metaid_map.SetAt(id2, pt); } ASSERT(g_metaid_map.GetCount() > 0); } VERIFY(g_metaid_map.Lookup(id, p)); return (const CMetaKey::MDFIELDDEF *)p; } /* 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. --*/ { #if 0 int nID = MapMDIDToTableIndex(dwID); if (nID == -1) { // // Unrecognized meta data ID // ASSERT_MSG("Unrecognized meta data id"); return FALSE; } dwMDIdentifier = s_rgMetaTable[nID].dwMDIdentifier; dwMDAttributes = s_rgMetaTable[nID].dwMDAttributes; dwMDUserType = s_rgMetaTable[nID].dwMDUserType; dwMDDataType = s_rgMetaTable[nID].dwMDDataType; return TRUE; #endif const MDFIELDDEF * p = GetMetaProp(dwID); if (p != NULL) { dwMDIdentifier = p->dwMDIdentifier; dwMDAttributes = p->dwMDAttributes; dwMDUserType = p->dwMDUserType; dwMDDataType = p->dwMDDataType; return TRUE; } return FALSE; } /* 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. --*/ { const MDFIELDDEF * p = GetMetaProp(dwID); if (p == NULL) { ASSERT_MSG("Unrecognized meta data ID"); return FALSE; } return (p->dwMDAttributes & METADATA_INHERIT) != 0; #if 0 int nID = MapMDIDToTableIndex(dwID); if (nID == -1) { // // Unrecognized meta data ID // ASSERT_MSG("Unrecognized meta data ID"); return FALSE; } return (s_rgMetaTable[nID].dwMDAttributes & METADATA_INHERIT) != 0; #endif } /* 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 --*/ { const MDFIELDDEF * p = GetMetaProp(dwID); if (p == NULL) { ASSERT_MSG("Unrecognized meta data ID"); return FALSE; } UINT uID = p->uStringID; #if 0 int nID = MapMDIDToTableIndex(dwID); if (nID == -1) { // // Unrecognized meta data ID // ASSERT_MSG("Unrecognized meta data ID"); return FALSE; } UINT uID = s_rgMetaTable[nID].uStringID; #endif BOOL fResult = TRUE; if (uID > 0) { fResult = (strName.LoadString(uID) != 0); ASSERT(fResult); } else { // // Don't have a friendly name -- fake it // CComBSTR bstrFmt; VERIFY(bstrFmt.LoadString(hDLLInstance, IDS_INHERITANCE_NO_NAME)); strName.Format(bstrFmt, dwID); } return fResult; } CMetaKey::CMetaKey( IN CComAuthInfo * pAuthInfo 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: CComAuthInfo * pAuthInfo : If NULL, opens interface on local machine Return Value: N/A --*/ : CMetaInterface(pAuthInfo), 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 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 CComAuthInfo * pAuthInfo, OPTIONAL IN LPCTSTR lpszMDPath, OPTIONAL IN DWORD dwFlags, IN METADATA_HANDLE hkBase ) /*++ Routine Description: Fully defined constructor that opens a key Arguments: CComAuthInfo * pAuthInfo : Auth info or NULL LPCTSTR lpszMDPath : Path or NULL DWORD dwFlags : Open permissions METADATA_HANDLE hkBase : Base key Return Value: N/A --*/ : CMetaInterface(pAuthInfo), 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, lpszMDPath, hkBase); } } CMetaKey::CMetaKey( IN CMetaInterface * pInterface, IN LPCTSTR lpszMDPath, OPTIONAL IN DWORD dwFlags, IN METADATA_HANDLE hkBase ) /*++ 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, lpszMDPath, hkBase); } } CMetaKey::CMetaKey( IN BOOL fOwnKey, IN 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 LPCTSTR lpszMDPath, OPTIONAL IN METADATA_HANDLE hkBase ) /*++ Routine Description: Attempt to open a metabase key Arguments: DWORD dwFlags : Permission flags LPCTSTR lpszMDPath : Optional path METADATA_HANDLE hkBase : Base metabase key Return Value: HRESULT --*/ { ASSURE_PROPER_INTERFACE(); if (m_hKey != NULL) { // ASSERT_MSG("Attempting to open key that already has an open handle"); 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::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); CMetabasePath::SplitMetaPathAtInstance( m_strMetaPath, strParentPath, strObjectName ); CError err(Open( METADATA_PERMISSION_WRITE, 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; } 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 (!CMetabasePath::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; } /* 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_MSG("Invalid parameter"); 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 = FALSE; 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.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 CComAuthInfo * pAuthInfo, OPTIONAL 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 CComAuthInfo * pAuthInfo : Server or NULL LPCTSTR lpszMDPath : Metabase path or NULL 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()) { // // Bring up the inheritance override dialog // CInheritanceDlg dlg( dwID, FROM_WRITE_PROPERTY, pAuthInfo, 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_MSG("No Data"); 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 = FALSE; 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 CStrPassword & 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 CStrPassword & 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 = (LPCTSTR) 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 CComBSTR & 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 & CComBSTR : 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) { strValue = lpData; } 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::GetChildPaths(CStringListEx& child_paths, LPCTSTR path) { DWORD bsize = 0; CError err; LPTSTR pData = _T(""); do { err = CMetaInterface::GetChildPaths( m_hKey, path, 0, pData, &bsize); if (err.Failed() && err.Win32Error() != ERROR_INSUFFICIENT_BUFFER) break; pData = (LPTSTR)::LocalAlloc(LPTR, bsize * sizeof(WCHAR)); if (pData == NULL) { err = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY); break; } err = CMetaInterface::GetChildPaths( m_hKey, path, bsize, pData, &bsize); if (err.Failed()) break; ConvertDoubleNullListToStringList(pData, child_paths); } while (FALSE); if (pData != NULL) { ::LocalFree(pData); } return err; } 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_READ_PTR2(pbData, dwSize); blValue.SetValue(dwSize, pbData, FALSE); } return hr; } HRESULT CMetaKey::SetValue( IN DWORD dwID, IN CStrPassword & strlValue, IN BOOL * pfInheritanceOverride, OPTIONAL IN LPCTSTR lpszMDPath OPTIONAL ) { LPTSTR lpstr = NULL; HRESULT hr = S_OK; lpstr = strlValue.GetClearTextPassword(); if (lpstr) { hr = SetPropertyValue( dwID, strlValue.GetByteLength(), (void *)lpstr, pfInheritanceOverride, lpszMDPath ); strlValue.DestroyClearTextPassword(lpstr); } 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); } 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_PTR(m_pInterface); // Must have been initialised SAFE_RELEASE(m_pInterface); m_hrInterface = Create(); return m_hrInterface; } #define GET_TO_INTERFACE2()\ IMSAdminBase2 * pInterface2 = NULL;\ HRESULT hr = GetAdminInterface2(&pInterface2);\ if (SUCCEEDED(hr)) { #define GET_TO_INTERFACE3()\ IMSAdminBase3 * pInterface3 = NULL;\ HRESULT hr = GetAdminInterface3(&pInterface3);\ if (SUCCEEDED(hr)) { #define RELEASE_AND_RETURN2()\ if (pInterface2 != NULL)\ pInterface2->Release();\ }\ return hr #define RELEASE_AND_RETURN3()\ if (pInterface3 != NULL)\ pInterface3->Release();\ }\ return hr HRESULT CMetaInterface::GetAdminInterface2(IMSAdminBase2 ** pp) { HRESULT hr = S_OK; IMSAdminBase2 * p = NULL; if (pp == NULL) return E_POINTER; if (m_auth.UsesImpersonation()) { IUnknown * punk = NULL; hr = m_pInterface->QueryInterface(__uuidof(IUnknown), (void **)&punk); if (SUCCEEDED(hr)) { if (SUCCEEDED(hr = m_auth.ApplyProxyBlanket(punk))) { if (SUCCEEDED(hr = punk->QueryInterface(IID_IMSAdminBase2, (void **)&p))) { if (p != NULL) { hr = m_auth.ApplyProxyBlanket(p); if (SUCCEEDED(hr)) { *pp = p; } } } } } if (punk != NULL) punk->Release(); } else { if (m_pInterface) { hr = m_pInterface->QueryInterface(IID_IMSAdminBase2, (void **)pp); } else { hr = E_NOINTERFACE; } } return hr; } HRESULT CMetaInterface::GetAdminInterface3(IMSAdminBase3 ** pp) { HRESULT hr = S_OK; IMSAdminBase3 * p = NULL; if (pp == NULL) return E_POINTER; if (m_auth.UsesImpersonation()) { IUnknown * punk = NULL; hr = m_pInterface->QueryInterface(__uuidof(IUnknown), (void **)&punk); if (SUCCEEDED(hr)) { if (SUCCEEDED(hr = m_auth.ApplyProxyBlanket(punk))) { if (SUCCEEDED(hr = punk->QueryInterface(IID_IMSAdminBase3, (void **)&p))) { if (p != NULL) { hr = m_auth.ApplyProxyBlanket(p); if (SUCCEEDED(hr)) { *pp = p; } } } } } if (punk != NULL) punk->Release(); } else { if (m_pInterface) { hr = m_pInterface->QueryInterface(IID_IMSAdminBase3, (void **)pp); } else { hr = E_NOINTERFACE; } } return hr; } HRESULT CMetaInterface::BackupWithPassword( IN LPCTSTR lpszBackupLocation, IN DWORD dwMDVersion, IN DWORD dwMDFlags, IN LPCTSTR lpszPassword ) { GET_TO_INTERFACE2(); hr = pInterface2->BackupWithPasswd(lpszBackupLocation, dwMDVersion, dwMDFlags, lpszPassword); RELEASE_AND_RETURN2(); } HRESULT CMetaInterface::RestoreWithPassword( IN LPCTSTR lpszBackupLocation, IN DWORD dwMDVersion, IN DWORD dwMDFlags, IN LPCTSTR lpszPassword ) { GET_TO_INTERFACE2(); hr = pInterface2->RestoreWithPasswd(lpszBackupLocation, dwMDVersion, dwMDFlags, lpszPassword); RELEASE_AND_RETURN2(); } HRESULT CMetaInterface::EnumHistory( OUT LPTSTR pszMDHistoryLocation, OUT DWORD * pdwMDMajorVersion, OUT DWORD * pdwMDMinorVersion, OUT FILETIME * pftMDHistoryTime, IN DWORD dwIndex ) { GET_TO_INTERFACE2(); hr = pInterface2->EnumHistory(pszMDHistoryLocation, pdwMDMajorVersion, pdwMDMinorVersion, pftMDHistoryTime, dwIndex); RELEASE_AND_RETURN2(); } HRESULT CMetaInterface::RestoreHistory( IN LPCTSTR pszMDHistoryLocation, IN DWORD dwMDMajorVersion, IN DWORD dwMDMinorVersion, IN DWORD dwMDFlags ) { // dwMDFlags. The flag is set to RESTORE_LATEST would signal the API that the Major and Minor version parameters // are to be ignored and the history file at the HistoryLocation with the largest Major (and corresponding // largest Minor version) should be restored. If this flag is specified, the dwMDMajorVersion, dwMDMinorVersion // parameters must be set to 0 (zero). GET_TO_INTERFACE2(); hr = pInterface2->RestoreHistory(pszMDHistoryLocation, dwMDMajorVersion, dwMDMinorVersion, dwMDFlags); RELEASE_AND_RETURN2(); } HRESULT CMetaInterface::GetChildPaths( METADATA_HANDLE hKey, LPCTSTR path, DWORD buf_size, WCHAR * pbuf, DWORD * preq_size ) { GET_TO_INTERFACE3(); hr = pInterface3->GetChildPaths(hKey, path, buf_size, pbuf, preq_size); RELEASE_AND_RETURN3(); } // // CWamInterface class // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CWamInterface::CWamInterface( IN CComAuthInfo * pAuthInfo OPTIONAL ) /*++ Routine Description: Construct and initialize the interface. Arguments: CComAuthInfo * pAuthInfo : Auth info. NULL indicates the local computer. Return Value: N/A --*/ : CIISInterface(pAuthInfo), m_pInterface(NULL), m_fSupportsPooledProc(FALSE) { // // Initialize the interface // m_hrInterface = Create(); } CWamInterface::CWamInterface( IN CWamInterface * pInterface ) /*++ Routine Description: Construct from existing interface (copy constructor) Arguments: CWamInterface * pInterface : Existing interface Return Value: N/A --*/ : CIISInterface(&pInterface->m_auth, pInterface->m_hrInterface), m_pInterface(pInterface->m_pInterface), m_fSupportsPooledProc(FALSE) { ASSERT_PTR(m_pInterface); 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() /*++ Routine Description: Create the interface with DCOM Arguments: None Return Value: HRESULT Notes: First, it will attempt to create the new interface, if it fails, it will attempt to create the downlevel interface --*/ { CLSID rgCLSID[2]; IID rgIID[2]; rgCLSID[1] = rgCLSID[0] = CLSID_WamAdmin; rgIID[0] = IID_IWamAdmin2; rgIID[1] = IID_IWamAdmin; ASSERT(ARRAY_SIZE(rgCLSID) == ARRAY_SIZE(rgIID)); int cInterfaces = ARRAY_SIZE(rgCLSID); int iInterface; HRESULT hr = CIISInterface::Create( cInterfaces, rgIID, rgCLSID, &iInterface, (IUnknown **)&m_pInterface ); if (SUCCEEDED(hr)) { // // Only supported on IWamAdmin2 // m_fSupportsPooledProc = (rgIID[iInterface] == IID_IWamAdmin2); } return hr; } 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_PTR(m_pInterface); ASSURE_PROPER_INTERFACE(); return m_pInterface->AppCreate(szMDPath, fInProc); } return CError(ERROR_INVALID_PARAMETER); } #define GET_TO_INTERFACE()\ IIISApplicationAdmin * pAppAdmin = NULL;\ HRESULT hr = GetAppAdminInterface(&pAppAdmin);\ if (SUCCEEDED(hr)) { #define RELEASE_AND_RETURN()\ if (pAppAdmin != NULL)\ pAppAdmin->Release();\ }\ return hr\ HRESULT CWamInterface::GetAppAdminInterface(IIISApplicationAdmin ** pp) { HRESULT hr = S_OK; IIISApplicationAdmin * p = NULL; if (pp == NULL) { return E_POINTER; } if (m_auth.UsesImpersonation()) { IUnknown * punk = NULL; hr = m_pInterface->QueryInterface(__uuidof(IUnknown), (void **)&punk); if (SUCCEEDED(hr)) { if (SUCCEEDED(hr = m_auth.ApplyProxyBlanket(punk))) { if (SUCCEEDED(hr = punk->QueryInterface(IID_IIISApplicationAdmin, (void **)&p))) { if (p != NULL) { hr = m_auth.ApplyProxyBlanket(p); if (SUCCEEDED(hr)) { *pp = p; } } } } } if (punk != NULL) { punk->Release(); } } else { if (m_pInterface) { hr = m_pInterface->QueryInterface(IID_IIISApplicationAdmin, (void **)pp); } else { hr = E_NOINTERFACE; } } return hr; } HRESULT CWamInterface::CreateApplication( LPCWSTR szMDPath, DWORD dwAppMode, LPCWSTR szAppPoolId, BOOL fCreatePool ) { GET_TO_INTERFACE(); hr = pAppAdmin->CreateApplication( szMDPath, dwAppMode, szAppPoolId, fCreatePool); RELEASE_AND_RETURN(); } HRESULT CWamInterface::DeleteApplication(LPCWSTR szMDPath, BOOL fRecursive) { GET_TO_INTERFACE(); hr = pAppAdmin->DeleteApplication(szMDPath, fRecursive); RELEASE_AND_RETURN(); } HRESULT CWamInterface::CreateApplicationPool(LPCWSTR szMDPath) { GET_TO_INTERFACE(); hr = pAppAdmin->CreateApplicationPool(szMDPath); RELEASE_AND_RETURN(); } HRESULT CWamInterface::DeleteApplicationPool(LPCWSTR szMDPath) { GET_TO_INTERFACE(); hr = pAppAdmin->DeleteApplicationPool(szMDPath); RELEASE_AND_RETURN(); } HRESULT CWamInterface::RecycleApplicationPool(LPCWSTR szMDPath) { GET_TO_INTERFACE(); hr = pAppAdmin->RecycleApplicationPool(szMDPath); RELEASE_AND_RETURN(); } HRESULT CWamInterface::EnumerateApplicationsInPool(LPCTSTR szMDPath, BSTR * pbstr) { GET_TO_INTERFACE(); hr = pAppAdmin->EnumerateApplicationsInPool(szMDPath, pbstr); RELEASE_AND_RETURN(); } HRESULT CWamInterface::GetProcessMode(DWORD * pdwMode) { GET_TO_INTERFACE(); if (pAppAdmin) { hr = pAppAdmin->GetProcessMode(pdwMode); } RELEASE_AND_RETURN(); } // // CMetaback Class // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< const LPCTSTR CMetaBack::s_szMasterAppRoot =\ SZ_MBN_SEP_STR SZ_MBN_MACHINE SZ_MBN_SEP_STR SZ_MBN_WEB; CMetaBack::CMetaBack( IN CComAuthInfo * pAuthInfo OPTIONAL ) /*++ Routine Description: Constructor for metabase backup/restore operations class. This object is both a WAM interface and a METABASE interface. Arguments: CComAuthInfo * pAuthInfo : Auth info. NULL indicates the local computer. Return Value: N/A --*/ : m_dwIndex(0), CMetaInterface(pAuthInfo), CWamInterface(pAuthInfo) { } /* virtual */ BOOL CMetaBack::Succeeded() const /*++ Routine Description: Determine if object was constructed successfully. Arguments: None Return Value: TRUE for success, FALSE for failure --*/ { BOOL bRet = FALSE; bRet = CMetaInterface::Succeeded(); if (TRUE == bRet) { bRet = CWamInterface::Succeeded(); if (FALSE == bRet) { HRESULT hr = CWamInterface::QueryResult(); if (REGDB_E_CLASSNOTREG == hr) { // could mean that only FTP is installed and WAM is not available. // just return success... bRet = TRUE; } } } return bRet; } /* 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(); if (REGDB_E_CLASSNOTREG == hr) { // could mean that only FTP is installed and WAM is not available. // just return success... hr = S_OK; } } 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 --*/ { HRESULT hr = S_OK; // // Backup and restore the application information from a restore // CString strPath(s_szMasterAppRoot); BOOL bDoesWamInterfaceExist = (REGDB_E_CLASSNOTREG != CWamInterface::QueryResult()); // Check if there is a WAM interface 1st... // could mean that only FTP is installed and WAM is not available. if (bDoesWamInterfaceExist) { // could mean that only FTP is installed and WAM is not available. // just return success... hr = AppDeleteRecoverable(strPath, TRUE); } if (SUCCEEDED(hr)) { hr = CMetaInterface::Restore(lpszLocation, dwVersion, 0); if (SUCCEEDED(hr)) { if (bDoesWamInterfaceExist) { 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 // // BUGBUG: clear it out, why we had an error "parameter is incorrect" from AppDeleteRecoverable 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 CComAuthInfo * pAuthInfo OPTIONAL ) /*++ Routine Description: Construct and initialize the interface. Arguments: CComAuthInfo * pAuthInfo : Auth info. NULL indicates the local computer. Return Value: N/A --*/ : CIISInterface(pAuthInfo), m_pInterface(NULL) { // // Initialize the interface // m_hrInterface = Create(); } CIISSvcControl::CIISSvcControl( IN CIISSvcControl * pInterface ) /*++ Routine Description: Construct from existing interface (copy constructor) Arguments: CIISSvcControl * pInterface : Existing interface Return Value: N/A --*/ : CIISInterface(&pInterface->m_auth, pInterface->m_hrInterface), m_pInterface(pInterface->m_pInterface) { ASSERT_PTR(m_pInterface); m_pInterface->AddRef(); } CIISSvcControl::~CIISSvcControl() /*++ Routine Description: Destructor -- releases the interface. Arguments: N/A Return Value: N/A --*/ { SAFE_RELEASE(m_pInterface); } // // CMetaEnumerator Clas // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CMetaEnumerator::CMetaEnumerator( IN CComAuthInfo * pAuthInfo OPTIONAL, IN LPCTSTR lpszMDPath OPTIONAL, IN METADATA_HANDLE hkBase OPTIONAL ) /*++ Routine Description: Metabase enumerator constructor. This constructor creates a new interface and opens a key. Arguments: CComAuthInfo * pAuthInfo : Auth info. NULL indicates the local computer. LPCTSTR lpszMDPath : Metabase path METADATA_HANDLE hkBase : Metabase handle Return Value: N/A --*/ : CMetaKey(pAuthInfo, lpszMDPath, METADATA_PERMISSION_READ, hkBase), m_dwIndex(0L) { } CMetaEnumerator::CMetaEnumerator( IN CMetaInterface * pInterface, IN LPCTSTR lpszMDPath, OPTIONAL IN METADATA_HANDLE hkBase OPTIONAL ) /*++ Routine Description: Metabase enumerator constructor. This constructor uses an existing interface and opens a key. Arguments: CMetaInterface * pInterface : Existing interface LPCTSTR lpszMDPath : Metabase path METADATA_HANDLE hkBase : Metabase handle Return Value: N/A --*/ : CMetaKey(pInterface, lpszMDPath, METADATA_PERMISSION_READ, hkBase), m_dwIndex(0L) { } CMetaEnumerator::CMetaEnumerator( IN BOOL fOwnKey, IN CMetaKey * pKey ) /*++ Routine Description: Metabase enumerator constructor. This constructor uses an existing interface and open key. Arguments: BOOL fOwnKey : TRUE if we own the key (destructor will close) CMetaKey * pKey : Open key Return Value: N/A --*/ : CMetaKey(fOwnKey, pKey), 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, OUT CString & strKey, 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 CString & strKey Same key in string format LPCTSTR lpszMDPath Optional subpath Return Value: HRESULT --*/ { ASSURE_PROPER_INTERFACE(); ASSURE_OPEN_KEY(); HRESULT hr = S_OK; BOOL fContinue = TRUE; while (fContinue) { fContinue = FALSE; LPTSTR lpKey = strKey.GetBuffer(MAX_PATH); hr = EnumKeys(m_hKey, lpszMDPath, lpKey, m_dwIndex++); strKey.ReleaseBuffer(); if (SUCCEEDED(hr)) { if (FALSE == (dwKey = _ttoi((LPCTSTR)strKey))) { // // Ignore this one // fContinue = TRUE; } } } return hr; } // // CIISApplication class // // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<