//*********************************************************************** // remote.cpp // // This file contains code required to expand environment variables in the // context of a remote machine. It does this by reading the environment variables // from the remote machine's registry and caching them here. // // This file also contains code required to map local paths read out of the // remote machine's registry into UNC paths such that c:\foo will be mapped // to \\machine\c$\foo // // Author: Larry A. French // // History: // 19-April-1996 Larry A. French // Wrote it. // // Copyright (C) 1995, 1996 Microsoft Corporation. All rights reserved. // //************************************************************************ #include "stdafx.h" #include "remote.h" #include "trapreg.h" #include "regkey.h" CEnvCache::CEnvCache() { } //***************************************************************** // CEnvCache::GetEnvironmentVars // // Read the system environment variables for the remote machine out // of its registry. // // Parameters: // LPCTSTR pszMachine // Pointer to the remote machine's name. // // CMapStringToString* pmapVars // This string to string map is where the environment variables // for the machine are returned. // // Returns: // SCODE // S_OK if everything was successful, otherwise E_FAIL. // //**************************************************************** SCODE CEnvCache::GetEnvironmentVars(LPCTSTR pszMachine, CMapStringToString* pmapVars) { CRegistryKey regkey; // SYSTEM\CurrentControlSet\Services\EventLogs CRegistryValue regval; static TCHAR* apszNames1[] = { _T("SourcePath"), _T("SystemRoot") }; if (regkey.Connect(pszMachine) != ERROR_SUCCESS) { goto CONNECT_FAILURE; } // First pick up the values for the SourcePath and SystemRoot environment variables and anything elese in // apszNames1. LONG nEntries; LONG iEntry; if (regkey.Open(_T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), KEY_READ ) == ERROR_SUCCESS) { nEntries = sizeof(apszNames1) / sizeof(TCHAR*); for (iEntry=0; iEntrySetAt(apszNames1[iEntry], (LPCTSTR) regval.m_pData); } } regkey.Close(); } // Now get the rest of the environment variables. if (regkey.Open(_T("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"), KEY_READ ) == ERROR_SUCCESS) { CStringArray* pasValues = regkey.EnumValues(); if (pasValues != NULL) { nEntries = (LONG)pasValues->GetSize(); for (iEntry=0; iEntry< nEntries; ++iEntry) { CString sValueName = pasValues->GetAt(iEntry); if (regkey.GetValue(sValueName, regval)) { pmapVars->SetAt(sValueName, (LPCTSTR) regval.m_pData); } } } regkey.Close(); } return S_OK; CONNECT_FAILURE: return E_FAIL; } SCODE CEnvCache::AddMachine(LPCTSTR pszMachine) { CMapStringToString* pmapVars; if (m_mapMachine.Lookup(pszMachine, (CObject*&) pmapVars)) { // The machine already has an entry, so don't add another return E_FAIL; } pmapVars = new CMapStringToString; m_mapMachine.SetAt(pszMachine, pmapVars); SCODE sc = GetEnvironmentVars(pszMachine, pmapVars); return sc; } //****************************************************************** // CEnvCache::Lookup // // Lookup an environment variable on the specified machine. // // Parameters: // LPCTSTR pszMachineName // Pointer to the machine name string. // // LPCTSTR pszName // Pointer to the name of the environment variable to lookup. // // CString& sValue // This is a reference to the place where the environment varaible's // value is returned. // // // Returns: // SCODE // S_OK if the environment variable was found. // E_FAIL if the environment varaible was not found. // //******************************************************************* SCODE CEnvCache::Lookup(LPCTSTR pszMachineName, LPCTSTR pszName, CString& sResult) { SCODE sc; CMapStringToString* pmapVars; // Get a pointer to the machine's cached map of environment variable values. // If the map hasn't been loaded yet, do so now and try to get its map again. if (!m_mapMachine.Lookup(pszMachineName, (CObject*&) pmapVars)) { sc = AddMachine(pszMachineName); if (FAILED(sc)) { return sc; } if (!m_mapMachine.Lookup(pszMachineName, (CObject*&) pmapVars)) { ASSERT(FALSE); } } // Look for the variable name in the environment name map if (pmapVars->Lookup(pszName, sResult)) { return S_OK; } else { return E_FAIL; } } //**************************************************************** // RemoteExpandEnvStrings // // Epand a string that may contain environment variables in the // context of a remote machine. // // Parameters: // LPCTSTR pszComputerName // A pointer to the name of the remote machine. // // CEnvCache& cache // The environment variable cache for all machines. Note: the // cached values for a particular machine are loaded when there // is a reference to the machine. // // CString& sValue // The string to expand. This string is expanded in-place such // that on return, the string will contain the expanded values. // // Returns: // SCODE // S_OK if all strings were expanded // //****************************************************************** SCODE RemoteExpandEnvStrings(LPCTSTR pszComputerName, CEnvCache& cache, CString& sValue) { SCODE sc = S_OK; LPCTSTR psz = sValue; TCHAR ch; CString sEnvVarName; CString sEnvVarValue; CString sResult; LPCTSTR pszPercent = NULL; while (ch = *psz++) { if (ch == _T('%')) { pszPercent = psz - 1; sEnvVarName = _T(""); while (ch = *psz) { ++psz; if (ch == _T('%')) { SCODE sc; sc = cache.Lookup(pszComputerName, sEnvVarName, sEnvVarValue); if (SUCCEEDED(sc)) { sResult += sEnvVarValue; pszPercent = NULL; } else { // If any environment variable is not found, then fail. sc = E_FAIL; } break; } if (iswspace(ch) || ch==_T(';')) { break; } sEnvVarName += ch; } if (pszPercent != NULL) { // Control comes here if the opening percent was not matched by a closing // percent. while(pszPercent < psz) { sResult += *pszPercent++; } } } else { sResult += ch; } } sValue = sResult; return sc; } //************************************************************ // SplitComplexPath // // Split a complex path consisting of several semicolon separated // paths into separate paths and return them in a string array. // // Parameters: // LPCTSTR pszComplexPath // Pointer to the path that may or may not be composed of // several semicolon separated paths. // // CStringArray& saPath // The place to return the split paths. // // Returns: // The individual paths are returned via saPath // //************************************************************* void SplitComplexPath(LPCTSTR pszComplexPath, CStringArray& saPath) { CString sPath; while (*pszComplexPath) { sPath.Empty(); while (isspace(*pszComplexPath)) { ++pszComplexPath; } while (*pszComplexPath && (*pszComplexPath != _T(';'))) { sPath += *pszComplexPath++; } if (!sPath.IsEmpty()) { saPath.Add(sPath); } if (*pszComplexPath==_T(';')) { ++pszComplexPath; } } } //************************************************************************** // MapPathToUNC // // Map a path to the UNC equivallent. Note that this method assumes that // for each path containing a drive letter that the target machine will have // the path shared out. For example, if the path contains a "c:\foodir" prefix, then // then you can get to "foodir" bygenerating the "\\machine\c$\foodir" path. // // Parameters: // LPCTSTR pszMachineName // Pointer to the machine name. // // CString& sPath // Pointer to the path to map. Upon return, this string will contain // the mapped path. // // Returns: // SCODE // S_OK if successful // E_FAIL if something went wrong. // //************************************************************************** SCODE MapPathToUNC(LPCTSTR pszMachineName, CString& sPath) { CStringArray saPaths; SplitComplexPath(sPath, saPaths); sPath.Empty(); LPCTSTR pszPath = sPath.GetBuffer(sPath.GetLength() + 1); LONG nPaths = (LONG)saPaths.GetSize(); SCODE sc = S_OK; for (LONG iPath=0; iPath < nPaths; ++iPath) { pszPath = saPaths[iPath]; if (isalpha(pszPath[0]) && pszPath[1]==_T(':')) { CString sResult; sResult += _T("\\\\"); sResult += pszMachineName; sResult += _T('\\'); sResult += pszPath[0]; // Drive letter sResult += _T("$\\"); pszPath += 2; if (pszPath[0]==_T('\\')) { ++pszPath; } sResult += pszPath; saPaths[iPath] = sResult; } else { sc = E_FAIL; } sPath += saPaths[iPath]; if (iPath < nPaths - 1) { sPath += _T("; "); } } return sc; }