windows-nt/Source/XPSP1/NT/ds/nw/install/setupdll/lodctr.c

1581 lines
40 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
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
lstrcpy(*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 * 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;
while (*lpThisLang) {
pThisElem->pNextLang = NULL;
pThisElem->LangId = (LPTSTR) malloc ((lstrlen(lpThisLang) + 1) * sizeof(TCHAR));
if (pThisElem->LangId == NULL) {
free(lpEnumeratedLangs);
SetLastError (ERROR_OUTOFMEMORY);
return FALSE;
}
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) {
free(pThisElem->LangId);
free(lpEnumeratedLangs);
SetLastError (ERROR_OUTOFMEMORY);
return FALSE;
}
pThisElem = pThisElem->pNextLang; // point to new one
}
}
free(lpEnumeratedLangs);
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;
BOOL bReturn = TRUE;
PSYMBOL_TABLE_ENTRY pThisSymbol;
LPTSTR lpIncludeFileName = NULL;
LPSTR lpIncludeFile = NULL;
LPSTR lpLineBuffer = NULL;
LPSTR lpAnsiSymbol = NULL;
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 || !lpIncludeFile || !lpLineBuffer || !lpAnsiSymbol) {
if (lpIncludeFileName) {
free(lpIncludeFileName);
}
if (lpIncludeFile) {
free(lpIncludeFile);
}
if (lpLineBuffer) {
free(lpLineBuffer);
}
if (lpAnsiSymbol) {
free(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;
goto CleanUp2;
}
// 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;
bReturn = FALSE;
goto CleanUp2;
} else {
// open a stream
fIncludeFile = fopen (ofIncludeFile.szPathName, "rt");
if (!fIncludeFile) {
*pTable = NULL;
bReturn = FALSE;
goto CleanUp2;
}
}
//
// 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);
bReturn = FALSE;
goto CleanUp;
}
// 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);
bReturn = FALSE;
goto CleanUp;
}
}
// 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;
}
}
}
CleanUp:
fclose (fIncludeFile);
CleanUp2:
if (lpIncludeFileName) free (lpIncludeFileName);
if (lpIncludeFile) free (lpIncludeFile);
if (lpLineBuffer) free (lpLineBuffer);
if (lpAnsiSymbol) free (lpAnsiSymbol);
return bReturn;
}
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 * sizeof(TCHAR));
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 * sizeof(TCHAR)))) {
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 = NULL;
LPTSTR pNameBuffer = NULL;
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) {
if (pNameBuffer) {
free(pNameBuffer);
}
if (pHelpBuffer) {
free(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);
goto ErrorExit;
}
// 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);
goto ErrorExit;
}
// 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);
goto ErrorExit;
}
lStatus = RegSetValueEx (
hKeyThisLang,
Help,
RESERVED,
REG_MULTI_SZ,
(LPBYTE)pHelpBuffer,
dwHelpSize);
if (lStatus != ERROR_SUCCESS) {
SetLastError (lStatus);
goto ErrorExit;
}
ErrorExit:
free (pNameBuffer);
free (pHelpBuffer);
CloseHandle (hKeyThisLang);
if (lStatus != ERROR_SUCCESS)
return FALSE;
} 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
if (hPerflib) {
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));
if ((lpIniFile == NULL) || (lpDriverName == NULL)) {
if (lpIniFile) {
free(lpIniFile);
}
if (lpDriverName) {
free(lpDriverName);
}
SetLastError (ERROR_OUTOFMEMORY);
return FALSE;
}
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 (lpIniFile);
if (lpDriverName) free (lpDriverName);
*ppszResult = achBuff;
return (fReturn); // success
}