From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/nw/install/setupdll/lodctr.c | 1531 ++++++++++++++++++++++++++++++++++ 1 file changed, 1531 insertions(+) create mode 100644 private/nw/install/setupdll/lodctr.c (limited to 'private/nw/install/setupdll/lodctr.c') diff --git a/private/nw/install/setupdll/lodctr.c b/private/nw/install/setupdll/lodctr.c new file mode 100644 index 000000000..bfe95538d --- /dev/null +++ b/private/nw/install/setupdll/lodctr.c @@ -0,0 +1,1531 @@ +/*++ + +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 +// +#define _INITIALIZE_GLOBALS_ 1 +#include "common.h" +#undef _INITIALIZE_GLOBALS_ + +#define TYPE_HELP 1 +#define TYPE_NAME 2 + +#include "nwcfg.hxx" + +#define OLD_VERSION 0x010000 +DWORD dwSystemVersion; + + +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, + DISP_BUFF_SIZE, + 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; + } +} + +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); + + 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; + + while (*lpThisLang) { + 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; + + // go to next string + + lpThisLang += lstrlen(lpThisLang) + 1; + + if (*lpThisLang) { // there's another so allocate a new element + pThisElem->pNextLang = malloc (sizeof(LANGUAGE_LIST_ELEMENT)); + if (!pThisElem) { + SetLastError (ERROR_OUTOFMEMORY); + return FALSE; + } + pThisElem = pThisElem->pNextLang; // point to new one + } + } + + return TRUE; +} + +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; + + 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, + _msize(lpIncludeFileName), + 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 read include filename + // error is already in GetLastError + *pTable = NULL; + return FALSE; + } else { + // open a stream + fIncludeFile = fopen (ofIncludeFile.szPathName, "rt"); + + if (!fIncludeFile) { + *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; + +} + +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; + } +} + +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 +} + +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; + + lpLocalStringBuff = malloc (SMALL_BUFFER_SIZE); + + if (!lpLocalStringBuff) { + SetLastError (ERROR_OUTOFMEMORY); + return FALSE; + } + + dwSize = GetPrivateProfileString ( + TEXT("text"), // section + lpValueKey, // key + TEXT("DefaultValue"), // default value + lpLocalStringBuff, + SMALL_BUFFER_SIZE, + 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); +} + +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; + + if (!(lpTextIdArray = malloc (SMALL_BUFFER_SIZE))) { + SetLastError (ERROR_OUTOFMEMORY); + return FALSE; + } + + if (!(lpLocalKey = malloc (MAX_PATH))) { + 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 + SMALL_BUFFER_SIZE, // buffer size + 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)) { + } + } else { // language not in list + } + } else { // unable to parse ID string + } + } + + if (lpTextIdArray) free (lpTextIdArray); + if (lpLocalKey) free (lpLocalKey); + return TRUE; + +} + +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 + pPrevName->pNext = pThisName->pNext; + pThisName->pNext = pThisName->pNext->pNext; + pThisName->pNext->pNext = pThisName; + 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; +} + +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; + + for (pThisLang = pFirstLang; + pThisLang; + pThisLang = pThisLang->pNextLang) { + + lStatus = RegOpenKeyEx( + hPerflibRoot, + pThisLang->LangId, + RESERVED, + KEY_READ | KEY_WRITE, + &hKeyThisLang); + + if (lStatus == ERROR_SUCCESS) { + + // get size of counter names + + dwBufferSize = 0; + lStatus = RegQueryValueEx ( + hKeyThisLang, + Counters, + RESERVED, + &dwValueType, + NULL, + &dwBufferSize); + + if (lStatus != ERROR_SUCCESS) { + SetLastError (lStatus); + return FALSE; + } + + dwCounterSize = dwBufferSize; + + // get size of help text + + dwBufferSize = 0; + lStatus = RegQueryValueEx ( + hKeyThisLang, + Help, + RESERVED, + &dwValueType, + NULL, + &dwBufferSize); + + if (lStatus != ERROR_SUCCESS) { + 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, + Counters, + 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, + Help, + 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); + + 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; + } + free (pNameBuffer); + free (pHelpBuffer); + CloseHandle (hKeyThisLang); + } else { + } + } + + return TRUE; +} + +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; + + bStatus = FALSE; + + // 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); + + // 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) { + 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) { + 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. + 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. + 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; + } + + if ( dwSystemVersion != OLD_VERSION ) + { + // ERROR. The caller does not check the version. It is the caller + // fault + goto UpdateRegExit; + } + + // 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) { + SetLastError (ERROR_SUCCESS); + goto UpdateRegExit; + } + } + + // 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 + return ERROR_BUSY; + } + + // 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) { + 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)) { + goto UpdateRegExit; + } + + if (!UpdateEachLanguage (hPerflib, pFirstLang)) { + goto UpdateRegExit; + } + + // update last counters for driver and perflib + + // perflib... + + lStatus = RegSetValueEx( + hPerflib, + LastCounter, + RESERVED, + REG_DWORD, + (LPBYTE)&dwLastPerflibCounter, + sizeof(DWORD)); + + lStatus = RegSetValueEx( + hPerflib, + LastHelp, + RESERVED, + REG_DWORD, + (LPBYTE)&dwLastPerflibHelp, + sizeof(DWORD)); + + // and the driver + + lStatus = RegSetValueEx( + hDriverPerf, + LastCounter, + RESERVED, + REG_DWORD, + (LPBYTE)&dwLastPerflibCounter, + sizeof(DWORD)); + + lStatus = RegSetValueEx( + hDriverPerf, + LastHelp, + RESERVED, + REG_DWORD, + (LPBYTE)&dwLastPerflibHelp, + sizeof(DWORD)); + + lStatus = RegSetValueEx( + hDriverPerf, + FirstCounter, + RESERVED, + REG_DWORD, + (LPBYTE)&dwFirstDriverCounter, + sizeof(DWORD)); + + lStatus = RegSetValueEx( + hDriverPerf, + FirstHelp, + RESERVED, + REG_DWORD, + (LPBYTE)&dwFirstDriverHelp, + sizeof(DWORD)); + + bStatus = TRUE; + + // free temporary buffers +UpdateRegExit: + // clear busy flag + + lStatus = RegDeleteValue ( + hPerflib, + Busy); + + // free temporary buffers + + if (lpDriverKeyPath) free (lpDriverKeyPath); + if (hDriverPerf) CloseHandle (hDriverPerf); + if (hPerflib) CloseHandle (hPerflib); + + return bStatus; +} + +BOOL FAR PASCAL lodctr(DWORD argc,LPSTR argv[], LPSTR *ppszResult ) +/*++ + +main + + + +Arguments + + +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; + + BOOL fReturn = TRUE; + + lpIniFile = malloc( MAX_PATH * sizeof(TCHAR)); + lpDriverName = malloc (MAX_PATH * sizeof (TCHAR)); + + wsprintfA( achBuff, "{\"NO_ERROR\"}"); + + if ( argc == 1) { + MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, argv[0], -1, lpIniFile, MAX_PATH); + + if (!GetDriverName (lpIniFile, &lpDriverName)) { + wsprintfA(achBuff,"{\"ERROR\"}"); + fReturn = FALSE; + goto EndOfMain; + } + + if (!BuildLanguageTables(lpIniFile, &LangList)) { + wsprintfA (achBuff, "{\"ERROR\"}"); + fReturn = FALSE; + goto EndOfMain; + } + + if (!LoadIncludeFile(lpIniFile, &SymbolTable)) { + // open errors displayed in routine + fReturn = FALSE; + goto EndOfMain; + } + + if (!UpdateRegistry(lpIniFile, + HKEY_LOCAL_MACHINE, + lpDriverName, + &LangList, + SymbolTable)) { + wsprintfA (achBuff, "{\"ERROR\"}"); + fReturn = FALSE; + } + + } + +EndOfMain: + + if (lpIniFile) free (lpDriverName); + if (lpDriverName) free (lpDriverName); + + *ppszResult = achBuff; + + return (fReturn); // success +} -- cgit v1.2.3