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.

1265 lines
34 KiB

  1. //
  2. // MODULE: TSMapClient.cpp
  3. //
  4. // PURPOSE: Part of launching a Local Troubleshooter from an arbitrary NT5 application
  5. // Class TSMapClient is available at runtime for mapping from the application's
  6. // way of naming a problem to the Troubleshooter's way.
  7. // Only a single thread should operate on any one object of class TSMapClient. The object is not
  8. // threadsafe.
  9. // In addition to the overtly noted returns, many methods can return a preexisting error.
  10. // However, if the calling program has wishes to ignore an error and continue, we
  11. // recommend an explicit call to inherited method ClearStatus().
  12. // Note that the mapping file is always strictly SBCS (Single Byte Character Set), but the
  13. // calls into this code may use Unicode. This file consequently mixes char and TCHAR.
  14. //
  15. // COMPANY: Saltmine Creative, Inc. (206)-633-4743 [email protected]
  16. //
  17. // AUTHOR: Joe Mabel
  18. //
  19. // ORIGINAL DATE: 2-26-98
  20. //
  21. //
  22. // Version Date By Comments
  23. //--------------------------------------------------------------------
  24. // V0.1 - JM Original
  25. ///////////////////////
  26. // TSMapClient
  27. //
  28. // AUTHOR: Joe Mabel
  29. #include "stdafx.h"
  30. #include "TSLError.h"
  31. #include "RSSTACK.H"
  32. #include "TSMapAbstract.h"
  33. #include "TSMap.h"
  34. #include "TSMapClient.h"
  35. // uncomment the following line to turn on Joe's hard-core debugging
  36. //#define KDEBUG 1
  37. #ifdef KDEBUG
  38. static HANDLE hDebugFile = INVALID_HANDLE_VALUE;
  39. static DWORD dwBytesWritten;
  40. #include <stdio.h>
  41. #endif
  42. // because the null string is a perfectly valid value for some strings, we reserve an
  43. // arbitrary implausible value so we don't get a false cache match on startup.
  44. const char * const szBogus = "**BOGUS**";
  45. // Convert TCHAR *szt to char *sz. *sz should point to a big enough buffer
  46. // to contain an SNCS version of *szt. count indicates the size of buffer *sz.
  47. // returns sz (convenient for use in string functions).
  48. static char* ToSBCS (char * const sz, const TCHAR * szt, size_t count)
  49. {
  50. if (sz)
  51. {
  52. if (count != 0 && !szt)
  53. sz[0] = '\0';
  54. else
  55. {
  56. #ifdef _UNICODE
  57. wcstombs( sz, szt, count );
  58. #else
  59. strcpy(sz, szt);
  60. #endif
  61. }
  62. }
  63. return sz;
  64. }
  65. // Convert char *sz to TCHAR *szt. *szt should point to a big enough buffer
  66. // to contain a TCHAR* version of *sz (twice as big if its Unicode).
  67. // count indicates the size of buffer *szt.
  68. // returns szt (convenient for use in string functions).
  69. static TCHAR* FromSBCS (TCHAR * const szt, const char * const sz, size_t count)
  70. {
  71. if (szt)
  72. {
  73. if (count != 0 && !sz)
  74. szt[0] = _T('\0');
  75. else
  76. {
  77. #ifdef _UNICODE
  78. mbstowcs( szt, sz, count);
  79. #else
  80. strcpy(szt, sz);
  81. #endif
  82. }
  83. }
  84. return szt;
  85. }
  86. TSMapClient::TSMapClient(const TCHAR * const sztMapFile)
  87. {
  88. TSMapRuntimeAbstract::TSMapRuntimeAbstract();
  89. _tcscpy(m_sztMapFile, sztMapFile);
  90. m_hMapFile = INVALID_HANDLE_VALUE;
  91. // >>> 1/16/98 we are setting these false until we can arrange to use the same'
  92. // collating sequence in SQL Server & in this code.
  93. m_bAppAlphaOrder = false;
  94. m_bVerAlphaOrder = false;
  95. m_bDevIDAlphaOrder = false;
  96. m_bDevClassGUIDAlphaOrder = false;
  97. m_bProbAlphaOrder = false;
  98. Initialize();
  99. ClearAll();
  100. }
  101. TSMapClient::~TSMapClient()
  102. {
  103. if (m_hMapFile != INVALID_HANDLE_VALUE)
  104. CloseHandle(m_hMapFile);
  105. }
  106. // If not already initialized, open the mapping file & read the header
  107. // Note that this is not thread-safe. Only a single thread should use a given TSMapClient
  108. // object.
  109. // Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
  110. // parent class.
  111. // Typically, on entry m_dwStatus should be 0 and will be left alone if there are no errors
  112. // Can set m_dwStatus to any of the following values:
  113. // TSL_ERROR_MAP_CANT_OPEN_MAP_FILE
  114. // TSL_ERROR_MAP_BAD_HEAD_MAP_FILE
  115. DWORD TSMapClient::Initialize()
  116. {
  117. static bool bInit = false;
  118. DWORD dwStatus = 0;
  119. if (!bInit)
  120. {
  121. m_hMapFile = CreateFile(
  122. m_sztMapFile,
  123. GENERIC_READ,
  124. FILE_SHARE_READ,
  125. NULL, // no security attributes
  126. OPEN_EXISTING,
  127. FILE_FLAG_RANDOM_ACCESS,
  128. NULL // handle to template file
  129. );
  130. if (m_hMapFile == INVALID_HANDLE_VALUE)
  131. {
  132. dwStatus = TSL_ERROR_MAP_CANT_OPEN_MAP_FILE;
  133. }
  134. else
  135. {
  136. DWORD dwBytesRead;
  137. if (!Read( &m_header, sizeof(m_header), &dwBytesRead))
  138. dwStatus = TSL_ERROR_MAP_BAD_HEAD_MAP_FILE;
  139. }
  140. if (dwStatus)
  141. m_dwStatus = dwStatus;
  142. else
  143. bInit = true;
  144. }
  145. return m_dwStatus;
  146. }
  147. // This function sets us back to a starting state, but has no effect on the mapping
  148. // file. It should succeed unless we've encountered a "hard" error, which would indicate
  149. // a bug either in the code or in the mapping file. Note that it wipes out the caching.
  150. // If you want ot leave caching intact, just call inherited method ClearStatus().
  151. // Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
  152. // parent class. returned value is either 0 or a _preexisting_ hard error we can't clear.
  153. DWORD TSMapClient::ClearAll ()
  154. {
  155. if (!HardMappingError(m_dwStatus))
  156. {
  157. ClearStatus();
  158. TSMapRuntimeAbstract::ClearAll();
  159. strcpy(m_szApp, szBogus);
  160. strcpy(m_appmap.szMapped, szBogus);
  161. strcpy(m_szVer, szBogus);
  162. strcpy(m_vermap.szMapped, szBogus);
  163. strcpy(m_szDevID, szBogus);
  164. m_uidDev = uidNil;
  165. strcpy(m_szDevClassGUID, szBogus);
  166. m_uidDevClass = uidNil;
  167. strcpy(m_szProb, szBogus);
  168. m_uidProb = uidNil;
  169. }
  170. return m_dwStatus;
  171. }
  172. // Get information about an application (input sztApp) from the mapping file into m_appmap
  173. // Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
  174. // parent class.
  175. // RETURNS: 0 or TSL_ERROR_UNKNOWN_APP.
  176. // Can also return hard errors:
  177. // TSL_ERROR_MAP_BAD_SEEK
  178. // TSL_ERROR_MAP_BAD_READ
  179. // (or preexisting hard error)
  180. DWORD TSMapClient::SetApp (const TCHAR * const sztApp)
  181. {
  182. char szApp[BUFSIZE];
  183. bool bFound = false;
  184. ToSBCS (szApp, sztApp, BUFSIZE);
  185. if (HardMappingError(m_dwStatus))
  186. return m_dwStatus;
  187. else
  188. ClearStatus();
  189. if ( strcmp(szApp, m_szApp) )
  190. {
  191. // it's not already in the cache; let's try to load it.
  192. int cmp = 1; // in alpha order, it's still ahead
  193. DWORD dwPosition;
  194. bool bFirstTime = true;
  195. dwPosition = m_header.dwOffApp;
  196. while (
  197. !m_dwStatus
  198. && !bFound
  199. && dwPosition < m_header.dwLastOffApp
  200. && ! (cmp < 0 && m_bAppAlphaOrder) )
  201. {
  202. if (ReadAppMap (m_appmap, dwPosition, bFirstTime) )
  203. {
  204. cmp = strcmp(szApp, m_appmap.szMapped);
  205. bFound = ( cmp == 0 );
  206. }
  207. bFirstTime = false;
  208. }
  209. if (bFound)
  210. {
  211. strcpy( m_szApp, szApp );
  212. // Different application invalidates the version
  213. strcpy( m_szVer, szBogus );
  214. }
  215. else
  216. m_dwStatus = TSL_ERROR_UNKNOWN_APP;
  217. }
  218. return m_dwStatus;
  219. }
  220. // Get information about a version (input sztVer) from the mapping file into m_vermap.
  221. // A version makes sense only in the context of an application.
  222. // The null string is a valid input value and corresponds to leaving version blank.
  223. // Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
  224. // parent class.
  225. // RETURNS:
  226. // 0 - OK
  227. // TSM_STAT_NEED_APP_TO_SET_VER
  228. // TSL_ERROR_UNKNOWN_VER
  229. // Can also return hard errors:
  230. // TSL_ERROR_MAP_BAD_SEEK
  231. // TSL_ERROR_MAP_BAD_READ
  232. // (or preexisting hard error)
  233. DWORD TSMapClient::SetVer (const TCHAR * const sztVer)
  234. {
  235. char szVer[BUFSIZE];
  236. bool bFound = false;
  237. ToSBCS (szVer, sztVer, BUFSIZE);
  238. if (HardMappingError(m_dwStatus))
  239. return m_dwStatus;
  240. else
  241. ClearStatus();
  242. if ( !strcmp(m_szApp, szBogus) )
  243. {
  244. m_dwStatus = TSM_STAT_NEED_APP_TO_SET_VER;
  245. return m_dwStatus;
  246. }
  247. if (strcmp(m_szVer, szVer) )
  248. {
  249. // it's not already in the cache; let's try to load it.
  250. int cmp = 1; // in alpha order, it's still ahead
  251. DWORD dwPosition;
  252. bool bFirstTime = true;
  253. dwPosition = m_appmap.dwOffVer;
  254. while (
  255. !m_dwStatus
  256. && !bFound
  257. && dwPosition < m_appmap.dwLastOffVer
  258. && ! (cmp < 0 && m_bVerAlphaOrder) )
  259. {
  260. if (ReadVerMap (m_vermap, dwPosition, bFirstTime) )
  261. {
  262. cmp = strcmp(szVer, m_vermap.szMapped);
  263. bFound = ( cmp == 0 );
  264. }
  265. bFirstTime = false;
  266. }
  267. if (bFound)
  268. strcpy( m_szVer, szVer );
  269. else
  270. m_dwStatus = TSL_ERROR_UNKNOWN_VER;
  271. }
  272. return m_dwStatus;
  273. }
  274. // INPUT sztProb should be either a problem name or represent a number < 2**16. In the
  275. // former case, we look up the UID in the mapping file. In the latter
  276. // case, we just translate it to a number to get a problem UID.
  277. // The null string is a valid input value and corresponds to leaving version blank. Only
  278. // makes sense if there is a device (or device class) specified before we try to launch.
  279. // Sets m_uidProb, m_szProb
  280. // Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
  281. // parent class.
  282. // RETURNS:
  283. // 0 - OK
  284. // TSL_WARNING_UNKNOWN_APPPROBLEM - This is not necessarily bad, and results in setting
  285. // m_uidProb = uidNil
  286. // Can also return hard errors:
  287. // TSL_ERROR_MAP_BAD_SEEK
  288. // TSL_ERROR_MAP_BAD_READ
  289. // (or preexisting hard error)
  290. DWORD TSMapClient::SetProb (const TCHAR * const sztProb)
  291. {
  292. char szProb[BUFSIZE];
  293. bool bIsNumber = true;
  294. ToSBCS (szProb, sztProb, BUFSIZE);
  295. if (HardMappingError(m_dwStatus))
  296. return m_dwStatus;
  297. else
  298. ClearStatus();
  299. // Null string is not a number; any string with a non-digit in it is not a number
  300. if (szProb[0] == '\0')
  301. bIsNumber = false;
  302. else
  303. {
  304. int i = 0;
  305. while (szProb[i] != '\0')
  306. if (! isdigit(szProb[i]))
  307. {
  308. bIsNumber = false;
  309. break;
  310. }
  311. else
  312. i++;
  313. }
  314. if (bIsNumber)
  315. m_uidProb = atoi(szProb);
  316. else if ( strcmp(szProb, m_szProb) )
  317. {
  318. // it's not already in the cache; let's try to load it.
  319. m_uidProb = GetGenericMapToUID(sztProb,
  320. m_header.dwOffProb, m_header.dwLastOffProb, m_bProbAlphaOrder);
  321. if (m_dwStatus == TSM_STAT_UID_NOT_FOUND)
  322. m_dwStatus = TSL_WARNING_UNKNOWN_APPPROBLEM;
  323. if (m_uidProb != uidNil)
  324. strcpy( m_szProb, szProb );
  325. }
  326. return m_dwStatus;
  327. }
  328. // Get information about a device (input sztDevID) from the mapping file into m_appmap.
  329. // The null string is a valid input value and corresponds to no specified device.
  330. // Except for Device Manager, this is typical usage.
  331. // Sets m_uidDev, m_szDev
  332. // Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
  333. // parent class.
  334. // RETURNS:
  335. // 0 - OK
  336. // TSL_WARNING_BAD_DEV_ID - This is not necessarily bad, and results in setting
  337. // m_uidDev = uidNil
  338. // Can also return hard errors:
  339. // TSL_ERROR_MAP_BAD_SEEK
  340. // TSL_ERROR_MAP_BAD_READ
  341. // (or preexisting hard error)
  342. DWORD TSMapClient::SetDevID (const TCHAR * const sztDevID)
  343. {
  344. char szDevID[BUFSIZE];
  345. ToSBCS (szDevID, sztDevID, BUFSIZE);
  346. if (HardMappingError(m_dwStatus))
  347. return m_dwStatus;
  348. else
  349. ClearStatus();
  350. if ( strcmp(szDevID, m_szDevID) )
  351. {
  352. // it's not already in the cache; let's try to load it.
  353. m_uidDev = GetGenericMapToUID (sztDevID,
  354. m_header.dwOffDevID, m_header.dwLastOffDevID, m_bDevIDAlphaOrder);
  355. if (m_dwStatus == TSM_STAT_UID_NOT_FOUND)
  356. m_dwStatus = TSL_WARNING_BAD_DEV_ID;
  357. if (m_uidDev != uidNil)
  358. strcpy( m_szDevID, szDevID );
  359. }
  360. return m_dwStatus;
  361. }
  362. // Get information about a device class (input sztDevClassGUID) from the mapping file
  363. // into m_appmap.
  364. // The null string is a valid input value and corresponds to no specified device.
  365. // Except for Device Manager, this is typical usage.
  366. // Sets m_uidDevClass, m_szDevClass
  367. // Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
  368. // parent class.
  369. // RETURNS:
  370. // 0 - OK
  371. // TSL_WARNING_BAD_CLASS_GUID - This is not necessarily bad, and results in setting
  372. // m_uidDevClass = uidNil
  373. // Can also return hard errors:
  374. // TSL_ERROR_MAP_BAD_SEEK
  375. // TSL_ERROR_MAP_BAD_READ
  376. // (or preexisting hard error)
  377. DWORD TSMapClient::SetDevClassGUID (const TCHAR * const sztDevClassGUID)
  378. {
  379. char szDevClassGUID[BUFSIZE];
  380. ToSBCS (szDevClassGUID, sztDevClassGUID, BUFSIZE);
  381. if (HardMappingError(m_dwStatus))
  382. return m_dwStatus;
  383. else
  384. ClearStatus();
  385. if ( strcmp(szDevClassGUID, m_szDevClassGUID) )
  386. {
  387. // it's not already in the cache; let's try to load it.
  388. m_uidDevClass = GetGenericMapToUID (sztDevClassGUID,
  389. m_header.dwOffDevClass, m_header.dwLastOffDevClass, m_bDevClassGUIDAlphaOrder);
  390. if (m_dwStatus == TSM_STAT_UID_NOT_FOUND)
  391. m_dwStatus = TSL_WARNING_BAD_CLASS_GUID;
  392. if (m_uidDevClass != uidNil)
  393. strcpy( m_szDevClassGUID, szDevClassGUID );
  394. }
  395. return m_dwStatus;
  396. }
  397. // Set troubleshooter (& possibly problem node) on the basis of application, version,
  398. // problem (ignoring device information). This is achieved by a lookup in the mapping file
  399. // on the basis of previously set member values of this object.
  400. // "TSBN" means "Troubleshooter Belief Network"
  401. // On INPUT, sztTSBN, sztNode must both point to buffers allowing BUFSIZE characters
  402. // OUTPUT: *sztTSBN, *sztNode filled in. If *sztNode is blank, that means launch to
  403. // the problem page of the TSBN with no problem selected.
  404. // Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
  405. // parent class.
  406. // RETURNS:
  407. // 0 - OK
  408. // TSL_ERROR_NO_NETWORK - Mapping failed
  409. // Can also return hard errors:
  410. // TSL_ERROR_MAP_BAD_SEEK
  411. // TSL_ERROR_MAP_BAD_READ
  412. // (or preexisting hard error)
  413. DWORD TSMapClient::FromProbToTS (TCHAR * const sztTSBN, TCHAR * const sztNode )
  414. {
  415. char szTSBN[BUFSIZE];
  416. char szNode[BUFSIZE];
  417. FromSBCS (sztTSBN, "", BUFSIZE);
  418. FromSBCS (sztNode, "", BUFSIZE);
  419. if (HardMappingError(m_dwStatus))
  420. return m_dwStatus;
  421. else
  422. ClearStatus();
  423. if ( m_uidProb == uidNil )
  424. {
  425. // Can't do this if m_uidProb is NIL
  426. m_dwStatus = TSL_ERROR_NO_NETWORK;
  427. return m_dwStatus;
  428. }
  429. DWORD dwPosition;
  430. bool bFirstTime = true;
  431. bool bFound = false;
  432. PROBMAP probmap;
  433. dwPosition = m_vermap.dwOffProbUID;
  434. while (
  435. !m_dwStatus
  436. && !bFound
  437. && dwPosition < m_vermap.dwLastOffProbUID )
  438. {
  439. if ( ReadProbMap (probmap, dwPosition, bFirstTime) )
  440. {
  441. bFound = ( probmap.uidProb == m_uidProb );
  442. }
  443. if (probmap.uidProb > m_uidProb)
  444. break; // we're past it. No hit.
  445. bFirstTime = false;
  446. }
  447. if (bFound)
  448. {
  449. strcpy( szNode, probmap.szProblemNode );
  450. if (! ReadString (szTSBN, BUFSIZE, probmap.dwOffTSName, TRUE) )
  451. {
  452. m_dwStatus = TSL_ERROR_NO_NETWORK;
  453. }
  454. }
  455. else
  456. m_dwStatus = TSL_ERROR_NO_NETWORK;
  457. FromSBCS (sztTSBN, szTSBN, BUFSIZE);
  458. FromSBCS (sztNode, szNode, BUFSIZE);
  459. return m_dwStatus;
  460. }
  461. // Set troubleshooter (& possibly problem node) on the basis of application, version, device
  462. // and (optionally) problem. This is achieved by a lookup in the mapping file on the basis
  463. // of previously set member values of this object.
  464. // "TSBN" means "Troubleshooter Belief Network"
  465. // On INPUT, sztTSBN, sztNode must both point to buffers allowing BUFSIZE characters
  466. // OUTPUT: *sztTSBN, *sztNode filled in. If *sztNode is blank, that means launch to
  467. // the problem page of the TSBN with no problem selected.
  468. // Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
  469. // parent class.
  470. // RETURNS:
  471. // 0 - OK
  472. // TSL_ERROR_NO_NETWORK - Mapping failed
  473. // Can also return hard errors:
  474. // TSL_ERROR_MAP_BAD_SEEK
  475. // TSL_ERROR_MAP_BAD_READ
  476. // (or preexisting hard error)
  477. DWORD TSMapClient::FromDevToTS (TCHAR * const sztTSBN, TCHAR * const sztNode )
  478. {
  479. char szTSBN[BUFSIZE];
  480. char szNode[BUFSIZE];
  481. FromSBCS (sztTSBN, "", BUFSIZE);
  482. FromSBCS (sztNode, "", BUFSIZE);
  483. if (HardMappingError(m_dwStatus))
  484. return m_dwStatus;
  485. else
  486. ClearStatus();
  487. if ( m_uidDev == uidNil )
  488. {
  489. // Can't do this if m_uidDev is NIL
  490. m_dwStatus = TSL_ERROR_NO_NETWORK;
  491. return m_dwStatus;
  492. }
  493. DWORD dwPosition;
  494. bool bFirstTime = true;
  495. bool bFoundDev = false;
  496. bool bFoundProb = false;
  497. DEVMAP devmap;
  498. dwPosition = m_vermap.dwOffDevUID;
  499. // Look in the version-specific list of device-mappings, till we find the right device.
  500. while (
  501. !m_dwStatus
  502. && !bFoundDev
  503. && dwPosition < m_vermap.dwLastOffDevUID )
  504. {
  505. if ( ReadDevMap (devmap, dwPosition, bFirstTime) )
  506. {
  507. bFoundDev = ( devmap.uidDev == m_uidDev );
  508. }
  509. if (devmap.uidDev > m_uidDev)
  510. break; // we're past it. No hit.
  511. bFirstTime = false;
  512. }
  513. if ( bFoundDev )
  514. {
  515. // The very first one might be the right problem, or we might have to scan through
  516. // several mappings for this device before we get the right problem.
  517. bFoundProb = ( devmap.uidDev == m_uidDev && devmap.uidProb == m_uidProb );
  518. while (
  519. !m_dwStatus
  520. && !bFoundProb
  521. && dwPosition < m_vermap.dwLastOffDevUID )
  522. {
  523. if ( ReadDevMap (devmap, dwPosition ) )
  524. {
  525. bFoundProb = ( devmap.uidDev == m_uidDev && devmap.uidProb == m_uidProb );
  526. }
  527. if ( devmap.uidDev > m_uidDev || devmap.uidProb > m_uidProb )
  528. break; // we're past it. No hit.
  529. }
  530. }
  531. if (bFoundProb)
  532. {
  533. strcpy( szNode, devmap.szProblemNode );
  534. if (! ReadString (szTSBN, BUFSIZE, devmap.dwOffTSName, TRUE) )
  535. {
  536. m_dwStatus = TSL_ERROR_NO_NETWORK;
  537. }
  538. }
  539. else
  540. m_dwStatus = TSL_ERROR_NO_NETWORK;
  541. FromSBCS (sztTSBN, szTSBN, BUFSIZE);
  542. FromSBCS (sztNode, szNode, BUFSIZE);
  543. return m_dwStatus;
  544. }
  545. // Set troubleshooter (& possibly problem node) on the basis of application, version, device
  546. // class and (optionally) problem. This is achieved by a lookup in the mapping file on
  547. // the basis of previously set member values of this object.
  548. // "TSBN" means "Troubleshooter Belief Network"
  549. // On INPUT, sztTSBN, sztNode must both point to buffers allowing BUFSIZE characters
  550. // OUTPUT: *sztTSBN, *sztNode filled in. If *sztNode is blank, that means launch to
  551. // the problem page of the TSBN with no problem selected.
  552. // Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
  553. // parent class.
  554. // RETURNS:
  555. // 0 - OK
  556. // TSL_ERROR_NO_NETWORK - Mapping failed
  557. // Can also return hard errors:
  558. // TSL_ERROR_MAP_BAD_SEEK
  559. // TSL_ERROR_MAP_BAD_READ
  560. // (or preexisting hard error)
  561. // >>> There is probably some way to share common code with FromDevToTS()
  562. DWORD TSMapClient::FromDevClassToTS (TCHAR * const sztTSBN, TCHAR * const sztNode )
  563. {
  564. char szTSBN[BUFSIZE];
  565. char szNode[BUFSIZE];
  566. FromSBCS (sztTSBN, "", BUFSIZE);
  567. FromSBCS (sztNode, "", BUFSIZE);
  568. if (HardMappingError(m_dwStatus))
  569. return m_dwStatus;
  570. else
  571. ClearStatus();
  572. #ifdef KDEBUG
  573. char* szStart = "START\n";
  574. char* szEnd = "END\n";
  575. char sz[150];
  576. hDebugFile = CreateFile(
  577. (m_uidProb == uidNil) ? _T("k0debug.txt") : _T("k1debug.txt"),
  578. GENERIC_WRITE,
  579. FILE_SHARE_READ,
  580. NULL,
  581. CREATE_ALWAYS,
  582. FILE_ATTRIBUTE_NORMAL,
  583. NULL);
  584. WriteFile(
  585. hDebugFile,
  586. szStart,
  587. strlen(szStart),
  588. &dwBytesWritten,
  589. NULL);
  590. sprintf (sz, "look for DevClassUID %d, ProbUID %d\n", m_uidDevClass, m_uidProb);
  591. WriteFile(
  592. hDebugFile,
  593. sz,
  594. strlen(sz),
  595. &dwBytesWritten,
  596. NULL);
  597. #endif
  598. if ( m_uidDevClass == uidNil )
  599. {
  600. // Can't do this if m_uidDevClass is NIL
  601. m_dwStatus = TSL_ERROR_NO_NETWORK;
  602. return m_dwStatus;
  603. }
  604. DWORD dwPosition;
  605. bool bFirstTime = true;
  606. bool bFoundDevClass = false;
  607. bool bFoundProb = false;
  608. DEVCLASSMAP devclassmap;
  609. dwPosition = m_vermap.dwOffDevClassUID;
  610. // Look in the version-specific list of device-class-mappings, till we find the right device class.
  611. while (
  612. !m_dwStatus
  613. && !bFoundDevClass
  614. && dwPosition < m_vermap.dwLastOffDevClassUID )
  615. {
  616. if ( ReadDevClassMap (devclassmap, dwPosition, bFirstTime) )
  617. {
  618. bFoundDevClass = ( devclassmap.uidDevClass == m_uidDevClass );
  619. }
  620. if (devclassmap.uidDevClass > m_uidDevClass)
  621. break; // we're past it. No hit.
  622. bFirstTime = false;
  623. }
  624. if ( bFoundDevClass )
  625. {
  626. #ifdef KDEBUG
  627. sprintf (sz, "found DevClassUID %d w/ ProbUID %d\n", m_uidDevClass, devclassmap.uidProb);
  628. WriteFile(
  629. hDebugFile,
  630. sz,
  631. strlen(sz),
  632. &dwBytesWritten,
  633. NULL);
  634. #endif
  635. // The very first one might be the right problem, or we might have to scan through
  636. // several mappings for this device class before we get the right problem.
  637. bFoundProb = ( devclassmap.uidDevClass == m_uidDevClass && devclassmap.uidProb == m_uidProb );
  638. while (
  639. !m_dwStatus
  640. && !bFoundProb
  641. && dwPosition < m_vermap.dwLastOffDevClassUID )
  642. {
  643. if ( ReadDevClassMap (devclassmap, dwPosition) )
  644. {
  645. bFoundProb = ( devclassmap.uidDevClass == m_uidDevClass && devclassmap.uidProb == m_uidProb );
  646. }
  647. if ( devclassmap.uidDevClass > m_uidDevClass || devclassmap.uidProb > m_uidProb )
  648. break; // we're past it. No hit.
  649. #ifdef KDEBUG
  650. sprintf (sz, "found DevClassUID %d w/ ProbUID %d\n", m_uidDevClass, devclassmap.uidProb);
  651. WriteFile(
  652. hDebugFile,
  653. sz,
  654. strlen(sz),
  655. &dwBytesWritten,
  656. NULL);
  657. #endif
  658. }
  659. }
  660. if (bFoundProb)
  661. {
  662. #ifdef KDEBUG
  663. sprintf (sz, "found right problem");
  664. WriteFile(
  665. hDebugFile,
  666. sz,
  667. strlen(sz),
  668. &dwBytesWritten,
  669. NULL);
  670. #endif
  671. strcpy( szNode, devclassmap.szProblemNode );
  672. if (! ReadString (szTSBN, BUFSIZE, devclassmap.dwOffTSName, TRUE) )
  673. {
  674. m_dwStatus = TSL_ERROR_NO_NETWORK;
  675. #ifdef KDEBUG
  676. sprintf (sz, ", but can't read its name\n");
  677. WriteFile(
  678. hDebugFile,
  679. sz,
  680. strlen(sz),
  681. &dwBytesWritten,
  682. NULL);
  683. #endif
  684. }
  685. else
  686. {
  687. #ifdef KDEBUG
  688. sprintf (sz, ": net [%s] node [%s]\n", szTSBN, szNode);
  689. WriteFile(
  690. hDebugFile,
  691. sz,
  692. strlen(sz),
  693. &dwBytesWritten,
  694. NULL);
  695. #endif
  696. }
  697. }
  698. else
  699. {
  700. m_dwStatus = TSL_ERROR_NO_NETWORK;
  701. #ifdef KDEBUG
  702. sprintf (sz, "No match");
  703. WriteFile(
  704. hDebugFile,
  705. sz,
  706. strlen(sz),
  707. &dwBytesWritten,
  708. NULL);
  709. #endif
  710. }
  711. FromSBCS (sztTSBN, szTSBN, BUFSIZE);
  712. FromSBCS (sztNode, szNode, BUFSIZE);
  713. return m_dwStatus;
  714. #ifdef KDEBUG
  715. CloseHandle(hDebugFile);
  716. hDebugFile = INVALID_HANDLE_VALUE;
  717. #endif
  718. }
  719. // To be used after we have failed to find a mapping for the currently selected version.
  720. // Each version can specify a version to try as a default, including the "blank" version,
  721. // which is distinct from "no version".
  722. // The last version in a chain of defaults will "default" to uidNil: "no version".
  723. // Return m_dwStatus, which can also be obtained via GetStatus(), inherited from the
  724. // parent class.
  725. // RETURNS:
  726. // 0 - OK
  727. // TSL_WARNING_END_OF_VER_CHAIN - OK, but there's nothing to default to.
  728. // TSM_STAT_NEED_APP_TO_SET_VER
  729. // TSM_STAT_NEED_VER_TO_SET_VER - there was no version set, so no basis for a default
  730. // TSL_ERROR_UNKNOWN_VER
  731. // Can also return hard errors:
  732. // TSL_ERROR_MAP_BAD_SEEK
  733. // TSL_ERROR_MAP_BAD_READ
  734. // (or preexisting hard error)
  735. DWORD TSMapClient::ApplyDefaultVer()
  736. {
  737. bool bFound = false;
  738. if (HardMappingError(m_dwStatus))
  739. return m_dwStatus;
  740. else
  741. ClearStatus();
  742. if ( !strcmp(m_szApp, szBogus) )
  743. {
  744. m_dwStatus = TSM_STAT_NEED_APP_TO_SET_VER;
  745. return m_dwStatus;
  746. }
  747. if ( !strcmp(m_szVer, szBogus) )
  748. {
  749. m_dwStatus = TSM_STAT_NEED_VER_TO_SET_DEF_VER;
  750. return m_dwStatus;
  751. }
  752. DWORD dwPosition;
  753. bool bFirstTime = true;
  754. UID uidDefault = m_vermap.uidDefault;
  755. if (uidDefault == uidNil)
  756. {
  757. m_dwStatus = TSL_WARNING_END_OF_VER_CHAIN;
  758. return m_dwStatus;
  759. }
  760. dwPosition = m_appmap.dwOffVer;
  761. while (
  762. !m_dwStatus
  763. && !bFound
  764. && dwPosition < m_appmap.dwLastOffVer )
  765. {
  766. if (ReadVerMap (m_vermap, dwPosition, bFirstTime) )
  767. {
  768. bFound = ( m_vermap.uid == uidDefault );
  769. }
  770. bFirstTime = false;
  771. }
  772. if (bFound)
  773. strcpy( m_szVer, m_vermap.szMapped );
  774. else
  775. m_dwStatus = TSL_ERROR_UNKNOWN_VER;
  776. return m_dwStatus;
  777. }
  778. // Within a particular range of the mapping file, read UIDMAP records to try to map from
  779. // input sztName to a UID.
  780. // Return resulting UID, including possibly UidNil
  781. // Sets m_dwStatus, which can be obtained via GetStatus(), inherited from the parent class.
  782. // Can set m_dwStatus to:
  783. // 0 - OK
  784. // TSM_STAT_UID_NOT_FOUND
  785. // Can also set m_dwStatus to hard errors:
  786. // TSL_ERROR_MAP_BAD_SEEK
  787. // TSL_ERROR_MAP_BAD_READ
  788. // (or may be left reflecting a preexisting hard error)
  789. UID TSMapClient::GetGenericMapToUID (const TCHAR * const sztName,
  790. DWORD dwOffFirst, DWORD dwOffLast,
  791. bool bAlphaOrder)
  792. {
  793. char szName[BUFSIZE];
  794. DWORD dwPosition;
  795. UIDMAP uidmap;
  796. bool bFirstTime = true;
  797. bool bFound = false;
  798. ToSBCS (szName, sztName, BUFSIZE);
  799. if (HardMappingError(m_dwStatus))
  800. return m_dwStatus;
  801. else
  802. ClearStatus();
  803. dwPosition = dwOffFirst;
  804. while ( !m_dwStatus && !bFound && dwPosition < dwOffLast)
  805. {
  806. if (ReadUIDMap (uidmap, dwPosition, bFirstTime) )
  807. {
  808. int cmp = strcmp(szName, uidmap.szMapped);
  809. bFound = ( cmp == 0 );
  810. if ( cmp < 0 && bAlphaOrder )
  811. // relying here on alphabetical order; we've passed what we're looking for
  812. break;
  813. }
  814. else
  815. {
  816. m_dwStatus = TSM_STAT_UID_NOT_FOUND;
  817. }
  818. bFirstTime = false;
  819. }
  820. if (bFound)
  821. return uidmap.uid;
  822. else
  823. {
  824. m_dwStatus = TSM_STAT_UID_NOT_FOUND;
  825. return uidNil;
  826. }
  827. }
  828. // ------------------- utility functions ------------------------
  829. // I/O, wrapped the way we are using it.
  830. // SetFilePointerAbsolute sets map file to a location & returns that location if successful
  831. // returns -1 and sets m_dwStatus on failure
  832. // Sets m_dwStatus, which can be obtained via GetStatus(), inherited from the parent class.
  833. // Although, in theory, a bad seek just indicates a bad dwMoveTo value, in practice
  834. // a bad seek would indicate a serious problem either in the mapping file or in the calling
  835. // function: we should only be seeking to offsets which the contents of the mapping file
  836. // told us to seek to.
  837. // RETURNS:
  838. // 0 - OK
  839. // TSL_ERROR_MAP_BAD_SEEK
  840. DWORD TSMapClient::SetFilePointerAbsolute( DWORD dwMoveTo )
  841. {
  842. DWORD dwPosition = SetFilePointer(m_hMapFile, dwMoveTo, NULL, FILE_BEGIN);
  843. if( dwPosition != dwMoveTo)
  844. {
  845. // >>> could call GetLastError, but what do we do with it?
  846. m_dwStatus= TSL_ERROR_MAP_BAD_SEEK;
  847. dwPosition = -1;
  848. }
  849. return dwPosition;
  850. }
  851. // Low-level read n bytes. Calls Win32 function ReadFile.
  852. // Read from map file into lpBuffer
  853. // returns true if requested # of bytes are read
  854. // Returns false and sets m_dwStatus on failure
  855. // Although, in theory, a bad read just indicates (for example) reading past EOF, in practice
  856. // a bad read would indicate a serious problem either in the mapping file or in the calling
  857. // function: we should only be reading (1) the header or (2) records which the contents of
  858. // the mapping file told us to read.
  859. // RETURNS:
  860. // 0 - OK
  861. // TSL_ERROR_MAP_BAD_READ
  862. // TSL_ERROR_MAP_BAD_SEEK
  863. bool TSMapClient::Read(LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpdwBytesRead)
  864. {
  865. if (! ReadFile( m_hMapFile, lpBuffer, nNumberOfBytesToRead, lpdwBytesRead, NULL)
  866. || *lpdwBytesRead != nNumberOfBytesToRead )
  867. {
  868. // >>> On ReadFile returning false, could call GetLastError,
  869. // but what do we do with it?
  870. m_dwStatus= TSL_ERROR_MAP_BAD_READ;
  871. return false;
  872. }
  873. return true;
  874. }
  875. // Read a single UIDMAP from the mapping file (maps text to a UID)
  876. // If INPUT bSetPosition == true, use INPUT dwPosition to position the file before reading.
  877. // Otherwise, dwPosition is assumed to be the correct file position at time of input.
  878. // OUTPUT uidmap
  879. // RETURNS true on success
  880. // On failure, returns false & sets m_dwStatus:
  881. // TSL_ERROR_MAP_BAD_SEEK
  882. // TSL_ERROR_MAP_BAD_READ
  883. bool TSMapClient::ReadUIDMap (UIDMAP &uidmap, DWORD &dwPosition, bool bSetPosition)
  884. {
  885. if (! bSetPosition || (SetFilePointerAbsolute(dwPosition) != -1) )
  886. {
  887. DWORD dwBytesRead;
  888. BOOL ret;
  889. // First just read the byte count, then the rest
  890. ret = Read( &uidmap, sizeof(short), &dwBytesRead);
  891. if ( ret )
  892. {
  893. // The first argument below may be a bit confusing. We take a pointer to
  894. // the byte count (a short*) then increment it to point immediately past the
  895. // byte count. Note that "+1" adds not "1 byte" but "1*sizeof(short)".
  896. ret = Read( (&(uidmap.cb))+1, uidmap.cb - sizeof(short), &dwBytesRead);
  897. if ( ret )
  898. {
  899. dwPosition += uidmap.cb;
  900. return true;
  901. }
  902. }
  903. }
  904. return false;
  905. }
  906. // Read a single APPMAP from the mapping file (contains info about an application)
  907. // If INPUT bSetPosition == true, use INPUT dwPosition to position the file before reading.
  908. // Otherwise, dwPosition is assumed to be the correct file position at time of input.
  909. // OUTPUT appmap
  910. // RETURNS true on success
  911. // On failure, returns false & sets m_dwStatus:
  912. // TSL_ERROR_MAP_BAD_SEEK
  913. // TSL_ERROR_MAP_BAD_READ
  914. bool TSMapClient::ReadAppMap (APPMAP &appmap, DWORD &dwPosition, bool bSetPosition)
  915. {
  916. if (! bSetPosition || (SetFilePointerAbsolute(dwPosition) != -1) )
  917. {
  918. DWORD dwBytesRead;
  919. BOOL ret;
  920. // First just read the byte count, then the rest
  921. ret = Read( &appmap, sizeof(short), &dwBytesRead);
  922. if ( ret )
  923. {
  924. // The first argument below may be a bit confusing. We take a pointer to
  925. // the byte count (a short*) then increment it to point immediately past the
  926. // byte count. Note that "+1" adds not "1 byte" but "1*sizeof(short)".
  927. ret = Read( (&(appmap.cb))+1, appmap.cb - sizeof(short), &dwBytesRead);
  928. if ( ret )
  929. {
  930. dwPosition += appmap.cb;
  931. return true;
  932. }
  933. }
  934. }
  935. return false;
  936. }
  937. // Read a single VERMAP from the mapping file (contains info about a version)
  938. // If INPUT bSetPosition == true, use INPUT dwPosition to position the file before reading.
  939. // Otherwise, dwPosition is assumed to be the correct file position at time of input.
  940. // OUTPUT vermap
  941. // RETURNS true on success
  942. // On failure, returns false & sets m_dwStatus:
  943. // TSL_ERROR_MAP_BAD_SEEK
  944. // TSL_ERROR_MAP_BAD_READ
  945. bool TSMapClient::ReadVerMap (VERMAP &vermap, DWORD &dwPosition, bool bSetPosition)
  946. {
  947. if (! bSetPosition || (SetFilePointerAbsolute(dwPosition) != -1) )
  948. {
  949. DWORD dwBytesRead;
  950. BOOL ret;
  951. // First just read the byte count, then the rest
  952. ret = Read( &vermap, sizeof(short), &dwBytesRead);
  953. if ( ret )
  954. {
  955. // The first argument below may be a bit confusing. We take a pointer to
  956. // the byte count (a short*) then increment it to point immediately past the
  957. // byte count. Note that "+1" adds not "1 byte" but "1*sizeof(short)".
  958. ret = Read( (&(vermap.cb))+1, vermap.cb - sizeof(short), &dwBytesRead);
  959. if ( ret )
  960. {
  961. dwPosition += vermap.cb;
  962. return true;
  963. }
  964. }
  965. }
  966. return false;
  967. }
  968. // Read a single PROBMAP from the mapping file (contains a mapping for use by FromProbToTS())
  969. // If INPUT bSetPosition == true, use INPUT dwPosition to position the file before reading.
  970. // Otherwise, dwPosition is assumed to be the correct file position at time of input.
  971. // OUTPUT vermap
  972. // RETURNS true on success
  973. // On failure, returns false & sets m_dwStatus:
  974. // TSL_ERROR_MAP_BAD_SEEK
  975. // TSL_ERROR_MAP_BAD_READ
  976. bool TSMapClient::ReadProbMap (PROBMAP &probmap, DWORD &dwPosition, bool bSetPosition)
  977. {
  978. if (! bSetPosition || (SetFilePointerAbsolute(dwPosition) != -1) )
  979. {
  980. DWORD dwBytesRead;
  981. BOOL ret;
  982. // First just read the byte count, then the rest
  983. ret = Read( &probmap, sizeof(short), &dwBytesRead);
  984. if ( ret )
  985. {
  986. // The first argument below may be a bit confusing. We take a pointer to
  987. // the byte count (a short*) then increment it to point immediately past the
  988. // byte count. Note that "+1" adds not "1 byte" but "1*sizeof(short)".
  989. ret = Read( (&(probmap.cb))+1, probmap.cb - sizeof(short), &dwBytesRead);
  990. if ( ret )
  991. {
  992. dwPosition += probmap.cb;
  993. return true;
  994. }
  995. }
  996. }
  997. return false;
  998. }
  999. // Read a single DEVMAP from the mapping file (contains a mapping for use by FromDevToTS())
  1000. // If INPUT bSetPosition == true, use INPUT dwPosition to position the file before reading.
  1001. // Otherwise, dwPosition is assumed to be the correct file position at time of input.
  1002. // OUTPUT vermap
  1003. // RETURNS true on success
  1004. // On failure, returns false & sets m_dwStatus:
  1005. // TSL_ERROR_MAP_BAD_SEEK
  1006. // TSL_ERROR_MAP_BAD_READ
  1007. bool TSMapClient::ReadDevMap (DEVMAP &devmap, DWORD &dwPosition, bool bSetPosition)
  1008. {
  1009. if (! bSetPosition || (SetFilePointerAbsolute(dwPosition) != -1) )
  1010. {
  1011. DWORD dwBytesRead;
  1012. BOOL ret;
  1013. // First just read the byte count, then the rest
  1014. ret = Read( &devmap, sizeof(short), &dwBytesRead);
  1015. if ( ret )
  1016. {
  1017. // The first argument below may be a bit confusing. We take a pointer to
  1018. // the byte count (a short*) then increment it to point immediately past the
  1019. // byte count. Note that "+1" adds not "1 byte" but "1*sizeof(short)".
  1020. ret = Read( (&(devmap.cb))+1, devmap.cb - sizeof(short), &dwBytesRead);
  1021. if ( ret )
  1022. {
  1023. dwPosition += devmap.cb;
  1024. return true;
  1025. }
  1026. }
  1027. }
  1028. return false;
  1029. }
  1030. // Read a single DEVCLASSMAP from the mapping file (contains a mapping for use by
  1031. // FromDevClassToTS())
  1032. // If INPUT bSetPosition == true, use INPUT dwPosition to position the file before reading.
  1033. // Otherwise, dwPosition is assumed to be the correct file position at time of input.
  1034. // OUTPUT vermap
  1035. // RETURNS true on success
  1036. // On failure, returns false & sets m_dwStatus:
  1037. // TSL_ERROR_MAP_BAD_SEEK
  1038. // TSL_ERROR_MAP_BAD_READ
  1039. bool TSMapClient::ReadDevClassMap (DEVCLASSMAP &devclassmap, DWORD &dwPosition, bool bSetPosition)
  1040. {
  1041. if (! bSetPosition || (SetFilePointerAbsolute(dwPosition) != -1) )
  1042. {
  1043. DWORD dwBytesRead;
  1044. BOOL ret;
  1045. // First just read the byte count, then the rest
  1046. ret = Read( &devclassmap, sizeof(short), &dwBytesRead);
  1047. if ( ret )
  1048. {
  1049. // The first argument below may be a bit confusing. We take a pointer to
  1050. // the byte count (a short*) then increment it to point immediately past the
  1051. // byte count. Note that "+1" adds not "1 byte" but "1*sizeof(short)".
  1052. ret = Read( (&(devclassmap.cb))+1, devclassmap.cb - sizeof(short), &dwBytesRead);
  1053. if ( ret )
  1054. {
  1055. dwPosition += devclassmap.cb;
  1056. return true;
  1057. }
  1058. }
  1059. }
  1060. return false;
  1061. }
  1062. // Low-level read a null-terminated string. Calls Win32 function ReadFile.
  1063. // If INPUT bSetPosition == true, use INPUT dwPosition to position the file before reading.
  1064. // Otherwise, dwPosition is assumed to be the correct file position at time of input.
  1065. // INPUT chMax is maximum # of bytes (not necessarily characters) to read. The last character
  1066. // will not actually be read: a null character will always be imposed.
  1067. // OUTPUT vermap
  1068. // RETURNS true on success
  1069. // On failure, returns false & sets m_dwStatus:
  1070. // TSL_ERROR_MAP_BAD_SEEK
  1071. // Note that on completion the file position is unreliable. It is based on the size of the
  1072. // buffer passed in, not the actual string.
  1073. bool TSMapClient::ReadString (char * sz, DWORD cbMax, DWORD &dwPosition, bool bSetPosition)
  1074. {
  1075. DWORD dwBytesRead;
  1076. if (! bSetPosition || (SetFilePointerAbsolute(dwPosition) != -1) )
  1077. {
  1078. if (cbMax == 0)
  1079. return true;
  1080. if ( cbMax == 1 || ReadFile( m_hMapFile, sz, cbMax-1, &dwBytesRead, NULL) )
  1081. {
  1082. sz[cbMax-1] = '\0';
  1083. return true;
  1084. }
  1085. }
  1086. return false;
  1087. }
  1088. // Once one of these errors has occurred, we consider recovery impossible, except by closing
  1089. // this object and opening a new one.
  1090. // Although, in theory, a bad seek or read just indicates bad arguments
  1091. // to the relevant function, in practice a bad seek or read would indicate
  1092. // a serious problem either in the mapping file or in the calling
  1093. // function: beyond the header, we should only be seeking to and reading
  1094. // from offsets which the contents of the mapping file old us to seek/read.
  1095. bool TSMapClient::HardMappingError (DWORD dwStatus)
  1096. {
  1097. if (TSMapRuntimeAbstract::HardMappingError(dwStatus))
  1098. return true;
  1099. else
  1100. switch (dwStatus)
  1101. {
  1102. case TSL_ERROR_MAP_BAD_SEEK:
  1103. case TSL_ERROR_MAP_BAD_READ:
  1104. case TSL_ERROR_MAP_CANT_OPEN_MAP_FILE:
  1105. case TSL_ERROR_MAP_BAD_HEAD_MAP_FILE:
  1106. return true;
  1107. default:
  1108. return false;
  1109. }
  1110. }