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.

717 lines
15 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. //#define DEBUG_ALL_FILES
  19. OSVERSIONINFOA g_OsInfo;
  20. extern OUR_CRITICAL_SECTION g_DebugMsgCs;
  21. #define TEXT_GROWTH_SIZE 65536
  22. //
  23. // Out of memory string -- loaded at initialization
  24. //
  25. PCSTR g_OutOfMemoryString = NULL;
  26. PCSTR g_OutOfMemoryRetry = NULL;
  27. PCSTR g_ErrorString = NULL;
  28. HWND g_OutOfMemoryParentWnd;
  29. //
  30. // OS-dependent flags for MultiByteToWideChar
  31. //
  32. DWORD g_MigutilWCToMBFlags = 0;
  33. //
  34. // A dynamic string. Among other things, this list can hold lists of imports
  35. // as they are read out Win32 executables.
  36. //
  37. //DYNSTRING dynImp;
  38. //
  39. // g_ShortTermAllocTable is the default table used for resource string
  40. // management. New strings are allocated from the table.
  41. //
  42. // Allocation tables are very simple ways to store strings loaded in from
  43. // the exe image. The loaded string is copied into the table and kept
  44. // around until it is explicitly freed. Multiple attempts at getting the
  45. // same resource string return the same string, inc'ing a use counter.
  46. //
  47. // g_LastAllocTable is a temporary holder for the wrapper APIs that
  48. // do not require the caller to supply the alloc table. DO NOT ALTER!
  49. //
  50. // g_OutOfMemoryTable is the table used to hold out-of-memory text. It
  51. // is loaded up at init time and is kept in memory for the whole time
  52. // migutil is in use, so out-of-memory messages can always be displayed.
  53. //
  54. PGROWBUFFER g_ShortTermAllocTable;
  55. PGROWBUFFER g_LastAllocTable;
  56. PGROWBUFFER g_OutOfMemoryTable;
  57. //
  58. // We make sure the message APIs (GetStringResource, ParseMessageID, etc)
  59. // are thread-safe
  60. //
  61. OUR_CRITICAL_SECTION g_MessageCs;
  62. BOOL fInitedMessageCs = FALSE;
  63. //
  64. // The PoolMem routines must also be thread-safe
  65. //
  66. CRITICAL_SECTION g_PoolMemCs;
  67. BOOL fInitedPoolMemCs = FALSE;
  68. //
  69. // MemAlloc critical section
  70. //
  71. CRITICAL_SECTION g_MemAllocCs;
  72. BOOL fInitedMemAllocCs = FALSE;
  73. //
  74. // The following pools are used for text management. g_RegistryApiPool is
  75. // for reg.c, g_PathsPool is for the JoinPaths/DuplicatePath/etc routines,
  76. // and g_TextPool is for AllocText, DupText, etc.
  77. //
  78. POOLHANDLE g_RegistryApiPool;
  79. POOLHANDLE g_PathsPool;
  80. POOLHANDLE g_TextPool;
  81. //
  82. // PC98 settings
  83. //
  84. BOOL g_IsPc98;
  85. static CHAR g_BootDrivePathBufA[8];
  86. static WCHAR g_BootDrivePathBufW[4];
  87. PCSTR g_BootDrivePathA;
  88. PCWSTR g_BootDrivePathW;
  89. static CHAR g_BootDriveBufA[6];
  90. static WCHAR g_BootDriveBufW[3];
  91. PCSTR g_BootDriveA;
  92. PCWSTR g_BootDriveW;
  93. CHAR g_BootDriveLetterA;
  94. WCHAR g_BootDriveLetterW;
  95. //
  96. // Implementation
  97. //
  98. BOOL
  99. WINAPI
  100. MigUtil_Entry (
  101. HINSTANCE hInstance,
  102. DWORD dwReason,
  103. LPVOID lpReserved
  104. )
  105. {
  106. switch (dwReason) {
  107. case DLL_PROCESS_ATTACH:
  108. //
  109. // NOTE: If FALSE is returned, none of the executables will run.
  110. // Every project executable links to this library.
  111. //
  112. if(!pSetupInitializeUtils()) {
  113. DEBUGMSG ((DBG_ERROR, "Cannot initialize SpUtils"));
  114. return FALSE;
  115. }
  116. //
  117. // Load in OSVERSION info.
  118. //
  119. g_OsInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
  120. // this function only fails if we specify an invalid value
  121. // for the dwOSVersionInfoSize member (which we don't)
  122. if(!GetVersionExA(&g_OsInfo))
  123. MYASSERT(FALSE);
  124. //g_IsPc98 = (GetKeyboardType (0) == 7) && ((GetKeyboardType (1) & 0xff00) == 0x0d00);
  125. g_IsPc98 = FALSE;
  126. g_BootDrivePathA = g_BootDrivePathBufA;
  127. g_BootDrivePathW = g_BootDrivePathBufW;
  128. g_BootDriveA = g_BootDriveBufA;
  129. g_BootDriveW = g_BootDriveBufW;
  130. if (g_IsPc98) {
  131. StringCopyA ((PSTR) g_BootDrivePathA, "A:\\");
  132. StringCopyW ((PWSTR) g_BootDrivePathW, L"A:\\");
  133. StringCopyA ((PSTR) g_BootDriveA, "A:");
  134. StringCopyW ((PWSTR) g_BootDriveW, L"A:");
  135. g_BootDriveLetterA = 'A';
  136. g_BootDriveLetterW = L'A';
  137. } else {
  138. StringCopyA ((PSTR) g_BootDrivePathA, "C:\\");
  139. StringCopyW ((PWSTR) g_BootDrivePathW, L"C:\\");
  140. StringCopyA ((PSTR) g_BootDriveA, "C:");
  141. StringCopyW ((PWSTR) g_BootDriveW, L"C:");
  142. g_BootDriveLetterA = 'C';
  143. g_BootDriveLetterW = L'C';
  144. }
  145. // initialize log
  146. if (!LogInit (NULL)) {
  147. return FALSE;
  148. }
  149. // MemAlloc critical section
  150. InitializeCriticalSection (&g_MemAllocCs);
  151. fInitedMemAllocCs = TRUE;
  152. // Now that MemAlloc will work, initialize allocation tracking
  153. InitAllocationTracking();
  154. // PoolMem critical section
  155. InitializeCriticalSection (&g_PoolMemCs);
  156. fInitedPoolMemCs = TRUE;
  157. // The short-term alloc table for string resource utils
  158. g_ShortTermAllocTable = CreateAllocTable();
  159. if (!g_ShortTermAllocTable) {
  160. DEBUGMSG ((DBG_ERROR, "Cannot create short-term AllocTable"));
  161. return FALSE;
  162. }
  163. //
  164. // MultiByteToWideChar has desirable flags that only function on NT
  165. //
  166. g_MigutilWCToMBFlags = (ISNT()) ? WC_NO_BEST_FIT_CHARS : 0;
  167. // The critical section that guards ParseMessage/GetStringResource
  168. if (!InitializeOurCriticalSection (&g_MessageCs)) {
  169. DEBUGMSG ((DBG_ERROR, "Cannot initialize critical section"));
  170. DestroyAllocTable (g_ShortTermAllocTable);
  171. g_ShortTermAllocTable = NULL;
  172. }
  173. else
  174. {
  175. fInitedMessageCs = TRUE;
  176. }
  177. // A pool for APIs in reg.c
  178. g_RegistryApiPool = PoolMemInitNamedPool ("Registry API");
  179. g_PathsPool = PoolMemInitNamedPool ("Paths");
  180. g_TextPool = PoolMemInitNamedPool ("Text");
  181. if (!g_RegistryApiPool || !g_PathsPool || !g_TextPool) {
  182. return FALSE;
  183. }
  184. PoolMemSetMinimumGrowthSize (g_TextPool, TEXT_GROWTH_SIZE);
  185. // The "out of memory" message
  186. g_OutOfMemoryTable = CreateAllocTable();
  187. if (!g_OutOfMemoryTable) {
  188. DEBUGMSG ((DBG_ERROR, "Cannot create out of memory AllocTable"));
  189. return FALSE;
  190. }
  191. g_OutOfMemoryRetry = GetStringResourceExA (g_OutOfMemoryTable, 10001 /* MSG_OUT_OF_MEMORY_RETRY */);
  192. g_OutOfMemoryString = GetStringResourceExA (g_OutOfMemoryTable, 10002 /* MSG_OUT_OF_MEMORY */);
  193. if (!g_OutOfMemoryString || !g_OutOfMemoryRetry) {
  194. DEBUGMSG ((DBG_WARNING, "Cannot load out of memory messages"));
  195. }
  196. g_ErrorString = GetStringResourceExA (g_OutOfMemoryTable, 10003 /* MSG_ERROR */);
  197. if (!g_ErrorString || g_ErrorString[0] == 0) {
  198. g_ErrorString = "Error";
  199. }
  200. //
  201. // set the locale to the system locale. Not doing this can cause isspace to Av in certain MBSCHR circumstances.
  202. //
  203. setlocale(LC_ALL,"");
  204. InfGlobalInit (FALSE);
  205. RegInitialize();
  206. break;
  207. case DLL_PROCESS_DETACH:
  208. #ifdef DEBUG
  209. DumpOpenKeys();
  210. RegTerminate();
  211. #endif
  212. InfGlobalInit (TRUE);
  213. if (g_RegistryApiPool) {
  214. PoolMemDestroyPool (g_RegistryApiPool);
  215. }
  216. if (g_PathsPool) {
  217. PoolMemDestroyPool (g_PathsPool);
  218. }
  219. if (g_TextPool) {
  220. PoolMemDestroyPool (g_TextPool);
  221. }
  222. if (g_ShortTermAllocTable) {
  223. DestroyAllocTable (g_ShortTermAllocTable);
  224. }
  225. if (g_OutOfMemoryTable) {
  226. DestroyAllocTable (g_OutOfMemoryTable);
  227. }
  228. FreeAllocationTracking();
  229. //
  230. // VERY LAST CODE TO RUN
  231. //
  232. DumpHeapStats();
  233. LogExit();
  234. pSetupUninitializeUtils();
  235. if (fInitedMessageCs) {
  236. DeleteOurCriticalSection (&g_MessageCs);
  237. }
  238. if (fInitedPoolMemCs) {
  239. DeleteCriticalSection (&g_PoolMemCs);
  240. }
  241. if (fInitedMemAllocCs) {
  242. DeleteCriticalSection (&g_MemAllocCs);
  243. }
  244. break;
  245. }
  246. return TRUE;
  247. }
  248. #define WIDTH(rect) (rect.right - rect.left)
  249. #define HEIGHT(rect) (rect.bottom - rect.top)
  250. void
  251. CenterWindow (
  252. IN HWND hwnd,
  253. IN HWND Parent
  254. )
  255. {
  256. RECT WndRect, ParentRect;
  257. int x, y;
  258. if (!Parent) {
  259. ParentRect.left = 0;
  260. ParentRect.top = 0;
  261. ParentRect.right = GetSystemMetrics (SM_CXFULLSCREEN);
  262. ParentRect.bottom = GetSystemMetrics (SM_CYFULLSCREEN);
  263. } else {
  264. GetWindowRect (Parent, &ParentRect);
  265. }
  266. MYASSERT (IsWindow (hwnd));
  267. GetWindowRect (hwnd, &WndRect);
  268. x = ParentRect.left + (WIDTH(ParentRect) - WIDTH(WndRect)) / 2;
  269. y = ParentRect.top + (HEIGHT(ParentRect) - HEIGHT(WndRect)) / 2;
  270. SetWindowPos (hwnd, NULL, x, y, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
  271. }
  272. static INT g_MigUtilWaitCounter = 0;
  273. static HCURSOR g_MigUtilWaitCursor = NULL;
  274. VOID
  275. TurnOnWaitCursor (
  276. VOID
  277. )
  278. /*++
  279. Routine Description:
  280. TurnOnWaitCursor sets the cursor to IDC_WAIT. It maintains a use
  281. counter, so code requring the wait cursor can be nested.
  282. Arguments:
  283. none
  284. Return Value:
  285. none
  286. --*/
  287. {
  288. if (g_MigUtilWaitCounter == 0) {
  289. g_MigUtilWaitCursor = SetCursor (LoadCursor (NULL, IDC_WAIT));
  290. }
  291. g_MigUtilWaitCounter++;
  292. }
  293. VOID
  294. TurnOffWaitCursor (
  295. VOID
  296. )
  297. /*++
  298. Routine Description:
  299. TurnOffWaitCursor decrements the wait cursor counter, and if it
  300. reaches zero the cursor is restored.
  301. Arguments:
  302. none
  303. Return Value:
  304. none
  305. --*/
  306. {
  307. if (!g_MigUtilWaitCounter) {
  308. DEBUGMSG ((DBG_WHOOPS, "TurnOffWaitCursor called too many times"));
  309. } else {
  310. g_MigUtilWaitCounter--;
  311. if (!g_MigUtilWaitCounter) {
  312. SetCursor (g_MigUtilWaitCursor);
  313. }
  314. }
  315. }
  316. /*++
  317. Routine Description:
  318. Win9x does not support TryEnterOurCriticalSection, so we must implement
  319. our own version because it is quite a useful function.
  320. Arguments:
  321. pcs - A pointer to an OUR_CRITICAL_SECTION object
  322. Return Value:
  323. TRUE if the function succeeded, or FALSE if it failed. See Win32
  324. SDK docs on critical sections, as these routines are identical to
  325. the caller.
  326. --*/
  327. BOOL
  328. InitializeOurCriticalSection (
  329. OUR_CRITICAL_SECTION *pcs
  330. )
  331. {
  332. // Create initially signaled, auto-reset event
  333. pcs->EventHandle = CreateEvent (NULL, FALSE, TRUE, NULL);
  334. if (!pcs->EventHandle) {
  335. return FALSE;
  336. }
  337. return TRUE;
  338. }
  339. VOID
  340. DeleteOurCriticalSection (
  341. OUR_CRITICAL_SECTION *pcs
  342. )
  343. {
  344. if (pcs->EventHandle) {
  345. CloseHandle (pcs->EventHandle);
  346. pcs->EventHandle = NULL;
  347. }
  348. }
  349. BOOL
  350. EnterOurCriticalSection (
  351. OUR_CRITICAL_SECTION *pcs
  352. )
  353. {
  354. DWORD rc;
  355. // Wait for event to become signaled, then turn it off
  356. rc = WaitForSingleObject (pcs->EventHandle, INFINITE);
  357. if (rc == WAIT_OBJECT_0) {
  358. return TRUE;
  359. }
  360. return FALSE;
  361. }
  362. VOID
  363. LeaveOurCriticalSection (
  364. OUR_CRITICAL_SECTION *pcs
  365. )
  366. {
  367. SetEvent (pcs->EventHandle);
  368. }
  369. BOOL
  370. TryEnterOurCriticalSection (
  371. OUR_CRITICAL_SECTION *pcs
  372. )
  373. {
  374. DWORD rc;
  375. rc = WaitForSingleObject (pcs->EventHandle, 0);
  376. if (rc == WAIT_OBJECT_0) {
  377. return TRUE;
  378. }
  379. return FALSE;
  380. }
  381. #define REUSE_SIZE_PTR(ptr) ((PDWORD) ((PBYTE) ptr - sizeof (DWORD)))
  382. #define REUSE_TAG_PTR(ptr) ((PDWORD) ((PBYTE) ptr + (*REUSE_SIZE_PTR(ptr))))
  383. PVOID
  384. ReuseAlloc (
  385. HANDLE Heap,
  386. PVOID OldPtr,
  387. DWORD SizeNeeded
  388. )
  389. {
  390. DWORD CurrentSize;
  391. PVOID Ptr = NULL;
  392. UINT AllocAdjustment = sizeof(DWORD);
  393. //
  394. // HeapSize is bad, so while it may look good, don't
  395. // use it.
  396. //
  397. #ifdef DEBUG
  398. AllocAdjustment += sizeof (DWORD);
  399. #endif
  400. if (!OldPtr) {
  401. Ptr = MemAlloc (Heap, 0, SizeNeeded + AllocAdjustment);
  402. } else {
  403. CurrentSize = *REUSE_SIZE_PTR(OldPtr);
  404. #ifdef DEBUG
  405. if (*REUSE_TAG_PTR(OldPtr) != 0x10a28a70) {
  406. DEBUGMSG ((DBG_WHOOPS, "MemReuse detected corruption!"));
  407. Ptr = MemAlloc (Heap, 0, SizeNeeded + AllocAdjustment);
  408. } else
  409. #endif
  410. if (SizeNeeded > CurrentSize) {
  411. SizeNeeded += 1024 - (SizeNeeded & 1023);
  412. Ptr = MemReAlloc (Heap, 0, REUSE_SIZE_PTR(OldPtr), SizeNeeded + AllocAdjustment);
  413. OldPtr = NULL;
  414. }
  415. }
  416. if (Ptr) {
  417. *((PDWORD) Ptr) = SizeNeeded;
  418. Ptr = (PVOID) ((PBYTE) Ptr + sizeof (DWORD));
  419. #ifdef DEBUG
  420. *REUSE_TAG_PTR(Ptr) = 0x10a28a70;
  421. #endif
  422. }
  423. return Ptr ? Ptr : OldPtr;
  424. }
  425. VOID
  426. ReuseFree (
  427. HANDLE Heap,
  428. PVOID Ptr
  429. )
  430. {
  431. if (Ptr) {
  432. MemFree (Heap, 0, REUSE_SIZE_PTR(Ptr));
  433. }
  434. }
  435. VOID
  436. SetOutOfMemoryParent (
  437. HWND hwnd
  438. )
  439. {
  440. g_OutOfMemoryParentWnd = hwnd;
  441. }
  442. VOID
  443. OutOfMemory_Terminate (
  444. VOID
  445. )
  446. {
  447. MessageBoxA (
  448. g_OutOfMemoryParentWnd,
  449. g_OutOfMemoryString,
  450. g_ErrorString,
  451. MB_OK|MB_ICONHAND|MB_SYSTEMMODAL|MB_SETFOREGROUND|MB_TOPMOST
  452. );
  453. ExitProcess (0);
  454. TerminateProcess (GetModuleHandle (NULL), 0);
  455. }
  456. VOID
  457. pValidateBlock (
  458. PVOID Block,
  459. DWORD Size
  460. )
  461. /*++
  462. Routine Description:
  463. pValidateBlock makes sure Block is non-NULL. If it is NULL, then the user
  464. is given a popup, unless the request size is bogus.
  465. There are two cases for the popup.
  466. - If g_OutOfMemoryParentWnd was set with SetOutOfMemoryParent,
  467. then the user is asked to close other programs, and is given a retry
  468. option.
  469. - If there is no out of memory parent, then the user is told they
  470. need to get more memory.
  471. In either case, Setup is terminated. In GUI mode, Setup will be
  472. stuck and the machine will be unbootable.
  473. Arguments:
  474. Block - Specifies the block to validate.
  475. Size - Specifies the request size
  476. Return Value:
  477. none
  478. --*/
  479. {
  480. LONG rc;
  481. if (!Block && Size < 0x2000000) {
  482. if (g_OutOfMemoryParentWnd) {
  483. rc = MessageBoxA (
  484. g_OutOfMemoryParentWnd,
  485. g_OutOfMemoryRetry,
  486. g_ErrorString,
  487. MB_RETRYCANCEL|MB_ICONHAND|MB_SYSTEMMODAL|MB_SETFOREGROUND|MB_TOPMOST
  488. );
  489. if (rc == IDCANCEL) {
  490. OutOfMemory_Terminate();
  491. }
  492. } else {
  493. OutOfMemory_Terminate();
  494. }
  495. }
  496. }
  497. PVOID
  498. SafeHeapAlloc (
  499. HANDLE Heap,
  500. DWORD Flags,
  501. DWORD Size
  502. )
  503. {
  504. PVOID Block;
  505. do {
  506. Block = HeapAlloc (Heap, Flags, Size);
  507. pValidateBlock (Block, Size);
  508. } while (!Block);
  509. return Block;
  510. }
  511. PVOID
  512. SafeHeapReAlloc (
  513. HANDLE Heap,
  514. DWORD Flags,
  515. PVOID OldBlock,
  516. DWORD Size
  517. )
  518. {
  519. PVOID Block;
  520. do {
  521. Block = HeapReAlloc (Heap, Flags, OldBlock, Size);
  522. pValidateBlock (Block, Size);
  523. } while (!Block);
  524. return Block;
  525. }
  526. HANDLE
  527. StartThread (
  528. IN PTHREAD_START_ROUTINE Address,
  529. IN PVOID Arg
  530. )
  531. {
  532. DWORD DontCare;
  533. return CreateThread (NULL, 0, Address, Arg, 0, &DontCare);
  534. }