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.

547 lines
10 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. marcw 2-Sep-1999 Moved over from Win9xUpg project.
  11. jimschm 23-Sep-1998 Start thread
  12. marcw 23-Sep-1998 Locale fix
  13. jimschm 03-Nov-1997 Added TextAlloc routines
  14. marcw 22-Jul-1997 Added IS<platform> functions.
  15. --*/
  16. #include "pch.h"
  17. #include "utilsp.h"
  18. #include "locale.h"
  19. //#define DEBUG_ALL_FILES
  20. HINSTANCE g_hInst;
  21. HANDLE g_hHeap;
  22. OSVERSIONINFOA g_OsInfo;
  23. #define TEXT_GROWTH_SIZE 65536
  24. //
  25. // OS-dependent flags for MultiByteToWideChar
  26. //
  27. DWORD g_MigutilWCToMBFlags = 0;
  28. //
  29. // g_ShortTermAllocTable is the default table used for resource string
  30. // management. New strings are allocated from the table.
  31. //
  32. // Allocation tables are very simple ways to store strings loaded in from
  33. // the exe image. The loaded string is copied into the table and kept
  34. // around until it is explicitly freed. Multiple attempts at getting the
  35. // same resource string return the same string, inc'ing a use counter.
  36. //
  37. // g_OutOfMemoryTable is the table used to hold out-of-memory text. It
  38. // is loaded up at init time and is kept in memory for the whole time
  39. // migutil is in use, so out-of-memory messages can always be displayed.
  40. //
  41. PGROWBUFFER g_ShortTermAllocTable;
  42. PGROWBUFFER g_OutOfMemoryTable;
  43. //
  44. // We make sure the message APIs (GetStringResource, ParseMessageID, etc)
  45. // are thread-safe
  46. //
  47. OUR_CRITICAL_SECTION g_MessageCs;
  48. //
  49. // The PoolMem routines must also be thread-safe
  50. //
  51. CRITICAL_SECTION g_PmCs;
  52. //
  53. // MemAlloc critical section
  54. //
  55. CRITICAL_SECTION g_MemAllocCs;
  56. //
  57. // The following pools are used for text management. g_RegistryApiPool is
  58. // for reg.c, g_PathsPool is for the JoinPaths/DuplicatePath/etc routines,
  59. // and g_TextPool is for AllocText, DupText, etc.
  60. //
  61. PMHANDLE g_RegistryApiPool;
  62. PMHANDLE g_PathsPool;
  63. PMHANDLE g_TextPool;
  64. static BOOL g_UtilsInitialized;
  65. VOID
  66. UtInitialize (
  67. IN HANDLE Heap OPTIONAL
  68. )
  69. {
  70. if (g_UtilsInitialized) {
  71. DEBUGMSG ((DBG_ERROR, "Utilities already initialized"));
  72. return;
  73. }
  74. g_UtilsInitialized = TRUE;
  75. //
  76. // Set globals
  77. //
  78. if (Heap) {
  79. g_hHeap = Heap;
  80. } else {
  81. g_hHeap = GetProcessHeap();
  82. }
  83. if (!g_hInst) {
  84. g_hInst = GetModuleHandle (NULL);
  85. }
  86. //
  87. // Load in OSVERSION info.
  88. //
  89. g_OsInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
  90. GetVersionExA (&g_OsInfo);
  91. //
  92. // Create critical sections
  93. //
  94. __try {
  95. InitializeCriticalSection (&g_MemAllocCs);
  96. InitializeCriticalSection (&g_PmCs);
  97. InitializeOurCriticalSection (&g_MessageCs);
  98. } __except (EXCEPTION_CONTINUE_EXECUTION) {
  99. // Might raise an out of memory exception, but we don't check for that in this function.
  100. // Ignored
  101. }
  102. //
  103. // Create text pool, needed for the log
  104. //
  105. g_TextPool = PmCreateNamedPool ("Text");
  106. PmSetMinimumGrowthSize (g_TextPool, TEXT_GROWTH_SIZE);
  107. //
  108. // Create the rest of the pools
  109. //
  110. g_RegistryApiPool = PmCreateNamedPool ("Registry API");
  111. g_PathsPool = PmCreateNamedPool ("Paths");
  112. //
  113. // Now that MemAlloc will work, initialize allocation tracking
  114. //
  115. InitAllocationTracking();
  116. //
  117. // Create the short-term alloc table for string resource utils
  118. //
  119. g_ShortTermAllocTable = CreateAllocTable();
  120. //
  121. // MultiByteToWideChar has desirable flags that only function on NT
  122. //
  123. if (g_OsInfo.dwPlatformId == VER_PLATFORM_WIN32_NT && g_OsInfo.dwMajorVersion > 4) {
  124. // This flag is only valid for Win2k and above, it will cause conversion to fail on NT4
  125. g_MigutilWCToMBFlags = WC_NO_BEST_FIT_CHARS;
  126. } else {
  127. g_MigutilWCToMBFlags = 0;
  128. }
  129. //
  130. // The "out of memory" message
  131. //
  132. g_OutOfMemoryTable = CreateAllocTable();
  133. g_OutOfMemoryRetry = GetStringResourceExA (
  134. g_OutOfMemoryTable,
  135. 10001 /* MSG_OUT_OF_MEMORY_RETRY */
  136. );
  137. g_OutOfMemoryString = GetStringResourceExA (
  138. g_OutOfMemoryTable,
  139. 10002 /* MSG_OUT_OF_MEMORY */
  140. );
  141. if (!g_OutOfMemoryString || !g_OutOfMemoryRetry) {
  142. //
  143. //DEBUGMSG ((
  144. // DBG_WARNING,
  145. // "Cannot load out of memory messages; resources 10001 and 10002 do not exist"
  146. // ));
  147. }
  148. ObsInitialize ();
  149. ElInitialize ();
  150. //
  151. // set the locale to the system locale. Not doing this can cause isspace
  152. // to AV in certain MBSCHR circumstances.
  153. //
  154. setlocale(LC_ALL,"");
  155. InitLeadByteTable();
  156. }
  157. VOID
  158. UtTerminate (
  159. VOID
  160. )
  161. {
  162. if (!g_UtilsInitialized) {
  163. DEBUGMSG ((DBG_ERROR, "UtTerminate already called"));
  164. return;
  165. }
  166. g_UtilsInitialized = FALSE;
  167. //
  168. // Free utility pools
  169. //
  170. ElTerminate ();
  171. ObsTerminate ();
  172. if (g_RegistryApiPool) {
  173. PmDestroyPool (g_RegistryApiPool);
  174. }
  175. if (g_PathsPool) {
  176. PmDestroyPool (g_PathsPool);
  177. }
  178. if (g_ShortTermAllocTable) {
  179. DestroyAllocTable (g_ShortTermAllocTable);
  180. }
  181. if (g_OutOfMemoryTable) {
  182. DestroyAllocTable (g_OutOfMemoryTable);
  183. }
  184. if (g_TextPool) {
  185. PmDestroyPool (g_TextPool);
  186. }
  187. //
  188. // Clean up handles used by critical sections
  189. //
  190. FreeAllocationTracking();
  191. DumpHeapLeaks ();
  192. PmDumpStatistics ();
  193. GbDumpStatistics ();
  194. DumpHeapStats();
  195. DeleteCriticalSection (&g_MemAllocCs);
  196. DeleteCriticalSection (&g_PmCs);
  197. DeleteOurCriticalSection (&g_MessageCs);
  198. }
  199. #define WIDTH(rect) (rect.right - rect.left)
  200. #define HEIGHT(rect) (rect.bottom - rect.top)
  201. void
  202. CenterWindow (
  203. IN HWND hwnd,
  204. IN HWND Parent
  205. )
  206. {
  207. RECT WndRect, ParentRect;
  208. int x, y;
  209. if (!Parent) {
  210. ParentRect.left = 0;
  211. ParentRect.top = 0;
  212. ParentRect.right = GetSystemMetrics (SM_CXFULLSCREEN);
  213. ParentRect.bottom = GetSystemMetrics (SM_CYFULLSCREEN);
  214. } else {
  215. GetWindowRect (Parent, &ParentRect);
  216. }
  217. MYASSERT (IsWindow (hwnd));
  218. GetWindowRect (hwnd, &WndRect);
  219. x = ParentRect.left + (WIDTH(ParentRect) - WIDTH(WndRect)) / 2;
  220. y = ParentRect.top + (HEIGHT(ParentRect) - HEIGHT(WndRect)) / 2;
  221. SetWindowPos (hwnd, NULL, x, y, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
  222. }
  223. static INT g_MigUtilWaitCounter = 0;
  224. static HCURSOR g_MigUtilWaitCursor = NULL;
  225. VOID
  226. TurnOnWaitCursor (
  227. VOID
  228. )
  229. /*++
  230. Routine Description:
  231. TurnOnWaitCursor sets the cursor to IDC_WAIT. It maintains a use
  232. counter, so code requring the wait cursor can be nested.
  233. Arguments:
  234. none
  235. Return Value:
  236. none
  237. --*/
  238. {
  239. if (g_MigUtilWaitCounter == 0) {
  240. g_MigUtilWaitCursor = SetCursor (LoadCursor (NULL, IDC_WAIT));
  241. }
  242. g_MigUtilWaitCounter++;
  243. }
  244. VOID
  245. TurnOffWaitCursor (
  246. VOID
  247. )
  248. /*++
  249. Routine Description:
  250. TurnOffWaitCursor decrements the wait cursor counter, and if it
  251. reaches zero the cursor is restored.
  252. Arguments:
  253. none
  254. Return Value:
  255. none
  256. --*/
  257. {
  258. if (!g_MigUtilWaitCounter) {
  259. DEBUGMSG ((DBG_WHOOPS, "TurnOffWaitCursor called too many times"));
  260. } else {
  261. g_MigUtilWaitCounter--;
  262. if (!g_MigUtilWaitCounter) {
  263. SetCursor (g_MigUtilWaitCursor);
  264. }
  265. }
  266. }
  267. /*++
  268. Routine Description:
  269. Win9x does not support TryEnterOurCriticalSection, so we must implement
  270. our own version because it is quite a useful function.
  271. Arguments:
  272. pcs - A pointer to an OUR_CRITICAL_SECTION object
  273. Return Value:
  274. TRUE if the function succeeded, or FALSE if it failed. See Win32
  275. SDK docs on critical sections, as these routines are identical to
  276. the caller.
  277. --*/
  278. BOOL
  279. InitializeOurCriticalSection (
  280. OUR_CRITICAL_SECTION *pcs
  281. )
  282. {
  283. // Create initially signaled, auto-reset event
  284. pcs->EventHandle = CreateEvent (NULL, FALSE, TRUE, NULL);
  285. if (!pcs->EventHandle) {
  286. return FALSE;
  287. }
  288. return TRUE;
  289. }
  290. VOID
  291. DeleteOurCriticalSection (
  292. OUR_CRITICAL_SECTION *pcs
  293. )
  294. {
  295. if (pcs->EventHandle) {
  296. CloseHandle (pcs->EventHandle);
  297. pcs->EventHandle = NULL;
  298. }
  299. }
  300. BOOL
  301. EnterOurCriticalSection (
  302. OUR_CRITICAL_SECTION *pcs
  303. )
  304. {
  305. DWORD rc;
  306. // Wait for event to become signaled, then turn it off
  307. rc = WaitForSingleObject (pcs->EventHandle, INFINITE);
  308. if (rc == WAIT_OBJECT_0) {
  309. return TRUE;
  310. }
  311. return FALSE;
  312. }
  313. VOID
  314. LeaveOurCriticalSection (
  315. OUR_CRITICAL_SECTION *pcs
  316. )
  317. {
  318. SetEvent (pcs->EventHandle);
  319. }
  320. BOOL
  321. TryEnterOurCriticalSection (
  322. OUR_CRITICAL_SECTION *pcs
  323. )
  324. {
  325. DWORD rc;
  326. rc = WaitForSingleObject (pcs->EventHandle, 0);
  327. if (rc == WAIT_OBJECT_0) {
  328. return TRUE;
  329. }
  330. return FALSE;
  331. }
  332. HANDLE
  333. StartThread (
  334. IN PTHREAD_START_ROUTINE Address,
  335. IN PVOID Arg
  336. )
  337. {
  338. DWORD DontCare;
  339. return CreateThread (NULL, 0, Address, Arg, 0, &DontCare);
  340. }
  341. HANDLE
  342. StartProcessA (
  343. IN PCSTR CmdLine
  344. )
  345. {
  346. STARTUPINFOA si;
  347. PROCESS_INFORMATION pi;
  348. PSTR copyOfCmdLine;
  349. BOOL b;
  350. copyOfCmdLine = DuplicateTextA (CmdLine);
  351. ZeroMemory (&si, sizeof (si));
  352. b = CreateProcessA (
  353. NULL,
  354. copyOfCmdLine,
  355. NULL,
  356. NULL,
  357. FALSE,
  358. CREATE_NEW_PROCESS_GROUP,
  359. NULL,
  360. NULL,
  361. &si,
  362. &pi
  363. );
  364. FreeTextA (copyOfCmdLine);
  365. if (!b) {
  366. return NULL;
  367. }
  368. CloseHandle (pi.hThread);
  369. return pi.hProcess;
  370. }
  371. HANDLE
  372. StartProcessW (
  373. IN PCWSTR CmdLine
  374. )
  375. {
  376. STARTUPINFOW si;
  377. PROCESS_INFORMATION pi;
  378. PWSTR copyOfCmdLine;
  379. BOOL b;
  380. copyOfCmdLine = DuplicateTextW (CmdLine);
  381. ZeroMemory (&si, sizeof (si));
  382. b = CreateProcessW (
  383. NULL,
  384. copyOfCmdLine,
  385. NULL,
  386. NULL,
  387. FALSE,
  388. CREATE_NEW_PROCESS_GROUP,
  389. NULL,
  390. NULL,
  391. &si,
  392. &pi
  393. );
  394. FreeTextW (copyOfCmdLine);
  395. if (!b) {
  396. return NULL;
  397. }
  398. CloseHandle (pi.hThread);
  399. return pi.hProcess;
  400. }