Source code of Windows XP (NT5)
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.

1580 lines
40 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. OemToChar (lpAnsiSymbol, pThisSymbol->SymbolName);
  271. bReUse = FALSE;
  272. }
  273. }
  274. }
  275. CleanUp:
  276. fclose (fIncludeFile);
  277. CleanUp2:
  278. if (lpIncludeFileName) free (lpIncludeFileName);
  279. if (lpIncludeFile) free (lpIncludeFile);
  280. if (lpLineBuffer) free (lpLineBuffer);
  281. if (lpAnsiSymbol) free (lpAnsiSymbol);
  282. return bReturn;
  283. }
  284. BOOL
  285. ParseTextId (
  286. IN LPTSTR lpTextId,
  287. IN PSYMBOL_TABLE_ENTRY pFirstSymbol,
  288. OUT PDWORD pdwOffset,
  289. OUT LPTSTR *lpLangId,
  290. OUT PDWORD pdwType
  291. )
  292. /*++
  293. ParseTextId
  294. decodes Text Id key from .INI file
  295. syntax for this process is:
  296. {<DecimalNumber>} {"NAME"}
  297. {<SymbolInTable>}_<LangIdString>_{"HELP"}
  298. e.g. 0_009_NAME
  299. OBJECT_1_009_HELP
  300. Arguments
  301. lpTextId
  302. string to decode
  303. pFirstSymbol
  304. pointer to first entry in symbol table (NULL if no table)
  305. pdwOffset
  306. address of DWORD to recive offest value
  307. lpLangId
  308. address of pointer to Language Id string
  309. (NOTE: this will point into the string lpTextID which will be
  310. modified by this routine)
  311. pdwType
  312. pointer to dword that will recieve the type of string i.e.
  313. HELP or NAME
  314. Return Value
  315. TRUE text Id decoded successfully
  316. FALSE unable to decode string
  317. NOTE: the string in lpTextID will be modified by this procedure
  318. --*/
  319. {
  320. LPTSTR lpThisChar;
  321. PSYMBOL_TABLE_ENTRY pThisSymbol;
  322. // check for valid return arguments
  323. if (!(pdwOffset) ||
  324. !(lpLangId) ||
  325. !(pdwType)) {
  326. SetLastError (ERROR_INVALID_PARAMETER);
  327. return FALSE;
  328. }
  329. // search string from right to left in order to identify the
  330. // components of the string.
  331. lpThisChar = lpTextId + lstrlen(lpTextId); // point to end of string
  332. while (*lpThisChar != TEXT('_')) {
  333. lpThisChar--;
  334. if (lpThisChar <= lpTextId) {
  335. // underscore not found in string
  336. SetLastError (ERROR_INVALID_DATA);
  337. return FALSE;
  338. }
  339. }
  340. // first underscore found
  341. if ((lstrcmpi(lpThisChar, TEXT("_NAME"))) == 0) {
  342. // name found, so set type
  343. *pdwType = TYPE_NAME;
  344. } else if ((lstrcmpi(lpThisChar, TEXT("_HELP"))) == 0) {
  345. // help text found, so set type
  346. *pdwType = TYPE_HELP;
  347. } else {
  348. // bad format
  349. SetLastError (ERROR_INVALID_DATA);
  350. return FALSE;
  351. }
  352. // set the current underscore to \0 and look for language ID
  353. *lpThisChar-- = TEXT('\0');
  354. while (*lpThisChar != TEXT('_')) {
  355. lpThisChar--;
  356. if (lpThisChar <= lpTextId) {
  357. // underscore not found in string
  358. SetLastError (ERROR_INVALID_DATA);
  359. return FALSE;
  360. }
  361. }
  362. // set lang ID string pointer to current char ('_') + 1
  363. *lpLangId = lpThisChar + 1;
  364. // set this underscore to a NULL and try to decode the remaining text
  365. *lpThisChar = TEXT('\0');
  366. // see if the first part of the string is a decimal digit
  367. if ((_stscanf (lpTextId, TEXT(" %d"), pdwOffset)) != 1) {
  368. // it's not a digit, so try to decode it as a symbol in the
  369. // loaded symbol table
  370. for (pThisSymbol=pFirstSymbol;
  371. pThisSymbol && *(pThisSymbol->SymbolName);
  372. pThisSymbol = pThisSymbol->pNext) {
  373. if ((lstrcmpi(lpTextId, pThisSymbol->SymbolName)) == 0) {
  374. // a matching symbol was found, so insert it's value
  375. // and return (that's all that needs to be done
  376. *pdwOffset = pThisSymbol->Value;
  377. return TRUE;
  378. }
  379. }
  380. // if here, then no matching symbol was found, and it's not
  381. // a number, so return an error
  382. SetLastError (ERROR_BAD_TOKEN_TYPE);
  383. return FALSE;
  384. } else {
  385. // symbol was prefixed with a decimal number
  386. return TRUE;
  387. }
  388. }
  389. PLANGUAGE_LIST_ELEMENT
  390. FindLanguage (
  391. IN PLANGUAGE_LIST_ELEMENT pFirstLang,
  392. IN LPTSTR pLangId
  393. )
  394. /*++
  395. FindLanguage
  396. searchs the list of languages and returns a pointer to the language
  397. list entry that matches the pLangId string argument
  398. Arguments
  399. pFirstLang
  400. pointer to first language list element
  401. pLangId
  402. pointer to text string with language ID to look up
  403. Return Value
  404. Pointer to matching language list entry
  405. or NULL if no match
  406. --*/
  407. {
  408. PLANGUAGE_LIST_ELEMENT pThisLang;
  409. for (pThisLang = pFirstLang;
  410. pThisLang;
  411. pThisLang = pThisLang->pNextLang) {
  412. if ((lstrcmpi(pLangId, pThisLang->LangId)) == 0) {
  413. // match found so return pointer
  414. return pThisLang;
  415. }
  416. }
  417. return NULL; // no match found
  418. }
  419. BOOL
  420. AddEntryToLanguage (
  421. PLANGUAGE_LIST_ELEMENT pLang,
  422. LPTSTR lpValueKey,
  423. DWORD dwType,
  424. DWORD dwOffset,
  425. LPTSTR lpIniFile
  426. )
  427. /*++
  428. AddEntryToLanguage
  429. Add a text entry to the list of text entries for the specified language
  430. Arguments
  431. pLang
  432. pointer to language structure to update
  433. lpValueKey
  434. value key to look up in .ini file
  435. dwOffset
  436. numeric offset of name in registry
  437. lpIniFile
  438. ini file
  439. Return Value
  440. TRUE if added successfully
  441. FALSE if error
  442. (see GetLastError for status)
  443. --*/
  444. {
  445. LPTSTR lpLocalStringBuff;
  446. DWORD dwSize;
  447. lpLocalStringBuff = malloc (SMALL_BUFFER_SIZE * sizeof(TCHAR));
  448. if (!lpLocalStringBuff) {
  449. SetLastError (ERROR_OUTOFMEMORY);
  450. return FALSE;
  451. }
  452. dwSize = GetPrivateProfileString (
  453. TEXT("text"), // section
  454. lpValueKey, // key
  455. TEXT("DefaultValue"), // default value
  456. lpLocalStringBuff,
  457. SMALL_BUFFER_SIZE,
  458. lpIniFile);
  459. if ((lstrcmpi(lpLocalStringBuff, TEXT("DefaultValue")))== 0) {
  460. SetLastError (ERROR_BADKEY);
  461. if (lpLocalStringBuff) free (lpLocalStringBuff);
  462. return FALSE;
  463. }
  464. // key found, so load structure
  465. if (!pLang->pThisName) {
  466. // this is the first
  467. pLang->pThisName =
  468. malloc (sizeof (NAME_ENTRY) +
  469. (lstrlen(lpLocalStringBuff) + 1) * sizeof (TCHAR));
  470. if (!pLang->pThisName) {
  471. SetLastError (ERROR_OUTOFMEMORY);
  472. if (lpLocalStringBuff) free (lpLocalStringBuff);
  473. return FALSE;
  474. } else {
  475. pLang->pFirstName = pLang->pThisName;
  476. }
  477. } else {
  478. pLang->pThisName->pNext =
  479. malloc (sizeof (NAME_ENTRY) +
  480. (lstrlen(lpLocalStringBuff) + 1) * sizeof (TCHAR));
  481. if (!pLang->pThisName->pNext) {
  482. SetLastError (ERROR_OUTOFMEMORY);
  483. if (lpLocalStringBuff) free (lpLocalStringBuff);
  484. return FALSE;
  485. } else {
  486. pLang->pThisName = pLang->pThisName->pNext;
  487. }
  488. }
  489. // pLang->pThisName now points to an uninitialized structre
  490. pLang->pThisName->pNext = NULL;
  491. pLang->pThisName->dwOffset = dwOffset;
  492. pLang->pThisName->dwType = dwType;
  493. pLang->pThisName->lpText = (LPTSTR)&(pLang->pThisName[1]); // string follows
  494. lstrcpy (pLang->pThisName->lpText, lpLocalStringBuff);
  495. if (lpLocalStringBuff) free (lpLocalStringBuff);
  496. SetLastError (ERROR_SUCCESS);
  497. return (TRUE);
  498. }
  499. BOOL
  500. LoadLanguageLists (
  501. IN LPTSTR lpIniFile,
  502. IN DWORD dwFirstCounter,
  503. IN DWORD dwFirstHelp,
  504. IN PSYMBOL_TABLE_ENTRY pFirstSymbol,
  505. IN PLANGUAGE_LIST_ELEMENT pFirstLang
  506. )
  507. /*++
  508. LoadLanguageLists
  509. Reads in the name and explain text definitions from the ini file and
  510. builds a list of these items for each of the supported languages and
  511. then combines all the entries into a sorted MULTI_SZ string buffer.
  512. Arguments
  513. lpIniFile
  514. file containing the definitions to add to the registry
  515. dwFirstCounter
  516. starting counter name index number
  517. dwFirstHelp
  518. starting help text index number
  519. pFirstLang
  520. pointer to first element in list of language elements
  521. Return Value
  522. TRUE if all is well
  523. FALSE if not
  524. error is returned in GetLastError
  525. --*/
  526. {
  527. LPTSTR lpTextIdArray;
  528. LPTSTR lpLocalKey;
  529. LPTSTR lpThisKey;
  530. DWORD dwSize;
  531. LPTSTR lpLang;
  532. DWORD dwOffset;
  533. DWORD dwType;
  534. PLANGUAGE_LIST_ELEMENT pThisLang;
  535. if (!(lpTextIdArray = malloc (SMALL_BUFFER_SIZE * sizeof(TCHAR)))) {
  536. SetLastError (ERROR_OUTOFMEMORY);
  537. return FALSE;
  538. }
  539. if (!(lpLocalKey = malloc (MAX_PATH))) {
  540. SetLastError (ERROR_OUTOFMEMORY);
  541. if (lpTextIdArray) free (lpTextIdArray);
  542. return FALSE;
  543. }
  544. // get list of text keys to look up
  545. dwSize = GetPrivateProfileString (
  546. TEXT("text"), // [text] section of .INI file
  547. NULL, // return all keys
  548. TEXT("DefaultKeyValue"), // default
  549. lpTextIdArray, // return buffer
  550. SMALL_BUFFER_SIZE, // buffer size
  551. lpIniFile); // .INI file name
  552. if ((lstrcmpi(lpTextIdArray, TEXT("DefaultKeyValue"))) == 0) {
  553. // key not found, default returned
  554. SetLastError (ERROR_NO_SUCH_GROUP);
  555. if (lpTextIdArray) free (lpTextIdArray);
  556. if (lpLocalKey) free (lpLocalKey);
  557. return FALSE;
  558. }
  559. // do each key returned
  560. for (lpThisKey=lpTextIdArray;
  561. *lpThisKey;
  562. lpThisKey += (lstrlen(lpThisKey) + 1)) {
  563. lstrcpy (lpLocalKey, lpThisKey); // make a copy of the key
  564. // parse key to see if it's in the correct format
  565. if (ParseTextId(lpLocalKey, pFirstSymbol, &dwOffset, &lpLang, &dwType)) {
  566. // so get pointer to language entry structure
  567. pThisLang = FindLanguage (pFirstLang, lpLang);
  568. if (pThisLang) {
  569. if (!AddEntryToLanguage(pThisLang,
  570. lpThisKey, dwType,
  571. (dwOffset + ((dwType == TYPE_NAME) ? dwFirstCounter : dwFirstHelp)),
  572. lpIniFile)) {
  573. }
  574. } else { // language not in list
  575. }
  576. } else { // unable to parse ID string
  577. }
  578. }
  579. if (lpTextIdArray) free (lpTextIdArray);
  580. if (lpLocalKey) free (lpLocalKey);
  581. return TRUE;
  582. }
  583. BOOL
  584. SortLanguageTables (
  585. PLANGUAGE_LIST_ELEMENT pFirstLang,
  586. PDWORD pdwLastName,
  587. PDWORD pdwLastHelp
  588. )
  589. /*++
  590. SortLangageTables
  591. walks list of languages loaded, allocates and loads a sorted multi_SZ
  592. buffer containing new entries to be added to current names/help text
  593. Arguments
  594. pFirstLang
  595. pointer to first element in list of languages
  596. ReturnValue
  597. TRUE everything done as expected
  598. FALSE error occurred, status in GetLastError
  599. --*/
  600. {
  601. PLANGUAGE_LIST_ELEMENT pThisLang;
  602. BOOL bSorted;
  603. LPTSTR pNameBufPos, pHelpBufPos;
  604. PNAME_ENTRY pThisName, pPrevName;
  605. DWORD dwHelpSize, dwNameSize, dwSize;
  606. if (!pdwLastName || !pdwLastHelp) {
  607. SetLastError (ERROR_BAD_ARGUMENTS);
  608. return FALSE;
  609. }
  610. for (pThisLang = pFirstLang;
  611. pThisLang;
  612. pThisLang = pThisLang->pNextLang) {
  613. // do each language in list
  614. // sort elements in list by value (offset) so that lowest is first
  615. bSorted = FALSE;
  616. while (!bSorted ) {
  617. // point to start of list
  618. pPrevName = pThisLang->pFirstName;
  619. if (pPrevName) {
  620. pThisName = pPrevName->pNext;
  621. } else {
  622. break; // no elements in this list
  623. }
  624. if (!pThisName) {
  625. break; // only one element in the list
  626. }
  627. bSorted = TRUE; // assume that it's sorted
  628. // go until end of list
  629. while (pThisName->pNext) {
  630. if (pThisName->dwOffset > pThisName->pNext->dwOffset) {
  631. // switch 'em
  632. pPrevName->pNext = pThisName->pNext;
  633. pThisName->pNext = pThisName->pNext->pNext;
  634. pThisName->pNext->pNext = pThisName;
  635. bSorted = FALSE;
  636. }
  637. //move to next entry
  638. pPrevName = pThisName;
  639. pThisName = pThisName->pNext;
  640. }
  641. // if bSorted = TRUE , then we walked all the way down
  642. // the list without changing anything so that's the end.
  643. }
  644. // with the list sorted, build the MULTI_SZ strings for the
  645. // help and name text strings
  646. // compute buffer size
  647. dwNameSize = dwHelpSize = 0;
  648. *pdwLastName = *pdwLastHelp = 0;
  649. for (pThisName = pThisLang->pFirstName;
  650. pThisName;
  651. pThisName = pThisName->pNext) {
  652. // compute buffer requirements for this entry
  653. dwSize = SIZE_OF_OFFSET_STRING;
  654. dwSize += lstrlen (pThisName->lpText);
  655. dwSize += 1; // null
  656. dwSize *= sizeof (TCHAR); // adjust for character size
  657. // add to appropriate size register
  658. if (pThisName->dwType == TYPE_NAME) {
  659. dwNameSize += dwSize;
  660. if (pThisName->dwOffset > *pdwLastName) {
  661. *pdwLastName = pThisName->dwOffset;
  662. }
  663. } else if (pThisName->dwType == TYPE_HELP) {
  664. dwHelpSize += dwSize;
  665. if (pThisName->dwOffset > *pdwLastHelp) {
  666. *pdwLastHelp = pThisName->dwOffset;
  667. }
  668. }
  669. }
  670. // allocate buffers for the Multi_SZ strings
  671. pThisLang->NameBuffer = malloc (dwNameSize);
  672. pThisLang->HelpBuffer = malloc (dwHelpSize);
  673. if (!pThisLang->NameBuffer || !pThisLang->HelpBuffer) {
  674. SetLastError (ERROR_OUTOFMEMORY);
  675. return FALSE;
  676. }
  677. // fill in buffers with sorted strings
  678. pNameBufPos = (LPTSTR)pThisLang->NameBuffer;
  679. pHelpBufPos = (LPTSTR)pThisLang->HelpBuffer;
  680. for (pThisName = pThisLang->pFirstName;
  681. pThisName;
  682. pThisName = pThisName->pNext) {
  683. if (pThisName->dwType == TYPE_NAME) {
  684. // load number as first 0-term. string
  685. dwSize = _stprintf (pNameBufPos, TEXT("%d"), pThisName->dwOffset);
  686. pNameBufPos += dwSize + 1; // save NULL term.
  687. // load the text to match
  688. lstrcpy (pNameBufPos, pThisName->lpText);
  689. pNameBufPos += lstrlen(pNameBufPos) + 1;
  690. } else if (pThisName->dwType == TYPE_HELP) {
  691. // load number as first 0-term. string
  692. dwSize = _stprintf (pHelpBufPos, TEXT("%d"), pThisName->dwOffset);
  693. pHelpBufPos += dwSize + 1; // save NULL term.
  694. // load the text to match
  695. lstrcpy (pHelpBufPos, pThisName->lpText);
  696. pHelpBufPos += lstrlen(pHelpBufPos) + 1;
  697. }
  698. }
  699. // add additional NULL at end of string to terminate MULTI_SZ
  700. *pHelpBufPos = TEXT('\0');
  701. *pNameBufPos = TEXT('\0');
  702. // compute size of MULTI_SZ strings
  703. pThisLang->dwNameBuffSize = (DWORD)((PBYTE)pNameBufPos -
  704. (PBYTE)pThisLang->NameBuffer) +
  705. sizeof(TCHAR);
  706. pThisLang->dwHelpBuffSize = (DWORD)((PBYTE)pHelpBufPos -
  707. (PBYTE)pThisLang->HelpBuffer) +
  708. sizeof(TCHAR);
  709. }
  710. return TRUE;
  711. }
  712. BOOL
  713. UpdateEachLanguage (
  714. HKEY hPerflibRoot,
  715. PLANGUAGE_LIST_ELEMENT pFirstLang
  716. )
  717. /*++
  718. UpdateEachLanguage
  719. Goes through list of languages and adds the sorted MULTI_SZ strings
  720. to the existing counter and explain text in the registry.
  721. Also updates the "Last Counter and Last Help" values
  722. Arguments
  723. hPerflibRoot
  724. handle to Perflib key in the registry
  725. pFirstLanguage
  726. pointer to first language entry
  727. Return Value
  728. TRUE all went as planned
  729. FALSE an error occured, use GetLastError to find out what it was.
  730. --*/
  731. {
  732. PLANGUAGE_LIST_ELEMENT pThisLang;
  733. LPTSTR pHelpBuffer = NULL;
  734. LPTSTR pNameBuffer = NULL;
  735. LPTSTR pNewName;
  736. LPTSTR pNewHelp;
  737. DWORD dwBufferSize;
  738. DWORD dwValueType;
  739. DWORD dwCounterSize;
  740. DWORD dwHelpSize;
  741. HKEY hKeyThisLang;
  742. LONG lStatus;
  743. for (pThisLang = pFirstLang;
  744. pThisLang;
  745. pThisLang = pThisLang->pNextLang) {
  746. lStatus = RegOpenKeyEx(
  747. hPerflibRoot,
  748. pThisLang->LangId,
  749. RESERVED,
  750. KEY_READ | KEY_WRITE,
  751. &hKeyThisLang);
  752. if (lStatus == ERROR_SUCCESS) {
  753. // get size of counter names
  754. dwBufferSize = 0;
  755. lStatus = RegQueryValueEx (
  756. hKeyThisLang,
  757. Counters,
  758. RESERVED,
  759. &dwValueType,
  760. NULL,
  761. &dwBufferSize);
  762. if (lStatus != ERROR_SUCCESS) {
  763. SetLastError (lStatus);
  764. return FALSE;
  765. }
  766. dwCounterSize = dwBufferSize;
  767. // get size of help text
  768. dwBufferSize = 0;
  769. lStatus = RegQueryValueEx (
  770. hKeyThisLang,
  771. Help,
  772. RESERVED,
  773. &dwValueType,
  774. NULL,
  775. &dwBufferSize);
  776. if (lStatus != ERROR_SUCCESS) {
  777. SetLastError (lStatus);
  778. return FALSE;
  779. }
  780. dwHelpSize = dwBufferSize;
  781. // allocate new buffers
  782. dwCounterSize += pThisLang->dwNameBuffSize;
  783. pNameBuffer = malloc (dwCounterSize);
  784. dwHelpSize += pThisLang->dwHelpBuffSize;
  785. pHelpBuffer = malloc (dwHelpSize);
  786. if (!pNameBuffer || !pHelpBuffer) {
  787. if (pNameBuffer) {
  788. free(pNameBuffer);
  789. }
  790. if (pHelpBuffer) {
  791. free(pHelpBuffer);
  792. }
  793. SetLastError (ERROR_OUTOFMEMORY);
  794. return (FALSE);
  795. }
  796. // load current buffers into memory
  797. // read counter names into buffer. Counter names will be stored as
  798. // a MULTI_SZ string in the format of "###" "Name"
  799. dwBufferSize = dwCounterSize;
  800. lStatus = RegQueryValueEx (
  801. hKeyThisLang,
  802. Counters,
  803. RESERVED,
  804. &dwValueType,
  805. (LPVOID)pNameBuffer,
  806. &dwBufferSize);
  807. if (lStatus != ERROR_SUCCESS) {
  808. SetLastError (lStatus);
  809. goto ErrorExit;
  810. }
  811. // set pointer to location in buffer where new string should be
  812. // appended: end of buffer - 1 (second null at end of MULTI_SZ
  813. pNewName = (LPTSTR)((PBYTE)pNameBuffer + dwBufferSize - sizeof(TCHAR));
  814. // adjust buffer length to take into account 2nd null from 1st
  815. // buffer that has been overwritten
  816. dwCounterSize -= sizeof(TCHAR);
  817. // read explain text into buffer. Counter names will be stored as
  818. // a MULTI_SZ string in the format of "###" "Text..."
  819. dwBufferSize = dwHelpSize;
  820. lStatus = RegQueryValueEx (
  821. hKeyThisLang,
  822. Help,
  823. RESERVED,
  824. &dwValueType,
  825. (LPVOID)pHelpBuffer,
  826. &dwBufferSize);
  827. if (lStatus != ERROR_SUCCESS) {
  828. SetLastError (lStatus);
  829. goto ErrorExit;
  830. }
  831. // set pointer to location in buffer where new string should be
  832. // appended: end of buffer - 1 (second null at end of MULTI_SZ
  833. pNewHelp = (LPTSTR)((PBYTE)pHelpBuffer + dwBufferSize - sizeof(TCHAR));
  834. // adjust buffer length to take into account 2nd null from 1st
  835. // buffer that has been overwritten
  836. dwHelpSize -= sizeof(TCHAR);
  837. // append new strings to end of current strings
  838. memcpy (pNewHelp, pThisLang->HelpBuffer, pThisLang->dwHelpBuffSize);
  839. memcpy (pNewName, pThisLang->NameBuffer, pThisLang->dwNameBuffSize);
  840. lStatus = RegSetValueEx (
  841. hKeyThisLang,
  842. Counters,
  843. RESERVED,
  844. REG_MULTI_SZ,
  845. (LPBYTE)pNameBuffer,
  846. dwCounterSize);
  847. if (lStatus != ERROR_SUCCESS) {
  848. SetLastError (lStatus);
  849. goto ErrorExit;
  850. }
  851. lStatus = RegSetValueEx (
  852. hKeyThisLang,
  853. Help,
  854. RESERVED,
  855. REG_MULTI_SZ,
  856. (LPBYTE)pHelpBuffer,
  857. dwHelpSize);
  858. if (lStatus != ERROR_SUCCESS) {
  859. SetLastError (lStatus);
  860. goto ErrorExit;
  861. }
  862. ErrorExit:
  863. free (pNameBuffer);
  864. free (pHelpBuffer);
  865. CloseHandle (hKeyThisLang);
  866. if (lStatus != ERROR_SUCCESS)
  867. return FALSE;
  868. } else {
  869. }
  870. }
  871. return TRUE;
  872. }
  873. BOOL
  874. UpdateRegistry (
  875. LPTSTR lpIniFile,
  876. HKEY hKeyMachine,
  877. LPTSTR lpDriverName,
  878. PLANGUAGE_LIST_ELEMENT pFirstLang,
  879. PSYMBOL_TABLE_ENTRY pFirstSymbol
  880. )
  881. /*++
  882. UpdateRegistry
  883. - checks, and if not busy, sets the "busy" key in the registry
  884. - Reads in the text and help definitions from the .ini file
  885. - Reads in the current contents of the HELP and COUNTER names
  886. - Builds a sorted MULTI_SZ struct containing the new definitions
  887. - Appends the new MULTI_SZ to the current as read from the registry
  888. - loads the new MULTI_SZ string into the registry
  889. - updates the keys in the driver's entry and Perflib's entry in the
  890. registry (e.g. first, last, etc)
  891. - clears the "busy" key
  892. Arguments
  893. lpIniFile
  894. pathname to .ini file conatining definitions
  895. hKeyMachine
  896. handle to HKEY_LOCAL_MACHINE in registry on system to
  897. update counters for.
  898. lpDriverName
  899. Name of device driver to load counters for
  900. pFirstLang
  901. pointer to first element in language structure list
  902. pFirstSymbol
  903. pointer to first element in symbol definition list
  904. Return Value
  905. TRUE if registry updated successfully
  906. FALSE if registry not updated
  907. (This routine will print an error message to stdout if an error
  908. is encountered).
  909. --*/
  910. {
  911. HKEY hDriverPerf = NULL;
  912. HKEY hPerflib = NULL;
  913. LPTSTR lpDriverKeyPath;
  914. DWORD dwType;
  915. DWORD dwSize;
  916. DWORD dwFirstDriverCounter;
  917. DWORD dwFirstDriverHelp;
  918. DWORD dwLastDriverCounter;
  919. DWORD dwLastPerflibCounter;
  920. DWORD dwLastPerflibHelp;
  921. BOOL bStatus;
  922. LONG lStatus;
  923. bStatus = FALSE;
  924. // allocate temporary buffers
  925. lpDriverKeyPath = malloc (MAX_PATH * sizeof(TCHAR));
  926. if (!lpDriverKeyPath) {
  927. SetLastError (ERROR_OUTOFMEMORY);
  928. goto UpdateRegExit;
  929. }
  930. // build driver key path string
  931. lstrcpy (lpDriverKeyPath, DriverPathRoot);
  932. lstrcat (lpDriverKeyPath, Slash);
  933. lstrcat (lpDriverKeyPath, lpDriverName);
  934. lstrcat (lpDriverKeyPath, Slash);
  935. lstrcat (lpDriverKeyPath, Performance);
  936. // open keys to registry
  937. // open key to driver's performance key
  938. lStatus = RegOpenKeyEx (
  939. hKeyMachine,
  940. lpDriverKeyPath,
  941. RESERVED,
  942. KEY_WRITE | KEY_READ,
  943. &hDriverPerf);
  944. if (lStatus != ERROR_SUCCESS) {
  945. SetLastError (lStatus);
  946. goto UpdateRegExit;
  947. }
  948. // open key to perflib's "root" key
  949. lStatus = RegOpenKeyEx (
  950. hKeyMachine,
  951. NamesKey,
  952. RESERVED,
  953. KEY_WRITE | KEY_READ,
  954. &hPerflib);
  955. if (lStatus != ERROR_SUCCESS) {
  956. SetLastError (lStatus);
  957. goto UpdateRegExit;
  958. }
  959. // get "last" values from PERFLIB
  960. dwType = 0;
  961. dwLastPerflibCounter = 0;
  962. dwSize = sizeof (dwLastPerflibCounter);
  963. lStatus = RegQueryValueEx (
  964. hPerflib,
  965. LastCounter,
  966. RESERVED,
  967. &dwType,
  968. (LPBYTE)&dwLastPerflibCounter,
  969. &dwSize);
  970. if (lStatus != ERROR_SUCCESS) {
  971. // this request should always succeed, if not then worse things
  972. // will happen later on, so quit now and avoid the trouble.
  973. SetLastError (lStatus);
  974. goto UpdateRegExit;
  975. }
  976. // get last help value now
  977. dwType = 0;
  978. dwLastPerflibHelp = 0;
  979. dwSize = sizeof (dwLastPerflibHelp);
  980. lStatus = RegQueryValueEx (
  981. hPerflib,
  982. LastHelp,
  983. RESERVED,
  984. &dwType,
  985. (LPBYTE)&dwLastPerflibHelp,
  986. &dwSize);
  987. if (lStatus != ERROR_SUCCESS) {
  988. // this request should always succeed, if not then worse things
  989. // will happen later on, so quit now and avoid the trouble.
  990. SetLastError (lStatus);
  991. goto UpdateRegExit;
  992. }
  993. // get last help value now
  994. dwType = 0;
  995. dwSize = sizeof (dwSystemVersion);
  996. lStatus = RegQueryValueEx (
  997. hPerflib,
  998. VersionStr,
  999. RESERVED,
  1000. &dwType,
  1001. (LPBYTE)&dwSystemVersion,
  1002. &dwSize);
  1003. if (lStatus != ERROR_SUCCESS) {
  1004. dwSystemVersion = OLD_VERSION;
  1005. }
  1006. if ( dwSystemVersion != OLD_VERSION )
  1007. {
  1008. // ERROR. The caller does not check the version. It is the caller
  1009. // fault
  1010. goto UpdateRegExit;
  1011. }
  1012. // see if this driver's counter names have already been installed
  1013. // by checking to see if LastCounter's value is less than Perflib's
  1014. // Last Counter
  1015. dwType = 0;
  1016. dwLastDriverCounter = 0;
  1017. dwSize = sizeof (dwLastDriverCounter);
  1018. lStatus = RegQueryValueEx (
  1019. hDriverPerf,
  1020. LastCounter,
  1021. RESERVED,
  1022. &dwType,
  1023. (LPBYTE)&dwLastDriverCounter,
  1024. &dwSize);
  1025. if (lStatus == ERROR_SUCCESS) {
  1026. // if key found, then compare with perflib value and exit this
  1027. // procedure if the driver's last counter is <= to perflib's last
  1028. //
  1029. // if key not found, then continue with installation
  1030. // on the assumption that the counters have not been installed
  1031. if (dwLastDriverCounter <= dwLastPerflibCounter) {
  1032. SetLastError (ERROR_SUCCESS);
  1033. goto UpdateRegExit;
  1034. }
  1035. }
  1036. // everything looks like it's ready to go so first check the
  1037. // busy indicator
  1038. lStatus = RegQueryValueEx (
  1039. hPerflib,
  1040. Busy,
  1041. RESERVED,
  1042. &dwType,
  1043. NULL,
  1044. &dwSize);
  1045. if (lStatus == ERROR_SUCCESS) { // perflib is in use at the moment
  1046. return ERROR_BUSY;
  1047. }
  1048. // set the "busy" indicator under the PERFLIB key
  1049. dwSize = lstrlen(lpDriverName) * sizeof (TCHAR);
  1050. lStatus = RegSetValueEx (
  1051. hPerflib,
  1052. Busy,
  1053. RESERVED,
  1054. REG_SZ,
  1055. (LPBYTE)lpDriverName,
  1056. dwSize);
  1057. if (lStatus != ERROR_SUCCESS) {
  1058. SetLastError (lStatus);
  1059. goto UpdateRegExit;
  1060. }
  1061. // increment (by 2) the last counters so they point to the first
  1062. // unused index after the existing names and then
  1063. // set the first driver counters
  1064. dwFirstDriverCounter = dwLastPerflibCounter += 2;
  1065. dwFirstDriverHelp = dwLastPerflibHelp += 2;
  1066. // load .INI file definitions into language tables
  1067. if (!LoadLanguageLists (lpIniFile, dwLastPerflibCounter, dwLastPerflibHelp,
  1068. pFirstSymbol, pFirstLang)) {
  1069. // error message is displayed by LoadLanguageLists so just abort
  1070. // error is in GetLastError already
  1071. goto UpdateRegExit;
  1072. }
  1073. // all the symbols and definitions have been loaded into internal
  1074. // tables. so now they need to be sorted and merged into a multiSZ string
  1075. // this routine also updates the "last" counters
  1076. if (!SortLanguageTables (pFirstLang, &dwLastPerflibCounter, &dwLastPerflibHelp)) {
  1077. goto UpdateRegExit;
  1078. }
  1079. if (!UpdateEachLanguage (hPerflib, pFirstLang)) {
  1080. goto UpdateRegExit;
  1081. }
  1082. // update last counters for driver and perflib
  1083. // perflib...
  1084. lStatus = RegSetValueEx(
  1085. hPerflib,
  1086. LastCounter,
  1087. RESERVED,
  1088. REG_DWORD,
  1089. (LPBYTE)&dwLastPerflibCounter,
  1090. sizeof(DWORD));
  1091. lStatus = RegSetValueEx(
  1092. hPerflib,
  1093. LastHelp,
  1094. RESERVED,
  1095. REG_DWORD,
  1096. (LPBYTE)&dwLastPerflibHelp,
  1097. sizeof(DWORD));
  1098. // and the driver
  1099. lStatus = RegSetValueEx(
  1100. hDriverPerf,
  1101. LastCounter,
  1102. RESERVED,
  1103. REG_DWORD,
  1104. (LPBYTE)&dwLastPerflibCounter,
  1105. sizeof(DWORD));
  1106. lStatus = RegSetValueEx(
  1107. hDriverPerf,
  1108. LastHelp,
  1109. RESERVED,
  1110. REG_DWORD,
  1111. (LPBYTE)&dwLastPerflibHelp,
  1112. sizeof(DWORD));
  1113. lStatus = RegSetValueEx(
  1114. hDriverPerf,
  1115. FirstCounter,
  1116. RESERVED,
  1117. REG_DWORD,
  1118. (LPBYTE)&dwFirstDriverCounter,
  1119. sizeof(DWORD));
  1120. lStatus = RegSetValueEx(
  1121. hDriverPerf,
  1122. FirstHelp,
  1123. RESERVED,
  1124. REG_DWORD,
  1125. (LPBYTE)&dwFirstDriverHelp,
  1126. sizeof(DWORD));
  1127. bStatus = TRUE;
  1128. // free temporary buffers
  1129. UpdateRegExit:
  1130. // clear busy flag
  1131. if (hPerflib) {
  1132. lStatus = RegDeleteValue (
  1133. hPerflib,
  1134. Busy);
  1135. }
  1136. // free temporary buffers
  1137. if (lpDriverKeyPath) free (lpDriverKeyPath);
  1138. if (hDriverPerf) CloseHandle (hDriverPerf);
  1139. if (hPerflib) CloseHandle (hPerflib);
  1140. return bStatus;
  1141. }
  1142. BOOL FAR PASCAL lodctr(DWORD argc,LPSTR argv[], LPSTR *ppszResult )
  1143. /*++
  1144. main
  1145. Arguments
  1146. ReturnValue
  1147. 0 (ERROR_SUCCESS) if command was processed
  1148. Non-Zero if command error was detected.
  1149. --*/
  1150. {
  1151. LPTSTR lpIniFile;
  1152. LPTSTR lpDriverName;
  1153. LANGUAGE_LIST_ELEMENT LangList;
  1154. PSYMBOL_TABLE_ENTRY SymbolTable = NULL;
  1155. PSYMBOL_TABLE_ENTRY pThisSymbol = NULL;
  1156. BOOL fReturn = TRUE;
  1157. lpIniFile = malloc(MAX_PATH * sizeof(TCHAR));
  1158. lpDriverName = malloc(MAX_PATH * sizeof(TCHAR));
  1159. if ((lpIniFile == NULL) || (lpDriverName == NULL)) {
  1160. if (lpIniFile) {
  1161. free(lpIniFile);
  1162. }
  1163. if (lpDriverName) {
  1164. free(lpDriverName);
  1165. }
  1166. SetLastError (ERROR_OUTOFMEMORY);
  1167. return FALSE;
  1168. }
  1169. wsprintfA( achBuff, "{\"NO_ERROR\"}");
  1170. if ( argc == 1) {
  1171. MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, argv[0], -1, lpIniFile, MAX_PATH);
  1172. if (!GetDriverName (lpIniFile, &lpDriverName)) {
  1173. wsprintfA(achBuff,"{\"ERROR\"}");
  1174. fReturn = FALSE;
  1175. goto EndOfMain;
  1176. }
  1177. if (!BuildLanguageTables(lpIniFile, &LangList)) {
  1178. wsprintfA (achBuff, "{\"ERROR\"}");
  1179. fReturn = FALSE;
  1180. goto EndOfMain;
  1181. }
  1182. if (!LoadIncludeFile(lpIniFile, &SymbolTable)) {
  1183. // open errors displayed in routine
  1184. fReturn = FALSE;
  1185. goto EndOfMain;
  1186. }
  1187. if (!UpdateRegistry(lpIniFile,
  1188. HKEY_LOCAL_MACHINE,
  1189. lpDriverName,
  1190. &LangList,
  1191. SymbolTable)) {
  1192. wsprintfA (achBuff, "{\"ERROR\"}");
  1193. fReturn = FALSE;
  1194. }
  1195. }
  1196. EndOfMain:
  1197. if (lpIniFile) free (lpIniFile);
  1198. if (lpDriverName) free (lpDriverName);
  1199. *ppszResult = achBuff;
  1200. return (fReturn); // success
  1201. }