summaryrefslogtreecommitdiffstats
path: root/private/nw/install/setupdll/lodctr.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/nw/install/setupdll/lodctr.c')
-rw-r--r--private/nw/install/setupdll/lodctr.c1531
1 files changed, 1531 insertions, 0 deletions
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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+//
+// Windows Include files
+//
+#include <windows.h>
+#include <winperf.h>
+#include <tchar.h>
+//
+#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:
+
+ {<DecimalNumber>} {"NAME"}
+ {<SymbolInTable>}_<LangIdString>_{"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
+}