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.

638 lines
14 KiB

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