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.

1010 lines
22 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. main.c
  5. Abstract:
  6. Main source file of migutil.dll
  7. Author:
  8. Jim Schmidt (jimschm) 01-Aug-1996
  9. Revision History:
  10. jimschm 23-Sep-1998 Start thread
  11. marcw 23-Sep-1998 Locale fix
  12. jimschm 03-Nov-1997 Added TextAlloc routines
  13. marcw 22-Jul-1997 Added IS<platform> functions.
  14. --*/
  15. #include "pch.h"
  16. #include "migutilp.h"
  17. #include "locale.h"
  18. #include <mbctype.h>
  19. //#define DEBUG_ALL_FILES
  20. OSVERSIONINFOA g_OsInfo;
  21. extern OUR_CRITICAL_SECTION g_DebugMsgCs;
  22. #define TEXT_GROWTH_SIZE 65536
  23. //
  24. // Out of memory string -- loaded at initialization
  25. //
  26. PCSTR g_OutOfMemoryString = NULL;
  27. PCSTR g_OutOfMemoryRetry = NULL;
  28. PCSTR g_ErrorString = NULL;
  29. HWND g_OutOfMemoryParentWnd;
  30. //
  31. // Flag used for MBCS string functions, which perform faster if the code page is NOT MBCS
  32. //
  33. BOOL g_IsMbcp = FALSE;
  34. //
  35. // OS-dependent flags for MultiByteToWideChar
  36. //
  37. DWORD g_MigutilWCToMBFlags = 0;
  38. //
  39. // A dynamic string. Among other things, this list can hold lists of imports
  40. // as they are read out Win32 executables.
  41. //
  42. //DYNSTRING dynImp;
  43. //
  44. // g_ShortTermAllocTable is the default table used for resource string
  45. // management. New strings are allocated from the table.
  46. //
  47. // Allocation tables are very simple ways to store strings loaded in from
  48. // the exe image. The loaded string is copied into the table and kept
  49. // around until it is explicitly freed. Multiple attempts at getting the
  50. // same resource string return the same string, inc'ing a use counter.
  51. //
  52. // g_LastAllocTable is a temporary holder for the wrapper APIs that
  53. // do not require the caller to supply the alloc table. DO NOT ALTER!
  54. //
  55. // g_OutOfMemoryTable is the table used to hold out-of-memory text. It
  56. // is loaded up at init time and is kept in memory for the whole time
  57. // migutil is in use, so out-of-memory messages can always be displayed.
  58. //
  59. PGROWBUFFER g_ShortTermAllocTable;
  60. PGROWBUFFER g_LastAllocTable;
  61. PGROWBUFFER g_OutOfMemoryTable;
  62. //
  63. // We make sure the message APIs (GetStringResource, ParseMessageID, etc)
  64. // are thread-safe
  65. //
  66. OUR_CRITICAL_SECTION g_MessageCs;
  67. BOOL fInitedMessageCs = FALSE;
  68. //
  69. // The PoolMem routines must also be thread-safe
  70. //
  71. CRITICAL_SECTION g_PoolMemCs;
  72. BOOL fInitedPoolMemCs = FALSE;
  73. //
  74. // MemAlloc critical section
  75. //
  76. CRITICAL_SECTION g_MemAllocCs;
  77. BOOL fInitedMemAllocCs = FALSE;
  78. //
  79. // The following pools are used for text management. g_RegistryApiPool is
  80. // for reg.c, g_PathsPool is for the JoinPaths/DuplicatePath/etc routines,
  81. // and g_TextPool is for AllocText, DupText, etc.
  82. //
  83. POOLHANDLE g_RegistryApiPool;
  84. POOLHANDLE g_PathsPool;
  85. POOLHANDLE g_TextPool;
  86. //
  87. // PC98 settings
  88. //
  89. BOOL g_IsPc98;
  90. static CHAR g_BootDrivePathBufA[8];
  91. static WCHAR g_BootDrivePathBufW[4];
  92. PCSTR g_BootDrivePathA;
  93. PCWSTR g_BootDrivePathW;
  94. static CHAR g_BootDriveBufA[6];
  95. static WCHAR g_BootDriveBufW[3];
  96. PCSTR g_BootDriveA;
  97. PCWSTR g_BootDriveW;
  98. CHAR g_BootDriveLetterA;
  99. WCHAR g_BootDriveLetterW;
  100. //
  101. // Implementation
  102. //
  103. BOOL
  104. WINAPI
  105. MigUtil_Entry (
  106. HINSTANCE hInstance,
  107. DWORD dwReason,
  108. LPVOID lpReserved
  109. )
  110. {
  111. switch (dwReason) {
  112. case DLL_PROCESS_ATTACH:
  113. //
  114. // NOTE: If FALSE is returned, none of the executables will run.
  115. // Every project executable links to this library.
  116. //
  117. if(!pSetupInitializeUtils()) {
  118. DEBUGMSG ((DBG_ERROR, "Cannot initialize SpUtils"));
  119. return FALSE;
  120. }
  121. //
  122. // Load in OSVERSION info.
  123. //
  124. g_OsInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
  125. // this function only fails if we specify an invalid value
  126. // for the dwOSVersionInfoSize member (which we don't)
  127. if(!GetVersionExA(&g_OsInfo))
  128. MYASSERT(FALSE);
  129. //
  130. // Initialize the global flag indicating that a MBCS code page is in use
  131. //
  132. g_IsMbcp = (_getmbcp () != 0);
  133. //g_IsPc98 = (GetKeyboardType (0) == 7) && ((GetKeyboardType (1) & 0xff00) == 0x0d00);
  134. g_IsPc98 = FALSE;
  135. g_BootDrivePathA = g_BootDrivePathBufA;
  136. g_BootDrivePathW = g_BootDrivePathBufW;
  137. g_BootDriveA = g_BootDriveBufA;
  138. g_BootDriveW = g_BootDriveBufW;
  139. if (g_IsPc98) {
  140. StringCopyA ((PSTR) g_BootDrivePathA, "A:\\");
  141. StringCopyW ((PWSTR) g_BootDrivePathW, L"A:\\");
  142. StringCopyA ((PSTR) g_BootDriveA, "A:");
  143. StringCopyW ((PWSTR) g_BootDriveW, L"A:");
  144. g_BootDriveLetterA = 'A';
  145. g_BootDriveLetterW = L'A';
  146. } else {
  147. StringCopyA ((PSTR) g_BootDrivePathA, "C:\\");
  148. StringCopyW ((PWSTR) g_BootDrivePathW, L"C:\\");
  149. StringCopyA ((PSTR) g_BootDriveA, "C:");
  150. StringCopyW ((PWSTR) g_BootDriveW, L"C:");
  151. g_BootDriveLetterA = 'C';
  152. g_BootDriveLetterW = L'C';
  153. }
  154. // initialize log
  155. if (!LogInit (NULL)) {
  156. return FALSE;
  157. }
  158. // MemAlloc critical section
  159. InitializeCriticalSection (&g_MemAllocCs);
  160. fInitedMemAllocCs = TRUE;
  161. // Now that MemAlloc will work, initialize allocation tracking
  162. InitAllocationTracking();
  163. // PoolMem critical section
  164. InitializeCriticalSection (&g_PoolMemCs);
  165. fInitedPoolMemCs = TRUE;
  166. // The short-term alloc table for string resource utils
  167. g_ShortTermAllocTable = CreateAllocTable();
  168. if (!g_ShortTermAllocTable) {
  169. DEBUGMSG ((DBG_ERROR, "Cannot create short-term AllocTable"));
  170. return FALSE;
  171. }
  172. //
  173. // MultiByteToWideChar has desirable flags that only function on NT.
  174. // Because of our SUBSYSTEM=4.00 header requirements, we don't get
  175. // this constant.
  176. //
  177. #ifndef WC_NO_BEST_FIT_CHARS
  178. #define WC_NO_BEST_FIT_CHARS 0x00000400
  179. #endif
  180. g_MigutilWCToMBFlags = (ISNT()) ? WC_NO_BEST_FIT_CHARS : 0;
  181. // The critical section that guards ParseMessage/GetStringResource
  182. if (!InitializeOurCriticalSection (&g_MessageCs)) {
  183. DEBUGMSG ((DBG_ERROR, "Cannot initialize critical section"));
  184. DestroyAllocTable (g_ShortTermAllocTable);
  185. g_ShortTermAllocTable = NULL;
  186. }
  187. else
  188. {
  189. fInitedMessageCs = TRUE;
  190. }
  191. // A pool for APIs in reg.c
  192. g_RegistryApiPool = PoolMemInitNamedPool ("Registry API");
  193. g_PathsPool = PoolMemInitNamedPool ("Paths");
  194. g_TextPool = PoolMemInitNamedPool ("Text");
  195. if (!g_RegistryApiPool || !g_PathsPool || !g_TextPool) {
  196. return FALSE;
  197. }
  198. PoolMemSetMinimumGrowthSize (g_TextPool, TEXT_GROWTH_SIZE);
  199. // The "out of memory" message
  200. g_OutOfMemoryTable = CreateAllocTable();
  201. if (!g_OutOfMemoryTable) {
  202. DEBUGMSG ((DBG_ERROR, "Cannot create out of memory AllocTable"));
  203. return FALSE;
  204. }
  205. g_OutOfMemoryRetry = GetStringResourceExA (g_OutOfMemoryTable, 10001 /* MSG_OUT_OF_MEMORY_RETRY */);
  206. g_OutOfMemoryString = GetStringResourceExA (g_OutOfMemoryTable, 10002 /* MSG_OUT_OF_MEMORY */);
  207. if (!g_OutOfMemoryString || !g_OutOfMemoryRetry) {
  208. DEBUGMSG ((DBG_WARNING, "Cannot load out of memory messages"));
  209. }
  210. g_ErrorString = GetStringResourceExA (g_OutOfMemoryTable, 10003 /* MSG_ERROR */);
  211. if (!g_ErrorString || g_ErrorString[0] == 0) {
  212. g_ErrorString = "Error";
  213. }
  214. //
  215. // set the locale to the system locale. Not doing this can cause isspace to Av in certain MBSCHR circumstances.
  216. //
  217. setlocale(LC_ALL,"");
  218. InfGlobalInit (FALSE);
  219. RegInitialize();
  220. break;
  221. case DLL_PROCESS_DETACH:
  222. #ifdef DEBUG
  223. DumpOpenKeys();
  224. RegTerminate();
  225. #endif
  226. InfGlobalInit (TRUE);
  227. if (g_RegistryApiPool) {
  228. PoolMemDestroyPool (g_RegistryApiPool);
  229. }
  230. if (g_PathsPool) {
  231. PoolMemDestroyPool (g_PathsPool);
  232. }
  233. if (g_TextPool) {
  234. PoolMemDestroyPool (g_TextPool);
  235. }
  236. if (g_ShortTermAllocTable) {
  237. DestroyAllocTable (g_ShortTermAllocTable);
  238. }
  239. if (g_OutOfMemoryTable) {
  240. DestroyAllocTable (g_OutOfMemoryTable);
  241. }
  242. FreeAllocationTracking();
  243. //
  244. // VERY LAST CODE TO RUN
  245. //
  246. DumpHeapStats();
  247. LogExit();
  248. pSetupUninitializeUtils();
  249. if (fInitedMessageCs) {
  250. DeleteOurCriticalSection (&g_MessageCs);
  251. }
  252. if (fInitedPoolMemCs) {
  253. DeleteCriticalSection (&g_PoolMemCs);
  254. }
  255. if (fInitedMemAllocCs) {
  256. DeleteCriticalSection (&g_MemAllocCs);
  257. }
  258. break;
  259. }
  260. return TRUE;
  261. }
  262. #define WIDTH(rect) (rect.right - rect.left)
  263. #define HEIGHT(rect) (rect.bottom - rect.top)
  264. void
  265. CenterWindow (
  266. IN HWND hwnd,
  267. IN HWND Parent
  268. )
  269. {
  270. RECT WndRect, ParentRect;
  271. int x, y;
  272. if (!Parent) {
  273. ParentRect.left = 0;
  274. ParentRect.top = 0;
  275. ParentRect.right = GetSystemMetrics (SM_CXFULLSCREEN);
  276. ParentRect.bottom = GetSystemMetrics (SM_CYFULLSCREEN);
  277. } else {
  278. GetWindowRect (Parent, &ParentRect);
  279. }
  280. MYASSERT (IsWindow (hwnd));
  281. GetWindowRect (hwnd, &WndRect);
  282. x = ParentRect.left + (WIDTH(ParentRect) - WIDTH(WndRect)) / 2;
  283. y = ParentRect.top + (HEIGHT(ParentRect) - HEIGHT(WndRect)) / 2;
  284. SetWindowPos (hwnd, NULL, x, y, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
  285. }
  286. static INT g_MigUtilWaitCounter = 0;
  287. static HCURSOR g_MigUtilWaitCursor = NULL;
  288. VOID
  289. TurnOnWaitCursor (
  290. VOID
  291. )
  292. /*++
  293. Routine Description:
  294. TurnOnWaitCursor sets the cursor to IDC_WAIT. It maintains a use
  295. counter, so code requring the wait cursor can be nested.
  296. Arguments:
  297. none
  298. Return Value:
  299. none
  300. --*/
  301. {
  302. if (g_MigUtilWaitCounter == 0) {
  303. g_MigUtilWaitCursor = SetCursor (LoadCursor (NULL, IDC_WAIT));
  304. }
  305. g_MigUtilWaitCounter++;
  306. }
  307. VOID
  308. TurnOffWaitCursor (
  309. VOID
  310. )
  311. /*++
  312. Routine Description:
  313. TurnOffWaitCursor decrements the wait cursor counter, and if it
  314. reaches zero the cursor is restored.
  315. Arguments:
  316. none
  317. Return Value:
  318. none
  319. --*/
  320. {
  321. if (!g_MigUtilWaitCounter) {
  322. DEBUGMSG ((DBG_WHOOPS, "TurnOffWaitCursor called too many times"));
  323. } else {
  324. g_MigUtilWaitCounter--;
  325. if (!g_MigUtilWaitCounter) {
  326. SetCursor (g_MigUtilWaitCursor);
  327. }
  328. }
  329. }
  330. /*++
  331. Routine Description:
  332. Win9x does not support TryEnterOurCriticalSection, so we must implement
  333. our own version because it is quite a useful function.
  334. Arguments:
  335. pcs - A pointer to an OUR_CRITICAL_SECTION object
  336. Return Value:
  337. TRUE if the function succeeded, or FALSE if it failed. See Win32
  338. SDK docs on critical sections, as these routines are identical to
  339. the caller.
  340. --*/
  341. BOOL
  342. InitializeOurCriticalSection (
  343. OUR_CRITICAL_SECTION *pcs
  344. )
  345. {
  346. // Create initially signaled, auto-reset event
  347. pcs->EventHandle = CreateEvent (NULL, FALSE, TRUE, NULL);
  348. if (!pcs->EventHandle) {
  349. return FALSE;
  350. }
  351. return TRUE;
  352. }
  353. VOID
  354. DeleteOurCriticalSection (
  355. OUR_CRITICAL_SECTION *pcs
  356. )
  357. {
  358. if (pcs->EventHandle) {
  359. CloseHandle (pcs->EventHandle);
  360. pcs->EventHandle = NULL;
  361. }
  362. }
  363. BOOL
  364. EnterOurCriticalSection (
  365. OUR_CRITICAL_SECTION *pcs
  366. )
  367. {
  368. DWORD rc;
  369. // Wait for event to become signaled, then turn it off
  370. rc = WaitForSingleObject (pcs->EventHandle, INFINITE);
  371. if (rc == WAIT_OBJECT_0) {
  372. return TRUE;
  373. }
  374. return FALSE;
  375. }
  376. VOID
  377. LeaveOurCriticalSection (
  378. OUR_CRITICAL_SECTION *pcs
  379. )
  380. {
  381. SetEvent (pcs->EventHandle);
  382. }
  383. BOOL
  384. TryEnterOurCriticalSection (
  385. OUR_CRITICAL_SECTION *pcs
  386. )
  387. {
  388. DWORD rc;
  389. rc = WaitForSingleObject (pcs->EventHandle, 0);
  390. if (rc == WAIT_OBJECT_0) {
  391. return TRUE;
  392. }
  393. return FALSE;
  394. }
  395. #define REUSE_SIZE_PTR(ptr) ((PSIZE_T) ((PBYTE) ptr - sizeof (SIZE_T)))
  396. #define REUSE_TAG_PTR(ptr) ((PSIZE_T) ((PBYTE) ptr + (*REUSE_SIZE_PTR(ptr))))
  397. PVOID
  398. ReuseAlloc (
  399. HANDLE Heap,
  400. PVOID OldPtr,
  401. SIZE_T SizeNeeded
  402. )
  403. {
  404. SIZE_T CurrentSize;
  405. PVOID Ptr = NULL;
  406. UINT AllocAdjustment = sizeof(SIZE_T);
  407. //
  408. // HeapSize is bad, so while it may look good, don't
  409. // use it.
  410. //
  411. #ifdef DEBUG
  412. AllocAdjustment += sizeof (SIZE_T);
  413. #endif
  414. if (!OldPtr) {
  415. Ptr = MemAlloc (Heap, 0, SizeNeeded + AllocAdjustment);
  416. } else {
  417. CurrentSize = *REUSE_SIZE_PTR(OldPtr);
  418. #ifdef DEBUG
  419. if (*REUSE_TAG_PTR(OldPtr) != 0x10a28a70) {
  420. DEBUGMSG ((DBG_WHOOPS, "MemReuse detected corruption!"));
  421. Ptr = MemAlloc (Heap, 0, SizeNeeded + AllocAdjustment);
  422. } else
  423. #endif
  424. if (SizeNeeded > CurrentSize) {
  425. SizeNeeded += 1024 - (SizeNeeded & 1023);
  426. Ptr = MemReAlloc (Heap, 0, REUSE_SIZE_PTR(OldPtr), SizeNeeded + AllocAdjustment);
  427. OldPtr = NULL;
  428. }
  429. }
  430. if (Ptr) {
  431. *((PSIZE_T) Ptr) = SizeNeeded;
  432. Ptr = (PVOID) ((PBYTE) Ptr + sizeof (SIZE_T));
  433. #ifdef DEBUG
  434. *REUSE_TAG_PTR(Ptr) = 0x10a28a70;
  435. #endif
  436. }
  437. return Ptr ? Ptr : OldPtr;
  438. }
  439. VOID
  440. ReuseFree (
  441. HANDLE Heap,
  442. PVOID Ptr
  443. )
  444. {
  445. if (Ptr) {
  446. MemFree (Heap, 0, REUSE_SIZE_PTR(Ptr));
  447. }
  448. }
  449. VOID
  450. SetOutOfMemoryParent (
  451. HWND hwnd
  452. )
  453. {
  454. g_OutOfMemoryParentWnd = hwnd;
  455. }
  456. VOID
  457. OutOfMemory_Terminate (
  458. VOID
  459. )
  460. {
  461. MessageBoxA (
  462. g_OutOfMemoryParentWnd,
  463. g_OutOfMemoryString,
  464. g_ErrorString,
  465. MB_OK|MB_ICONHAND|MB_SYSTEMMODAL|MB_SETFOREGROUND|MB_TOPMOST
  466. );
  467. ExitProcess (0);
  468. TerminateProcess (GetModuleHandle (NULL), 0);
  469. }
  470. VOID
  471. pValidateBlock (
  472. PVOID Block,
  473. SIZE_T Size
  474. )
  475. /*++
  476. Routine Description:
  477. pValidateBlock makes sure Block is non-NULL. If it is NULL, then the user
  478. is given a popup, unless the request size is bogus.
  479. There are two cases for the popup.
  480. - If g_OutOfMemoryParentWnd was set with SetOutOfMemoryParent,
  481. then the user is asked to close other programs, and is given a retry
  482. option.
  483. - If there is no out of memory parent, then the user is told they
  484. need to get more memory.
  485. In either case, Setup is terminated. In GUI mode, Setup will be
  486. stuck and the machine will be unbootable.
  487. Arguments:
  488. Block - Specifies the block to validate.
  489. Size - Specifies the request size
  490. Return Value:
  491. none
  492. --*/
  493. {
  494. LONG rc;
  495. if (!Block && Size < 0x2000000) {
  496. if (g_OutOfMemoryParentWnd) {
  497. rc = MessageBoxA (
  498. g_OutOfMemoryParentWnd,
  499. g_OutOfMemoryRetry,
  500. g_ErrorString,
  501. MB_RETRYCANCEL|MB_ICONHAND|MB_SYSTEMMODAL|MB_SETFOREGROUND|MB_TOPMOST
  502. );
  503. if (rc == IDCANCEL) {
  504. OutOfMemory_Terminate();
  505. }
  506. } else {
  507. OutOfMemory_Terminate();
  508. }
  509. }
  510. }
  511. PVOID
  512. SafeHeapAlloc (
  513. HANDLE Heap,
  514. DWORD Flags,
  515. SIZE_T Size
  516. )
  517. {
  518. PVOID Block;
  519. do {
  520. Block = HeapAlloc (Heap, Flags, Size);
  521. pValidateBlock (Block, Size);
  522. } while (!Block);
  523. return Block;
  524. }
  525. PVOID
  526. SafeHeapReAlloc (
  527. HANDLE Heap,
  528. DWORD Flags,
  529. PVOID OldBlock,
  530. SIZE_T Size
  531. )
  532. {
  533. PVOID Block;
  534. do {
  535. Block = HeapReAlloc (Heap, Flags, OldBlock, Size);
  536. pValidateBlock (Block, Size);
  537. } while (!Block);
  538. return Block;
  539. }
  540. HANDLE
  541. StartThread (
  542. IN PTHREAD_START_ROUTINE Address,
  543. IN PVOID Arg
  544. )
  545. {
  546. DWORD DontCare;
  547. return CreateThread (NULL, 0, Address, Arg, 0, &DontCare);
  548. }
  549. BOOL
  550. BuildSystemDirectoryPathA (
  551. OUT PSTR Buffer,
  552. IN UINT BufferSizeInTchars,
  553. IN PCSTR SubPath OPTIONAL
  554. )
  555. {
  556. INT tcharsLeft;
  557. INT tcharsCopied;
  558. HRESULT hr;
  559. PSTR endOfBuffer;
  560. //
  561. // Compute the number of TCHARs available for c:\windows\system
  562. //
  563. tcharsLeft = BufferSizeInTchars;
  564. if (SubPath) {
  565. while (_mbsnextc (SubPath) == '\\') {
  566. SubPath = _mbsinc (SubPath);
  567. }
  568. tcharsLeft -= 1; // account for wack
  569. tcharsLeft -= TcharCountA (SubPath); // account for subpath
  570. }
  571. if (tcharsLeft < 1) {
  572. return FALSE;
  573. }
  574. //
  575. // Get the system dir, validate the return result
  576. //
  577. tcharsCopied = GetSystemDirectoryA (Buffer, tcharsLeft);
  578. if (tcharsCopied == 0 || tcharsCopied >= tcharsLeft) {
  579. LOGA_IF ((SubPath != NULL, LOG_ERROR, "Can't build path to %s in system directory", SubPath));
  580. LOGA_IF ((!SubPath, LOG_ERROR, "Can't get system directory"));
  581. return FALSE;
  582. }
  583. //
  584. // Append the subpath if it was specified
  585. //
  586. if (SubPath) {
  587. //
  588. // Copy wack plus subpath, buffer space accounted for above.
  589. //
  590. endOfBuffer = Buffer + tcharsCopied;
  591. *endOfBuffer++ = '\\';
  592. tcharsLeft = BufferSizeInTchars - tcharsCopied - 1;
  593. MYASSERT (tcharsLeft > 0);
  594. hr = StringCchCopyA (endOfBuffer, tcharsLeft, SubPath);
  595. if (FAILED(hr)) {
  596. MYASSERT (FALSE);
  597. return FALSE;
  598. }
  599. }
  600. return TRUE;
  601. }
  602. BOOL
  603. BuildSystemDirectoryPathW (
  604. OUT PWSTR Buffer,
  605. IN UINT BufferSizeInTchars,
  606. IN PCWSTR SubPath OPTIONAL
  607. )
  608. {
  609. INT tcharsLeft;
  610. INT tcharsCopied;
  611. HRESULT hr;
  612. PWSTR endOfBuffer;
  613. //
  614. // Compute the number of TCHARs available for c:\windows\system
  615. //
  616. tcharsLeft = BufferSizeInTchars;
  617. if (SubPath) {
  618. while (*SubPath == '\\') {
  619. SubPath++;
  620. }
  621. tcharsLeft -= 1; // account for wack
  622. tcharsLeft -= TcharCountW (SubPath); // account for subpath
  623. }
  624. if (tcharsLeft < 1) {
  625. return FALSE;
  626. }
  627. //
  628. // Get the system dir, validate the return result
  629. //
  630. tcharsCopied = GetSystemDirectoryW (Buffer, tcharsLeft);
  631. if (tcharsCopied == 0 || tcharsCopied >= tcharsLeft) {
  632. LOGW_IF ((SubPath != NULL, LOG_ERROR, "Can't build path to %s in system directory", SubPath));
  633. LOGW_IF ((!SubPath, LOG_ERROR, "Can't get system directory"));
  634. return FALSE;
  635. }
  636. //
  637. // Append the subpath if it was specified
  638. //
  639. if (SubPath) {
  640. //
  641. // Copy wack plus subpath, buffer space accounted for above.
  642. //
  643. endOfBuffer = Buffer + tcharsCopied;
  644. *endOfBuffer++ = L'\\';
  645. tcharsLeft = BufferSizeInTchars - tcharsCopied - 1;
  646. MYASSERT (tcharsLeft > 0);
  647. hr = StringCchCopyW (endOfBuffer, tcharsLeft, SubPath);
  648. if (FAILED(hr)) {
  649. MYASSERT (FALSE);
  650. return FALSE;
  651. }
  652. }
  653. return TRUE;
  654. }
  655. HMODULE
  656. LoadSystemLibraryA (
  657. IN PCSTR DllFileName
  658. )
  659. /*++
  660. Routine Description:
  661. LoadSystemLibraryW loads a DLL located in c:\windows\system (9x) or
  662. c:\windows\system32 (NT). If the DLL is not there, an error is generated.
  663. Arguments:
  664. DllFileName - Specifies the file or file subpath to load. For example, it
  665. can be "kernel32.dll".
  666. Return Value:
  667. The module handle, or NULL if an error occurs. Call GetLastError() for the
  668. error code.
  669. --*/
  670. {
  671. CHAR fullLibPath[MAX_MBCHAR_PATH];
  672. UINT result;
  673. if (!BuildSystemDirectoryPathA (fullLibPath, ARRAYSIZE(fullLibPath), DllFileName)) {
  674. return NULL;
  675. }
  676. return LoadLibraryA (fullLibPath);
  677. }
  678. HMODULE
  679. LoadSystemLibraryW (
  680. IN PCWSTR DllFileName
  681. )
  682. /*++
  683. Routine Description:
  684. LoadSystemLibraryW loads a DLL located in c:\windows\system32. If the DLL is
  685. not there, an error is generated.
  686. This version runs only on Windows NT, or on Win9x with the unicode layer.
  687. Arguments:
  688. DllFileName - Specifies the file or file subpath to load. For example, it
  689. can be "kernel32.dll".
  690. Return Value:
  691. The module handle, or NULL if an error occurs. Call GetLastError() for the
  692. error code.
  693. --*/
  694. {
  695. WCHAR fullLibPath[MAX_WCHAR_PATH];
  696. UINT result;
  697. if (!BuildSystemDirectoryPathW (fullLibPath, ARRAYSIZE(fullLibPath), DllFileName)) {
  698. return NULL;
  699. }
  700. return LoadLibraryW (fullLibPath);
  701. }
  702. /*++
  703. Routine Description:
  704. OurGetModuleFileName is a wrapper for GetModuleFileName, but in addition
  705. it makes sure the output buffer is always nul-terminated.
  706. Arguments:
  707. Same as GetModuleFileName
  708. Return Value:
  709. Same as GetModuleFileName, but the output buffer is always nul-terminated
  710. --*/
  711. DWORD
  712. OurGetModuleFileNameA (
  713. IN HMODULE Module,
  714. OUT PSTR Buffer,
  715. IN INT BufferChars
  716. )
  717. {
  718. //
  719. // call the real API
  720. //
  721. #undef GetModuleFileNameA
  722. INT d = GetModuleFileNameA (Module, Buffer, BufferChars);
  723. if (BufferChars > 0) {
  724. Buffer[BufferChars - 1] = 0;
  725. } else {
  726. MYASSERT (FALSE);
  727. }
  728. return d < BufferChars ? d : 0;
  729. }
  730. DWORD
  731. OurGetModuleFileNameW (
  732. IN HMODULE Module,
  733. OUT PWSTR Buffer,
  734. IN INT BufferChars
  735. )
  736. {
  737. //
  738. // call the real API
  739. //
  740. #undef GetModuleFileNameW
  741. INT d = GetModuleFileNameW (Module, Buffer, BufferChars);
  742. if (BufferChars > 0) {
  743. Buffer[BufferChars - 1] = 0;
  744. } else {
  745. MYASSERT (FALSE);
  746. }
  747. return d < BufferChars ? d : 0;
  748. }