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.

662 lines
16 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. miscutil.c
  5. Abstract:
  6. Miscellaneous utility functions for SPUTILS
  7. Author:
  8. Ted Miller (tedm) 20-Jan-1995
  9. Revision History:
  10. Jamie Hunter (JamieHun) Jun-27-2000
  11. Moved various functions out of setupapi into sputils
  12. Jamie Hunter (JamieHun) Mar-05-2002
  13. Security code review
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. PTSTR
  18. pSetupDuplicateString(
  19. IN PCTSTR String
  20. )
  21. /*++
  22. Routine Description:
  23. Create a duplicate copy of a nul-terminated string.
  24. If the string pointer is not valid an exception is generated.
  25. Arguments:
  26. String - supplies string to be duplicated.
  27. Return Value:
  28. NULL if out of memory.
  29. Caller can free buffer with pSetupFree().
  30. --*/
  31. {
  32. PTSTR p;
  33. //
  34. // The win32 lstrlen and lstrcpy functions are guarded with
  35. // try/except (at least on NT). So if we use them and the string
  36. // is invalid, we may end up 'laundering' it into a valid 0-length
  37. // string. We don't want that -- we actually want to fault
  38. // in that case. So use the CRT functions, which we know are
  39. // unguarded and will generate exceptions with invalid args.
  40. //
  41. // Also handle the case where the string is valid when we are
  42. // taking its length, but becomes invalid before or while we
  43. // are copying it. If we're not careful this could be a memory
  44. // leak. A try/finally does exactly what we want -- allowing us
  45. // to clean up and still 'pass on' the exception.
  46. //
  47. if(p = pSetupCheckedMalloc((_tcslen(String)+1)*sizeof(TCHAR))) {
  48. try {
  49. //
  50. // If String is or becomes invalid, this will generate
  51. // an exception, but before execution leaves this routine
  52. // we'll hit the termination handler.
  53. //
  54. _tcscpy(p,String);
  55. } finally {
  56. //
  57. // If a fault occurred during the copy, free the copy.
  58. // Execution will then pass to whatever exception handler
  59. // might exist in the caller, etc.
  60. //
  61. if(AbnormalTermination()) {
  62. pSetupFree(p);
  63. p = NULL;
  64. }
  65. }
  66. }
  67. return(p);
  68. }
  69. #ifndef SPUTILSW
  70. PSTR
  71. pSetupUnicodeToMultiByte(
  72. IN PCWSTR UnicodeString,
  73. IN UINT Codepage
  74. )
  75. /*++
  76. Routine Description:
  77. Convert a string from unicode to ansi.
  78. Arguments:
  79. UnicodeString - supplies string to be converted.
  80. Codepage - supplies codepage to be used for the conversion.
  81. Return Value:
  82. NULL if out of memory or invalid codepage.
  83. Caller can free buffer with pSetupFree().
  84. --*/
  85. {
  86. UINT WideCharCount;
  87. PSTR String;
  88. UINT StringBufferSize;
  89. UINT BytesInString;
  90. PSTR p;
  91. WideCharCount = lstrlenW(UnicodeString) + 1;
  92. //
  93. // Allocate maximally sized buffer.
  94. // If every unicode character is a double-byte
  95. // character, then the buffer needs to be the same size
  96. // as the unicode string. Otherwise it might be smaller,
  97. // as some unicode characters will translate to
  98. // single-byte characters.
  99. //
  100. StringBufferSize = WideCharCount * 2;
  101. String = pSetupCheckedMalloc(StringBufferSize);
  102. if(String == NULL) {
  103. return(NULL);
  104. }
  105. //
  106. // Perform the conversion.
  107. //
  108. BytesInString = WideCharToMultiByte(
  109. Codepage,
  110. 0, // default composite char behavior
  111. UnicodeString,
  112. WideCharCount,
  113. String,
  114. StringBufferSize,
  115. NULL,
  116. NULL
  117. );
  118. if(BytesInString == 0) {
  119. pSetupFree(String);
  120. return(NULL);
  121. }
  122. //
  123. // Resize the string's buffer to its correct size.
  124. // If the realloc fails for some reason the original
  125. // buffer is not freed.
  126. //
  127. if(p = pSetupRealloc(String,BytesInString)) {
  128. String = p;
  129. }
  130. return(String);
  131. }
  132. PWSTR
  133. pSetupMultiByteToUnicode(
  134. IN PCSTR String,
  135. IN UINT Codepage
  136. )
  137. /*++
  138. Routine Description:
  139. Convert a string to unicode.
  140. Arguments:
  141. String - supplies string to be converted.
  142. Codepage - supplies codepage to be used for the conversion.
  143. Return Value:
  144. NULL if string could not be converted (out of memory or invalid cp)
  145. Caller can free buffer with pSetupFree().
  146. --*/
  147. {
  148. UINT BytesIn8BitString;
  149. UINT CharsInUnicodeString;
  150. PWSTR UnicodeString;
  151. PWSTR p;
  152. BytesIn8BitString = lstrlenA(String) + 1;
  153. //
  154. // Allocate maximally sized buffer.
  155. // If every character is a single-byte character,
  156. // then the buffer needs to be twice the size
  157. // as the 8bit string. Otherwise it might be smaller,
  158. // as some characters are 2 bytes in their unicode and
  159. // 8bit representations.
  160. //
  161. UnicodeString = pSetupCheckedMalloc(BytesIn8BitString * sizeof(WCHAR));
  162. if(UnicodeString == NULL) {
  163. return(NULL);
  164. }
  165. //
  166. // Perform the conversion.
  167. //
  168. CharsInUnicodeString = MultiByteToWideChar(
  169. Codepage,
  170. MB_PRECOMPOSED,
  171. String,
  172. BytesIn8BitString,
  173. UnicodeString,
  174. BytesIn8BitString
  175. );
  176. if(CharsInUnicodeString == 0) {
  177. pSetupFree(UnicodeString);
  178. return(NULL);
  179. }
  180. //
  181. // Resize the unicode string's buffer to its correct size.
  182. // If the realloc fails for some reason the original
  183. // buffer is not freed.
  184. //
  185. if(p = pSetupRealloc(UnicodeString,CharsInUnicodeString*sizeof(WCHAR))) {
  186. UnicodeString = p;
  187. }
  188. return(UnicodeString);
  189. }
  190. #endif // ! SPUTILSW
  191. #ifdef UNICODE
  192. DWORD
  193. pSetupCaptureAndConvertAnsiArg(
  194. IN PCSTR AnsiString,
  195. OUT PCWSTR *UnicodeString
  196. )
  197. /*++
  198. Routine Description:
  199. Capture an ANSI string whose validity is suspect and convert it
  200. into a Unicode string. The conversion is completely guarded and thus
  201. won't fault, leak memory in the error case, etc.
  202. Arguments:
  203. AnsiString - supplies string to be converted.
  204. UnicodeString - if successful, receives pointer to unicode equivalent
  205. of AnsiString. Caller must free with pSetupFree(). If not successful,
  206. receives NULL. This parameter is NOT validated so be careful.
  207. Return Value:
  208. Win32 error code indicating outcome.
  209. NO_ERROR - success, UnicodeString filled in.
  210. ERROR_NOT_ENOUGH_MEMORY - insufficient memory for conversion.
  211. ERROR_INVALID_PARAMETER - AnsiString was invalid.
  212. --*/
  213. {
  214. PSTR ansiString;
  215. DWORD d;
  216. //
  217. // Capture the string first. We do this because pSetupMultiByteToUnicode
  218. // won't fault if AnsiString were to become invalid, meaning we could
  219. // 'launder' a bogus argument into a valid one. Be careful not to
  220. // leak memory in the error case, etc (see comments in DuplicateString()).
  221. // Do NOT use Win32 string functions here; we rely on faults occuring
  222. // when pointers are invalid!
  223. //
  224. *UnicodeString = NULL;
  225. d = NO_ERROR;
  226. try {
  227. ansiString = pSetupCheckedMalloc(strlen(AnsiString)+1);
  228. if(!ansiString) {
  229. d = ERROR_NOT_ENOUGH_MEMORY;
  230. }
  231. } except(EXCEPTION_EXECUTE_HANDLER) {
  232. //
  233. // If we get here, strlen faulted and ansiString
  234. // was not allocated.
  235. //
  236. d = ERROR_INVALID_PARAMETER;
  237. }
  238. if(d == NO_ERROR) {
  239. try {
  240. strcpy(ansiString,AnsiString);
  241. } except(EXCEPTION_EXECUTE_HANDLER) {
  242. d = ERROR_INVALID_PARAMETER;
  243. pSetupFree(ansiString);
  244. }
  245. }
  246. if(d == NO_ERROR) {
  247. //
  248. // Now we have a local copy of the string; don't worry
  249. // about faults any more.
  250. //
  251. *UnicodeString = pSetupMultiByteToUnicode(ansiString,CP_ACP);
  252. if(*UnicodeString == NULL) {
  253. d = ERROR_NOT_ENOUGH_MEMORY;
  254. }
  255. pSetupFree(ansiString);
  256. }
  257. return(d);
  258. }
  259. #else
  260. DWORD
  261. pSetupCaptureAndConvertAnsiArg(
  262. IN PCSTR AnsiString,
  263. OUT PCWSTR *UnicodeString
  264. )
  265. {
  266. //
  267. // Stub so the dll will link.
  268. //
  269. UNREFERENCED_PARAMETER(AnsiString);
  270. UNREFERENCED_PARAMETER(UnicodeString);
  271. return(ERROR_CALL_NOT_IMPLEMENTED);
  272. }
  273. #endif
  274. BOOL
  275. pSetupConcatenatePaths(
  276. IN OUT PTSTR Target,
  277. IN PCTSTR Path,
  278. IN UINT TargetBufferSize,
  279. OUT PUINT RequiredSize OPTIONAL
  280. )
  281. /*++
  282. Routine Description:
  283. Concatenate 2 paths, ensuring that one, and only one,
  284. path separator character is introduced at the junction point.
  285. Arguments:
  286. Target - supplies first part of path. Path is appended to this.
  287. (Target should be a buffer under program control)
  288. Path - supplies path to be concatenated to Target.
  289. (Path should be a buffer under program control)
  290. TargetBufferSize - supplies the size of the Target buffer,
  291. in characters.
  292. RequiredSize - if specified, receives the number of characters
  293. required to hold the fully concatenated path, including
  294. the terminating nul.
  295. Return Value:
  296. TRUE if the full path fit in Target buffer. Otherwise the path
  297. will have been truncated.
  298. --*/
  299. {
  300. UINT TargetLength,PathLength;
  301. BOOL TrailingBackslash,LeadingBackslash;
  302. UINT EndingLength;
  303. PCTSTR CharTest;
  304. TargetLength = lstrlen(Target);
  305. PathLength = lstrlen(Path);
  306. //
  307. // See whether the target has a trailing backslash.
  308. // (allow forward slash here which is symantically equivalent)
  309. //
  310. if(TargetLength &&
  311. ((*(CharTest = CharPrev(Target,Target+TargetLength)) == TEXT('\\'))
  312. || (*CharTest == TEXT('/')))) {
  313. TrailingBackslash = TRUE;
  314. TargetLength--;
  315. } else {
  316. TrailingBackslash = FALSE;
  317. }
  318. //
  319. // See whether the path has a leading backshash.
  320. // (allow forward slash here which is symantically equivalent)
  321. //
  322. if((Path[0] == TEXT('\\')) || (Path[0] == TEXT('/'))) {
  323. LeadingBackslash = TRUE;
  324. PathLength--;
  325. } else {
  326. LeadingBackslash = FALSE;
  327. }
  328. //
  329. // Calculate the ending length, which is equal to the sum of
  330. // the length of the two strings modulo leading/trailing
  331. // backslashes, plus one path separator, plus a nul.
  332. //
  333. EndingLength = TargetLength + PathLength + 2;
  334. if(RequiredSize) {
  335. *RequiredSize = EndingLength;
  336. }
  337. if(!LeadingBackslash && (TargetLength < TargetBufferSize)) {
  338. Target[TargetLength++] = TEXT('\\');
  339. }
  340. if(TargetBufferSize > TargetLength) {
  341. lstrcpyn(Target+TargetLength,Path,TargetBufferSize-TargetLength);
  342. }
  343. //
  344. // Make sure the buffer is nul terminated in all cases.
  345. //
  346. if (TargetBufferSize) {
  347. Target[TargetBufferSize-1] = 0;
  348. }
  349. return(EndingLength <= TargetBufferSize);
  350. }
  351. PCTSTR
  352. pSetupGetFileTitle(
  353. IN PCTSTR FilePath
  354. )
  355. /*++
  356. Routine Description:
  357. This routine returns a pointer to the first character in the
  358. filename part of the supplied path. If only a filename was given,
  359. then this will be a pointer to the first character in the string
  360. (i.e., the same as what was passed in).
  361. To find the filename part, the routine returns the last component of
  362. the string, beginning with the character immediately following the
  363. last '\', '/' (Windows treats '/' as equivalent to '\' ) or initial
  364. 'd:' specification.
  365. Arguments:
  366. FilePath - Supplies the file path from which to retrieve the filename
  367. portion.
  368. Return Value:
  369. A pointer to the beginning of the filename portion of the path.
  370. --*/
  371. {
  372. PCTSTR LastComponent;
  373. TCHAR CurChar;
  374. if((_totupper(FilePath[0])>=TEXT('A')) &&
  375. (_totupper(FilePath[0])<=TEXT('Z')) &&
  376. (FilePath[1] == TEXT(':'))) {
  377. //
  378. // x: (drive letter - colon) is skipped, this
  379. // is the only time we don't treat ':' as part of path name
  380. //
  381. FilePath+=2;
  382. }
  383. LastComponent = FilePath;
  384. while(CurChar = *FilePath) {
  385. FilePath = CharNext(FilePath);
  386. if((CurChar == TEXT('\\')) || (CurChar == TEXT('/'))) {
  387. LastComponent = FilePath;
  388. }
  389. }
  390. return LastComponent;
  391. }
  392. #ifndef SPUTILSW
  393. BOOL
  394. _pSpUtilsInitializeSynchronizedAccess(
  395. OUT PMYLOCK Lock
  396. )
  397. /*++
  398. Routine Description:
  399. Initialize a lock structure to be used with Synchronization routines.
  400. Arguments:
  401. Lock - supplies structure to be initialized. This routine creates
  402. the locking event and mutex and places handles in this structure.
  403. Return Value:
  404. TRUE if the lock structure was successfully initialized. FALSE if not.
  405. --*/
  406. {
  407. if(Lock->Handles[TABLE_DESTROYED_EVENT] = CreateEvent(NULL,TRUE,FALSE,NULL)) {
  408. if(Lock->Handles[TABLE_ACCESS_MUTEX] = CreateMutex(NULL,FALSE,NULL)) {
  409. return(TRUE);
  410. }
  411. CloseHandle(Lock->Handles[TABLE_DESTROYED_EVENT]);
  412. }
  413. return(FALSE);
  414. }
  415. VOID
  416. _pSpUtilsDestroySynchronizedAccess(
  417. IN OUT PMYLOCK Lock
  418. )
  419. /*++
  420. Routine Description:
  421. Tears down a lock structure created by InitializeSynchronizedAccess.
  422. ASSUMES THAT THE CALLING ROUTINE HAS ALREADY ACQUIRED THE LOCK!
  423. Arguments:
  424. Lock - supplies structure to be torn down. The structure itself
  425. is not freed.
  426. Return Value:
  427. None.
  428. --*/
  429. {
  430. HANDLE h1,h2;
  431. h1 = Lock->Handles[TABLE_DESTROYED_EVENT];
  432. h2 = Lock->Handles[TABLE_ACCESS_MUTEX];
  433. Lock->Handles[TABLE_DESTROYED_EVENT] = NULL;
  434. Lock->Handles[TABLE_ACCESS_MUTEX] = NULL;
  435. CloseHandle(h2);
  436. SetEvent(h1);
  437. CloseHandle(h1);
  438. }
  439. VOID
  440. pSetupCenterWindowRelativeToParent(
  441. HWND hwnd
  442. )
  443. /*++
  444. Routine Description:
  445. Centers a dialog relative to its owner, taking into account
  446. the 'work area' of the desktop.
  447. Arguments:
  448. hwnd - window handle of dialog to center
  449. Return Value:
  450. None.
  451. --*/
  452. {
  453. RECT rcFrame,
  454. rcWindow;
  455. LONG x,
  456. y,
  457. w,
  458. h;
  459. POINT point;
  460. HWND Parent;
  461. Parent = GetWindow(hwnd,GW_OWNER);
  462. if(Parent == NULL) {
  463. return;
  464. }
  465. point.x = point.y = 0;
  466. ClientToScreen(Parent,&point);
  467. GetWindowRect(hwnd,&rcWindow);
  468. GetClientRect(Parent,&rcFrame);
  469. w = rcWindow.right - rcWindow.left + 1;
  470. h = rcWindow.bottom - rcWindow.top + 1;
  471. x = point.x + ((rcFrame.right - rcFrame.left + 1 - w) / 2);
  472. y = point.y + ((rcFrame.bottom - rcFrame.top + 1 - h) / 2);
  473. //
  474. // Get the work area for the current desktop (i.e., the area that
  475. // the tray doesn't occupy).
  476. //
  477. if(!SystemParametersInfo(SPI_GETWORKAREA, 0, (PVOID)&rcFrame, 0)) {
  478. //
  479. // For some reason SPI failed, so use the full screen.
  480. //
  481. rcFrame.top = rcFrame.left = 0;
  482. rcFrame.right = GetSystemMetrics(SM_CXSCREEN);
  483. rcFrame.bottom = GetSystemMetrics(SM_CYSCREEN);
  484. }
  485. if(x + w > rcFrame.right) {
  486. x = rcFrame.right - w;
  487. } else if(x < rcFrame.left) {
  488. x = rcFrame.left;
  489. }
  490. if(y + h > rcFrame.bottom) {
  491. y = rcFrame.bottom - h;
  492. } else if(y < rcFrame.top) {
  493. y = rcFrame.top;
  494. }
  495. MoveWindow(hwnd,x,y,w,h,FALSE);
  496. }
  497. #endif // !SPUTILSW