/*++ Copyright (c) 1991 Microsoft Corporation Module Name: lodctr.c Abstract: Program to read the contents of the file specified in the command line and update the registry accordingly Author: Bob Watson (a-robw) 10 Feb 93 Revision History: a-robw 25-Feb-93 revised calls to make it compile as a UNICODE or an ANSI app. --*/ #define UNICODE 1 #define _UNICODE 1 // // "C" Include files // #include #include #include #include // // Windows Include files // #include #include #include // // application include files // #include "common.h" #include "lodctr.h" #define OLD_VERSION 0x010000 static DWORD dwSystemVersion; static DWORD dwFileSize; static TCHAR ComputerName[FILE_NAME_BUFFER_SIZE]; static HKEY hPerfData; static TCHAR szDataFileRoot[] = {TEXT("%systemroot%\\system32\\perf")}; static TCHAR szDatExt[] = {TEXT(".DAT")}; static TCHAR szBakExt[] = {TEXT(".BAK")}; static BOOL bQuietMode = TRUE; // quiet means no _tprintf's #define OUTPUT_MESSAGE if (bQuietMode) _tprintf static BOOL MakeBackupCopyOfLanguageFiles ( IN LPCTSTR szLangId ) { TCHAR szOldFileName[MAX_PATH]; TCHAR szNewFileName[MAX_PATH]; LPTSTR szOldBaseEnd; LPTSTR szNewBaseEnd; BOOL bStatus; ExpandEnvironmentStrings (szDataFileRoot, szOldFileName, MAX_PATH); lstrcpy (szNewFileName, szOldFileName); szOldBaseEnd = szOldFileName + lstrlen(szOldFileName); szNewBaseEnd = szNewFileName + lstrlen(szNewFileName); // copy Counter Name Files *szOldBaseEnd = TEXT('C'); *szNewBaseEnd = TEXT('C'); lstrcpy (szOldBaseEnd+1, szLangId); lstrcpy (szNewBaseEnd+1, szLangId); lstrcat (szOldBaseEnd, szDatExt); lstrcat (szNewBaseEnd, szBakExt); // copy the old file to the new file name and overwrite any // previous versions of the file bStatus = CopyFile (szOldFileName, szNewFileName, FALSE); if (bStatus) { // copy Explain Text Files *szOldBaseEnd = TEXT('H'); *szNewBaseEnd = TEXT('H'); // copy the old file to the new file name and overwrite any // previous versions of the file bStatus =CopyFile (szOldFileName, szNewFileName, FALSE); } return bStatus; } static BOOL LanguageInstalled ( IN LPCTSTR szLangId ) { BOOL bStatus; BOOL bReturn = FALSE; LONG lStatus; HKEY hKeyMachine; HKEY hKeyThisLang; HKEY hPerflib; // check if we need to connect to remote machine if (ComputerName[0]) { bStatus = FALSE; try { lStatus = RegConnectRegistry ( (LPTSTR)ComputerName, HKEY_LOCAL_MACHINE, &hKeyMachine); } finally { if (lStatus != ERROR_SUCCESS) { SetLastError (lStatus); hKeyMachine = NULL; } else { bStatus = TRUE; } } } else { hKeyMachine = HKEY_LOCAL_MACHINE; bStatus = TRUE; } if (bStatus) { // open key to perflib's "root" key lStatus = RegOpenKeyEx ( hKeyMachine, NamesKey, RESERVED, KEY_READ, &hPerflib); if (lStatus == ERROR_SUCCESS) { // make sure this language is loaded lStatus = RegOpenKeyEx( hPerflib, szLangId, RESERVED, KEY_READ, &hKeyThisLang); if (lStatus == ERROR_SUCCESS) { bReturn = TRUE; // we just need the open status, not the key handle so // close this handle and set the one we need. RegCloseKey (hKeyThisLang); } RegCloseKey (hPerflib); } RegCloseKey (hKeyMachine); } return bReturn; } static BOOL GetFileFromCommandLine ( IN LPTSTR lpCommandLine, OUT LPTSTR *lpFileName ) /*++ GetFileFromCommandLine parses the command line to retrieve the ini filename that should be the first and only argument. Arguments lpCommandLine pointer to command line (returned by GetCommandLine) lpFileName pointer to buffer that will recieve address of the validated filename entered on the command line Return Value TRUE if a valid filename was returned FALSE if the filename is not valid or missing error is returned in GetLastError --*/ { INT iNumArgs; HFILE hIniFile; OFSTRUCT ofIniFile; LPTSTR lpExeName = NULL; LPTSTR lpCmdLineName = NULL; LPSTR lpIniFileName = NULL; HANDLE hFileHandle; TCHAR LocalComputerName[FILE_NAME_BUFFER_SIZE]; DWORD NameBuffer; // check for valid arguments if (!lpCommandLine) return (ERROR_INVALID_PARAMETER); if (!lpFileName) return (ERROR_INVALID_PARAMETER); // allocate memory for parsing operation lpExeName = malloc (FILE_NAME_BUFFER_SIZE * sizeof(TCHAR)); lpCmdLineName = malloc (FILE_NAME_BUFFER_SIZE * sizeof(TCHAR)); lpIniFileName = malloc (FILE_NAME_BUFFER_SIZE); if (!lpExeName || !lpIniFileName || !lpCmdLineName) { SetLastError (ERROR_OUTOFMEMORY); if (lpExeName) free (lpExeName); if (lpIniFileName) free (lpIniFileName); if (lpCmdLineName) free (lpCmdLineName); return FALSE; } else { // get strings from command line ComputerName[0] = TEXT('\0'); // Get INI File name lstrcpy (lpCmdLineName, GetItemFromString (lpCommandLine, 3, TEXT(' '))); if (lstrlen(lpCmdLineName) == 0) { // then no computer name was specified so try to get the // ini file from the 2nd entry lstrcpy (lpCmdLineName, GetItemFromString (lpCommandLine, 2, TEXT(' '))); if (lstrlen(lpCmdLineName) == 0) { // no ini file found iNumArgs = 1; } else { // fill in a blank computer name iNumArgs = 2; ComputerName[0] = 0; } } else { // the computer name must be present so fetch it lstrcpy (LocalComputerName, GetItemFromString (lpCommandLine, 2, TEXT(' '))); iNumArgs = 3; } if (iNumArgs != 2 && iNumArgs != 3) { // wrong number of arguments SetLastError (ERROR_INVALID_PARAMETER); if (lpExeName) free (lpExeName); if (lpIniFileName) free (lpIniFileName); return FALSE; } else { // check for usage if (lpCmdLineName[1] == TEXT('?') || LocalComputerName[1] == TEXT('?')) { // ask for usage if (lpExeName) free (lpExeName); if (lpIniFileName) free (lpIniFileName); return FALSE; } // check if there is a computer name in the input line if (LocalComputerName[0] == TEXT('\\') && LocalComputerName[1] == TEXT('\\')) { // save it form now lstrcpy (ComputerName, LocalComputerName); // reuse local buffer to get the this computer's name NameBuffer = sizeof (LocalComputerName) / sizeof (TCHAR); GetComputerName(LocalComputerName, &NameBuffer); if (!lstrcmpi(LocalComputerName, &ComputerName[2])) { // same name as local computer name // so clear computer name buffer ComputerName[0] = TEXT('\0'); } } // see if file specified exists // file name is always an ANSI buffer CharToOem (lpCmdLineName, lpIniFileName); hIniFile = OpenFile (lpIniFileName, &ofIniFile, OF_PARSE); if (hIniFile != HFILE_ERROR) { if (hIniFile) _lclose (hIniFile); hFileHandle = CreateFile ( lpCmdLineName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); free (lpCmdLineName); if (hFileHandle && hFileHandle != INVALID_HANDLE_VALUE) { // get file size dwFileSize = GetFileSize (hFileHandle, NULL); if (dwFileSize == 0xffffffff) { dwFileSize = 0L; } else { dwFileSize *= sizeof (TCHAR); } CloseHandle (hFileHandle); // file exists, so return name and success if (lpExeName) free (lpExeName); if (lpIniFileName) free (lpIniFileName); // return full pathname if found OemToChar (ofIniFile.szPathName, *lpFileName); return TRUE; } else { // filename was on command line, but not valid so return // false, but send name back for error message if (lpExeName) free (lpExeName); OemToChar (lpIniFileName, *lpFileName); return FALSE; } } else { free (lpCmdLineName); SetLastError (ERROR_FILE_NOT_FOUND); if (lpExeName) free (lpExeName); if (lpIniFileName) free (lpIniFileName); return FALSE; } } } } static BOOL GetDriverName ( IN LPTSTR lpIniFile, OUT LPTSTR *lpDevName ) /*++ GetDriverName looks up driver name in the .ini file and returns it in lpDevName Arguments lpIniFile Filename of ini file lpDevName pointer to pointer to reciev buffer w/dev name in it Return Value TRUE if found FALSE if not found in .ini file --*/ { DWORD dwRetSize; if (lpDevName) { dwRetSize = GetPrivateProfileString ( TEXT("info"), // info section TEXT("drivername"), // driver name value TEXT("drivernameNotFound"), // default value *lpDevName, MAX_PATH, lpIniFile); if ((lstrcmpi(*lpDevName, TEXT("drivernameNotFound"))) != 0) { // name found return TRUE; } else { // name not found, default returned so return NULL string *lpDevName = TEXT("\0"); return FALSE; } } else { SetLastError (ERROR_OUTOFMEMORY); return FALSE; } } static BOOL BuildLanguageTables ( IN LPTSTR lpIniFile, IN OUT PLANGUAGE_LIST_ELEMENT pFirstElem ) /*++ BuildLanguageTables Creates a list of structures that will hold the text for each supported language Arguments lpIniFile Filename with data pFirstElem pointer to first list entry ReturnValue TRUE if all OK FALSE if not --*/ { LPTSTR lpEnumeratedLangs; LPTSTR lpThisLang; PLANGUAGE_LIST_ELEMENT pThisElem; DWORD dwSize; lpEnumeratedLangs = malloc(SMALL_BUFFER_SIZE * sizeof(TCHAR)); if (!lpEnumeratedLangs) { SetLastError (ERROR_OUTOFMEMORY); return FALSE; } dwSize = GetPrivateProfileString ( TEXT("languages"), NULL, // return all values in multi-sz string TEXT("009"), // english as the default lpEnumeratedLangs, SMALL_BUFFER_SIZE, lpIniFile); // do first language lpThisLang = lpEnumeratedLangs; // pThisElem = pFirstElem; pThisElem = NULL; while (*lpThisLang) { // // see if this language is supporte on this machine // if (LanguageInstalled(lpThisLang)) { if (pThisElem == NULL) { pThisElem = pFirstElem; } else { pThisElem->pNextLang = malloc (sizeof(LANGUAGE_LIST_ELEMENT)); if (!pThisElem) { SetLastError (ERROR_OUTOFMEMORY); return FALSE; } pThisElem = pThisElem->pNextLang; // point to new one } pThisElem->pNextLang = NULL; pThisElem->LangId = (LPTSTR) malloc ((lstrlen(lpThisLang) + 1) * sizeof(TCHAR)); lstrcpy (pThisElem->LangId, lpThisLang); pThisElem->pFirstName = NULL; pThisElem->pThisName = NULL; pThisElem->dwNumElements=0; pThisElem->NameBuffer = NULL; pThisElem->HelpBuffer = NULL; } else { // skip this language since it isn't installed on the target // machine } // go to next string lpThisLang += lstrlen(lpThisLang) + 1; } return TRUE; } static BOOL TryOtherPath ( IN LPTSTR lpIniFile, IN LPTSTR lpIncludeFileName, OUT OFSTRUCT * pofIncludeFile ) /*++ TryOtherPath Get the include file from other locations since it is not found in the specified location as stated inint ini file. Arguments lpIniFile Ini file with include file name lpIncludeFileName Include file name read from the ini file pofIncludeFile address of the ofstruct to return the OEM full path name. Return Value TRUE if the Include file is nound. FALSE if it is not found. --*/ { BOOL RetCode = FALSE; TCHAR LocalFileName [MAX_PATH]; CHAR AnsiFileName [MAX_PATH]; int StringLen; LPTSTR lpTemp; HFILE hIncludeFile; LPSTR lpFileName; lstrcpy (LocalFileName, lpIniFile) ; lpTemp = LocalFileName + lstrlen(LocalFileName); while (lpTemp != LocalFileName) { // location the end of path name for the ini file if (*lpTemp == TEXT('\\')) { lpTemp++; *lpTemp = TEXT('\0'); break; } else { lpTemp--; } } if (lpTemp != LocalFileName) { // now append the IncludeFileName if we have spaces StringLen = lstrlen (lpIncludeFileName) + lstrlen (LocalFileName); if (StringLen < sizeof(LocalFileName) / sizeof(TCHAR)) { lstrcat (LocalFileName, lpIncludeFileName); } wcstombs (AnsiFileName, LocalFileName, sizeof(AnsiFileName)); hIncludeFile = OpenFile ( AnsiFileName, pofIncludeFile, OF_EXIST); if (hIncludeFile != HFILE_ERROR) { CharToOemA ( pofIncludeFile->szPathName, pofIncludeFile->szPathName); RetCode = TRUE; goto Exit0; } // last try, use filename only so OpenFile will serach // along the path lpFileName = AnsiFileName + strlen(AnsiFileName); while (lpFileName != AnsiFileName) { if (*lpFileName == ':' || *lpFileName == '\\') { lpFileName++; break; } lpFileName--; } if (lpFileName != AnsiFileName) { hIncludeFile = OpenFile ( lpFileName, pofIncludeFile, OF_EXIST); if (hIncludeFile != HFILE_ERROR) { CharToOemA ( pofIncludeFile->szPathName, pofIncludeFile->szPathName); RetCode = TRUE; goto Exit0; } } } Exit0: return (RetCode); } static BOOL LoadIncludeFile ( IN LPTSTR lpIniFile, OUT PSYMBOL_TABLE_ENTRY *pTable ) /*++ LoadIncludeFile Reads the include file that contains symbolic name definitions and loads a table with the values defined Arguments lpIniFile Ini file with include file name pTable address of pointer to table structure created Return Value TRUE if table read or if no table defined FALSE if error encountere reading table --*/ { INT iNumArgs; DWORD dwSize; BOOL bReUse; PSYMBOL_TABLE_ENTRY pThisSymbol = NULL; LPTSTR lpIncludeFileName; LPSTR lpIncludeFile; LPSTR lpLineBuffer; LPSTR lpAnsiSymbol; FILE *fIncludeFile; HFILE hIncludeFile; OFSTRUCT ofIncludeFile; lpIncludeFileName = malloc (MAX_PATH * sizeof (TCHAR)); lpIncludeFile = malloc (MAX_PATH); lpLineBuffer = malloc (DISP_BUFF_SIZE); lpAnsiSymbol = malloc (DISP_BUFF_SIZE); if (!lpIncludeFileName || !lpLineBuffer || !lpAnsiSymbol) { SetLastError (ERROR_OUTOFMEMORY); return FALSE; } // get name of include file (if present) dwSize = GetPrivateProfileString ( TEXT("info"), TEXT("symbolfile"), TEXT("SymbolFileNotFound"), lpIncludeFileName, MAX_PATH, lpIniFile); if ((lstrcmpi(lpIncludeFileName, TEXT("SymbolFileNotFound"))) == 0) { // no symbol file defined *pTable = NULL; return TRUE; } // if here, then a symbol file was defined and is now stored in // lpIncludeFileName CharToOem (lpIncludeFileName, lpIncludeFile); hIncludeFile = OpenFile ( lpIncludeFile, &ofIncludeFile, OF_PARSE); if (hIncludeFile == HFILE_ERROR) { // unable to generate include filename // error is already in GetLastError OUTPUT_MESSAGE (GetFormatResource(LC_ERR_OPEN_INCLUDE), lpIncludeFileName); *pTable = NULL; return FALSE; } else { // open a stream fIncludeFile = fopen (ofIncludeFile.szPathName, "rt"); if (!fIncludeFile) { // try other locations if (TryOtherPath ( lpIniFile, lpIncludeFileName, &ofIncludeFile)) { // try it again fIncludeFile = fopen (ofIncludeFile.szPathName, "rt"); } } if (!fIncludeFile) { OUTPUT_MESSAGE (GetFormatResource(LC_ERR_OPEN_INCLUDE), lpIncludeFileName); *pTable = NULL; return FALSE; } } // // read ANSI Characters from include file // bReUse = FALSE; while (fgets(lpLineBuffer, DISP_BUFF_SIZE, fIncludeFile) != NULL) { if (strlen(lpLineBuffer) > 8) { if (!bReUse) { if (*pTable) { // then add to list pThisSymbol->pNext = malloc (sizeof (SYMBOL_TABLE_ENTRY)); pThisSymbol = pThisSymbol->pNext; } else { // allocate first element *pTable = malloc (sizeof (SYMBOL_TABLE_ENTRY)); pThisSymbol = *pTable; } if (!pThisSymbol) { SetLastError (ERROR_OUTOFMEMORY); return FALSE; } // allocate room for the symbol name by using the line length // - the size of "#define " // pThisSymbol->SymbolName = malloc ((strlen(lpLineBuffer) - 8) * sizeof (TCHAR)); pThisSymbol->SymbolName = malloc (DISP_BUFF_SIZE * sizeof (TCHAR)); if (!pThisSymbol->SymbolName) { SetLastError (ERROR_OUTOFMEMORY); return FALSE; } } // all the memory is allocated so load the fields pThisSymbol->pNext = NULL; iNumArgs = sscanf (lpLineBuffer, "#define %s %d", lpAnsiSymbol, &pThisSymbol->Value); if (iNumArgs != 2) { *(pThisSymbol->SymbolName) = TEXT('\0'); pThisSymbol->Value = (DWORD)-1L; bReUse = TRUE; } else { OemToChar (lpAnsiSymbol, pThisSymbol->SymbolName); bReUse = FALSE; } } } if (lpIncludeFileName) free (lpIncludeFileName); if (lpIncludeFile) free (lpIncludeFile); if (lpLineBuffer) free (lpLineBuffer); fclose (fIncludeFile); return TRUE; } static BOOL ParseTextId ( IN LPTSTR lpTextId, IN PSYMBOL_TABLE_ENTRY pFirstSymbol, OUT PDWORD pdwOffset, OUT LPTSTR *lpLangId, OUT PDWORD pdwType ) /*++ ParseTextId decodes Text Id key from .INI file syntax for this process is: {} {"NAME"} {}__{"HELP"} e.g. 0_009_NAME OBJECT_1_009_HELP Arguments lpTextId string to decode pFirstSymbol pointer to first entry in symbol table (NULL if no table) pdwOffset address of DWORD to recive offest value lpLangId address of pointer to Language Id string (NOTE: this will point into the string lpTextID which will be modified by this routine) pdwType pointer to dword that will recieve the type of string i.e. HELP or NAME Return Value TRUE text Id decoded successfully FALSE unable to decode string NOTE: the string in lpTextID will be modified by this procedure --*/ { LPTSTR lpThisChar; PSYMBOL_TABLE_ENTRY pThisSymbol; // check for valid return arguments if (!(pdwOffset) || !(lpLangId) || !(pdwType)) { SetLastError (ERROR_INVALID_PARAMETER); return FALSE; } // search string from right to left in order to identify the // components of the string. lpThisChar = lpTextId + lstrlen(lpTextId); // point to end of string while (*lpThisChar != TEXT('_')) { lpThisChar--; if (lpThisChar <= lpTextId) { // underscore not found in string SetLastError (ERROR_INVALID_DATA); return FALSE; } } // first underscore found if ((lstrcmpi(lpThisChar, TEXT("_NAME"))) == 0) { // name found, so set type *pdwType = TYPE_NAME; } else if ((lstrcmpi(lpThisChar, TEXT("_HELP"))) == 0) { // help text found, so set type *pdwType = TYPE_HELP; } else { // bad format SetLastError (ERROR_INVALID_DATA); return FALSE; } // set the current underscore to \0 and look for language ID *lpThisChar-- = TEXT('\0'); while (*lpThisChar != TEXT('_')) { lpThisChar--; if (lpThisChar <= lpTextId) { // underscore not found in string SetLastError (ERROR_INVALID_DATA); return FALSE; } } // set lang ID string pointer to current char ('_') + 1 *lpLangId = lpThisChar + 1; // set this underscore to a NULL and try to decode the remaining text *lpThisChar = TEXT('\0'); // see if the first part of the string is a decimal digit if ((_stscanf (lpTextId, TEXT(" %d"), pdwOffset)) != 1) { // it's not a digit, so try to decode it as a symbol in the // loaded symbol table for (pThisSymbol=pFirstSymbol; pThisSymbol && *(pThisSymbol->SymbolName); pThisSymbol = pThisSymbol->pNext) { if ((lstrcmpi(lpTextId, pThisSymbol->SymbolName)) == 0) { // a matching symbol was found, so insert it's value // and return (that's all that needs to be done *pdwOffset = pThisSymbol->Value; return TRUE; } } // if here, then no matching symbol was found, and it's not // a number, so return an error SetLastError (ERROR_BAD_TOKEN_TYPE); return FALSE; } else { // symbol was prefixed with a decimal number return TRUE; } } static PLANGUAGE_LIST_ELEMENT FindLanguage ( IN PLANGUAGE_LIST_ELEMENT pFirstLang, IN LPTSTR pLangId ) /*++ FindLanguage searchs the list of languages and returns a pointer to the language list entry that matches the pLangId string argument Arguments pFirstLang pointer to first language list element pLangId pointer to text string with language ID to look up Return Value Pointer to matching language list entry or NULL if no match --*/ { PLANGUAGE_LIST_ELEMENT pThisLang; for (pThisLang = pFirstLang; pThisLang; pThisLang = pThisLang->pNextLang) { if ((lstrcmpi(pLangId, pThisLang->LangId)) == 0) { // match found so return pointer return pThisLang; } } return NULL; // no match found } static BOOL AddEntryToLanguage ( PLANGUAGE_LIST_ELEMENT pLang, LPTSTR lpValueKey, DWORD dwType, DWORD dwOffset, LPTSTR lpIniFile ) /*++ AddEntryToLanguage Add a text entry to the list of text entries for the specified language Arguments pLang pointer to language structure to update lpValueKey value key to look up in .ini file dwOffset numeric offset of name in registry lpIniFile ini file Return Value TRUE if added successfully FALSE if error (see GetLastError for status) --*/ { LPTSTR lpLocalStringBuff; DWORD dwSize; DWORD dwBufferSize; dwBufferSize = SMALL_BUFFER_SIZE * 4 * sizeof(TCHAR); if (dwBufferSize < dwFileSize) { dwBufferSize = dwFileSize; } lpLocalStringBuff = malloc (dwBufferSize); if (!lpLocalStringBuff) { SetLastError (ERROR_OUTOFMEMORY); return FALSE; } dwSize = GetPrivateProfileString ( TEXT("text"), // section lpValueKey, // key TEXT("DefaultValue"), // default value lpLocalStringBuff, dwBufferSize / sizeof(TCHAR), lpIniFile); if ((lstrcmpi(lpLocalStringBuff, TEXT("DefaultValue")))== 0) { SetLastError (ERROR_BADKEY); if (lpLocalStringBuff) free (lpLocalStringBuff); return FALSE; } // key found, so load structure if (!pLang->pThisName) { // this is the first pLang->pThisName = malloc (sizeof (NAME_ENTRY) + (lstrlen(lpLocalStringBuff) + 1) * sizeof (TCHAR)); if (!pLang->pThisName) { SetLastError (ERROR_OUTOFMEMORY); if (lpLocalStringBuff) free (lpLocalStringBuff); return FALSE; } else { pLang->pFirstName = pLang->pThisName; } } else { pLang->pThisName->pNext = malloc (sizeof (NAME_ENTRY) + (lstrlen(lpLocalStringBuff) + 1) * sizeof (TCHAR)); if (!pLang->pThisName->pNext) { SetLastError (ERROR_OUTOFMEMORY); if (lpLocalStringBuff) free (lpLocalStringBuff); return FALSE; } else { pLang->pThisName = pLang->pThisName->pNext; } } // pLang->pThisName now points to an uninitialized structre pLang->pThisName->pNext = NULL; pLang->pThisName->dwOffset = dwOffset; pLang->pThisName->dwType = dwType; pLang->pThisName->lpText = (LPTSTR)&(pLang->pThisName[1]); // string follows lstrcpy (pLang->pThisName->lpText, lpLocalStringBuff); if (lpLocalStringBuff) free (lpLocalStringBuff); SetLastError (ERROR_SUCCESS); return (TRUE); } static BOOL LoadLanguageLists ( IN LPTSTR lpIniFile, IN DWORD dwFirstCounter, IN DWORD dwFirstHelp, IN PSYMBOL_TABLE_ENTRY pFirstSymbol, IN PLANGUAGE_LIST_ELEMENT pFirstLang ) /*++ LoadLanguageLists Reads in the name and explain text definitions from the ini file and builds a list of these items for each of the supported languages and then combines all the entries into a sorted MULTI_SZ string buffer. Arguments lpIniFile file containing the definitions to add to the registry dwFirstCounter starting counter name index number dwFirstHelp starting help text index number pFirstLang pointer to first element in list of language elements Return Value TRUE if all is well FALSE if not error is returned in GetLastError --*/ { LPTSTR lpTextIdArray; LPTSTR lpLocalKey; LPTSTR lpThisKey; DWORD dwSize; LPTSTR lpLang; DWORD dwOffset; DWORD dwType; PLANGUAGE_LIST_ELEMENT pThisLang; DWORD dwBufferSize; dwBufferSize = SMALL_BUFFER_SIZE * 4 * sizeof(TCHAR); if (dwBufferSize < dwFileSize) { dwBufferSize = dwFileSize; } if (!(lpTextIdArray = malloc (dwBufferSize))) { SetLastError (ERROR_OUTOFMEMORY); return FALSE; } if (!(lpLocalKey = malloc (MAX_PATH * sizeof(TCHAR)))) { SetLastError (ERROR_OUTOFMEMORY); if (lpTextIdArray) free (lpTextIdArray); return FALSE; } // get list of text keys to look up dwSize = GetPrivateProfileString ( TEXT("text"), // [text] section of .INI file NULL, // return all keys TEXT("DefaultKeyValue"), // default lpTextIdArray, // return buffer dwBufferSize / sizeof(TCHAR), lpIniFile); // .INI file name if ((lstrcmpi(lpTextIdArray, TEXT("DefaultKeyValue"))) == 0) { // key not found, default returned SetLastError (ERROR_NO_SUCH_GROUP); if (lpTextIdArray) free (lpTextIdArray); if (lpLocalKey) free (lpLocalKey); return FALSE; } // do each key returned for (lpThisKey=lpTextIdArray; *lpThisKey; lpThisKey += (lstrlen(lpThisKey) + 1)) { lstrcpy (lpLocalKey, lpThisKey); // make a copy of the key // parse key to see if it's in the correct format if (ParseTextId(lpLocalKey, pFirstSymbol, &dwOffset, &lpLang, &dwType)) { // so get pointer to language entry structure pThisLang = FindLanguage (pFirstLang, lpLang); if (pThisLang) { if (!AddEntryToLanguage(pThisLang, lpThisKey, dwType, (dwOffset + ((dwType == TYPE_NAME) ? dwFirstCounter : dwFirstHelp)), lpIniFile)) { OUTPUT_MESSAGE (GetFormatResource (LC_ERRADDTOLANG), lpThisKey, lpLang, GetLastError()); } } else { // language not in list OUTPUT_MESSAGE (GetFormatResource(LC_LANGNOTFOUND), lpLang, lpThisKey); } } else { // unable to parse ID string OUTPUT_MESSAGE(GetFormatResource(LC_BAD_KEY), lpThisKey); } } if (lpTextIdArray) free (lpTextIdArray); if (lpLocalKey) free (lpLocalKey); return TRUE; } static BOOL SortLanguageTables ( PLANGUAGE_LIST_ELEMENT pFirstLang, PDWORD pdwLastName, PDWORD pdwLastHelp ) /*++ SortLangageTables walks list of languages loaded, allocates and loads a sorted multi_SZ buffer containing new entries to be added to current names/help text Arguments pFirstLang pointer to first element in list of languages ReturnValue TRUE everything done as expected FALSE error occurred, status in GetLastError --*/ { PLANGUAGE_LIST_ELEMENT pThisLang; BOOL bSorted; LPTSTR pNameBufPos, pHelpBufPos; PNAME_ENTRY pThisName, pPrevName; DWORD dwHelpSize, dwNameSize, dwSize; if (!pdwLastName || !pdwLastHelp) { SetLastError (ERROR_BAD_ARGUMENTS); return FALSE; } for (pThisLang = pFirstLang; pThisLang; pThisLang = pThisLang->pNextLang) { // do each language in list // sort elements in list by value (offset) so that lowest is first bSorted = FALSE; while (!bSorted ) { // point to start of list pPrevName = pThisLang->pFirstName; if (pPrevName) { pThisName = pPrevName->pNext; } else { break; // no elements in this list } if (!pThisName) { break; // only one element in the list } bSorted = TRUE; // assume that it's sorted // go until end of list while (pThisName->pNext) { if (pThisName->dwOffset > pThisName->pNext->dwOffset) { // switch 'em PNAME_ENTRY pA, pB; pPrevName->pNext = pThisName->pNext; pA = pThisName->pNext; pB = pThisName->pNext->pNext; pThisName->pNext = pB; pA->pNext = pThisName; pThisName = pA; bSorted = FALSE; } //move to next entry pPrevName = pThisName; pThisName = pThisName->pNext; } // if bSorted = TRUE , then we walked all the way down // the list without changing anything so that's the end. } // with the list sorted, build the MULTI_SZ strings for the // help and name text strings // compute buffer size dwNameSize = dwHelpSize = 0; *pdwLastName = *pdwLastHelp = 0; for (pThisName = pThisLang->pFirstName; pThisName; pThisName = pThisName->pNext) { // compute buffer requirements for this entry dwSize = SIZE_OF_OFFSET_STRING; dwSize += lstrlen (pThisName->lpText); dwSize += 1; // null dwSize *= sizeof (TCHAR); // adjust for character size // add to appropriate size register if (pThisName->dwType == TYPE_NAME) { dwNameSize += dwSize; if (pThisName->dwOffset > *pdwLastName) { *pdwLastName = pThisName->dwOffset; } } else if (pThisName->dwType == TYPE_HELP) { dwHelpSize += dwSize; if (pThisName->dwOffset > *pdwLastHelp) { *pdwLastHelp = pThisName->dwOffset; } } } // allocate buffers for the Multi_SZ strings pThisLang->NameBuffer = malloc (dwNameSize); pThisLang->HelpBuffer = malloc (dwHelpSize); if (!pThisLang->NameBuffer || !pThisLang->HelpBuffer) { SetLastError (ERROR_OUTOFMEMORY); return FALSE; } // fill in buffers with sorted strings pNameBufPos = (LPTSTR)pThisLang->NameBuffer; pHelpBufPos = (LPTSTR)pThisLang->HelpBuffer; for (pThisName = pThisLang->pFirstName; pThisName; pThisName = pThisName->pNext) { if (pThisName->dwType == TYPE_NAME) { // load number as first 0-term. string dwSize = _stprintf (pNameBufPos, TEXT("%d"), pThisName->dwOffset); pNameBufPos += dwSize + 1; // save NULL term. // load the text to match lstrcpy (pNameBufPos, pThisName->lpText); pNameBufPos += lstrlen(pNameBufPos) + 1; } else if (pThisName->dwType == TYPE_HELP) { // load number as first 0-term. string dwSize = _stprintf (pHelpBufPos, TEXT("%d"), pThisName->dwOffset); pHelpBufPos += dwSize + 1; // save NULL term. // load the text to match lstrcpy (pHelpBufPos, pThisName->lpText); pHelpBufPos += lstrlen(pHelpBufPos) + 1; } } // add additional NULL at end of string to terminate MULTI_SZ *pHelpBufPos = TEXT('\0'); *pNameBufPos = TEXT('\0'); // compute size of MULTI_SZ strings pThisLang->dwNameBuffSize = (DWORD)((PBYTE)pNameBufPos - (PBYTE)pThisLang->NameBuffer) + sizeof(TCHAR); pThisLang->dwHelpBuffSize = (DWORD)((PBYTE)pHelpBufPos - (PBYTE)pThisLang->HelpBuffer) + sizeof(TCHAR); } return TRUE; } static BOOL UpdateEachLanguage ( HKEY hPerflibRoot, PLANGUAGE_LIST_ELEMENT pFirstLang ) /*++ UpdateEachLanguage Goes through list of languages and adds the sorted MULTI_SZ strings to the existing counter and explain text in the registry. Also updates the "Last Counter and Last Help" values Arguments hPerflibRoot handle to Perflib key in the registry pFirstLanguage pointer to first language entry Return Value TRUE all went as planned FALSE an error occured, use GetLastError to find out what it was. --*/ { PLANGUAGE_LIST_ELEMENT pThisLang; LPTSTR pHelpBuffer; LPTSTR pNameBuffer; LPTSTR pNewName; LPTSTR pNewHelp; DWORD dwBufferSize; DWORD dwValueType; DWORD dwCounterSize; DWORD dwHelpSize; HKEY hKeyThisLang; LONG lStatus; TCHAR CounterNameBuffer [20]; TCHAR HelpNameBuffer [20]; TCHAR AddCounterNameBuffer [20]; TCHAR AddHelpNameBuffer [20]; for (pThisLang = pFirstLang; pThisLang; pThisLang = pThisLang->pNextLang) { if (dwSystemVersion == OLD_VERSION) { // Open key for this language lStatus = RegOpenKeyEx( hPerflibRoot, pThisLang->LangId, RESERVED, KEY_READ | KEY_WRITE, &hKeyThisLang); } else { lstrcpy (CounterNameBuffer, CounterNameStr); lstrcat (CounterNameBuffer, pThisLang->LangId); lstrcpy (HelpNameBuffer, HelpNameStr); lstrcat (HelpNameBuffer, pThisLang->LangId); lstrcpy (AddCounterNameBuffer, AddCounterNameStr); lstrcat (AddCounterNameBuffer, pThisLang->LangId); lstrcpy (AddHelpNameBuffer, AddHelpNameStr); lstrcat (AddHelpNameBuffer, pThisLang->LangId); // make sure this language is loaded lStatus = RegOpenKeyEx( hPerflibRoot, pThisLang->LangId, RESERVED, KEY_READ, &hKeyThisLang); // we just need the open status, not the key handle so // close this handle and set the one we need. RegCloseKey (hKeyThisLang); // hKeyThisLang = HKEY_PERFORMANCE_DATA; hKeyThisLang = hPerfData; } if (lStatus == ERROR_SUCCESS) { // make a backup copy of the data file before updating the // contents if (dwSystemVersion != OLD_VERSION) { // this isn't possible on 3.1 MakeBackupCopyOfLanguageFiles (pThisLang->LangId); } // get size of counter names dwBufferSize = 0; lStatus = RegQueryValueEx ( hKeyThisLang, (dwSystemVersion == OLD_VERSION) ? Counters : CounterNameBuffer, RESERVED, &dwValueType, NULL, &dwBufferSize); if (lStatus != ERROR_SUCCESS) { if (dwSystemVersion != OLD_VERSION) { // this means the language is not installed in the system. continue; } SetLastError (lStatus); return FALSE; } dwCounterSize = dwBufferSize; // get size of help text dwBufferSize = 0; lStatus = RegQueryValueEx ( hKeyThisLang, (dwSystemVersion == OLD_VERSION) ? Help : HelpNameBuffer, RESERVED, &dwValueType, NULL, &dwBufferSize); if (lStatus != ERROR_SUCCESS) { if (dwSystemVersion != OLD_VERSION) { // this means the language is not installed in the system. continue; } SetLastError (lStatus); return FALSE; } dwHelpSize = dwBufferSize; // allocate new buffers dwCounterSize += pThisLang->dwNameBuffSize; pNameBuffer = malloc (dwCounterSize); dwHelpSize += pThisLang->dwHelpBuffSize; pHelpBuffer = malloc (dwHelpSize); if (!pNameBuffer || !pHelpBuffer) { SetLastError (ERROR_OUTOFMEMORY); return (FALSE); } // load current buffers into memory // read counter names into buffer. Counter names will be stored as // a MULTI_SZ string in the format of "###" "Name" dwBufferSize = dwCounterSize; lStatus = RegQueryValueEx ( hKeyThisLang, (dwSystemVersion == OLD_VERSION) ? Counters : CounterNameBuffer, RESERVED, &dwValueType, (LPVOID)pNameBuffer, &dwBufferSize); if (lStatus != ERROR_SUCCESS) { SetLastError (lStatus); return FALSE; } // set pointer to location in buffer where new string should be // appended: end of buffer - 1 (second null at end of MULTI_SZ pNewName = (LPTSTR)((PBYTE)pNameBuffer + dwBufferSize - sizeof(TCHAR)); // adjust buffer length to take into account 2nd null from 1st // buffer that has been overwritten dwCounterSize -= sizeof(TCHAR); // read explain text into buffer. Counter names will be stored as // a MULTI_SZ string in the format of "###" "Text..." dwBufferSize = dwHelpSize; lStatus = RegQueryValueEx ( hKeyThisLang, (dwSystemVersion == OLD_VERSION) ? Help : HelpNameBuffer, RESERVED, &dwValueType, (LPVOID)pHelpBuffer, &dwBufferSize); if (lStatus != ERROR_SUCCESS) { SetLastError (lStatus); return FALSE; } // set pointer to location in buffer where new string should be // appended: end of buffer - 1 (second null at end of MULTI_SZ pNewHelp = (LPTSTR)((PBYTE)pHelpBuffer + dwBufferSize - sizeof(TCHAR)); // adjust buffer length to take into account 2nd null from 1st // buffer that has been overwritten dwHelpSize -= sizeof(TCHAR); // append new strings to end of current strings memcpy (pNewHelp, pThisLang->HelpBuffer, pThisLang->dwHelpBuffSize); memcpy (pNewName, pThisLang->NameBuffer, pThisLang->dwNameBuffSize); if (dwSystemVersion == OLD_VERSION) { // load new strings back to the registry lStatus = RegSetValueEx ( hKeyThisLang, Counters, RESERVED, REG_MULTI_SZ, (LPBYTE)pNameBuffer, dwCounterSize); if (lStatus != ERROR_SUCCESS) { SetLastError (lStatus); return FALSE; } lStatus = RegSetValueEx ( hKeyThisLang, Help, RESERVED, REG_MULTI_SZ, (LPBYTE)pHelpBuffer, dwHelpSize); if (lStatus != ERROR_SUCCESS) { SetLastError (lStatus); return FALSE; } } else { // write to the file thru PerfLib dwBufferSize = dwCounterSize; lStatus = RegQueryValueEx ( hKeyThisLang, AddCounterNameBuffer, RESERVED, &dwValueType, (LPVOID)pNameBuffer, &dwBufferSize); if (lStatus != ERROR_SUCCESS) { SetLastError (lStatus); return FALSE; } dwBufferSize = dwHelpSize; lStatus = RegQueryValueEx ( hKeyThisLang, AddHelpNameBuffer, RESERVED, &dwValueType, (LPVOID)pHelpBuffer, &dwBufferSize); if (lStatus != ERROR_SUCCESS) { SetLastError (lStatus); return FALSE; } } free (pNameBuffer); free (pHelpBuffer); if (dwSystemVersion == OLD_VERSION) RegCloseKey (hKeyThisLang); } else { OUTPUT_MESSAGE (GetFormatResource (LC_UNABLEOPENLANG), pThisLang->LangId); } } return TRUE; } static BOOL UpdateRegistry ( LPTSTR lpIniFile, HKEY hKeyMachine, LPTSTR lpDriverName, PLANGUAGE_LIST_ELEMENT pFirstLang, PSYMBOL_TABLE_ENTRY pFirstSymbol ) /*++ UpdateRegistry - checks, and if not busy, sets the "busy" key in the registry - Reads in the text and help definitions from the .ini file - Reads in the current contents of the HELP and COUNTER names - Builds a sorted MULTI_SZ struct containing the new definitions - Appends the new MULTI_SZ to the current as read from the registry - loads the new MULTI_SZ string into the registry - updates the keys in the driver's entry and Perflib's entry in the registry (e.g. first, last, etc) - clears the "busy" key Arguments lpIniFile pathname to .ini file conatining definitions hKeyMachine handle to HKEY_LOCAL_MACHINE in registry on system to update counters for. lpDriverName Name of device driver to load counters for pFirstLang pointer to first element in language structure list pFirstSymbol pointer to first element in symbol definition list Return Value TRUE if registry updated successfully FALSE if registry not updated (This routine will print an error message to stdout if an error is encountered). --*/ { HKEY hDriverPerf = NULL; HKEY hPerflib = NULL; LPTSTR lpDriverKeyPath; DWORD dwType; DWORD dwSize; DWORD dwFirstDriverCounter; DWORD dwFirstDriverHelp; DWORD dwLastDriverCounter; DWORD dwLastPerflibCounter; DWORD dwLastPerflibHelp; BOOL bStatus; LONG lStatus; HANDLE hFileMapping = NULL; DWORD MapFileSize; SECURITY_ATTRIBUTES SecAttr; TCHAR MapFileName[] = TEXT("Perflib Busy"); DWORD *lpData; bStatus = FALSE; SetLastError (ERROR_SUCCESS); // allocate temporary buffers lpDriverKeyPath = malloc (MAX_PATH * sizeof(TCHAR)); if (!lpDriverKeyPath) { SetLastError (ERROR_OUTOFMEMORY); goto UpdateRegExit; } // build driver key path string lstrcpy (lpDriverKeyPath, DriverPathRoot); lstrcat (lpDriverKeyPath, Slash); lstrcat (lpDriverKeyPath, lpDriverName); lstrcat (lpDriverKeyPath, Slash); lstrcat (lpDriverKeyPath, Performance); // check if we need to connect to remote machine if (ComputerName[0]) { lStatus = !ERROR_SUCCESS; try { lStatus = RegConnectRegistry ( (LPTSTR)ComputerName, HKEY_LOCAL_MACHINE, &hKeyMachine); } finally { if (lStatus != ERROR_SUCCESS) { SetLastError (lStatus); hKeyMachine = NULL; OUTPUT_MESSAGE (GetFormatResource(LC_CONNECT_PROBLEM), ComputerName, lStatus); bStatus = FALSE; goto UpdateRegExit; } } } else { hKeyMachine = HKEY_LOCAL_MACHINE; } // open keys to registry // open key to driver's performance key lStatus = RegOpenKeyEx ( hKeyMachine, lpDriverKeyPath, RESERVED, KEY_WRITE | KEY_READ, &hDriverPerf); if (lStatus != ERROR_SUCCESS) { OUTPUT_MESSAGE (GetFormatResource(LC_ERR_OPEN_DRIVERPERF1), lpDriverKeyPath); OUTPUT_MESSAGE (GetFormatResource(LC_ERR_OPEN_DRIVERPERF2), lStatus); SetLastError (lStatus); goto UpdateRegExit; } // open key to perflib's "root" key lStatus = RegOpenKeyEx ( hKeyMachine, NamesKey, RESERVED, KEY_WRITE | KEY_READ, &hPerflib); if (lStatus != ERROR_SUCCESS) { OUTPUT_MESSAGE (GetFormatResource(LC_ERR_OPEN_PERFLIB), lStatus); SetLastError (lStatus); goto UpdateRegExit; } // get "last" values from PERFLIB dwType = 0; dwLastPerflibCounter = 0; dwSize = sizeof (dwLastPerflibCounter); lStatus = RegQueryValueEx ( hPerflib, LastCounter, RESERVED, &dwType, (LPBYTE)&dwLastPerflibCounter, &dwSize); if (lStatus != ERROR_SUCCESS) { // this request should always succeed, if not then worse things // will happen later on, so quit now and avoid the trouble. OUTPUT_MESSAGE (GetFormatResource (LC_ERR_READLASTPERFLIB), lStatus); SetLastError (lStatus); goto UpdateRegExit; } // get last help value now dwType = 0; dwLastPerflibHelp = 0; dwSize = sizeof (dwLastPerflibHelp); lStatus = RegQueryValueEx ( hPerflib, LastHelp, RESERVED, &dwType, (LPBYTE)&dwLastPerflibHelp, &dwSize); if (lStatus != ERROR_SUCCESS) { // this request should always succeed, if not then worse things // will happen later on, so quit now and avoid the trouble. OUTPUT_MESSAGE (GetFormatResource (LC_ERR_READLASTPERFLIB), lStatus); SetLastError (lStatus); goto UpdateRegExit; } // get last help value now dwType = 0; dwSize = sizeof (dwSystemVersion); lStatus = RegQueryValueEx ( hPerflib, VersionStr, RESERVED, &dwType, (LPBYTE)&dwSystemVersion, &dwSize); if (lStatus != ERROR_SUCCESS) { dwSystemVersion = OLD_VERSION; } // set the hPerfData to HKEY_PERFORMANCE_DATA for new version // if remote machine, then need to connect to it. if (dwSystemVersion != OLD_VERSION) { hPerfData = HKEY_PERFORMANCE_DATA; lStatus = !ERROR_SUCCESS; if (ComputerName[0]) { #if 0 // the following is not working for remote machine since we // are using RegQueryValue to add the counter. // Need to fix up Perflib before it will work try { lStatus = RegConnectRegistry ( (LPTSTR)ComputerName, HKEY_PERFORMANCE_DATA, &hPerfData); } finally { if (lStatus != ERROR_SUCCESS) { SetLastError (lStatus); hPerfData = NULL; OUTPUT_MESSAGE (GetFormatResource(LC_CONNECT_PROBLEM), ComputerName, lStatus); bStatus = FALSE; goto UpdateRegExit; } } #else // have to do it the old faction way dwSystemVersion = OLD_VERSION; lStatus = ERROR_SUCCESS; #endif } } // NEW_VERSION // see if this driver's counter names have already been installed // by checking to see if LastCounter's value is less than Perflib's // Last Counter dwType = 0; dwLastDriverCounter = 0; dwSize = sizeof (dwLastDriverCounter); lStatus = RegQueryValueEx ( hDriverPerf, LastCounter, RESERVED, &dwType, (LPBYTE)&dwLastDriverCounter, &dwSize); if (lStatus == ERROR_SUCCESS) { // if key found, then compare with perflib value and exit this // procedure if the driver's last counter is <= to perflib's last // // if key not found, then continue with installation // on the assumption that the counters have not been installed if (dwLastDriverCounter <= dwLastPerflibCounter) { OUTPUT_MESSAGE (GetFormatResource(LC_ERR_ALREADY_IN), lpDriverName); SetLastError (ERROR_ALREADY_EXISTS); goto UpdateRegExit; } } // This checking is causing more problems than necessary. Removed // for now. SHould use named semaphore instead. #if 0 // everything looks like it's ready to go so first check the // busy indicator lStatus = RegQueryValueEx ( hPerflib, Busy, RESERVED, &dwType, NULL, &dwSize); if (lStatus == ERROR_SUCCESS) { // perflib is in use at the moment OUTPUT_MESSAGE (GetFormatResource (LC_PERFLIBISBUSY)); return ERROR_BUSY; } #endif // create the file mapping SecAttr.nLength = sizeof (SecAttr); SecAttr.bInheritHandle = TRUE; SecAttr.lpSecurityDescriptor = NULL; MapFileSize = sizeof(DWORD); hFileMapping = CreateFileMapping ((HANDLE)0xFFFFFFFF, &SecAttr, PAGE_READWRITE, (DWORD)0, MapFileSize, (LPCTSTR)MapFileName); if (hFileMapping) { lpData = MapViewOfFile (hFileMapping, FILE_MAP_ALL_ACCESS, 0L, 0L, 0L); if (lpData) { *lpData = 1L; UnmapViewOfFile (lpData); } } // set the "busy" indicator under the PERFLIB key dwSize = lstrlen(lpDriverName) * sizeof (TCHAR); lStatus = RegSetValueEx ( hPerflib, Busy, RESERVED, REG_SZ, (LPBYTE)lpDriverName, dwSize); if (lStatus != ERROR_SUCCESS) { OUTPUT_MESSAGE (GetFormatResource (LC_ERR_UNABLESETBUSY), lStatus); SetLastError (lStatus); goto UpdateRegExit; } // increment (by 2) the last counters so they point to the first // unused index after the existing names and then // set the first driver counters dwFirstDriverCounter = dwLastPerflibCounter += 2; dwFirstDriverHelp = dwLastPerflibHelp += 2; // load .INI file definitions into language tables if (!LoadLanguageLists (lpIniFile, dwLastPerflibCounter, dwLastPerflibHelp, pFirstSymbol, pFirstLang)) { // error message is displayed by LoadLanguageLists so just abort // error is in GetLastError already goto UpdateRegExit; } // all the symbols and definitions have been loaded into internal // tables. so now they need to be sorted and merged into a multiSZ string // this routine also updates the "last" counters if (!SortLanguageTables (pFirstLang, &dwLastPerflibCounter, &dwLastPerflibHelp)) { OUTPUT_MESSAGE (GetFormatResource(LC_UNABLESORTTABLES), GetLastError()); goto UpdateRegExit; } if (!UpdateEachLanguage (hPerflib, pFirstLang)) { OUTPUT_MESSAGE (GetFormatResource(LC_ERR_UPDATELANG), GetLastError()); goto UpdateRegExit; } // update last counters for driver and perflib // perflib... lStatus = RegSetValueEx( hPerflib, LastCounter, RESERVED, REG_DWORD, (LPBYTE)&dwLastPerflibCounter, sizeof(DWORD)); if (lStatus != ERROR_SUCCESS) { OUTPUT_MESSAGE (GetFormatResource (LC_UNABLESETVALUE), LastCounter, TEXT("Perflib")); } lStatus = RegSetValueEx( hPerflib, LastHelp, RESERVED, REG_DWORD, (LPBYTE)&dwLastPerflibHelp, sizeof(DWORD)); if (lStatus != ERROR_SUCCESS) { OUTPUT_MESSAGE (GetFormatResource (LC_UNABLESETVALUE), LastHelp, TEXT("Perflib")); } // and the driver lStatus = RegSetValueEx( hDriverPerf, LastCounter, RESERVED, REG_DWORD, (LPBYTE)&dwLastPerflibCounter, sizeof(DWORD)); if (lStatus != ERROR_SUCCESS) { OUTPUT_MESSAGE (GetFormatResource (LC_UNABLESETVALUE), LastCounter, lpDriverName); } lStatus = RegSetValueEx( hDriverPerf, LastHelp, RESERVED, REG_DWORD, (LPBYTE)&dwLastPerflibHelp, sizeof(DWORD)); if (lStatus != ERROR_SUCCESS) { OUTPUT_MESSAGE (GetFormatResource (LC_UNABLESETVALUE), LastHelp, lpDriverName); } lStatus = RegSetValueEx( hDriverPerf, FirstCounter, RESERVED, REG_DWORD, (LPBYTE)&dwFirstDriverCounter, sizeof(DWORD)); if (lStatus != ERROR_SUCCESS) { OUTPUT_MESSAGE (GetFormatResource (LC_UNABLESETVALUE), FirstCounter, lpDriverName); } lStatus = RegSetValueEx( hDriverPerf, FirstHelp, RESERVED, REG_DWORD, (LPBYTE)&dwFirstDriverHelp, sizeof(DWORD)); if (lStatus != ERROR_SUCCESS) { OUTPUT_MESSAGE (GetFormatResource (LC_UNABLESETVALUE), FirstHelp, lpDriverName); } bStatus = TRUE; // free temporary buffers UpdateRegExit: // clear busy flag lStatus = RegDeleteValue ( hPerflib, Busy); // free temporary buffers if (lpDriverKeyPath) free (lpDriverKeyPath); if (hDriverPerf) RegCloseKey (hDriverPerf); if (hPerflib) RegCloseKey (hPerflib); // if (dwSystemVersion != OLD_VERSION) { // RegCloseKey (HKEY_PERFORMANCE_DATA) ; // } if (hFileMapping) { CloseHandle (hFileMapping); } if (hPerfData && hPerfData != HKEY_PERFORMANCE_DATA) { RegCloseKey (hPerfData); } if (hKeyMachine && hKeyMachine != HKEY_LOCAL_MACHINE) { RegCloseKey (hKeyMachine) ; } return bStatus; } LOADPERF_FUNCTION LoadPerfCounterTextStringsW ( IN LPWSTR lpCommandLine, IN BOOL bQuietModeArg ) /*++ LoadPerfCounterTexStringsW loads the perf counter strings into the registry and updates the perf counter text registry values Arguments command line string in the following format: "/?" displays the usage text "file.ini" loads the perf strings found in file.ini "\\machine file.ini" loads the perf strings found onto machine ReturnValue 0 (ERROR_SUCCESS) if command was processed Non-Zero if command error was detected. --*/ { LPTSTR lpIniFile; LPTSTR lpDriverName; LANGUAGE_LIST_ELEMENT LangList; PSYMBOL_TABLE_ENTRY SymbolTable = NULL; PSYMBOL_TABLE_ENTRY pThisSymbol = NULL; int ErrorCode = ERROR_SUCCESS; lpIniFile = malloc (MAX_PATH * sizeof (TCHAR)); lpDriverName = malloc (MAX_PATH * sizeof (TCHAR)); if (!lpIniFile || !lpDriverName) { return (ERROR_OUTOFMEMORY); } *lpIniFile = TEXT('\0'); *lpDriverName = TEXT('\0'); // save quiet mode flag value bQuietMode = bQuietModeArg; // read command line to determine what to do if (GetFileFromCommandLine (lpCommandLine, &lpIniFile)) { // valid filename (i.e. file exists) // get device driver name if (!GetDriverName (lpIniFile, &lpDriverName)) { OUTPUT_MESSAGE (GetFormatResource(LC_DEVNAME_ERR_1), lpIniFile); OUTPUT_MESSAGE (GetFormatResource(LC_DEVNAME_ERR_2)); ErrorCode = ERROR_INVALID_PARAMETER; goto EndOfMain; } if (!BuildLanguageTables(lpIniFile, &LangList)) { OUTPUT_MESSAGE (GetFormatResource(LC_LANGLIST_ERR), lpIniFile); ErrorCode = LC_LANGLIST_ERR; goto EndOfMain; } if (!LoadIncludeFile(lpIniFile, &SymbolTable)) { // open errors displayed in routine ErrorCode = LC_LANGLIST_ERR; goto EndOfMain; } if (!UpdateRegistry(lpIniFile, HKEY_LOCAL_MACHINE, lpDriverName, &LangList, SymbolTable)) { OUTPUT_MESSAGE (GetFormatResource(LC_ERR_UPDATE_REG)); ErrorCode = LC_ERR_UPDATE_REG; } } else { if (*lpIniFile) { OUTPUT_MESSAGE (GetFormatResource(LC_NO_INIFILE), lpIniFile); } else { //Incorrect Command Format // display command line usage if (!bQuietMode) { DisplayCommandHelp(LC_FIRST_CMD_HELP, LC_LAST_CMD_HELP); } ErrorCode = ERROR_INVALID_PARAMETER; } } EndOfMain: if (lpIniFile) free (lpIniFile); if (lpDriverName) free (lpDriverName); return (ErrorCode); } LOADPERF_FUNCTION LoadPerfCounterTextStringsA ( IN LPSTR lpAnsiCommandLine, IN BOOL bQuietModeArg ) { LPWSTR lpWideCommandLine; DWORD dwStrLen; LONG lReturn; if (lpAnsiCommandLine != NULL) { //length of string including terminator dwStrLen = lstrlenA(lpAnsiCommandLine) + 1; lpWideCommandLine = GlobalAlloc (GPTR, (dwStrLen * sizeof(WCHAR))); if (lpWideCommandLine != NULL) { mbstowcs (lpWideCommandLine, lpAnsiCommandLine, dwStrLen); lReturn = LoadPerfCounterTextStringsW (lpWideCommandLine, bQuietModeArg ); GlobalFree (lpWideCommandLine); } else { lReturn = GetLastError(); } } else { lReturn = ERROR_INVALID_PARAMETER; } return lReturn; }