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.

886 lines
24 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. miscutil.c
  5. Abstract:
  6. Miscellaneous utility functions for Windows NT Setup API dll.
  7. Author:
  8. Ted Miller (tedm) 20-Jan-1995
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #if MEM_DBG
  14. PTSTR
  15. TrackedDuplicateString(
  16. IN TRACK_ARG_DECLARE,
  17. IN PCTSTR String
  18. )
  19. {
  20. PTSTR Str;
  21. TRACK_PUSH
  22. Str = pSetupDuplicateString (String);
  23. TRACK_POP
  24. return Str;
  25. }
  26. #endif
  27. DWORD
  28. CaptureStringArg(
  29. IN PCTSTR String,
  30. OUT PCTSTR *CapturedString
  31. )
  32. /*++
  33. Routine Description:
  34. Capture a string whose validity is suspect.
  35. This operation is completely guarded and thus won't fault,
  36. leak memory in the error case, etc.
  37. Arguments:
  38. String - supplies string to be captured.
  39. CapturedString - if successful, receives pointer to captured equivalent
  40. of String. Caller must free with MyFree(). If not successful,
  41. receives NULL. This parameter is NOT validated so be careful.
  42. Return Value:
  43. Win32 error code indicating outcome.
  44. NO_ERROR - success, CapturedString filled in.
  45. ERROR_NOT_ENOUGH_MEMORY - insufficient memory for conversion.
  46. ERROR_INVALID_PARAMETER - String was invalid.
  47. --*/
  48. {
  49. DWORD d;
  50. try {
  51. //
  52. // DuplicateString is guaranteed to generate a fault
  53. // if the string is invalid. Otherwise if it is non-NULL
  54. // the it succeeded.
  55. //
  56. *CapturedString = DuplicateString(String);
  57. d = (*CapturedString == NULL) ? ERROR_NOT_ENOUGH_MEMORY : NO_ERROR;
  58. } except(EXCEPTION_EXECUTE_HANDLER) {
  59. d = ERROR_INVALID_PARAMETER;
  60. *CapturedString = NULL;
  61. }
  62. return(d);
  63. }
  64. DWORD
  65. DelimStringToMultiSz(
  66. IN PTSTR String,
  67. IN DWORD StringLen,
  68. IN TCHAR Delim
  69. )
  70. /*++
  71. Routine Description:
  72. Converts a string containing a list of items delimited by
  73. 'Delim' into a MultiSz buffer. The conversion is done in-place.
  74. Leading and trailing whitespace is removed from each constituent
  75. string. Delimiters inside of double-quotes (") are ignored. The
  76. quotation marks are removed during processing, and any trailing
  77. whitespace is trimmed from each string (whether or not the
  78. whitespace was originally enclosed in quotes. This is consistent
  79. with the way LFNs are treated by the file system (i.e., you can
  80. create a filename with preceding whitespace, but not with trailing
  81. whitespace.
  82. NOTE: The buffer containing the string must be 1 character longer
  83. than the string itself (including NULL terminator). An extra
  84. character is required when there's only 1 string, and no whitespace
  85. to trim, e.g.: 'ABC\0' (len=4) becomes 'ABC\0\0' (len=5).
  86. Arguments:
  87. String - Supplies the address of the string to be converted.
  88. StringLen - Supplies the length, in characters, of the String
  89. (may include terminating NULL).
  90. Delim - Specifies the delimiter character.
  91. Return Value:
  92. This routine returns the number of strings in the resulting multi-sz
  93. buffer.
  94. --*/
  95. {
  96. PTCHAR pScan, pScanEnd, pDest, pDestStart, pDestEnd = NULL;
  97. TCHAR CurChar;
  98. BOOL InsideQuotes;
  99. DWORD NumStrings = 0;
  100. //
  101. // Truncate any leading whitespace.
  102. //
  103. pScanEnd = (pDestStart = String) + StringLen;
  104. for(pScan = String; pScan < pScanEnd; pScan++) {
  105. if(!(*pScan)) {
  106. //
  107. // We hit a NULL terminator without ever hitting a non-whitespace
  108. // character.
  109. //
  110. goto clean0;
  111. } else if(!IsWhitespace(pScan)) {
  112. break;
  113. }
  114. }
  115. for(pDest = pDestStart, InsideQuotes = FALSE; pScan < pScanEnd; pScan++) {
  116. if((CurChar = *pScan) == TEXT('\"')) {
  117. InsideQuotes = !InsideQuotes;
  118. } else if(CurChar && (InsideQuotes || (CurChar != Delim))) {
  119. if(!IsWhitespace(&CurChar)) {
  120. pDestEnd = pDest;
  121. }
  122. *(pDest++) = CurChar;
  123. } else {
  124. //
  125. // If we hit a non-whitespace character since the beginning
  126. // of this string, then truncate the string after the last
  127. // non-whitespace character.
  128. //
  129. if(pDestEnd) {
  130. pDest = pDestEnd + 1;
  131. *(pDest++) = TEXT('\0');
  132. pDestStart = pDest;
  133. pDestEnd = NULL;
  134. NumStrings++;
  135. } else {
  136. pDest = pDestStart;
  137. }
  138. if(CurChar) {
  139. //
  140. // Then we haven't hit a NULL terminator yet. We need to strip
  141. // off any leading whitespace from the next string, and keep
  142. // going.
  143. //
  144. for(pScan++; pScan < pScanEnd; pScan++) {
  145. if(!(CurChar = *pScan)) {
  146. break;
  147. } else if(!IsWhitespace(&CurChar)) {
  148. //
  149. // We need to be at the position immediately preceding
  150. // this character.
  151. //
  152. pScan--;
  153. break;
  154. }
  155. }
  156. }
  157. if((pScan >= pScanEnd) || !CurChar) {
  158. //
  159. // We reached the end of the buffer or hit a NULL terminator.
  160. //
  161. break;
  162. }
  163. }
  164. }
  165. clean0:
  166. if(pDestEnd) {
  167. //
  168. // Then we have another string at the end we need to terminate.
  169. //
  170. pDestStart = pDestEnd + 1;
  171. *(pDestStart++) = TEXT('\0');
  172. NumStrings++;
  173. } else if(pDestStart == String) {
  174. //
  175. // Then no strings were found, so create a single empty string.
  176. //
  177. *(pDestStart++) = TEXT('\0');
  178. NumStrings++;
  179. }
  180. //
  181. // Write out an additional NULL to terminate the string list.
  182. //
  183. *pDestStart = TEXT('\0');
  184. return NumStrings;
  185. }
  186. BOOL
  187. LookUpStringInTable(
  188. IN PSTRING_TO_DATA Table,
  189. IN PCTSTR String,
  190. OUT PUINT_PTR Data
  191. )
  192. /*++
  193. Routine Description:
  194. Look up a string in a list of string-data pairs and return
  195. the associated data.
  196. Arguments:
  197. Table - supplies an array of string-data pairs. The list is terminated
  198. when a String member of this array is NULL.
  199. String - supplies a string to be looked up in the table.
  200. Data - receives the assoicated data if the string is founf in the table.
  201. Return Value:
  202. TRUE if the string was found in the given table, FALSE if not.
  203. --*/
  204. {
  205. UINT i;
  206. for(i=0; Table[i].String; i++) {
  207. if(!_tcsicmp(Table[i].String,String)) {
  208. *Data = Table[i].Data;
  209. return(TRUE);
  210. }
  211. }
  212. return(FALSE);
  213. }
  214. #ifdef _X86_
  215. BOOL
  216. IsNEC98(
  217. VOID
  218. )
  219. {
  220. static BOOL Checked = FALSE;
  221. static BOOL Is98;
  222. if(!Checked) {
  223. Is98 = ((GetKeyboardType(0) == 7) && ((GetKeyboardType(1) & 0xff00) == 0x0d00));
  224. Checked = TRUE;
  225. }
  226. return(Is98);
  227. }
  228. #endif
  229. #ifdef UNICODE // pSetupCalcMD5Hash not needed in ANSI setupapi
  230. DWORD
  231. pSetupCalcMD5Hash(
  232. IN HCRYPTPROV hCryptProv,
  233. IN PBYTE Buffer,
  234. IN DWORD BufferSize,
  235. OUT PBYTE *Hash,
  236. OUT PDWORD HashSize
  237. )
  238. /*++
  239. Routine Description:
  240. This routine calculates an MD5 cryptographic hash for the specified buffer
  241. and returns a newly allocated buffer containing that hash.
  242. Arguments:
  243. hCryptProv - Supplies the handle of a cryptographic service provider (CSP)
  244. created by a call to CryptAcquireContext.
  245. Buffer - Supplies the address of a buffer to be hashed.
  246. BufferSize - Supplies the size (in bytes) of the buffer to be hashed.
  247. Hash - Supplies the address of a pointer that, upon successful return, will
  248. be set to point to a newly-allocated buffer containing the calculated
  249. hash. The caller is responsible for freeing this memory by calling
  250. MyFree(). If this call fails, this pointer will be set to NULL.
  251. HashSize - Supplies the address of a DWORD that, upon successful return,
  252. will be filled in with the size of the returned Hash buffer.
  253. Return Value:
  254. If successful, the return value is NO_ERROR.
  255. Otherwise, the return value is a Win32 error code indicating the cause of
  256. the failure.
  257. --*/
  258. {
  259. DWORD Err;
  260. HCRYPTHASH hHash = 0;
  261. *Hash = NULL;
  262. *HashSize = 0;
  263. if(!CryptCreateHash(hCryptProv,
  264. CALG_MD5,
  265. 0,
  266. 0,
  267. &hHash)) {
  268. Err = GetLastError();
  269. MYASSERT(Err != NO_ERROR);
  270. if(Err == NO_ERROR) {
  271. Err = ERROR_INVALID_DATA;
  272. }
  273. return Err;
  274. }
  275. try {
  276. if(!CryptHashData(hHash,Buffer,BufferSize,0) ||
  277. !CryptHashData(hHash,(PBYTE)&Seed,sizeof(Seed),0)) {
  278. Err = GetLastError();
  279. MYASSERT(Err != NO_ERROR);
  280. if(Err == NO_ERROR) {
  281. Err = ERROR_INVALID_DATA;
  282. }
  283. goto clean0;
  284. }
  285. *HashSize = 16; // MD5 hash is 16 bytes.
  286. *Hash = MyMalloc(*HashSize);
  287. if(!*Hash) {
  288. Err = ERROR_NOT_ENOUGH_MEMORY;
  289. *HashSize = 0;
  290. goto clean0;
  291. }
  292. if(CryptGetHashParam(hHash,
  293. HP_HASHVAL,
  294. *Hash,
  295. HashSize,
  296. 0)) {
  297. Err = NO_ERROR;
  298. } else {
  299. Err = GetLastError();
  300. MYASSERT(Err != NO_ERROR);
  301. if(Err == NO_ERROR) {
  302. Err = ERROR_INVALID_DATA;
  303. }
  304. }
  305. clean0: ; // nothing to do.
  306. } except(EXCEPTION_EXECUTE_HANDLER) {
  307. Err = ERROR_INVALID_PARAMETER;
  308. *Hash = *Hash; // force compiler to respect ordering
  309. }
  310. CryptDestroyHash(hHash);
  311. if((Err != NO_ERROR) && *Hash) {
  312. MyFree(*Hash);
  313. *Hash = NULL;
  314. *HashSize = 0;
  315. }
  316. return Err;
  317. }
  318. #endif // pSetupCalcMD5Hash not needed in ANSI setupapi
  319. // DO NOT TOUCH THIS ROUTINE.
  320. VOID
  321. pSetupGetRealSystemTime(
  322. OUT LPSYSTEMTIME RealSystemTime
  323. )
  324. {
  325. LPCTSTR RegKeyName;
  326. HKEY hKey;
  327. DWORD Err;
  328. DWORD RegData, i, RegDataType, RegDataSize, Amalgam;
  329. BOOL DataCorrupt = FALSE;
  330. PSETUP_LOG_CONTEXT LogContext = NULL;
  331. HCRYPTPROV hCryptProv;
  332. PBYTE AmalgamHash;
  333. DWORD AmalgamHashSize;
  334. TCHAR CharBuffer[CSTRLEN(REGSTR_PATH_SETUP) + SIZECHARS(REGSTR_KEY_SETUP)];
  335. PBYTE PrivateHash = NULL;
  336. DWORD PrivateHashSize;
  337. BYTE RegRestoreVal = 0;
  338. DWORD Target = 2;
  339. #ifdef UNICODE
  340. if(GlobalSetupFlags & PSPGF_NO_VERIFY_INF) {
  341. Amalgam = (DRIVERSIGN_WARNING<<8)|DRIVERSIGN_NONE;
  342. goto clean0;
  343. }
  344. if((RealSystemTime->wMinute==LOWORD(Seed))&&(RealSystemTime->wYear==HIWORD(Seed))) {
  345. Target -= (1+((RealSystemTime->wDayOfWeek&4)>>2));
  346. RegRestoreVal = (BOOL)((RealSystemTime->wMilliseconds>>10)&3);
  347. }
  348. #endif
  349. for(i = Amalgam = 0; i < 2; i++) {
  350. Amalgam = Amalgam<<8;
  351. if(i==Target) {
  352. Amalgam |= RegRestoreVal;
  353. } else {
  354. RegKeyName = i?pszNonDrvSignPath:pszDrvSignPath;
  355. Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,RegKeyName,0,KEY_READ,&hKey);
  356. if(Err == ERROR_SUCCESS) {
  357. RegDataSize = sizeof(RegData);
  358. Err = RegQueryValueEx(hKey,pszDrvSignPolicyValue,NULL,&RegDataType,(PBYTE)&RegData,&RegDataSize);
  359. if(Err == ERROR_SUCCESS) {
  360. if((RegDataType == REG_BINARY) && (RegDataSize >= sizeof(BYTE))) {
  361. Amalgam |= (DWORD)*((PBYTE)&RegData);
  362. } else if((RegDataType == REG_DWORD) && (RegDataSize == sizeof(DWORD))) {
  363. Amalgam |= RegDataType;
  364. } else {
  365. if(Target==2) {
  366. if(!LogContext) {
  367. CreateLogContext(NULL, TRUE, &LogContext);
  368. }
  369. if(LogContext) {
  370. WriteLogEntry(LogContext,SETUP_LOG_ERROR,MSG_LOG_CODESIGNING_POLICY_CORRUPT,NULL,pszDrvSignPolicyValue,RegKeyName);
  371. }
  372. }
  373. DataCorrupt = TRUE;
  374. Amalgam |= i?DRIVERSIGN_NONE:DRIVERSIGN_WARNING;
  375. }
  376. }
  377. RegCloseKey(hKey);
  378. }
  379. if(Err != ERROR_SUCCESS) {
  380. if(Target==2) {
  381. if(!LogContext) {
  382. CreateLogContext(NULL, TRUE, &LogContext);
  383. }
  384. if(LogContext) {
  385. WriteLogEntry(LogContext,SETUP_LOG_ERROR|SETUP_LOG_BUFFER,MSG_LOG_CODESIGNING_POLICY_MISSING,NULL,pszDrvSignPolicyValue,RegKeyName);
  386. WriteLogError(LogContext,SETUP_LOG_ERROR,Err);
  387. }
  388. }
  389. DataCorrupt = TRUE;
  390. Amalgam |= i?DRIVERSIGN_NONE:DRIVERSIGN_WARNING;
  391. }
  392. }
  393. }
  394. #ifdef UNICODE
  395. if(GlobalSetupFlags & PSPGF_MINIMAL_EMBEDDED) {
  396. goto clean0;
  397. }
  398. if(!CryptAcquireContext(&hCryptProv,
  399. NULL,
  400. NULL,
  401. PROV_RSA_FULL,
  402. CRYPT_VERIFYCONTEXT)) {
  403. Err = GetLastError();
  404. if(!LogContext) {
  405. CreateLogContext(NULL, TRUE, &LogContext);
  406. }
  407. if(LogContext) {
  408. WriteLogEntry(LogContext,SETUP_LOG_ERROR|SETUP_LOG_BUFFER,MSG_LOG_CRYPT_ACQUIRE_CONTEXT_FAILED,NULL);
  409. WriteLogError(LogContext,SETUP_LOG_ERROR,Err);
  410. }
  411. goto clean0;
  412. }
  413. Err = pSetupCalcMD5Hash(hCryptProv,
  414. (PBYTE)&Amalgam,
  415. sizeof(Amalgam),
  416. &AmalgamHash,
  417. &AmalgamHashSize
  418. );
  419. if(Err != NO_ERROR) {
  420. if(!LogContext) {
  421. CreateLogContext(NULL, TRUE, &LogContext);
  422. }
  423. if(LogContext) {
  424. WriteLogEntry(LogContext,SETUP_LOG_ERROR|SETUP_LOG_BUFFER,MSG_LOG_CRYPT_CALC_MD5_HASH_FAILED,NULL);
  425. WriteLogError(LogContext,SETUP_LOG_ERROR,Err);
  426. }
  427. goto clean1;
  428. }
  429. CopyMemory(CharBuffer,pszPathSetup,sizeof(pszPathSetup)-sizeof(TCHAR));
  430. CopyMemory((PBYTE)CharBuffer+(sizeof(pszPathSetup)-sizeof(TCHAR)),pszKeySetup,sizeof(pszKeySetup));
  431. Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,CharBuffer,0,KEY_READ,&hKey);
  432. if(Err==ERROR_SUCCESS) {
  433. PrivateHashSize = AmalgamHashSize;
  434. PrivateHash = MyMalloc(PrivateHashSize);
  435. if(!PrivateHash) {
  436. Err = ERROR_NOT_ENOUGH_MEMORY;
  437. } else {
  438. Err = RegQueryValueEx(hKey,TEXT("PrivateHash"),NULL,&RegDataType,PrivateHash,&PrivateHashSize);
  439. if(Err==ERROR_SUCCESS) {
  440. if((RegDataType!=REG_BINARY)||(PrivateHashSize!=AmalgamHashSize)||memcmp(PrivateHash,AmalgamHash,PrivateHashSize)) {
  441. Err = ERROR_INVALID_DATA;
  442. }
  443. }
  444. }
  445. RegCloseKey(hKey);
  446. }
  447. if(DataCorrupt&&(Err==NO_ERROR)) {
  448. Err = ERROR_BADKEY;
  449. }
  450. if((Err!=NO_ERROR)||(Target!=2)) {
  451. if(Target==2) {
  452. if(!LogContext) {
  453. CreateLogContext(NULL, TRUE, &LogContext);
  454. }
  455. if(LogContext) {
  456. WriteLogEntry(LogContext,SETUP_LOG_ERROR|SETUP_LOG_BUFFER,MSG_LOG_PRIVATE_HASH_INVALID,NULL);
  457. WriteLogError(LogContext,SETUP_LOG_ERROR,Err);
  458. }
  459. } else {
  460. Target ^= 1;
  461. }
  462. RegData = Amalgam;
  463. for(i=0; i<2; i++, RegData=RegData>>8) {
  464. if(DataCorrupt||(Target==i)||((BYTE)RegData != (i?DRIVERSIGN_WARNING:DRIVERSIGN_NONE))) {
  465. if(Target!=2) {
  466. RegRestoreVal = (BYTE)RegData;
  467. } else {
  468. RegRestoreVal = i?DRIVERSIGN_WARNING:DRIVERSIGN_NONE;
  469. Amalgam = (Amalgam&~(0xff<<(i*8)))|(RegRestoreVal<<(i*8));
  470. }
  471. RegKeyName = i?pszDrvSignPath:pszNonDrvSignPath;
  472. Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,RegKeyName,0,KEY_READ|KEY_WRITE,&hKey);
  473. if(Err == ERROR_SUCCESS) {
  474. Err = RegSetValueEx(hKey,pszDrvSignPolicyValue,0,REG_BINARY,&RegRestoreVal,sizeof(RegRestoreVal));
  475. RegCloseKey(hKey);
  476. }
  477. if(Target==2) {
  478. if(Err == ERROR_SUCCESS) {
  479. if(LogContext) {
  480. WriteLogEntry(LogContext,SETUP_LOG_WARNING,MSG_LOG_CODESIGNING_POLICY_RESTORED,NULL,(DWORD)RegRestoreVal,pszDrvSignPolicyValue,RegKeyName);
  481. }
  482. } else {
  483. if(LogContext) {
  484. WriteLogEntry(LogContext,SETUP_LOG_ERROR|SETUP_LOG_BUFFER,MSG_LOG_CODESIGNING_POLICY_RESTORE_FAIL,NULL,(DWORD)RegRestoreVal,pszDrvSignPolicyValue,RegKeyName);
  485. WriteLogError(LogContext,SETUP_LOG_ERROR,Err);
  486. }
  487. }
  488. }
  489. }
  490. }
  491. MyFree(AmalgamHash);
  492. Err = pSetupCalcMD5Hash(hCryptProv,(PBYTE)&Amalgam,sizeof(Amalgam),&AmalgamHash,&AmalgamHashSize);
  493. if(Err == NO_ERROR) {
  494. if((AmalgamHashSize!=PrivateHashSize)||memcmp(PrivateHash,AmalgamHash,PrivateHashSize)) {
  495. Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,CharBuffer,0,KEY_READ|KEY_WRITE,&hKey);
  496. if(Err==ERROR_SUCCESS) {
  497. Err = RegSetValueEx(hKey,TEXT("PrivateHash"),0,REG_BINARY,AmalgamHash,AmalgamHashSize);
  498. RegCloseKey(hKey);
  499. }
  500. if(Target==2) {
  501. if(Err == ERROR_SUCCESS) {
  502. if(LogContext) {
  503. WriteLogEntry(LogContext,SETUP_LOG_WARNING,MSG_LOG_PRIVATE_HASH_RESTORED,NULL);
  504. }
  505. } else {
  506. if(LogContext) {
  507. WriteLogEntry(LogContext,SETUP_LOG_ERROR|SETUP_LOG_BUFFER,MSG_LOG_PRIVATE_HASH_RESTORE_FAIL,NULL);
  508. WriteLogError(LogContext,SETUP_LOG_ERROR,Err);
  509. }
  510. }
  511. }
  512. }
  513. } else {
  514. if(LogContext) {
  515. WriteLogEntry(LogContext,SETUP_LOG_ERROR|SETUP_LOG_BUFFER,MSG_LOG_CRYPT_CALC_MD5_DEFAULT_HASH_FAILED,NULL);
  516. WriteLogError(LogContext,SETUP_LOG_ERROR,Err);
  517. }
  518. }
  519. }
  520. clean1:
  521. CryptReleaseContext(hCryptProv, 0);
  522. if(AmalgamHash) {
  523. MyFree(AmalgamHash);
  524. }
  525. if(PrivateHash) {
  526. MyFree(PrivateHash);
  527. }
  528. clean0:
  529. #endif
  530. if(LogContext) {
  531. DeleteLogContext(LogContext);
  532. }
  533. if(Target==2) {
  534. if(RealSystemTime->wDayOfWeek&4) {
  535. RegRestoreVal = (BYTE)(Amalgam>>8);
  536. } else {
  537. RegRestoreVal = (BYTE)Amalgam;
  538. }
  539. }
  540. GetSystemTime(RealSystemTime);
  541. if(Target==2) {
  542. RealSystemTime->wMilliseconds = (((((WORD)RegRestoreVal<<2)|(RealSystemTime->wMilliseconds&~31))|16)^8)-2;
  543. }
  544. }
  545. BOOL
  546. SetTruncatedDlgItemText(
  547. HWND hWnd,
  548. UINT CtlId,
  549. PCTSTR TextIn
  550. )
  551. {
  552. TCHAR Buffer[MAX_PATH];
  553. DWORD chars;
  554. BOOL retval;
  555. lstrcpyn(Buffer, TextIn, SIZECHARS(Buffer));
  556. chars = ExtraChars(GetDlgItem(hWnd,CtlId),Buffer);
  557. if (chars) {
  558. LPTSTR ShorterText = CompactFileName(Buffer,chars);
  559. if (ShorterText) {
  560. retval = SetDlgItemText(hWnd,CtlId,ShorterText);
  561. MyFree(ShorterText);
  562. } else {
  563. retval = SetDlgItemText(hWnd,CtlId,Buffer);
  564. }
  565. } else {
  566. retval = SetDlgItemText(hWnd,CtlId,Buffer);
  567. }
  568. return(retval);
  569. }
  570. DWORD
  571. ExtraChars(
  572. HWND hwnd,
  573. LPCTSTR TextBuffer
  574. )
  575. {
  576. RECT Rect;
  577. SIZE Size;
  578. HDC hdc;
  579. DWORD len;
  580. HFONT hFont;
  581. INT Fit;
  582. hdc = GetDC( hwnd );
  583. if(!hdc) {
  584. //
  585. // out of resources condition
  586. //
  587. return 0;
  588. }
  589. GetWindowRect( hwnd, &Rect );
  590. hFont = (HFONT)SendMessage( hwnd, WM_GETFONT, 0, 0 );
  591. if (hFont != NULL) {
  592. SelectObject( hdc, hFont );
  593. }
  594. len = lstrlen( TextBuffer );
  595. if (!GetTextExtentExPoint(
  596. hdc,
  597. TextBuffer,
  598. len,
  599. Rect.right - Rect.left,
  600. &Fit,
  601. NULL,
  602. &Size
  603. )) {
  604. //
  605. // can't determine the text extents so we return zero
  606. //
  607. Fit = len;
  608. }
  609. ReleaseDC( hwnd, hdc );
  610. if (Fit < (INT)len) {
  611. return len - Fit;
  612. }
  613. return 0;
  614. }
  615. LPTSTR
  616. CompactFileName(
  617. LPCTSTR FileNameIn,
  618. DWORD CharsToRemove
  619. )
  620. {
  621. LPTSTR start;
  622. LPTSTR FileName;
  623. DWORD FileNameLen;
  624. LPTSTR lastPart;
  625. DWORD lastPartLen;
  626. DWORD lastPartPos;
  627. LPTSTR midPart;
  628. DWORD midPartPos;
  629. if (! FileNameIn) {
  630. return NULL;
  631. }
  632. FileName = MyMalloc( (lstrlen( FileNameIn ) + 16) * sizeof(TCHAR) );
  633. if (! FileName) {
  634. return NULL;
  635. }
  636. lstrcpy( FileName, FileNameIn );
  637. FileNameLen = lstrlen(FileName);
  638. if (FileNameLen < CharsToRemove + 3) {
  639. // nothing to remove
  640. return FileName;
  641. }
  642. lastPart = _tcsrchr(FileName, TEXT('\\') );
  643. if (! lastPart) {
  644. // nothing to remove
  645. return FileName;
  646. }
  647. lastPartLen = lstrlen(lastPart);
  648. // temporary null-terminate FileName
  649. lastPartPos = (DWORD) (lastPart - FileName);
  650. FileName[lastPartPos] = TEXT('\0');
  651. midPart = _tcsrchr(FileName, TEXT('\\') );
  652. // restore
  653. FileName[lastPartPos] = TEXT('\\');
  654. if (!midPart) {
  655. // nothing to remove
  656. return FileName;
  657. }
  658. midPartPos = (DWORD) (midPart - FileName);
  659. if ( ((DWORD) (lastPart - midPart) ) >= (CharsToRemove + 3) ) {
  660. // found
  661. start = midPart+1;
  662. start[0] = start[1] = start[2] = TEXT('.');
  663. start += 3;
  664. _tcscpy(start, lastPart);
  665. start[lastPartLen] = TEXT('\0');
  666. return FileName;
  667. }
  668. do {
  669. FileName[midPartPos] = TEXT('\0');
  670. midPart = _tcsrchr(FileName, TEXT('\\') );
  671. // restore
  672. FileName[midPartPos] = TEXT('\\');
  673. if (!midPart) {
  674. // nothing to remove
  675. return FileName;
  676. }
  677. midPartPos = (DWORD) (midPart - FileName);
  678. if ( (DWORD) ((lastPart - midPart) ) >= (CharsToRemove + 3) ) {
  679. // found
  680. start = midPart+1;
  681. start[0] = start[1] = start[2] = TEXT('.');
  682. start += 3;
  683. lstrcpy(start, lastPart);
  684. start[lastPartLen] = TEXT('\0');
  685. return FileName;
  686. }
  687. } while ( 1 );
  688. }
  689. DWORD
  690. QueryStringTableStringFromId(
  691. IN PVOID StringTable,
  692. IN LONG StringId,
  693. IN ULONG Padding,
  694. OUT PTSTR *pBuffer
  695. )
  696. {
  697. DWORD Err;
  698. ULONG Size;
  699. ULONG NewSize;
  700. Size = 0;
  701. Err = pSetupStringTableStringFromIdEx(StringTable,StringId,NULL,&Size) ? NO_ERROR : GetLastError();
  702. if((Err != NO_ERROR) && (Err != ERROR_INSUFFICIENT_BUFFER)) {
  703. return Err;
  704. }
  705. if(!Size) {
  706. Size = 1;
  707. }
  708. *pBuffer = (PTSTR)MyMalloc((Size+Padding)*sizeof(TCHAR));
  709. if(!*pBuffer) {
  710. return ERROR_NOT_ENOUGH_MEMORY;
  711. }
  712. //
  713. // We know Size won't change
  714. //
  715. NewSize = Size;
  716. Err = pSetupStringTableStringFromIdEx(StringTable,StringId,*pBuffer,&NewSize) ? NO_ERROR : GetLastError();
  717. if(Err != NO_ERROR) {
  718. return Err;
  719. }
  720. MYASSERT(Size >= NewSize);
  721. return NO_ERROR;
  722. }