/******************************************************************** Copyright (c) 1999 Microsoft Corporation Module Name: util.CPP Abstract: File containing utility classes Revision History: Ghim-Sim Chua (gschua) 04/27/99 - Created Jim Martin (a-jammar) 04/30/99 - Changed to use global IWbemServices pointer, and added GetWbemServices, CopyProperty, and GetCIMDataFile Ghim-Sim Chua (gschua) 05/01/99 - Modified GetWbemServices, GetCIMDataFile Kalyani Narlanka (kalyanin) 05/11/99 - Added the function GetCompletePath ********************************************************************/ #include "pchealth.h" #define TRACE_ID DCID_UTIL //----------------------------------------------------------------------------- // Returns an IWbemServices pointer. The caller is responsible for releasing // the object. //----------------------------------------------------------------------------- HRESULT GetWbemServices(IWbemServices **ppServices) { TraceFunctEnter("::GetWbemServices"); HRESULT hRes = S_OK; CComPtr pWbemLocator; // If global variable already initialized, use it if (g_pWbemServices) { *ppServices = g_pWbemServices; (*ppServices)->AddRef(); goto End; } // First we have the get the IWbemLocator object with a CoCreateInstance. hRes = CoCreateInstance(CLSID_WbemAdministrativeLocator, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IID_IUnknown, (void **)&pWbemLocator); if (FAILED(hRes)) { ErrorTrace(TRACE_ID, "CoCreateInstance failed to create IWbemAdministrativeLocator."); goto End; } // Then we connect to the WMI server for the local CIMV2 namespace. hRes = pWbemLocator->ConnectServer(CComBSTR(CIM_NAMESPACE), NULL, NULL, NULL, 0, NULL, NULL, ppServices); if (FAILED(hRes)) { ErrorTrace(TRACE_ID, "ConnectServer failed to connect to cimv2 namespace."); goto End; } // Store it in the global variable g_pWbemServices = *ppServices; (*ppServices)->AddRef(); // CODEWORK: check out why this stops fault on NET STOP WINMGMT End : TraceFunctLeave(); return hRes; } //----------------------------------------------------------------------------- // Executes the WQL query and returns the enumerated list //----------------------------------------------------------------------------- HRESULT ExecWQLQuery(IEnumWbemClassObject **ppEnumInst, BSTR bstrQuery) { TraceFunctEnter("::ExecWQLQuery"); HRESULT hRes; CComPtr pWbemServices; // Get pointer to WbemServices hRes = GetWbemServices(&pWbemServices); if (FAILED(hRes)) goto End; // execute the query hRes = pWbemServices->ExecQuery( CComBSTR("WQL"), bstrQuery, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, ppEnumInst); if (FAILED(hRes)) { ErrorTrace(TRACE_ID, "ExecQuery failed."); goto End; } End: TraceFunctLeave(); return hRes; } //----------------------------------------------------------------------------- // Copies the property named szFrom from pFrom to the property named szTo in // to CInstance object pTo. //----------------------------------------------------------------------------- HRESULT CopyProperty(IWbemClassObject *pFrom, LPCWSTR szFrom, CInstance *pTo, LPCWSTR szTo) { TraceFunctEnter("::CopyProperty"); _ASSERT(pFrom && szFrom && pTo && szTo); HRESULT hRes = S_OK; CComVariant varValue; CComBSTR bstrFrom(szFrom); // First, get the property (as a variant) from the source class object. hRes = pFrom->Get(bstrFrom, 0, &varValue, NULL, NULL); if (FAILED(hRes)) ErrorTrace(TRACE_ID, "GetVariant on %s field failed.", szFrom); else { // Then set the variant for the target CInstance object. if (!pTo->SetVariant(szTo, varValue)) { ErrorTrace(TRACE_ID, "SetVariant on %s field failed.", szTo); hRes = WBEM_E_FAILED; } } TraceFunctLeave(); return hRes; } //----------------------------------------------------------------------------- // Returns an IWbemClassObject pointer for the CIM_DataFile object represented // by the bstrFile parameter. The bstrFile parameter should contain the full // path to the file. If the pServices parameter is non-null, it is used to // retrieve the file info, otherwise a new (and temporary) services pointer is // created. //----------------------------------------------------------------------------- HRESULT GetCIMDataFile(BSTR bstrFile, IWbemClassObject ** ppFileObject, BOOL fHasDoubleSlashes) { TraceFunctEnter("::GetCIMDataFile"); HRESULT hRes = S_OK; CComBSTR bstrObjectPath("\\\\.\\root\\cimv2:CIM_DataFile.Name=\""); wchar_t * pwch; UINT uLen; CComPtr pWbemServices; hRes = GetWbemServices(&pWbemServices); if (FAILED(hRes)) goto END; if (bstrFile == NULL || ppFileObject == NULL) { ErrorTrace(TRACE_ID, "Parameter pointer is null."); hRes = WBEM_E_INVALID_PARAMETER; goto END; } // Construct the path for the file we are trying to get. Note, the path needs // the have double backslashes for the GetObject call to work. We scan through // the string and do this manually here. // // CODEWORK: there has to be a faster way to do this, although the Append is // probably not too expensive, since the BSTR length can be found without // scanning the string. Unless it's reallocating more memory as it goes. pwch = bstrFile; if (fHasDoubleSlashes) bstrObjectPath.Append(pwch, SysStringLen(bstrFile)); else for (uLen = SysStringLen(bstrFile); uLen > 0; uLen--) { if (*pwch == L'\\') bstrObjectPath.Append("\\"); bstrObjectPath.Append(pwch, 1); pwch++; } bstrObjectPath.Append("\""); // Make the call to get the CIM_DataFile object. hRes = pWbemServices->GetObject(bstrObjectPath, 0, NULL, ppFileObject, NULL); if (FAILED(hRes)) ErrorTrace(TRACE_ID, "GetObject on CIM_DataFile failed."); END: TraceFunctLeave(); return hRes; } //***************************************************************************** // // Function Name : getCompletePath // // Input Parameters : bstrFileName // CComBSTR which represents the file // whose complete path is required. // Output Parameters : bstrFileWithPathName // CComBSTR which represents the file // with the Path // Returns : BOOL // TRUE if bstrFileWithPathName can be set. // FALSE if bstrFileWithPathName cannot be set. // // // Synopsis : Given a file name (bstrFileName) this function // searches the "System" directory for the existence // of the file. // // If it finds the file it pre appends the directory // path to the input file and copies into the output // file (bstrFileWithPathName). // // If it doesnot find the file in "System" directory // searches for the file in "Windows" Directoy and does // the same as above. // //***************************************************************************** BOOL getCompletePath(CComBSTR bstrFileName, CComBSTR &bstrFileWithPathName) { // Return BOOL bFoundFile = FALSE; ULONG uiReturn; TCHAR szDirectory[MAX_PATH]; TCHAR temp[MAX_PATH]; TCHAR lpstrTemp[MAX_PATH]; struct _stat filestat; CComVariant varValue = NULL; CComBSTR bstrDirectory; // Check for the File in the System Directory uiReturn = GetSystemDirectory(szDirectory, MAX_PATH); if (uiReturn != 0 && uiReturn < MAX_PATH) { bstrDirectory = szDirectory; bstrDirectory.Append("\\"); bstrDirectory.Append(bstrFileName); USES_CONVERSION; int Result = _tstat(W2T(bstrDirectory), &filestat) ; if (Result == 0) { bstrFileWithPathName = bstrDirectory; bFoundFile = TRUE; } } // If not there, then check in the windows directory. if (!bFoundFile) { uiReturn = GetWindowsDirectory(szDirectory, MAX_PATH); if (uiReturn != 0 && uiReturn < MAX_PATH) { bstrDirectory = szDirectory; bstrDirectory.Append("\\"); bstrDirectory.Append(bstrFileName); USES_CONVERSION; int Result = _tstat(W2T(bstrDirectory), &filestat) ; if (Result == 0) { bstrFileWithPathName = bstrDirectory; bFoundFile = TRUE; } } } return(bFoundFile); } // Used by GetCim32NetDll and FreeCim32NetDll. CCritSec g_csCim32Net; HINSTANCE s_Handle = NULL; // There is a problem with loading Cim32Net.dll over and over, so this code // makes sure we only load it once, then unloads it at exit. // these are used with GetCim32NetHandle void FreeCim32NetHandle() { if (s_Handle) { FreeLibrary(s_Handle); s_Handle = NULL; } } HINSTANCE GetCim32NetHandle() { // Have we ever loaded it before? if (s_Handle == NULL) { // Avoid contention on static g_csCim32Net.Enter(); // Check for race condition if (s_Handle == NULL) { s_Handle = LoadLibrary(_T("Cim32Net.dll")); // Register to free the handle at exit // NO! bad....badddd juju... call from FlushAll instead (o.w., when // cimwin32.dll unloads this pointer is invalid, but atexit gets // called when framedyn.dll unloads) // atexit(FreeCim32NetHandle); } g_csCim32Net.Leave(); } // By re-opening the handle, we ensure proper refcounting on the handle, // and facilitate leak checking. HINSTANCE hHandle = LoadLibrary(_T("Cim32Net.dll")); return hHandle; } // // Given a delimited string, convert tokens into strings and store them into an array // returns the number of tokens parsed. Caller is responsible for freeing up the memory // allocated using delete // #ifndef UNICODE int DelimitedStringToArray(LPWSTR strString, LPTSTR strDelimiter, LPTSTR apstrArray[], int iMaxArraySize) { USES_CONVERSION; LPTSTR szString = W2A(strString); return DelimitedStringToArray(szString, strDelimiter, apstrArray, iMaxArraySize); } #endif int DelimitedStringToArray(LPTSTR strString, LPTSTR strDelimiter, LPTSTR apstrArray[], int iMaxArraySize) { // make a copy of the string to begin parsing LPTSTR strDelimitedString = (TCHAR *) new TCHAR [_tcslen(strString) + 1]; // if out of memory, just return error value -1 if (!strDelimitedString) return -1; // copy the token into the new allocated string _tcscpy(strDelimitedString, strString); // initialize _tcstok LPTSTR strTok = _tcstok(strDelimitedString, strDelimiter); int iCount = 0; // loop through all tokens parsed while ((strTok) && (iCount < iMaxArraySize)) { LPTSTR strNewTok = (TCHAR *) new TCHAR[_tcslen(strTok) + 1]; // if out of memory, just return error value -1 if (!strNewTok) return -1; // copy the token into the new allocated string _tcscpy(strNewTok, strTok); // save it in the array apstrArray[iCount] = strNewTok; // increment the index iCount++; // get the next token strTok = _tcstok(NULL, strDelimiter); } // free up the memory used delete [] strDelimitedString; return iCount; }