Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1581 lines
41 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. lodctr.c
  5. Abstract:
  6. Program to read the contents of the file specified in the command line
  7. and update the registry accordingly
  8. Author:
  9. Bob Watson (a-robw) 10 Feb 93
  10. Revision History:
  11. a-robw 25-Feb-93 revised calls to make it compile as a UNICODE or
  12. an ANSI app.
  13. --*/
  14. #define UNICODE 1
  15. #define _UNICODE 1
  16. //
  17. // "C" Include files
  18. //
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <malloc.h>
  23. //
  24. // Windows Include files
  25. //
  26. #include <windows.h>
  27. #include <winperf.h>
  28. #include <tchar.h>
  29. //
  30. #define _INITIALIZE_GLOBALS_ 1
  31. #include "common.h"
  32. #undef _INITIALIZE_GLOBALS_
  33. #define TYPE_HELP 1
  34. #define TYPE_NAME 2
  35. #include "nwcfg.hxx"
  36. #define OLD_VERSION 0x010000
  37. DWORD dwSystemVersion;
  38. BOOL
  39. GetDriverName (
  40. IN LPTSTR lpIniFile,
  41. OUT LPTSTR *lpDevName
  42. )
  43. /*++
  44. GetDriverName
  45. looks up driver name in the .ini file and returns it in lpDevName
  46. Arguments
  47. lpIniFile
  48. Filename of ini file
  49. lpDevName
  50. pointer to pointer to reciev buffer w/dev name in it
  51. Return Value
  52. TRUE if found
  53. FALSE if not found in .ini file
  54. --*/
  55. {
  56. DWORD dwRetSize;
  57. if (lpDevName) {
  58. dwRetSize = GetPrivateProfileString (
  59. TEXT("info"), // info section
  60. TEXT("drivername"), // driver name value
  61. TEXT("drivernameNotFound"), // default value
  62. *lpDevName,
  63. DISP_BUFF_SIZE,
  64. lpIniFile);
  65. if ((lstrcmpi(*lpDevName, TEXT("drivernameNotFound"))) != 0) {
  66. // name found
  67. return TRUE;
  68. } else {
  69. // name not found, default returned so return NULL string
  70. lstrcpy(*lpDevName,TEXT("\0"));
  71. return FALSE;
  72. }
  73. } else {
  74. SetLastError (ERROR_OUTOFMEMORY);
  75. return FALSE;
  76. }
  77. }
  78. BOOL
  79. BuildLanguageTables (
  80. IN LPTSTR lpIniFile,
  81. IN OUT PLANGUAGE_LIST_ELEMENT pFirstElem
  82. )
  83. /*++
  84. BuildLanguageTables
  85. Creates a list of structures that will hold the text for
  86. each supported language
  87. Arguments
  88. lpIniFile
  89. Filename with data
  90. pFirstElem
  91. pointer to first list entry
  92. ReturnValue
  93. TRUE if all OK
  94. FALSE if not
  95. --*/
  96. {
  97. LPTSTR lpEnumeratedLangs;
  98. LPTSTR lpThisLang;
  99. PLANGUAGE_LIST_ELEMENT pThisElem;
  100. DWORD dwSize;
  101. lpEnumeratedLangs = malloc(SMALL_BUFFER_SIZE * sizeof(TCHAR));
  102. if (!lpEnumeratedLangs) {
  103. SetLastError (ERROR_OUTOFMEMORY);
  104. return FALSE;
  105. }
  106. dwSize = GetPrivateProfileString (
  107. TEXT("languages"),
  108. NULL, // return all values in multi-sz string
  109. TEXT("009"), // english as the default
  110. lpEnumeratedLangs,
  111. SMALL_BUFFER_SIZE,
  112. lpIniFile);
  113. // do first language
  114. lpThisLang = lpEnumeratedLangs;
  115. pThisElem = pFirstElem;
  116. while (*lpThisLang) {
  117. pThisElem->pNextLang = NULL;
  118. pThisElem->LangId = (LPTSTR) malloc ((lstrlen(lpThisLang) + 1) * sizeof(TCHAR));
  119. if (pThisElem->LangId == NULL) {
  120. free(lpEnumeratedLangs);
  121. SetLastError (ERROR_OUTOFMEMORY);
  122. return FALSE;
  123. }
  124. lstrcpy (pThisElem->LangId, lpThisLang);
  125. pThisElem->pFirstName = NULL;
  126. pThisElem->pThisName = NULL;
  127. pThisElem->dwNumElements=0;
  128. pThisElem->NameBuffer = NULL;
  129. pThisElem->HelpBuffer = NULL;
  130. // go to next string
  131. lpThisLang += lstrlen(lpThisLang) + 1;
  132. if (*lpThisLang) { // there's another so allocate a new element
  133. pThisElem->pNextLang = malloc (sizeof(LANGUAGE_LIST_ELEMENT));
  134. if (!pThisElem) {
  135. free(pThisElem->LangId);
  136. free(lpEnumeratedLangs);
  137. SetLastError (ERROR_OUTOFMEMORY);
  138. return FALSE;
  139. }
  140. pThisElem = pThisElem->pNextLang; // point to new one
  141. }
  142. }
  143. free(lpEnumeratedLangs);
  144. return TRUE;
  145. }
  146. BOOL
  147. LoadIncludeFile (
  148. IN LPTSTR lpIniFile,
  149. OUT PSYMBOL_TABLE_ENTRY *pTable
  150. )
  151. /*++
  152. LoadIncludeFile
  153. Reads the include file that contains symbolic name definitions and
  154. loads a table with the values defined
  155. Arguments
  156. lpIniFile
  157. Ini file with include file name
  158. pTable
  159. address of pointer to table structure created
  160. Return Value
  161. TRUE if table read or if no table defined
  162. FALSE if error encountere reading table
  163. --*/
  164. {
  165. INT iNumArgs;
  166. DWORD dwSize;
  167. BOOL bReUse;
  168. BOOL bReturn = TRUE;
  169. PSYMBOL_TABLE_ENTRY pThisSymbol;
  170. LPTSTR lpIncludeFileName = NULL;
  171. LPSTR lpIncludeFile = NULL;
  172. LPSTR lpLineBuffer = NULL;
  173. LPSTR lpAnsiSymbol = NULL;
  174. FILE *fIncludeFile;
  175. HFILE hIncludeFile;
  176. OFSTRUCT ofIncludeFile;
  177. lpIncludeFileName = malloc (MAX_PATH * sizeof (TCHAR));
  178. lpIncludeFile = malloc (MAX_PATH);
  179. lpLineBuffer = malloc (DISP_BUFF_SIZE);
  180. lpAnsiSymbol = malloc (DISP_BUFF_SIZE);
  181. if (!lpIncludeFileName || !lpIncludeFile || !lpLineBuffer || !lpAnsiSymbol) {
  182. if (lpIncludeFileName) {
  183. free(lpIncludeFileName);
  184. }
  185. if (lpIncludeFile) {
  186. free(lpIncludeFile);
  187. }
  188. if (lpLineBuffer) {
  189. free(lpLineBuffer);
  190. }
  191. if (lpAnsiSymbol) {
  192. free(lpAnsiSymbol);
  193. }
  194. SetLastError (ERROR_OUTOFMEMORY);
  195. return FALSE;
  196. }
  197. // get name of include file (if present)
  198. dwSize = GetPrivateProfileString (
  199. TEXT("info"),
  200. TEXT("symbolfile"),
  201. TEXT("SymbolFileNotFound"),
  202. lpIncludeFileName,
  203. _msize(lpIncludeFileName),
  204. lpIniFile);
  205. if ((lstrcmpi(lpIncludeFileName, TEXT("SymbolFileNotFound"))) == 0) {
  206. // no symbol file defined
  207. *pTable = NULL;
  208. goto CleanUp2;
  209. }
  210. // if here, then a symbol file was defined and is now stored in
  211. // lpIncludeFileName
  212. CharToOem (lpIncludeFileName, lpIncludeFile);
  213. hIncludeFile = OpenFile (
  214. lpIncludeFile,
  215. &ofIncludeFile,
  216. OF_PARSE);
  217. if (hIncludeFile == HFILE_ERROR) { // unable to read include filename
  218. // error is already in GetLastError
  219. *pTable = NULL;
  220. bReturn = FALSE;
  221. goto CleanUp2;
  222. } else {
  223. // open a stream
  224. fIncludeFile = fopen (ofIncludeFile.szPathName, "rt");
  225. if (!fIncludeFile) {
  226. *pTable = NULL;
  227. bReturn = FALSE;
  228. goto CleanUp2;
  229. }
  230. }
  231. //
  232. // read ANSI Characters from include file
  233. //
  234. bReUse = FALSE;
  235. while (fgets(lpLineBuffer, DISP_BUFF_SIZE, fIncludeFile) != NULL) {
  236. if (strlen(lpLineBuffer) > 8) {
  237. if (!bReUse) {
  238. if (*pTable) {
  239. // then add to list
  240. pThisSymbol->pNext = malloc (sizeof (SYMBOL_TABLE_ENTRY));
  241. pThisSymbol = pThisSymbol->pNext;
  242. } else { // allocate first element
  243. *pTable = malloc (sizeof (SYMBOL_TABLE_ENTRY));
  244. pThisSymbol = *pTable;
  245. }
  246. if (!pThisSymbol) {
  247. SetLastError (ERROR_OUTOFMEMORY);
  248. bReturn = FALSE;
  249. goto CleanUp;
  250. }
  251. // allocate room for the symbol name by using the line length
  252. // - the size of "#define "
  253. // pThisSymbol->SymbolName = malloc ((strlen(lpLineBuffer) - 8) * sizeof (TCHAR));
  254. pThisSymbol->SymbolName = malloc (DISP_BUFF_SIZE * sizeof (TCHAR));
  255. if (!pThisSymbol->SymbolName) {
  256. SetLastError (ERROR_OUTOFMEMORY);
  257. bReturn = FALSE;
  258. goto CleanUp;
  259. }
  260. }
  261. // all the memory is allocated so load the fields
  262. pThisSymbol->pNext = NULL;
  263. iNumArgs = sscanf (lpLineBuffer, "#define %s %d",
  264. lpAnsiSymbol, &pThisSymbol->Value);
  265. if (iNumArgs != 2) {
  266. *(pThisSymbol->SymbolName) = TEXT('\0');
  267. pThisSymbol->Value = (DWORD)-1L;
  268. bReUse = TRUE;
  269. } else {
  270. OemToCharBuff (lpAnsiSymbol, pThisSymbol->SymbolName, DISP_BUFF_SIZE);
  271. pThisSymbol->SymbolName[DISP_BUFF_SIZE -1] = '\0'; // make sure string is terminated
  272. bReUse = FALSE;
  273. }
  274. }
  275. }
  276. CleanUp:
  277. fclose (fIncludeFile);
  278. CleanUp2:
  279. if (lpIncludeFileName) free (lpIncludeFileName);
  280. if (lpIncludeFile) free (lpIncludeFile);
  281. if (lpLineBuffer) free (lpLineBuffer);
  282. if (lpAnsiSymbol) free (lpAnsiSymbol);
  283. return bReturn;
  284. }
  285. BOOL
  286. ParseTextId (
  287. IN LPTSTR lpTextId,
  288. IN PSYMBOL_TABLE_ENTRY pFirstSymbol,
  289. OUT PDWORD pdwOffset,
  290. OUT LPTSTR *lpLangId,
  291. OUT PDWORD pdwType
  292. )
  293. /*++
  294. ParseTextId
  295. decodes Text Id key from .INI file
  296. syntax for this process is:
  297. {<DecimalNumber>} {"NAME"}
  298. {<SymbolInTable>}_<LangIdString>_{"HELP"}
  299. e.g. 0_009_NAME
  300. OBJECT_1_009_HELP
  301. Arguments
  302. lpTextId
  303. string to decode
  304. pFirstSymbol
  305. pointer to first entry in symbol table (NULL if no table)
  306. pdwOffset
  307. address of DWORD to recive offest value
  308. lpLangId
  309. address of pointer to Language Id string
  310. (NOTE: this will point into the string lpTextID which will be
  311. modified by this routine)
  312. pdwType
  313. pointer to dword that will recieve the type of string i.e.
  314. HELP or NAME
  315. Return Value
  316. TRUE text Id decoded successfully
  317. FALSE unable to decode string
  318. NOTE: the string in lpTextID will be modified by this procedure
  319. --*/
  320. {
  321. LPTSTR lpThisChar;
  322. PSYMBOL_TABLE_ENTRY pThisSymbol;
  323. // check for valid return arguments
  324. if (!(pdwOffset) ||
  325. !(lpLangId) ||
  326. !(pdwType)) {
  327. SetLastError (ERROR_INVALID_PARAMETER);
  328. return FALSE;
  329. }
  330. // search string from right to left in order to identify the
  331. // components of the string.
  332. lpThisChar = lpTextId + lstrlen(lpTextId); // point to end of string
  333. while (*lpThisChar != TEXT('_')) {
  334. lpThisChar--;
  335. if (lpThisChar <= lpTextId) {
  336. // underscore not found in string
  337. SetLastError (ERROR_INVALID_DATA);
  338. return FALSE;
  339. }
  340. }
  341. // first underscore found
  342. if ((lstrcmpi(lpThisChar, TEXT("_NAME"))) == 0) {
  343. // name found, so set type
  344. *pdwType = TYPE_NAME;
  345. } else if ((lstrcmpi(lpThisChar, TEXT("_HELP"))) == 0) {
  346. // help text found, so set type
  347. *pdwType = TYPE_HELP;
  348. } else {
  349. // bad format
  350. SetLastError (ERROR_INVALID_DATA);
  351. return FALSE;
  352. }
  353. // set the current underscore to \0 and look for language ID
  354. *lpThisChar-- = TEXT('\0');
  355. while (*lpThisChar != TEXT('_')) {
  356. lpThisChar--;
  357. if (lpThisChar <= lpTextId) {
  358. // underscore not found in string
  359. SetLastError (ERROR_INVALID_DATA);
  360. return FALSE;
  361. }
  362. }
  363. // set lang ID string pointer to current char ('_') + 1
  364. *lpLangId = lpThisChar + 1;
  365. // set this underscore to a NULL and try to decode the remaining text
  366. *lpThisChar = TEXT('\0');
  367. // see if the first part of the string is a decimal digit
  368. if ((_stscanf (lpTextId, TEXT(" %d"), pdwOffset)) != 1) {
  369. // it's not a digit, so try to decode it as a symbol in the
  370. // loaded symbol table
  371. for (pThisSymbol=pFirstSymbol;
  372. pThisSymbol && *(pThisSymbol->SymbolName);
  373. pThisSymbol = pThisSymbol->pNext) {
  374. if ((lstrcmpi(lpTextId, pThisSymbol->SymbolName)) == 0) {
  375. // a matching symbol was found, so insert it's value
  376. // and return (that's all that needs to be done
  377. *pdwOffset = pThisSymbol->Value;
  378. return TRUE;
  379. }
  380. }
  381. // if here, then no matching symbol was found, and it's not
  382. // a number, so return an error
  383. SetLastError (ERROR_BAD_TOKEN_TYPE);
  384. return FALSE;
  385. } else {
  386. // symbol was prefixed with a decimal number
  387. return TRUE;
  388. }
  389. }
  390. PLANGUAGE_LIST_ELEMENT
  391. FindLanguage (
  392. IN PLANGUAGE_LIST_ELEMENT pFirstLang,
  393. IN LPTSTR pLangId
  394. )
  395. /*++
  396. FindLanguage
  397. searchs the list of languages and returns a pointer to the language
  398. list entry that matches the pLangId string argument
  399. Arguments
  400. pFirstLang
  401. pointer to first language list element
  402. pLangId
  403. pointer to text string with language ID to look up
  404. Return Value
  405. Pointer to matching language list entry
  406. or NULL if no match
  407. --*/
  408. {
  409. PLANGUAGE_LIST_ELEMENT pThisLang;
  410. for (pThisLang = pFirstLang;
  411. pThisLang;
  412. pThisLang = pThisLang->pNextLang) {
  413. if ((lstrcmpi(pLangId, pThisLang->LangId)) == 0) {
  414. // match found so return pointer
  415. return pThisLang;
  416. }
  417. }
  418. return NULL; // no match found
  419. }
  420. BOOL
  421. AddEntryToLanguage (
  422. PLANGUAGE_LIST_ELEMENT pLang,
  423. LPTSTR lpValueKey,
  424. DWORD dwType,
  425. DWORD dwOffset,
  426. LPTSTR lpIniFile
  427. )
  428. /*++
  429. AddEntryToLanguage
  430. Add a text entry to the list of text entries for the specified language
  431. Arguments
  432. pLang
  433. pointer to language structure to update
  434. lpValueKey
  435. value key to look up in .ini file
  436. dwOffset
  437. numeric offset of name in registry
  438. lpIniFile
  439. ini file
  440. Return Value
  441. TRUE if added successfully
  442. FALSE if error
  443. (see GetLastError for status)
  444. --*/
  445. {
  446. LPTSTR lpLocalStringBuff;
  447. DWORD dwSize;
  448. lpLocalStringBuff = malloc (SMALL_BUFFER_SIZE * sizeof(TCHAR));
  449. if (!lpLocalStringBuff) {
  450. SetLastError (ERROR_OUTOFMEMORY);
  451. return FALSE;
  452. }
  453. dwSize = GetPrivateProfileString (
  454. TEXT("text"), // section
  455. lpValueKey, // key
  456. TEXT("DefaultValue"), // default value
  457. lpLocalStringBuff,
  458. SMALL_BUFFER_SIZE,
  459. lpIniFile);
  460. if ((lstrcmpi(lpLocalStringBuff, TEXT("DefaultValue")))== 0) {
  461. SetLastError (ERROR_BADKEY);
  462. if (lpLocalStringBuff) free (lpLocalStringBuff);
  463. return FALSE;
  464. }
  465. // key found, so load structure
  466. if (!pLang->pThisName) {
  467. // this is the first
  468. pLang->pThisName =
  469. malloc (sizeof (NAME_ENTRY) +
  470. (lstrlen(lpLocalStringBuff) + 1) * sizeof (TCHAR));
  471. if (!pLang->pThisName) {
  472. SetLastError (ERROR_OUTOFMEMORY);
  473. if (lpLocalStringBuff) free (lpLocalStringBuff);
  474. return FALSE;
  475. } else {
  476. pLang->pFirstName = pLang->pThisName;
  477. }
  478. } else {
  479. pLang->pThisName->pNext =
  480. malloc (sizeof (NAME_ENTRY) +
  481. (lstrlen(lpLocalStringBuff) + 1) * sizeof (TCHAR));
  482. if (!pLang->pThisName->pNext) {
  483. SetLastError (ERROR_OUTOFMEMORY);
  484. if (lpLocalStringBuff) free (lpLocalStringBuff);
  485. return FALSE;
  486. } else {
  487. pLang->pThisName = pLang->pThisName->pNext;
  488. }
  489. }
  490. // pLang->pThisName now points to an uninitialized structre
  491. pLang->pThisName->pNext = NULL;
  492. pLang->pThisName->dwOffset = dwOffset;
  493. pLang->pThisName->dwType = dwType;
  494. pLang->pThisName->lpText = (LPTSTR)&(pLang->pThisName[1]); // string follows
  495. lstrcpy (pLang->pThisName->lpText, lpLocalStringBuff);
  496. if (lpLocalStringBuff) free (lpLocalStringBuff);
  497. SetLastError (ERROR_SUCCESS);
  498. return (TRUE);
  499. }
  500. BOOL
  501. LoadLanguageLists (
  502. IN LPTSTR lpIniFile,
  503. IN DWORD dwFirstCounter,
  504. IN DWORD dwFirstHelp,
  505. IN PSYMBOL_TABLE_ENTRY pFirstSymbol,
  506. IN PLANGUAGE_LIST_ELEMENT pFirstLang
  507. )
  508. /*++
  509. LoadLanguageLists
  510. Reads in the name and explain text definitions from the ini file and
  511. builds a list of these items for each of the supported languages and
  512. then combines all the entries into a sorted MULTI_SZ string buffer.
  513. Arguments
  514. lpIniFile
  515. file containing the definitions to add to the registry
  516. dwFirstCounter
  517. starting counter name index number
  518. dwFirstHelp
  519. starting help text index number
  520. pFirstLang
  521. pointer to first element in list of language elements
  522. Return Value
  523. TRUE if all is well
  524. FALSE if not
  525. error is returned in GetLastError
  526. --*/
  527. {
  528. LPTSTR lpTextIdArray;
  529. LPTSTR lpLocalKey;
  530. LPTSTR lpThisKey;
  531. DWORD dwSize;
  532. LPTSTR lpLang;
  533. DWORD dwOffset;
  534. DWORD dwType;
  535. PLANGUAGE_LIST_ELEMENT pThisLang;
  536. if (!(lpTextIdArray = malloc (SMALL_BUFFER_SIZE * sizeof(TCHAR)))) {
  537. SetLastError (ERROR_OUTOFMEMORY);
  538. return FALSE;
  539. }
  540. if (!(lpLocalKey = malloc (MAX_PATH))) {
  541. SetLastError (ERROR_OUTOFMEMORY);
  542. if (lpTextIdArray) free (lpTextIdArray);
  543. return FALSE;
  544. }
  545. // get list of text keys to look up
  546. dwSize = GetPrivateProfileString (
  547. TEXT("text"), // [text] section of .INI file
  548. NULL, // return all keys
  549. TEXT("DefaultKeyValue"), // default
  550. lpTextIdArray, // return buffer
  551. SMALL_BUFFER_SIZE, // buffer size
  552. lpIniFile); // .INI file name
  553. if ((lstrcmpi(lpTextIdArray, TEXT("DefaultKeyValue"))) == 0) {
  554. // key not found, default returned
  555. SetLastError (ERROR_NO_SUCH_GROUP);
  556. if (lpTextIdArray) free (lpTextIdArray);
  557. if (lpLocalKey) free (lpLocalKey);
  558. return FALSE;
  559. }
  560. // do each key returned
  561. for (lpThisKey=lpTextIdArray;
  562. *lpThisKey;
  563. lpThisKey += (lstrlen(lpThisKey) + 1)) {
  564. lstrcpy (lpLocalKey, lpThisKey); // make a copy of the key
  565. // parse key to see if it's in the correct format
  566. if (ParseTextId(lpLocalKey, pFirstSymbol, &dwOffset, &lpLang, &dwType)) {
  567. // so get pointer to language entry structure
  568. pThisLang = FindLanguage (pFirstLang, lpLang);
  569. if (pThisLang) {
  570. if (!AddEntryToLanguage(pThisLang,
  571. lpThisKey, dwType,
  572. (dwOffset + ((dwType == TYPE_NAME) ? dwFirstCounter : dwFirstHelp)),
  573. lpIniFile)) {
  574. }
  575. } else { // language not in list
  576. }
  577. } else { // unable to parse ID string
  578. }
  579. }
  580. if (lpTextIdArray) free (lpTextIdArray);
  581. if (lpLocalKey) free (lpLocalKey);
  582. return TRUE;
  583. }
  584. BOOL
  585. SortLanguageTables (
  586. PLANGUAGE_LIST_ELEMENT pFirstLang,
  587. PDWORD pdwLastName,
  588. PDWORD pdwLastHelp
  589. )
  590. /*++
  591. SortLangageTables
  592. walks list of languages loaded, allocates and loads a sorted multi_SZ
  593. buffer containing new entries to be added to current names/help text
  594. Arguments
  595. pFirstLang
  596. pointer to first element in list of languages
  597. ReturnValue
  598. TRUE everything done as expected
  599. FALSE error occurred, status in GetLastError
  600. --*/
  601. {
  602. PLANGUAGE_LIST_ELEMENT pThisLang;
  603. BOOL bSorted;
  604. LPTSTR pNameBufPos, pHelpBufPos;
  605. PNAME_ENTRY pThisName, pPrevName;
  606. DWORD dwHelpSize, dwNameSize, dwSize;
  607. if (!pdwLastName || !pdwLastHelp) {
  608. SetLastError (ERROR_BAD_ARGUMENTS);
  609. return FALSE;
  610. }
  611. for (pThisLang = pFirstLang;
  612. pThisLang;
  613. pThisLang = pThisLang->pNextLang) {
  614. // do each language in list
  615. // sort elements in list by value (offset) so that lowest is first
  616. bSorted = FALSE;
  617. while (!bSorted ) {
  618. // point to start of list
  619. pPrevName = pThisLang->pFirstName;
  620. if (pPrevName) {
  621. pThisName = pPrevName->pNext;
  622. } else {
  623. break; // no elements in this list
  624. }
  625. if (!pThisName) {
  626. break; // only one element in the list
  627. }
  628. bSorted = TRUE; // assume that it's sorted
  629. // go until end of list
  630. while (pThisName->pNext) {
  631. if (pThisName->dwOffset > pThisName->pNext->dwOffset) {
  632. // switch 'em
  633. pPrevName->pNext = pThisName->pNext;
  634. pThisName->pNext = pThisName->pNext->pNext;
  635. pThisName->pNext->pNext = pThisName;
  636. bSorted = FALSE;
  637. }
  638. //move to next entry
  639. pPrevName = pThisName;
  640. pThisName = pThisName->pNext;
  641. }
  642. // if bSorted = TRUE , then we walked all the way down
  643. // the list without changing anything so that's the end.
  644. }
  645. // with the list sorted, build the MULTI_SZ strings for the
  646. // help and name text strings
  647. // compute buffer size
  648. dwNameSize = dwHelpSize = 0;
  649. *pdwLastName = *pdwLastHelp = 0;
  650. for (pThisName = pThisLang->pFirstName;
  651. pThisName;
  652. pThisName = pThisName->pNext) {
  653. // compute buffer requirements for this entry
  654. dwSize = SIZE_OF_OFFSET_STRING;
  655. dwSize += lstrlen (pThisName->lpText);
  656. dwSize += 1; // null
  657. dwSize *= sizeof (TCHAR); // adjust for character size
  658. // add to appropriate size register
  659. if (pThisName->dwType == TYPE_NAME) {
  660. dwNameSize += dwSize;
  661. if (pThisName->dwOffset > *pdwLastName) {
  662. *pdwLastName = pThisName->dwOffset;
  663. }
  664. } else if (pThisName->dwType == TYPE_HELP) {
  665. dwHelpSize += dwSize;
  666. if (pThisName->dwOffset > *pdwLastHelp) {
  667. *pdwLastHelp = pThisName->dwOffset;
  668. }
  669. }
  670. }
  671. // allocate buffers for the Multi_SZ strings
  672. pThisLang->NameBuffer = malloc (dwNameSize);
  673. pThisLang->HelpBuffer = malloc (dwHelpSize);
  674. if (!pThisLang->NameBuffer || !pThisLang->HelpBuffer) {
  675. SetLastError (ERROR_OUTOFMEMORY);
  676. return FALSE;
  677. }
  678. // fill in buffers with sorted strings
  679. pNameBufPos = (LPTSTR)pThisLang->NameBuffer;
  680. pHelpBufPos = (LPTSTR)pThisLang->HelpBuffer;
  681. for (pThisName = pThisLang->pFirstName;
  682. pThisName;
  683. pThisName = pThisName->pNext) {
  684. if (pThisName->dwType == TYPE_NAME) {
  685. // load number as first 0-term. string
  686. dwSize = _stprintf (pNameBufPos, TEXT("%d"), pThisName->dwOffset);
  687. pNameBufPos += dwSize + 1; // save NULL term.
  688. // load the text to match
  689. lstrcpy (pNameBufPos, pThisName->lpText);
  690. pNameBufPos += lstrlen(pNameBufPos) + 1;
  691. } else if (pThisName->dwType == TYPE_HELP) {
  692. // load number as first 0-term. string
  693. dwSize = _stprintf (pHelpBufPos, TEXT("%d"), pThisName->dwOffset);
  694. pHelpBufPos += dwSize + 1; // save NULL term.
  695. // load the text to match
  696. lstrcpy (pHelpBufPos, pThisName->lpText);
  697. pHelpBufPos += lstrlen(pHelpBufPos) + 1;
  698. }
  699. }
  700. // add additional NULL at end of string to terminate MULTI_SZ
  701. *pHelpBufPos = TEXT('\0');
  702. *pNameBufPos = TEXT('\0');
  703. // compute size of MULTI_SZ strings
  704. pThisLang->dwNameBuffSize = (DWORD)((PBYTE)pNameBufPos -
  705. (PBYTE)pThisLang->NameBuffer) +
  706. sizeof(TCHAR);
  707. pThisLang->dwHelpBuffSize = (DWORD)((PBYTE)pHelpBufPos -
  708. (PBYTE)pThisLang->HelpBuffer) +
  709. sizeof(TCHAR);
  710. }
  711. return TRUE;
  712. }
  713. BOOL
  714. UpdateEachLanguage (
  715. HKEY hPerflibRoot,
  716. PLANGUAGE_LIST_ELEMENT pFirstLang
  717. )
  718. /*++
  719. UpdateEachLanguage
  720. Goes through list of languages and adds the sorted MULTI_SZ strings
  721. to the existing counter and explain text in the registry.
  722. Also updates the "Last Counter and Last Help" values
  723. Arguments
  724. hPerflibRoot
  725. handle to Perflib key in the registry
  726. pFirstLanguage
  727. pointer to first language entry
  728. Return Value
  729. TRUE all went as planned
  730. FALSE an error occured, use GetLastError to find out what it was.
  731. --*/
  732. {
  733. PLANGUAGE_LIST_ELEMENT pThisLang;
  734. LPTSTR pHelpBuffer = NULL;
  735. LPTSTR pNameBuffer = NULL;
  736. LPTSTR pNewName;
  737. LPTSTR pNewHelp;
  738. DWORD dwBufferSize;
  739. DWORD dwValueType;
  740. DWORD dwCounterSize;
  741. DWORD dwHelpSize;
  742. HKEY hKeyThisLang;
  743. LONG lStatus;
  744. for (pThisLang = pFirstLang;
  745. pThisLang;
  746. pThisLang = pThisLang->pNextLang) {
  747. lStatus = RegOpenKeyEx(
  748. hPerflibRoot,
  749. pThisLang->LangId,
  750. RESERVED,
  751. KEY_READ | KEY_WRITE,
  752. &hKeyThisLang);
  753. if (lStatus == ERROR_SUCCESS) {
  754. // get size of counter names
  755. dwBufferSize = 0;
  756. lStatus = RegQueryValueEx (
  757. hKeyThisLang,
  758. Counters,
  759. RESERVED,
  760. &dwValueType,
  761. NULL,
  762. &dwBufferSize);
  763. if (lStatus != ERROR_SUCCESS) {
  764. SetLastError (lStatus);
  765. return FALSE;
  766. }
  767. dwCounterSize = dwBufferSize;
  768. // get size of help text
  769. dwBufferSize = 0;
  770. lStatus = RegQueryValueEx (
  771. hKeyThisLang,
  772. Help,
  773. RESERVED,
  774. &dwValueType,
  775. NULL,
  776. &dwBufferSize);
  777. if (lStatus != ERROR_SUCCESS) {
  778. SetLastError (lStatus);
  779. return FALSE;
  780. }
  781. dwHelpSize = dwBufferSize;
  782. // allocate new buffers
  783. dwCounterSize += pThisLang->dwNameBuffSize;
  784. pNameBuffer = malloc (dwCounterSize);
  785. dwHelpSize += pThisLang->dwHelpBuffSize;
  786. pHelpBuffer = malloc (dwHelpSize);
  787. if (!pNameBuffer || !pHelpBuffer) {
  788. if (pNameBuffer) {
  789. free(pNameBuffer);
  790. }
  791. if (pHelpBuffer) {
  792. free(pHelpBuffer);
  793. }
  794. SetLastError (ERROR_OUTOFMEMORY);
  795. return (FALSE);
  796. }
  797. // load current buffers into memory
  798. // read counter names into buffer. Counter names will be stored as
  799. // a MULTI_SZ string in the format of "###" "Name"
  800. dwBufferSize = dwCounterSize;
  801. lStatus = RegQueryValueEx (
  802. hKeyThisLang,
  803. Counters,
  804. RESERVED,
  805. &dwValueType,
  806. (LPVOID)pNameBuffer,
  807. &dwBufferSize);
  808. if (lStatus != ERROR_SUCCESS) {
  809. SetLastError (lStatus);
  810. goto ErrorExit;
  811. }
  812. // set pointer to location in buffer where new string should be
  813. // appended: end of buffer - 1 (second null at end of MULTI_SZ
  814. pNewName = (LPTSTR)((PBYTE)pNameBuffer + dwBufferSize - sizeof(TCHAR));
  815. // adjust buffer length to take into account 2nd null from 1st
  816. // buffer that has been overwritten
  817. dwCounterSize -= sizeof(TCHAR);
  818. // read explain text into buffer. Counter names will be stored as
  819. // a MULTI_SZ string in the format of "###" "Text..."
  820. dwBufferSize = dwHelpSize;
  821. lStatus = RegQueryValueEx (
  822. hKeyThisLang,
  823. Help,
  824. RESERVED,
  825. &dwValueType,
  826. (LPVOID)pHelpBuffer,
  827. &dwBufferSize);
  828. if (lStatus != ERROR_SUCCESS) {
  829. SetLastError (lStatus);
  830. goto ErrorExit;
  831. }
  832. // set pointer to location in buffer where new string should be
  833. // appended: end of buffer - 1 (second null at end of MULTI_SZ
  834. pNewHelp = (LPTSTR)((PBYTE)pHelpBuffer + dwBufferSize - sizeof(TCHAR));
  835. // adjust buffer length to take into account 2nd null from 1st
  836. // buffer that has been overwritten
  837. dwHelpSize -= sizeof(TCHAR);
  838. // append new strings to end of current strings
  839. memcpy (pNewHelp, pThisLang->HelpBuffer, pThisLang->dwHelpBuffSize);
  840. memcpy (pNewName, pThisLang->NameBuffer, pThisLang->dwNameBuffSize);
  841. lStatus = RegSetValueEx (
  842. hKeyThisLang,
  843. Counters,
  844. RESERVED,
  845. REG_MULTI_SZ,
  846. (LPBYTE)pNameBuffer,
  847. dwCounterSize);
  848. if (lStatus != ERROR_SUCCESS) {
  849. SetLastError (lStatus);
  850. goto ErrorExit;
  851. }
  852. lStatus = RegSetValueEx (
  853. hKeyThisLang,
  854. Help,
  855. RESERVED,
  856. REG_MULTI_SZ,
  857. (LPBYTE)pHelpBuffer,
  858. dwHelpSize);
  859. if (lStatus != ERROR_SUCCESS) {
  860. SetLastError (lStatus);
  861. goto ErrorExit;
  862. }
  863. ErrorExit:
  864. free (pNameBuffer);
  865. free (pHelpBuffer);
  866. CloseHandle (hKeyThisLang);
  867. if (lStatus != ERROR_SUCCESS)
  868. return FALSE;
  869. } else {
  870. }
  871. }
  872. return TRUE;
  873. }
  874. BOOL
  875. UpdateRegistry (
  876. LPTSTR lpIniFile,
  877. HKEY hKeyMachine,
  878. LPTSTR lpDriverName,
  879. PLANGUAGE_LIST_ELEMENT pFirstLang,
  880. PSYMBOL_TABLE_ENTRY pFirstSymbol
  881. )
  882. /*++
  883. UpdateRegistry
  884. - checks, and if not busy, sets the "busy" key in the registry
  885. - Reads in the text and help definitions from the .ini file
  886. - Reads in the current contents of the HELP and COUNTER names
  887. - Builds a sorted MULTI_SZ struct containing the new definitions
  888. - Appends the new MULTI_SZ to the current as read from the registry
  889. - loads the new MULTI_SZ string into the registry
  890. - updates the keys in the driver's entry and Perflib's entry in the
  891. registry (e.g. first, last, etc)
  892. - clears the "busy" key
  893. Arguments
  894. lpIniFile
  895. pathname to .ini file conatining definitions
  896. hKeyMachine
  897. handle to HKEY_LOCAL_MACHINE in registry on system to
  898. update counters for.
  899. lpDriverName
  900. Name of device driver to load counters for
  901. pFirstLang
  902. pointer to first element in language structure list
  903. pFirstSymbol
  904. pointer to first element in symbol definition list
  905. Return Value
  906. TRUE if registry updated successfully
  907. FALSE if registry not updated
  908. (This routine will print an error message to stdout if an error
  909. is encountered).
  910. --*/
  911. {
  912. HKEY hDriverPerf = NULL;
  913. HKEY hPerflib = NULL;
  914. LPTSTR lpDriverKeyPath;
  915. DWORD dwType;
  916. DWORD dwSize;
  917. DWORD dwFirstDriverCounter;
  918. DWORD dwFirstDriverHelp;
  919. DWORD dwLastDriverCounter;
  920. DWORD dwLastPerflibCounter;
  921. DWORD dwLastPerflibHelp;
  922. BOOL bStatus;
  923. LONG lStatus;
  924. bStatus = FALSE;
  925. // allocate temporary buffers
  926. lpDriverKeyPath = malloc (MAX_PATH * sizeof(TCHAR));
  927. if (!lpDriverKeyPath) {
  928. SetLastError (ERROR_OUTOFMEMORY);
  929. goto UpdateRegExit;
  930. }
  931. // build driver key path string
  932. lstrcpy (lpDriverKeyPath, DriverPathRoot);
  933. lstrcat (lpDriverKeyPath, Slash);
  934. lstrcat (lpDriverKeyPath, lpDriverName);
  935. lstrcat (lpDriverKeyPath, Slash);
  936. lstrcat (lpDriverKeyPath, Performance);
  937. // open keys to registry
  938. // open key to driver's performance key
  939. lStatus = RegOpenKeyEx (
  940. hKeyMachine,
  941. lpDriverKeyPath,
  942. RESERVED,
  943. KEY_WRITE | KEY_READ,
  944. &hDriverPerf);
  945. if (lStatus != ERROR_SUCCESS) {
  946. SetLastError (lStatus);
  947. goto UpdateRegExit;
  948. }
  949. // open key to perflib's "root" key
  950. lStatus = RegOpenKeyEx (
  951. hKeyMachine,
  952. NamesKey,
  953. RESERVED,
  954. KEY_WRITE | KEY_READ,
  955. &hPerflib);
  956. if (lStatus != ERROR_SUCCESS) {
  957. SetLastError (lStatus);
  958. goto UpdateRegExit;
  959. }
  960. // get "last" values from PERFLIB
  961. dwType = 0;
  962. dwLastPerflibCounter = 0;
  963. dwSize = sizeof (dwLastPerflibCounter);
  964. lStatus = RegQueryValueEx (
  965. hPerflib,
  966. LastCounter,
  967. RESERVED,
  968. &dwType,
  969. (LPBYTE)&dwLastPerflibCounter,
  970. &dwSize);
  971. if (lStatus != ERROR_SUCCESS) {
  972. // this request should always succeed, if not then worse things
  973. // will happen later on, so quit now and avoid the trouble.
  974. SetLastError (lStatus);
  975. goto UpdateRegExit;
  976. }
  977. // get last help value now
  978. dwType = 0;
  979. dwLastPerflibHelp = 0;
  980. dwSize = sizeof (dwLastPerflibHelp);
  981. lStatus = RegQueryValueEx (
  982. hPerflib,
  983. LastHelp,
  984. RESERVED,
  985. &dwType,
  986. (LPBYTE)&dwLastPerflibHelp,
  987. &dwSize);
  988. if (lStatus != ERROR_SUCCESS) {
  989. // this request should always succeed, if not then worse things
  990. // will happen later on, so quit now and avoid the trouble.
  991. SetLastError (lStatus);
  992. goto UpdateRegExit;
  993. }
  994. // get last help value now
  995. dwType = 0;
  996. dwSize = sizeof (dwSystemVersion);
  997. lStatus = RegQueryValueEx (
  998. hPerflib,
  999. VersionStr,
  1000. RESERVED,
  1001. &dwType,
  1002. (LPBYTE)&dwSystemVersion,
  1003. &dwSize);
  1004. if (lStatus != ERROR_SUCCESS) {
  1005. dwSystemVersion = OLD_VERSION;
  1006. }
  1007. if ( dwSystemVersion != OLD_VERSION )
  1008. {
  1009. // ERROR. The caller does not check the version. It is the caller
  1010. // fault
  1011. goto UpdateRegExit;
  1012. }
  1013. // see if this driver's counter names have already been installed
  1014. // by checking to see if LastCounter's value is less than Perflib's
  1015. // Last Counter
  1016. dwType = 0;
  1017. dwLastDriverCounter = 0;
  1018. dwSize = sizeof (dwLastDriverCounter);
  1019. lStatus = RegQueryValueEx (
  1020. hDriverPerf,
  1021. LastCounter,
  1022. RESERVED,
  1023. &dwType,
  1024. (LPBYTE)&dwLastDriverCounter,
  1025. &dwSize);
  1026. if (lStatus == ERROR_SUCCESS) {
  1027. // if key found, then compare with perflib value and exit this
  1028. // procedure if the driver's last counter is <= to perflib's last
  1029. //
  1030. // if key not found, then continue with installation
  1031. // on the assumption that the counters have not been installed
  1032. if (dwLastDriverCounter <= dwLastPerflibCounter) {
  1033. SetLastError (ERROR_SUCCESS);
  1034. goto UpdateRegExit;
  1035. }
  1036. }
  1037. // everything looks like it's ready to go so first check the
  1038. // busy indicator
  1039. lStatus = RegQueryValueEx (
  1040. hPerflib,
  1041. Busy,
  1042. RESERVED,
  1043. &dwType,
  1044. NULL,
  1045. &dwSize);
  1046. if (lStatus == ERROR_SUCCESS) { // perflib is in use at the moment
  1047. return ERROR_BUSY;
  1048. }
  1049. // set the "busy" indicator under the PERFLIB key
  1050. dwSize = lstrlen(lpDriverName) * sizeof (TCHAR);
  1051. lStatus = RegSetValueEx (
  1052. hPerflib,
  1053. Busy,
  1054. RESERVED,
  1055. REG_SZ,
  1056. (LPBYTE)lpDriverName,
  1057. dwSize);
  1058. if (lStatus != ERROR_SUCCESS) {
  1059. SetLastError (lStatus);
  1060. goto UpdateRegExit;
  1061. }
  1062. // increment (by 2) the last counters so they point to the first
  1063. // unused index after the existing names and then
  1064. // set the first driver counters
  1065. dwFirstDriverCounter = dwLastPerflibCounter += 2;
  1066. dwFirstDriverHelp = dwLastPerflibHelp += 2;
  1067. // load .INI file definitions into language tables
  1068. if (!LoadLanguageLists (lpIniFile, dwLastPerflibCounter, dwLastPerflibHelp,
  1069. pFirstSymbol, pFirstLang)) {
  1070. // error message is displayed by LoadLanguageLists so just abort
  1071. // error is in GetLastError already
  1072. goto UpdateRegExit;
  1073. }
  1074. // all the symbols and definitions have been loaded into internal
  1075. // tables. so now they need to be sorted and merged into a multiSZ string
  1076. // this routine also updates the "last" counters
  1077. if (!SortLanguageTables (pFirstLang, &dwLastPerflibCounter, &dwLastPerflibHelp)) {
  1078. goto UpdateRegExit;
  1079. }
  1080. if (!UpdateEachLanguage (hPerflib, pFirstLang)) {
  1081. goto UpdateRegExit;
  1082. }
  1083. // update last counters for driver and perflib
  1084. // perflib...
  1085. lStatus = RegSetValueEx(
  1086. hPerflib,
  1087. LastCounter,
  1088. RESERVED,
  1089. REG_DWORD,
  1090. (LPBYTE)&dwLastPerflibCounter,
  1091. sizeof(DWORD));
  1092. lStatus = RegSetValueEx(
  1093. hPerflib,
  1094. LastHelp,
  1095. RESERVED,
  1096. REG_DWORD,
  1097. (LPBYTE)&dwLastPerflibHelp,
  1098. sizeof(DWORD));
  1099. // and the driver
  1100. lStatus = RegSetValueEx(
  1101. hDriverPerf,
  1102. LastCounter,
  1103. RESERVED,
  1104. REG_DWORD,
  1105. (LPBYTE)&dwLastPerflibCounter,
  1106. sizeof(DWORD));
  1107. lStatus = RegSetValueEx(
  1108. hDriverPerf,
  1109. LastHelp,
  1110. RESERVED,
  1111. REG_DWORD,
  1112. (LPBYTE)&dwLastPerflibHelp,
  1113. sizeof(DWORD));
  1114. lStatus = RegSetValueEx(
  1115. hDriverPerf,
  1116. FirstCounter,
  1117. RESERVED,
  1118. REG_DWORD,
  1119. (LPBYTE)&dwFirstDriverCounter,
  1120. sizeof(DWORD));
  1121. lStatus = RegSetValueEx(
  1122. hDriverPerf,
  1123. FirstHelp,
  1124. RESERVED,
  1125. REG_DWORD,
  1126. (LPBYTE)&dwFirstDriverHelp,
  1127. sizeof(DWORD));
  1128. bStatus = TRUE;
  1129. // free temporary buffers
  1130. UpdateRegExit:
  1131. // clear busy flag
  1132. if (hPerflib) {
  1133. lStatus = RegDeleteValue (
  1134. hPerflib,
  1135. Busy);
  1136. }
  1137. // free temporary buffers
  1138. if (lpDriverKeyPath) free (lpDriverKeyPath);
  1139. if (hDriverPerf) CloseHandle (hDriverPerf);
  1140. if (hPerflib) CloseHandle (hPerflib);
  1141. return bStatus;
  1142. }
  1143. BOOL FAR PASCAL lodctr(DWORD argc,LPSTR argv[], LPSTR *ppszResult )
  1144. /*++
  1145. main
  1146. Arguments
  1147. ReturnValue
  1148. 0 (ERROR_SUCCESS) if command was processed
  1149. Non-Zero if command error was detected.
  1150. --*/
  1151. {
  1152. LPTSTR lpIniFile;
  1153. LPTSTR lpDriverName;
  1154. LANGUAGE_LIST_ELEMENT LangList;
  1155. PSYMBOL_TABLE_ENTRY SymbolTable = NULL;
  1156. PSYMBOL_TABLE_ENTRY pThisSymbol = NULL;
  1157. BOOL fReturn = TRUE;
  1158. lpIniFile = malloc(MAX_PATH * sizeof(TCHAR));
  1159. lpDriverName = malloc(MAX_PATH * sizeof(TCHAR));
  1160. if ((lpIniFile == NULL) || (lpDriverName == NULL)) {
  1161. if (lpIniFile) {
  1162. free(lpIniFile);
  1163. }
  1164. if (lpDriverName) {
  1165. free(lpDriverName);
  1166. }
  1167. SetLastError (ERROR_OUTOFMEMORY);
  1168. return FALSE;
  1169. }
  1170. wsprintfA( achBuff, "{\"NO_ERROR\"}");
  1171. if ( argc == 1) {
  1172. MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, argv[0], -1, lpIniFile, MAX_PATH);
  1173. if (!GetDriverName (lpIniFile, &lpDriverName)) {
  1174. wsprintfA(achBuff,"{\"ERROR\"}");
  1175. fReturn = FALSE;
  1176. goto EndOfMain;
  1177. }
  1178. if (!BuildLanguageTables(lpIniFile, &LangList)) {
  1179. wsprintfA (achBuff, "{\"ERROR\"}");
  1180. fReturn = FALSE;
  1181. goto EndOfMain;
  1182. }
  1183. if (!LoadIncludeFile(lpIniFile, &SymbolTable)) {
  1184. // open errors displayed in routine
  1185. fReturn = FALSE;
  1186. goto EndOfMain;
  1187. }
  1188. if (!UpdateRegistry(lpIniFile,
  1189. HKEY_LOCAL_MACHINE,
  1190. lpDriverName,
  1191. &LangList,
  1192. SymbolTable)) {
  1193. wsprintfA (achBuff, "{\"ERROR\"}");
  1194. fReturn = FALSE;
  1195. }
  1196. }
  1197. EndOfMain:
  1198. if (lpIniFile) free (lpIniFile);
  1199. if (lpDriverName) free (lpDriverName);
  1200. *ppszResult = achBuff;
  1201. return (fReturn); // success
  1202. }