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.

2030 lines
55 KiB

  1. /*
  2. * pminit.c - program manager
  3. *
  4. * Copyright (c) 1991, Microsoft Corporation
  5. *
  6. * DESCRIPTION
  7. *
  8. * This file is for support of program manager under NT Windows.
  9. * This file is/was ported from pminit.c (program manager).
  10. *
  11. * MODIFICATION HISTORY
  12. * Initial Version: x/x/90 Author Unknown, since he didn't feel
  13. * like commenting the code...
  14. *
  15. * NT 32b Version: 1/25/91 Jeff Pack
  16. * Intitial port to begin.
  17. *
  18. *
  19. */
  20. #include "progman.h"
  21. #include "util.h"
  22. #include "commdlg.h"
  23. //#ifdef FE_IME
  24. #include "winnls32.h"
  25. //#endif
  26. #include "uniconv.h"
  27. #include "security.h"
  28. #define MAX_USERNAME_LENGTH 256
  29. #define PROGMAN_KEY L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Program Manager"
  30. #define WINDOWS_KEY L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows"
  31. //#define MYDEBUG 1
  32. SECURITY_ATTRIBUTES SecurityAttributes;
  33. SECURITY_ATTRIBUTES AdminSecAttr; // security attributes for common groups
  34. BOOL bInitialArrange;
  35. BOOL bInNtSetup;
  36. TCHAR szProgramGroups[] = TEXT("UNICODE Program Groups"); // registry key for groups
  37. TCHAR szRestrict[] = TEXT("Restrictions");
  38. TCHAR szNoRun[] = TEXT("NoRun");
  39. TCHAR szNoClose[] = TEXT("NoClose");
  40. TCHAR szEditLevel[] = TEXT("EditLevel");
  41. TCHAR szNoFileMenu[] = TEXT("NoFileMenu");
  42. TCHAR szNoSave[] = TEXT("NoSaveSettings");
  43. TCHAR szShowCommonGroups[]= TEXT("ShowCommonGroups");
  44. TCHAR szSettings[] = TEXT("Settings");
  45. TCHAR szGroups[] = TEXT("UNICODE Groups");
  46. TCHAR szAnsiGroups[] = TEXT("Groups");
  47. TCHAR szCommonGroups[] = TEXT("Common Groups");
  48. TCHAR szSystemBoot[] = TEXT("Boot");
  49. TCHAR szSystemDisplay[] = TEXT("display.drv");
  50. TCHAR szDefPrograms[] = TEXT("EXE COM BAT PIF");
  51. TCHAR szSystemIni[] = TEXT("system.ini");
  52. TCHAR szWindows[] = TEXT("Windows");
  53. TCHAR szCheckBinaryType[] = TEXT("CheckBinaryType");
  54. TCHAR szCheckBinaryTimeout[] = TEXT("CheckBinaryTimeout");
  55. TCHAR szMigrateAnsi[] = TEXT("Migrate ANSI");
  56. BOOL bDisableDDE = FALSE;
  57. /* in hotkey.c */
  58. BOOL APIENTRY RegisterHotKeyClass(HANDLE hInstance);
  59. /* in pmgseg.c */
  60. HWND NEAR PASCAL IsGroupAlreadyLoaded(LPTSTR lpGroupKey, BOOL bCommonGroup);
  61. /*---------------------------------------------------------------------------
  62. *
  63. * A fixed buffer case and space insensative compare...
  64. * Returns true if they compare the same.
  65. *
  66. *--------------------------------------------------------------------------*/
  67. BOOL NEAR PASCAL StartupCmp(LPTSTR szSrc1, LPTSTR szSrc2)
  68. {
  69. TCHAR sz1[MAXGROUPNAMELEN+1];
  70. TCHAR sz2[MAXMESSAGELEN+1];
  71. LPTSTR lp1, lp2;
  72. lstrcpy(sz1, szSrc1);
  73. CharUpper(sz1);
  74. lstrcpy(sz2, szSrc2);
  75. CharUpper(sz2);
  76. lp1 = sz1;
  77. lp2 = sz2;
  78. for (;;) {
  79. while(*lp1 == TEXT(' '))
  80. lp1++;
  81. while(*lp2 == TEXT(' '))
  82. lp2++;
  83. if (*lp1 != *lp2)
  84. return FALSE;
  85. if (!*lp1)
  86. break;
  87. while (*lp1 == *lp2 && *lp1)
  88. lp1++, lp2++;
  89. }
  90. return TRUE;
  91. }
  92. /*---------------------------------------------------------------------------
  93. *
  94. * Handles finding and execing the items in the startup group.
  95. *
  96. *--------------------------------------------------------------------------*/
  97. VOID NEAR PASCAL HandleStartupGroup(int nCmdShow)
  98. {
  99. TCHAR szGroupTitle[MAXGROUPNAMELEN+1];
  100. HWND hwndT;
  101. DWORD cbData = sizeof(TCHAR)*(MAXGROUPNAMELEN+1);
  102. PGROUP pGroup;
  103. LPGROUPDEF lpgd;
  104. TCHAR szCommonStartupGroup[MAXGROUPNAMELEN+1];
  105. TCHAR szDefaultStartup[MAXGROUPNAMELEN+1] = TEXT("startup");
  106. TCHAR szStartupKana[] = TEXT("^?X^?^^?[^?g^?A^?b^?v");
  107. if (nCmdShow != SW_SHOWMINNOACTIVE) {
  108. //
  109. // Daytona security weenies decreed that GetAsyncKeyState only work
  110. // if threads window is foreground, so make it so.
  111. //
  112. hwndT = GetForegroundWindow();
  113. if (hwndProgman != hwndT)
  114. SetForegroundWindow( hwndProgman );
  115. if (GetAsyncKeyState(VK_SHIFT) < 0) // SHIFT will cancel the startup group
  116. return;
  117. }
  118. //
  119. // The Default startup group name is "Startup", for personal and common
  120. // groups.
  121. //
  122. LoadString(hAppInstance,IDS_DEFAULTSTARTUP,szDefaultStartup,CharSizeOf(szDefaultStartup));
  123. lstrcpy(szGroupTitle, szDefaultStartup);
  124. lstrcpy(szCommonStartupGroup, szDefaultStartup);
  125. //
  126. // Get the Personal startup group name.
  127. //
  128. if (hkeyPMSettings) {
  129. if ( RegQueryValueEx(hkeyPMSettings, szStartup, 0, 0, (LPBYTE)szGroupTitle, &cbData) != ERROR_SUCCESS ) {
  130. lstrcpy(szGroupTitle, szDefaultStartup);
  131. }
  132. }
  133. // Search for the startup group.
  134. hwndT = GetWindow(hwndMDIClient, GW_CHILD);
  135. while (hwndT) {
  136. //
  137. // Skip icon titles.
  138. //
  139. if (!GetWindow(hwndT, GW_OWNER)) {
  140. /* Compare the group name with the startup. */
  141. pGroup = (PGROUP)GetWindowLongPtr(hwndT, GWLP_PGROUP);
  142. if (lpgd = (LPGROUPDEF)GlobalLock(pGroup->hGroup)) {
  143. // ToddB: We want to check for three things here:
  144. // 1.) A common group with the name szCommonStartupGroup
  145. // 2.) Any group with the name szGroupTitle (which is a copy of szDefaultStartup)
  146. // 3.) If we are in Japan then we also search for two hardcoded strings,
  147. // szStartupKana AND szStartup. I think this special Japanese
  148. // check is a bug and should be removed.
  149. if (pGroup->fCommon) {
  150. if (StartupCmp(szCommonStartupGroup, (LPTSTR) PTR(lpgd, lpgd->pName)))
  151. StartupGroup(hwndT);
  152. }
  153. else if (StartupCmp(szGroupTitle, (LPTSTR) PTR(lpgd, lpgd->pName))) {
  154. StartupGroup(hwndT);
  155. }
  156. #ifdef JAPAN_HACK_WHICH_TODDB_THINKS_IS_A_BUG
  157. else if (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) == LANG_JAPANESE)
  158. {
  159. if (StartupCmp(szStartupKana,(LPTSTR)PTR(lpgd,lpgd->pName)) || // search for hardcoded localized startup
  160. StartupCmp(szStartup,(LPTSTR)PTR(lpgd,lpgd->pName))) // search for hardcoded non-localized "startup"
  161. {
  162. StartupGroup( hwndT );
  163. }
  164. }
  165. #endif
  166. GlobalUnlock(pGroup->hGroup);
  167. }
  168. }
  169. hwndT = GetWindow(hwndT, GW_HWNDNEXT);
  170. }
  171. }
  172. /*** BoilThatDustSpec -- strips string to program name
  173. *
  174. *
  175. * VOID APIENTRY BoilThatDustSpec(PSTR pStart, BOOL bLoadIt)
  176. *
  177. * ENTRY - PSTR pStart - Program to exec, and possible parameters
  178. * BOOL LoadIt -
  179. *
  180. * EXIT - VOID
  181. *
  182. * SYNOPSIS - strips everything after program name, then exec's program.
  183. *
  184. * WARNINGS -
  185. * EFFECTS -
  186. *
  187. */
  188. VOID APIENTRY BoilThatDustSpec(LPTSTR pStart, BOOL bLoadIt)
  189. {
  190. register LPTSTR pEnd;
  191. WORD ret;
  192. BOOL bFinished;
  193. TCHAR szText[MAXMESSAGELEN+1];
  194. TCHAR szExtra[MAXMESSAGELEN+1];
  195. TCHAR szFilename[MAXITEMPATHLEN+1];
  196. TCHAR szWindowsDirectory2[MAXITEMPATHLEN+1];
  197. if (*pStart == TEXT('\0')) { /*test for null string*/
  198. return;
  199. }
  200. // Used to massage any errors.
  201. LoadString(hAppInstance,IDS_WININIERR,szExtra, CharSizeOf(szExtra));
  202. // skip first spaces
  203. while (*pStart == ' ') {
  204. pStart = CharNext(pStart);
  205. }
  206. bFinished = !*pStart;
  207. GetWindowsDirectory(szWindowsDirectory2, CharSizeOf(szWindowsDirectory2));
  208. while (!bFinished){
  209. pEnd = pStart;
  210. /* strip anything after execprogram name*/
  211. while ((*pEnd) && (*pEnd != TEXT(' ')) && (*pEnd != TEXT(','))){
  212. pEnd = CharNext(pEnd);
  213. }
  214. if (*pEnd == TEXT('\0'))
  215. bFinished = TRUE;
  216. else
  217. *pEnd = TEXT('\0');
  218. if (!*pStart) {
  219. pStart = pEnd+1;
  220. continue;
  221. }
  222. if (GetFreeSpace(GMEM_NOT_BANKED) < 65535L)
  223. break;
  224. GetDirectoryFromPath(pStart, szDirField);
  225. // Load and Run lines are done relative to windows directory.
  226. SetCurrentDirectory(szWindowsDirectory2);
  227. GetFilenameFromPath(pStart, szFilename);
  228. ret = ExecProgram(szFilename, szDirField, NULL, bLoadIt, 0, 0, 0);
  229. if (ret) {
  230. // Insert a phrase mentioning win.ini after the file name.
  231. szText[0] = TEXT('\'');
  232. lstrcpy(&szText[1], pStart);
  233. lstrcat(szText, szExtra);
  234. MyMessageBox(NULL, IDS_APPTITLE, ret, szText, MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
  235. }
  236. pStart = pEnd+1;
  237. }
  238. SetCurrentDirectory(szWindowsDirectory); // in fact system32 directory
  239. }
  240. /*** DoRunEquals --
  241. *
  242. *
  243. * VOID APIENTRY DoRunEquals(PINT pnCmdShow)
  244. *
  245. * ENTRY - PINT pnCmdShow - point to cmdshow
  246. *
  247. * EXIT - VOID
  248. *
  249. * SYNOPSIS - ???
  250. *
  251. * WARNINGS -
  252. * EFFECTS -
  253. *
  254. */
  255. VOID APIENTRY DoRunEquals(PINT pnCmdShow)
  256. {
  257. TCHAR szBuffer[MAX_PATH];
  258. DWORD dwType;
  259. DWORD cbData;
  260. HKEY hkeyWindows;
  261. /* "Load" apps before "Run"ning any. */
  262. if (RegOpenKeyEx(HKEY_CURRENT_USER,
  263. WINDOWS_KEY,
  264. 0,
  265. KEY_READ,
  266. &hkeyWindows) != ERROR_SUCCESS) {
  267. return;
  268. }
  269. *szBuffer = 0;
  270. cbData = sizeof(szBuffer);
  271. RegQueryValueEx(hkeyWindows,
  272. L"Load",
  273. 0,
  274. &dwType,
  275. (LPBYTE)szBuffer, &cbData);
  276. if (*szBuffer)
  277. BoilThatDustSpec(szBuffer, TRUE);
  278. *szBuffer = 0;
  279. cbData = sizeof(szBuffer);
  280. RegQueryValueEx(hkeyWindows,
  281. L"Run",
  282. 0,
  283. &dwType,
  284. (LPBYTE)szBuffer, &cbData);
  285. if (*szBuffer) {
  286. BoilThatDustSpec(szBuffer, FALSE);
  287. *pnCmdShow = SW_SHOWMINNOACTIVE;
  288. }
  289. RegCloseKey(hkeyWindows);
  290. }
  291. /*** GetSettings --
  292. *
  293. *
  294. * PSTR APIENTRY GetSettings(VOID)
  295. *
  296. * ENTRY - VOID
  297. *
  298. * EXIT - PSTR - if NULL then error.
  299. *
  300. * SYNOPSIS - ??
  301. *
  302. * WARNINGS -
  303. * EFFECTS -
  304. *
  305. */
  306. LPTSTR APIENTRY GetSettings()
  307. {
  308. LPTSTR pszT;
  309. TCHAR szGroups[32];
  310. TCHAR szAppTitle[MAXKEYLEN + 1];
  311. DWORD cbData;
  312. DWORD dwType;
  313. DWORD rc;
  314. DWORD dwBinaryInfo;
  315. #define SETTING_SIZE 160
  316. /* Get the flags out of the INI file. */
  317. LoadString(hAppInstance, IDS_GROUPS, szGroups, CharSizeOf(szGroups));
  318. LoadString(hAppInstance, IDS_APPTITLE, szAppTitle, CharSizeOf(szAppTitle));
  319. /*
  320. * Use direct registry call.
  321. */
  322. if (hkeyPMSettings) {
  323. cbData = sizeof(bMinOnRun);
  324. RegQueryValueEx(hkeyPMSettings, szMinOnRun, 0, &dwType, (LPBYTE)&bMinOnRun, &cbData);
  325. cbData = sizeof(bAutoArrange);
  326. RegQueryValueEx(hkeyPMSettings, szAutoArrange, 0, &dwType, (LPBYTE)&bAutoArrange, &cbData);
  327. cbData = sizeof(bSaveSettings);
  328. RegQueryValueEx(hkeyPMSettings, szSaveSettings, 0, &dwType, (LPBYTE)&bSaveSettings, &cbData);
  329. cbData = sizeof(bInitialArrange);
  330. bInitialArrange = FALSE;
  331. rc = RegQueryValueEx(hkeyPMSettings, TEXT("InitialArrange"), 0, &dwType, (LPBYTE)&bInitialArrange, &cbData);
  332. if (bInitialArrange) {
  333. RegDeleteValue(hkeyPMSettings, TEXT("InitialArrange"));
  334. }
  335. //
  336. // Check if the binary type checking information exists. If not,
  337. // add it.
  338. //
  339. // First check for the enabled / disabled entry.
  340. //
  341. cbData = sizeof(dwBinaryInfo);
  342. if (RegQueryValueEx(hkeyPMSettings, szCheckBinaryType, 0, &dwType,
  343. (LPBYTE)&dwBinaryInfo, &cbData) == ERROR_FILE_NOT_FOUND) {
  344. //
  345. // Key doesn't exist, so create the default case.
  346. //
  347. dwBinaryInfo = BINARY_TYPE_DEFAULT;
  348. RegSetValueEx (hkeyPMSettings, szCheckBinaryType, 0, REG_DWORD,
  349. (LPBYTE) &dwBinaryInfo, cbData);
  350. }
  351. //
  352. // Now check for the timeout value. This is the number of milliseconds
  353. // of delay after the lastkeystroke and before the background thread
  354. // is signaled to check the type.
  355. //
  356. cbData = sizeof(dwBinaryInfo);
  357. if (RegQueryValueEx(hkeyPMSettings, szCheckBinaryTimeout, 0, &dwType,
  358. (LPBYTE)&dwBinaryInfo, &cbData) == ERROR_FILE_NOT_FOUND) {
  359. //
  360. // Key doesn't exist, so create the default case.
  361. //
  362. dwBinaryInfo = BINARY_TIMEOUT_DEFAULT;
  363. RegSetValueEx (hkeyPMSettings, szCheckBinaryTimeout, 0, REG_DWORD,
  364. (LPBYTE) &dwBinaryInfo, cbData);
  365. }
  366. }
  367. if (hkeyPMRestrict && !UserIsAdmin) {
  368. cbData = sizeof(fNoRun);
  369. RegQueryValueEx(hkeyPMRestrict, szNoRun, 0, &dwType, (LPBYTE)&fNoRun, &cbData);
  370. cbData = sizeof(fNoClose);
  371. RegQueryValueEx(hkeyPMRestrict, szNoClose, 0, &dwType, (LPBYTE)&fNoClose, &cbData);
  372. cbData = sizeof(fNoSave);
  373. RegQueryValueEx(hkeyPMRestrict, szNoSave, 0, &dwType, (LPBYTE)&fNoSave, &cbData);
  374. cbData = sizeof(dwEditLevel);
  375. RegQueryValueEx(hkeyPMRestrict, szEditLevel, 0, &dwType, (LPBYTE)&dwEditLevel, &cbData);
  376. }
  377. pszT = (LPTSTR)LocalAlloc(LPTR, SETTING_SIZE);
  378. if (!pszT)
  379. return(NULL);
  380. /*
  381. * Use direct registry call.
  382. */
  383. if (hkeyPMSettings) {
  384. cbData = SETTING_SIZE;
  385. if (RegQueryValueEx(hkeyPMSettings, szWindow, 0, &dwType, (LPBYTE)pszT, &cbData)) {
  386. LocalFree((HANDLE)pszT);
  387. return NULL;
  388. }
  389. }
  390. else {
  391. return(NULL);
  392. }
  393. return pszT;
  394. }
  395. //#if 0
  396. BOOL GetUserAndDomainName(LPTSTR lpBuffer, DWORD cb)
  397. {
  398. HANDLE hToken;
  399. DWORD cbTokenBuffer = 0;
  400. PTOKEN_USER pUserToken;
  401. LPTSTR lpUserName = NULL;
  402. LPTSTR lpUserDomain = NULL;
  403. DWORD cbAccountName = 0;
  404. DWORD cbUserDomain = 0;
  405. SID_NAME_USE SidNameUse;
  406. if (!OpenProcessToken(GetCurrentProcess(),
  407. TOKEN_QUERY,
  408. &hToken) ){
  409. return(FALSE);
  410. }
  411. //
  412. // Get space needed for token information
  413. //
  414. if (!GetTokenInformation(hToken,
  415. TokenUser,
  416. NULL,
  417. 0,
  418. &cbTokenBuffer) ) {
  419. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  420. return(FALSE);
  421. }
  422. }
  423. //
  424. // Get the actual token information
  425. //
  426. pUserToken = (PTOKEN_USER)Alloc(cbTokenBuffer);
  427. if (pUserToken == NULL) {
  428. return(FALSE);
  429. }
  430. if (!GetTokenInformation(hToken,
  431. TokenUser,
  432. pUserToken,
  433. cbTokenBuffer,
  434. &cbTokenBuffer) ) {
  435. Free(pUserToken);
  436. return(FALSE);
  437. }
  438. //
  439. // Get the space needed for the User name and the Domain name
  440. //
  441. if (!LookupAccountSid(NULL,
  442. pUserToken->User.Sid,
  443. NULL, &cbAccountName,
  444. NULL, &cbUserDomain,
  445. &SidNameUse
  446. ) ) {
  447. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  448. Free(pUserToken);
  449. return(FALSE);
  450. }
  451. }
  452. lpUserName = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR)*(cbAccountName+1));
  453. if (!lpUserName) {
  454. Free(pUserToken);
  455. return(FALSE);
  456. }
  457. lpUserDomain = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR)*(1+cbUserDomain));
  458. if (!lpUserDomain) {
  459. LocalFree(lpUserName);
  460. Free(pUserToken);
  461. return(FALSE);
  462. }
  463. //
  464. // Now get the user name and domain name
  465. //
  466. if (!LookupAccountSid(NULL,
  467. pUserToken->User.Sid,
  468. lpUserName, &cbAccountName,
  469. lpUserDomain, &cbUserDomain,
  470. &SidNameUse
  471. ) ) {
  472. LocalFree(lpUserName);
  473. LocalFree(lpUserDomain);
  474. Free(pUserToken);
  475. return(FALSE);
  476. }
  477. if (*lpUserName &&
  478. ((int)sizeof(TCHAR)*(lstrlen(lpBuffer) + lstrlen(lpUserName) + lstrlen(lpUserDomain)) < (int)(cb+4)) ) {
  479. lstrcat(lpBuffer, TEXT(" - "));
  480. lstrcat(lpBuffer, lpUserDomain);
  481. lstrcat(lpBuffer, TEXT("\\"));
  482. lstrcat(lpBuffer, lpUserName);
  483. }
  484. Free(pUserToken);
  485. LocalFree(lpUserName);
  486. LocalFree(lpUserDomain);
  487. return(TRUE);
  488. }
  489. //#endif
  490. /*** CreateFrameWindow --
  491. *
  492. *
  493. * HWND APIENTRY CreateFrameWindow(register PRECT prc, WORD nCmdShow)
  494. *
  495. * ENTRY - PRECT prc -
  496. * WORD nCmdShow -
  497. *
  498. * EXIT - HWND - (NULL = Error)
  499. *
  500. * SYNOPSIS - ??
  501. *
  502. * WARNINGS -
  503. * EFFECTS -
  504. *
  505. */
  506. HWND APIENTRY CreateFrameWindow(register PRECT prc, WORD nCmdShow)
  507. {
  508. HDC hdc;
  509. HBRUSH hbr;
  510. HMENU hMenu;
  511. HMENU hSystemMenu;
  512. TCHAR szBuffer[40 + MAX_USERNAME_LENGTH];
  513. TCHAR szProgmanClass[16];
  514. TCHAR szUserName[MAX_USERNAME_LENGTH + 1] = TEXT("");
  515. TCHAR szUserDomain[MAX_USERNAME_LENGTH + 1] = TEXT("");
  516. DWORD dwType, cbData;
  517. /* Create the Desktop Manager window. */
  518. LoadString(hAppInstance, IDS_APPTITLE, szBuffer, CharSizeOf(szBuffer));
  519. LoadString(hAppInstance, IDS_PMCLASS, szProgmanClass, CharSizeOf(szProgmanClass));
  520. #if 1
  521. GetUserAndDomainName(szBuffer,sizeof(szBuffer));
  522. #else
  523. cbData = CharSizeOf(szUserName);
  524. GetUserName(szUserName, &cbData) ;
  525. cbData = CharSizeOf(szUserDomain);
  526. GetEnvironmentVariable(TEXT("USERDOMAIN"), szUserDomain, cbData);
  527. if (*szUserName){
  528. lstrcat(szBuffer, TEXT(" - "));
  529. lstrcat(szBuffer, szUserDomain);
  530. lstrcat(szBuffer, TEXT("\\"));
  531. lstrcat(szBuffer, szUserName);
  532. }
  533. #endif
  534. hwndProgman = CreateWindow(szProgmanClass,
  535. szBuffer,
  536. WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
  537. prc->left, prc->top,
  538. prc->right-prc->left,
  539. prc->bottom-prc->top,
  540. NULL, /* No Parent */
  541. NULL, /* Use Class Menu */
  542. hAppInstance,
  543. NULL);
  544. if (!hwndProgman)
  545. return NULL;
  546. SetWindowLong (hwndProgman, GWL_EXITING, 0);
  547. hMenu = GetMenu(hwndProgman);
  548. hSystemMenu = GetSystemMenu(hwndProgman, FALSE);
  549. if (!bExitWindows) {
  550. LoadString(hAppInstance,IDS_EXIT,szBuffer,CharSizeOf(szBuffer));
  551. ModifyMenu(hMenu,IDM_EXIT,MF_BYCOMMAND|MF_STRING,IDM_EXIT,szBuffer);
  552. DeleteMenu(hMenu,IDM_SHUTDOWN,MF_BYCOMMAND);
  553. }
  554. else {
  555. // replace Close menu item with Logoff and Shutdown
  556. LoadString(hAppInstance,IDS_LOGOFF,szBuffer,CharSizeOf(szBuffer));
  557. InsertMenu(hSystemMenu, SC_CLOSE, MF_BYCOMMAND|MF_STRING, SC_CLOSE, szBuffer);
  558. LoadString(hAppInstance,IDS_SHUTDOWN,szBuffer,CharSizeOf(szBuffer));
  559. ModifyMenu(hSystemMenu, SC_CLOSE, MF_BYCOMMAND|MF_STRING, IDM_SHUTDOWN, szBuffer);
  560. }
  561. if (hkeyPMRestrict && !UserIsAdmin) {
  562. cbData = sizeof(fNoFileMenu);
  563. RegQueryValueEx(hkeyPMRestrict, szNoFileMenu, 0, &dwType, (LPBYTE)&fNoFileMenu, &cbData);
  564. }
  565. if (fNoFileMenu) {
  566. DeleteMenu(hMenu, IDM_FILE, MF_BYPOSITION);
  567. }
  568. if (fNoSave) {
  569. bSaveSettings = FALSE;
  570. EnableMenuItem(hMenu, IDM_SAVESETTINGS, MF_BYCOMMAND|MF_GRAYED|MF_DISABLED);
  571. EnableMenuItem(hMenu, IDM_SAVENOW, MF_BYCOMMAND|MF_GRAYED|MF_DISABLED);
  572. }
  573. /* Update the menu items here (no maximized kids to deal with). */
  574. if (bMinOnRun)
  575. CheckMenuItem(hMenu, IDM_MINONRUN, MF_CHECKED);
  576. if (bAutoArrange)
  577. CheckMenuItem(hMenu, IDM_AUTOARRANGE, MF_CHECKED);
  578. if (bSaveSettings)
  579. CheckMenuItem(hMenu, IDM_SAVESETTINGS, MF_CHECKED);
  580. if (bInNtSetup) {
  581. EnableWindow(hwndProgman, FALSE);
  582. }
  583. ShowWindow(hwndProgman, nCmdShow);
  584. UpdateWindow(hwndProgman);
  585. /* fake-paint the client area with the color of the MDI client so users
  586. * have something pleasent to stare at while we hit the disk for the
  587. * group files
  588. */
  589. hdc = GetDC(hwndProgman);
  590. GetClientRect(hwndProgman, prc);
  591. hbr = CreateSolidBrush(GetSysColor(COLOR_APPWORKSPACE));
  592. if (hbr) {
  593. FillRect(hdc, prc, hbr);
  594. DeleteObject(hbr);
  595. }
  596. ReleaseDC(hwndProgman, hdc);
  597. return hwndProgman;
  598. }
  599. /*** IsGroup --
  600. *
  601. *
  602. * BOOL APIENTRY IsGroup(PSTR p)
  603. *
  604. * ENTRY - PSTR p -
  605. *
  606. * EXIT - BOOL - (FALSE == ERROR)
  607. *
  608. * SYNOPSIS - ??
  609. *
  610. * WARNINGS -
  611. * EFFECTS -
  612. *
  613. */
  614. BOOL PASCAL IsGroup(LPTSTR p)
  615. {
  616. if (_wcsnicmp(p, TEXT("GROUP"), CCHGROUP) != 0) {
  617. return FALSE;
  618. }
  619. /*
  620. * Can't have 0 for first digit
  621. */
  622. if (p[5] == TEXT('0')) {
  623. return FALSE;
  624. }
  625. /*
  626. * Everything else must be a number
  627. */
  628. for (p += CCHGROUP; *p; p++) {
  629. if (*p != TEXT('C') && (*p < TEXT('0') || *p > TEXT('9'))) {
  630. return FALSE;
  631. }
  632. }
  633. return TRUE;
  634. }
  635. /*** RemoveString --
  636. *
  637. *
  638. * VOID APIENTRY RemoveString(PSTR pString)
  639. *
  640. * ENTRY - PSTR pString -
  641. *
  642. * EXIT - VOID
  643. *
  644. * SYNOPSIS - ??
  645. *
  646. * WARNINGS -
  647. * EFFECTS -
  648. *
  649. */
  650. VOID APIENTRY RemoveString(LPTSTR pString)
  651. {
  652. LPTSTR pT = pString + lstrlen(pString) + 1;
  653. while (*pT) {
  654. while (*pString++ = *pT++)
  655. ;
  656. }
  657. *pString = 0;
  658. }
  659. /*** StringToEnd --
  660. *
  661. *
  662. * VOID APIENTRY StringToEnd(PSTR pString)
  663. *
  664. * ENTRY - PSTR pString -
  665. *
  666. * EXIT - VOID
  667. *
  668. * SYNOPSIS - ??
  669. *
  670. * WARNINGS -
  671. * EFFECTS -
  672. *
  673. */
  674. VOID PASCAL StringToEnd(LPTSTR pString)
  675. {
  676. TCHAR *pT,*pTT;
  677. for (pT = pString; *pT; ) //go to end of strings
  678. while (*pT++)
  679. ;
  680. for (pTT = pString; *pT++ = *pTT++;) // copy first string to the end
  681. ;
  682. *pT = 0;
  683. RemoveString(pString); // remove first string
  684. }
  685. /*** GetGroupList --
  686. *
  687. *
  688. * VOID APIENTRY GetGroupList(PSTR szList)
  689. *
  690. * ENTRY - PSTR szList -
  691. *
  692. * EXIT - VOID
  693. *
  694. * SYNOPSIS - ??
  695. *
  696. * WARNINGS -
  697. * EFFECTS -
  698. *
  699. */
  700. VOID PASCAL GetGroupList(LPTSTR szList, HKEY hkeyPMGroups)
  701. {
  702. TCHAR szOrd[CGROUPSMAX*8+7];
  703. TCHAR szT[20];
  704. LPTSTR pT, pTT, pS;
  705. INT cGroups; // The number of Groups= lines.
  706. LPTSTR lpList;
  707. DWORD dwType;
  708. DWORD dwIndex = 0;
  709. DWORD cbValueName = 8;
  710. DWORD cbData;
  711. INT cbList = (CGROUPSMAX+1)*18;
  712. LPTSTR lpOrder;
  713. lpList = szList;
  714. //
  715. // Get the user's list of personal groups.
  716. //
  717. if (hkeyPMGroups) {
  718. cbValueName = cbList;
  719. while (!RegEnumValue(hkeyPMGroups, dwIndex, lpList, &cbValueName, 0, 0,
  720. 0, 0)) {
  721. dwIndex++; cbValueName++;
  722. lpList += cbValueName;
  723. cbList -= cbValueName;
  724. cbValueName = cbList;
  725. }
  726. }
  727. //
  728. // Now get the user's list of common groups.
  729. //
  730. if (hkeyPMCommonGroups) {
  731. cbValueName = cbList;
  732. dwIndex = 0;
  733. while (!RegEnumValue(hkeyPMCommonGroups, dwIndex, lpList, &cbValueName, 0, 0,
  734. 0, 0)) {
  735. dwIndex++; cbValueName++;
  736. lpList += cbValueName;
  737. cbList -= cbValueName;
  738. cbValueName = cbList;
  739. }
  740. }
  741. *lpList = TEXT('\0');
  742. cbData = sizeof(szOrd);
  743. if (bUseANSIGroups)
  744. lpOrder = szAnsiOrder;
  745. else
  746. lpOrder = szOrder;
  747. if (!hkeyPMSettings || RegQueryValueEx(hkeyPMSettings, lpOrder, 0, &dwType, (LPBYTE)szOrd, &cbData))
  748. *szOrd = TEXT('\0');
  749. cGroups = 0;
  750. /*
  751. * Filter out anything that isn't group#.
  752. */
  753. for (pT = szList; *pT; ) {
  754. CharUpper(pT);
  755. if (IsGroup(pT)) {
  756. pT += lstrlen(pT) + 1;
  757. cGroups++;
  758. } else {
  759. RemoveString(pT);
  760. }
  761. }
  762. /*
  763. * Sort the groups
  764. */
  765. lstrcpy(szT, TEXT("Group"));
  766. for (pT = szOrd; *pT; ) {
  767. while (*pT == TEXT(' ')) {
  768. pT++;
  769. }
  770. if ((*pT == TEXT('C') && (*(pT+1) < TEXT('0') || *(pT+1) > TEXT('9'))) ||
  771. (*pT != TEXT('C') && (*pT < TEXT('0') || *pT > TEXT('9'))) ) {
  772. break;
  773. }
  774. pTT = szT + CCHGROUP;
  775. while (*pT == TEXT('C') || (*pT >= TEXT('0') && *pT <= TEXT('9'))) {
  776. *pTT++ = *pT++;
  777. }
  778. *pTT=0;
  779. for (pS = szList; *pS; pS += lstrlen(pS) + 1) {
  780. if (!lstrcmpi(pS,szT)) {
  781. StringToEnd(pS);
  782. cGroups--;
  783. break;
  784. }
  785. }
  786. }
  787. /*
  788. * Move any remaining groups to the end of the list so that they load
  789. * last and appear on top of everything else - keeps DOS based install
  790. * programs happy.
  791. * If bInitialArrange is set then the remaining groups come from the
  792. * Windows 3.1 migration and we want these groups to be loaded before
  793. * the remaining groups so they appear below the regular groups.
  794. * 10-15-93 johannec
  795. */
  796. if (!bInitialArrange) {
  797. while (cGroups>0) {
  798. StringToEnd(szList);
  799. cGroups--;
  800. }
  801. }
  802. }
  803. /*** LoadCommonGroups --
  804. *
  805. *
  806. * VOID APIENTRY LoadCommonGroups(LPTSTR)
  807. *
  808. * ENTRY - LPTSTR the key name of the common group that should have the focus.
  809. *
  810. * EXIT - HWND hwnd of the common group which should have the focus.
  811. *
  812. * SYNOPSIS -
  813. *
  814. * WARNINGS -
  815. * EFFECTS -
  816. *
  817. */
  818. HWND LoadCommonGroups(LPTSTR lpFocusGroup)
  819. {
  820. int i = 0;
  821. TCHAR szGroupKey[MAXKEYLEN];
  822. DWORD cchGroupKey = CharSizeOf(szGroupKey);
  823. BOOL bRealArrange;
  824. FILETIME ft;
  825. HWND hwnd;
  826. if (!hkeyCommonGroups) { // cannot access registry.
  827. return(NULL);
  828. }
  829. /*
  830. * Set global to note that we haven't run out of memory yet.
  831. */
  832. fLowMemErrYet = FALSE;
  833. /*
  834. * Flag for extraction problems.
  835. */
  836. fErrorOnExtract = FALSE;
  837. // REVIEW - Why stop AutoArrange on load ? Switch it off for now.
  838. bRealArrange = bAutoArrange;
  839. //
  840. // For mow, just load the groups in whatever order they are enumerated
  841. // in the registry.
  842. //
  843. while (!RegEnumKeyEx(hkeyCommonGroups, i, szGroupKey, &cchGroupKey, 0, 0, 0, &ft)) {
  844. if (cchGroupKey) {
  845. hwnd = LoadGroupWindow(szGroupKey, 0, TRUE);
  846. }
  847. cchGroupKey = CharSizeOf(szGroupKey);
  848. i++;
  849. }
  850. bAutoArrange = bRealArrange;
  851. /*
  852. * Check to see if there was any trouble.
  853. */
  854. if (fErrorOnExtract) {
  855. /*
  856. * On observed problem with icon extraction has been to do
  857. * with a low memory.
  858. */
  859. MyMessageBox(hwndProgman, IDS_OOMEXITTITLE, IDS_LOWMEMONEXTRACT,
  860. NULL, MB_OK|MB_ICONHAND|MB_SYSTEMMODAL);
  861. }
  862. return(hwnd);
  863. }
  864. /*** LoadAllGroups --
  865. *
  866. *
  867. * VOID APIENTRY LoadAllGroups(VOID)
  868. *
  869. * ENTRY - VOID
  870. *
  871. * EXIT - VOID
  872. *
  873. * SYNOPSIS - ??
  874. *
  875. * WARNINGS -
  876. * EFFECTS -
  877. *
  878. */
  879. VOID PASCAL LoadAllGroups()
  880. {
  881. LPTSTR pT, pszT;
  882. TCHAR szGroupList[(CGROUPSMAX+1)*18];
  883. WORD wIndex;
  884. TCHAR szPath[120];
  885. TCHAR szGroupKey[MAXKEYLEN];
  886. BOOL bRealArrange;
  887. DWORD cbData;
  888. DWORD dwType;
  889. BOOL fShowCommonGrps = TRUE;
  890. HKEY hkeyPMAnsiGroups = NULL;
  891. HKEY hkeyGroups;
  892. TCHAR szCommonGrpInfo[MAXKEYLEN];
  893. INT i;
  894. BOOL bDefaultPosition = FALSE;
  895. INT rgiPos[7];
  896. HWND hwndGroup;
  897. if (bUseANSIGroups) {
  898. RegCreateKeyEx(hkeyProgramManager, szAnsiGroups, 0, szProgman, 0,
  899. KEY_READ | KEY_WRITE,
  900. pSecurityAttributes, &hkeyPMAnsiGroups, NULL);
  901. hkeyGroups = hkeyPMAnsiGroups;
  902. }
  903. else {
  904. hkeyGroups = hkeyPMGroups;
  905. }
  906. if (!hkeyGroups) { // cannot access registry.
  907. return;
  908. }
  909. /*
  910. * Set global to note that we haven't run out of memory yet.
  911. */
  912. fLowMemErrYet = FALSE;
  913. /*
  914. * Flag for extraction problems.
  915. */
  916. fErrorOnExtract = FALSE;
  917. // REVIEW - Why stop AutoArrange on load ? Switch it off for now.
  918. bRealArrange = bAutoArrange;
  919. //
  920. // If the user is allowed to see the common program groups, load them.
  921. //
  922. if (hkeyPMRestrict) {
  923. cbData = sizeof(fShowCommonGrps);
  924. RegQueryValueEx(hkeyPMRestrict, szShowCommonGroups, 0, &dwType, (LPBYTE)&fShowCommonGrps, &cbData);
  925. }
  926. if (fShowCommonGrps || AccessToCommonGroups) {
  927. RegCreateKeyEx(hkeyProgramManager, szCommonGroups, 0, szProgman, 0,
  928. KEY_READ | KEY_WRITE,
  929. pSecurityAttributes, &hkeyPMCommonGroups, NULL);
  930. //
  931. // Load all common program groups
  932. //
  933. LoadCommonGroups(szNULL);
  934. }
  935. //
  936. // Now load the user's personal program groups.
  937. //
  938. pT = szGroupList;
  939. for (GetGroupList(pT, hkeyGroups); *pT; pT += (lstrlen(pT) + 1)) {
  940. *szGroupKey = TEXT('\0');
  941. cbData = sizeof(szCommonGrpInfo);
  942. //
  943. // If we're loading a common group...
  944. //
  945. if (*(pT+CCHGROUP) == TEXT('C') && hkeyPMCommonGroups) {
  946. if (RegQueryValueEx(hkeyPMCommonGroups, pT, 0, 0,
  947. (LPBYTE)szCommonGrpInfo, &cbData))
  948. continue;
  949. wIndex = 0;
  950. for (pszT = pT + CCHCOMMONGROUP; *pszT; pszT++) {
  951. wIndex *= 10;
  952. wIndex += *pszT - TEXT('0');
  953. }
  954. //
  955. // Get the window coordinates of this common group.
  956. //
  957. pszT = szCommonGrpInfo;
  958. for (i=0; i < 7; i++) {
  959. rgiPos[i] = 0;
  960. while (*pszT && !((*pszT >= TEXT('0') && *pszT <= TEXT('9')) || *pszT == TEXT('-')))
  961. pszT++;
  962. if (!*pszT) {
  963. bDefaultPosition = TRUE;
  964. break;
  965. }
  966. rgiPos[i] = MyAtoi(pszT);
  967. while (*pszT && ((*pszT >= TEXT('0') && *pszT <= TEXT('9')) || *pszT == TEXT('-')))
  968. pszT++;
  969. }
  970. //
  971. // Now get the common group's name.
  972. //
  973. if (*pszT) {
  974. while(*pszT && *pszT == TEXT(' ')) pszT++;
  975. lstrcpy(szGroupKey, pszT);
  976. }
  977. hwndGroup = IsGroupAlreadyLoaded(szGroupKey, TRUE);
  978. if (!hwndGroup) {
  979. //
  980. // The common group no longer exists, remove this entry from
  981. // the user's list.
  982. //
  983. RegDeleteValue(hkeyPMCommonGroups, pT);
  984. }
  985. if (hwndGroup && !bDefaultPosition) {
  986. //
  987. // Position the common group according to the user's choice.
  988. //
  989. SetInternalWindowPos(hwndGroup, (UINT)rgiPos[6],
  990. (LPRECT)&rgiPos[0], (LPPOINT)&rgiPos[4]);
  991. }
  992. }
  993. else {
  994. if (RegQueryValueEx(hkeyGroups, pT, 0, 0, (LPBYTE)szGroupKey, &cbData))
  995. continue;
  996. wIndex = 0;
  997. for (pszT = pT + CCHGROUP; *pszT; pszT++) {
  998. wIndex *= 10;
  999. wIndex += *pszT - TEXT('0');
  1000. }
  1001. LoadGroupWindow(szGroupKey, wIndex, FALSE);
  1002. }
  1003. }
  1004. bAutoArrange = bRealArrange;
  1005. //
  1006. // If we started with ANSI groups, save the newly converted unicode
  1007. // groups now.
  1008. //
  1009. if (bUseANSIGroups) {
  1010. WriteINIFile();
  1011. }
  1012. if (hkeyPMAnsiGroups) {
  1013. RegCloseKey(hkeyPMAnsiGroups);
  1014. }
  1015. /*
  1016. * Record the current display driver.
  1017. */
  1018. GetPrivateProfileString(szSystemBoot, szSystemDisplay, szPath, szPath, CharSizeOf(szPath), szSystemIni);
  1019. RegSetValueEx(hkeyPMSettings, szSystemDisplay, 0, REG_SZ, (LPBYTE)szPath, sizeof(TCHAR)*(lstrlen(szPath)+1));
  1020. /*
  1021. * Check to see if there was any trouble.
  1022. */
  1023. if (fErrorOnExtract) {
  1024. /*
  1025. * On observed problem with icon extraction has been to do
  1026. * with a low memory.
  1027. */
  1028. MyMessageBox(hwndProgman, IDS_OOMEXITTITLE, IDS_LOWMEMONEXTRACT,
  1029. NULL, MB_OK|MB_ICONHAND|MB_SYSTEMMODAL);
  1030. }
  1031. }
  1032. //*************************************************************
  1033. //
  1034. // UseAnsiGroups()
  1035. //
  1036. // Purpose: Determine if we should convert the ANSI groups
  1037. // to Unicode groups.
  1038. //
  1039. // Parameters: DWORD dwDisp - disposition from RegCreateKeyEx
  1040. // on UNICODE Program Groups
  1041. //
  1042. // Return: BOOL TRUE if the groups should be converted
  1043. // FALSE if not
  1044. //
  1045. //*************************************************************
  1046. BOOL UseAnsiGroups(DWORD dwDisp)
  1047. {
  1048. DWORD dwType, dwMigrateValue, dwSize, dwAnsiValue = 0;
  1049. LONG lResult;
  1050. BOOL bRet = FALSE;
  1051. HKEY hKeyAnsiPG;
  1052. //
  1053. // If the dwDisp is a new key, then we return immediately and use
  1054. // the ANSI groups if they exist.
  1055. //
  1056. if (dwDisp == REG_CREATED_NEW_KEY) {
  1057. return TRUE;
  1058. }
  1059. //
  1060. // dwDisp is an existing key.
  1061. // If the "Migrate Ansi" value exist and the ANSI groups exist,
  1062. // then use them otherwise use the current UNICODE information.
  1063. //
  1064. dwSize = sizeof (DWORD);
  1065. lResult = RegQueryValueEx (hkeyProgramGroups, szMigrateAnsi,
  1066. NULL, &dwType, (LPBYTE) &dwMigrateValue,
  1067. &dwSize);
  1068. //
  1069. // Check the return value of registry call. If it fails
  1070. // then we are working with a machine that has UNICODE Program
  1071. // Groups, and does not need to be updated from the ANSI groups.
  1072. // Most of the time, we will exit here.
  1073. //
  1074. if (lResult != ERROR_SUCCESS) {
  1075. return FALSE;
  1076. }
  1077. //
  1078. // Now we need to know if any ANSI groups exist.
  1079. //
  1080. lResult = RegOpenKeyEx (HKEY_CURRENT_USER, szAnsiProgramGroups,
  1081. 0, KEY_READ, &hKeyAnsiPG);
  1082. if (lResult == ERROR_SUCCESS) {
  1083. TCHAR szName[MAX_PATH];
  1084. DWORD dwNameSize = MAX_PATH;
  1085. FILETIME ft;
  1086. //
  1087. // The "Program Groups" key exists, check to see if there is
  1088. // really something in it.
  1089. //
  1090. lResult = RegEnumKeyEx (hKeyAnsiPG, 0, szName, &dwNameSize, NULL,
  1091. NULL, NULL, &ft);
  1092. //
  1093. // If the return value is success, then there is one or more
  1094. // items in the ANSI key.
  1095. //
  1096. if (lResult == ERROR_SUCCESS) {
  1097. dwAnsiValue = 1;
  1098. } else {
  1099. dwAnsiValue = 0;
  1100. }
  1101. //
  1102. // Close the key
  1103. //
  1104. RegCloseKey (hKeyAnsiPG);
  1105. }
  1106. //
  1107. // If the MigrateValue is set, then we want to delete this entry
  1108. // so the next time the user logs we don't try to convert the ANSI
  1109. // groups again (and this function will execute faster).
  1110. //
  1111. if (dwMigrateValue) {
  1112. RegDeleteValue (hkeyProgramGroups, szMigrateAnsi);
  1113. }
  1114. //
  1115. // Determine the return value.
  1116. //
  1117. if (dwMigrateValue && dwAnsiValue) {
  1118. bRet = TRUE;
  1119. } else {
  1120. bRet = FALSE;
  1121. }
  1122. return (bRet);
  1123. }
  1124. /*** ReadConfigFile --
  1125. *
  1126. *
  1127. * BOOL APIENTRY ReadConfigFile(int nCmdShow)
  1128. *
  1129. * ENTRY - int CmdShow -
  1130. *
  1131. * EXIT - void
  1132. *
  1133. * SYNOPSIS - ??
  1134. *
  1135. * WARNINGS -
  1136. * EFFECTS -
  1137. *
  1138. */
  1139. VOID NEAR PASCAL ReadConfigFile(int nCmdShow)
  1140. {
  1141. int j;
  1142. int rgiPos[5];
  1143. LPTSTR pszT, pT;
  1144. HCURSOR hCursor;
  1145. BOOL bErrorMsgDisplayed = FALSE;
  1146. TCHAR szCommonGroupsKey[MAXKEYLEN];
  1147. DWORD dwDisposition;
  1148. HKEY hkey = NULL;
  1149. hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1150. ShowCursor(TRUE);
  1151. /*
  1152. * Create/Open the registry keys corresponding to progman.ini sections.
  1153. */
  1154. if (!RegCreateKeyEx(HKEY_CURRENT_USER, PROGMAN_KEY, 0, szProgman, 0,
  1155. KEY_READ | KEY_WRITE,
  1156. pSecurityAttributes, &hkeyProgramManager, NULL)) {
  1157. RegCreateKeyEx(hkeyProgramManager, szSettings, 0, szProgman, 0,
  1158. KEY_READ | KEY_WRITE,
  1159. pSecurityAttributes, &hkeyPMSettings, NULL);
  1160. RegCreateKeyEx(hkeyProgramManager, szRestrict, 0, szProgman, 0,
  1161. KEY_READ,
  1162. pSecurityAttributes, &hkeyPMRestrict, NULL);
  1163. RegCreateKeyEx(hkeyProgramManager, szGroups, 0, szProgman, 0,
  1164. KEY_READ | KEY_WRITE,
  1165. pSecurityAttributes, &hkeyPMGroups, NULL);
  1166. }
  1167. else {
  1168. MyMessageBox(NULL, IDS_APPTITLE, IDS_REGISTRYERROR, NULL, MB_OK | MB_ICONEXCLAMATION);
  1169. bErrorMsgDisplayed = TRUE;
  1170. }
  1171. /* Get the global variable settings out of the INI file. */
  1172. if (pszT = GetSettings()) {
  1173. /* Get the window coordinates for PROGMAN's main window. */
  1174. pT = pszT;
  1175. for (j=0; j < 5; j++) {
  1176. rgiPos[j] = 0;
  1177. while (*pT && !((*pT >= TEXT('0') && *pT <= TEXT('9')) || *pT == TEXT('-')))
  1178. pT++;
  1179. if (!*pT) {
  1180. LocalFree((HANDLE)pszT);
  1181. goto DefaultPosition;
  1182. }
  1183. rgiPos[j] = MyAtoi(pT);
  1184. while (*pT && ((*pT >= TEXT('0') && *pT <= TEXT('9')) || *pT == TEXT('-')))
  1185. pT++;
  1186. }
  1187. LocalFree((HANDLE)pszT);
  1188. }
  1189. else {
  1190. DefaultPosition:
  1191. /* NOTE: cx = 0 - CW_USEDEFAULT == CW_USEDEFAULT (0x8000) */
  1192. rgiPos[0] = rgiPos[1] = CW_USEDEFAULT;
  1193. rgiPos[2] = rgiPos[3] = 0;
  1194. rgiPos[4] = SW_SHOWNORMAL;
  1195. }
  1196. if (nCmdShow != SW_SHOWNORMAL)
  1197. rgiPos[4] = nCmdShow;
  1198. /*
  1199. * We don't want an invisible Program Manager!
  1200. */
  1201. if (!(rgiPos[4]))
  1202. rgiPos[4] = SW_SHOWNORMAL;
  1203. /* Create and paint the top-level frame window. */
  1204. if (!CreateFrameWindow((PRECT)rgiPos, (WORD)rgiPos[4]))
  1205. goto RCFErrExit;
  1206. /*
  1207. * Will create/open the key Program Groups, parent of all groups.
  1208. */
  1209. if (RegCreateKeyEx(HKEY_CURRENT_USER, szProgramGroups, 0, szGroups, 0,
  1210. KEY_READ | KEY_WRITE,
  1211. pSecurityAttributes, &hkeyProgramGroups, &dwDisposition)) {
  1212. if (!bErrorMsgDisplayed) {
  1213. MyMessageBox(NULL, IDS_APPTITLE, IDS_REGISTRYERROR, NULL, MB_OK | MB_ICONEXCLAMATION);
  1214. }
  1215. goto RCFErrExit;
  1216. }
  1217. if (UseAnsiGroups(dwDisposition)) {
  1218. //
  1219. // There are no UNICODE groups, so convert the ANSI groups and save
  1220. // them as UNICODE groups.
  1221. //
  1222. bUseANSIGroups = TRUE;
  1223. if (RegCreateKeyEx(HKEY_CURRENT_USER, szAnsiProgramGroups, 0, szGroups, 0,
  1224. KEY_READ,
  1225. pSecurityAttributes, &hkeyAnsiProgramGroups, &dwDisposition)) {
  1226. if (!bErrorMsgDisplayed) {
  1227. MyMessageBox(NULL, IDS_APPTITLE, IDS_REGISTRYERROR, NULL, MB_OK | MB_ICONEXCLAMATION);
  1228. }
  1229. goto RCFErrExit;
  1230. }
  1231. }
  1232. /*
  1233. * Will create/open the key Program Groups for common groups on the local
  1234. * machine.
  1235. */
  1236. lstrcpy(szCommonGroupsKey, TEXT("SOFTWARE\\"));
  1237. lstrcat(szCommonGroupsKey, szAnsiProgramGroups);
  1238. //
  1239. // Try opening/creating the common groups key with Write access
  1240. //
  1241. OpenCommonGroupsKey:
  1242. if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, szCommonGroupsKey, 0, szGroups, 0,
  1243. KEY_READ | KEY_WRITE | DELETE,
  1244. pAdminSecAttr, &hkeyCommonGroups, &dwDisposition)
  1245. == ERROR_SUCCESS) {
  1246. if (dwDisposition == REG_CREATED_NEW_KEY) {
  1247. //
  1248. // need to close and reopen the key to make sure we have the
  1249. // right access
  1250. //
  1251. RegCloseKey(hkeyCommonGroups);
  1252. goto OpenCommonGroupsKey;
  1253. }
  1254. AccessToCommonGroups = TRUE;
  1255. } else {
  1256. RegOpenKeyEx(HKEY_LOCAL_MACHINE, szCommonGroupsKey, 0, KEY_READ,
  1257. &hkeyCommonGroups);
  1258. }
  1259. //
  1260. // If we have Ansi groups in the profile, add a menu item under the Options menu
  1261. // to remove the old NT1.0 ANSI groups. This menu item will be deleted we the
  1262. // user selects to remove the old groups
  1263. //
  1264. if (!fNoSave && (bUseANSIGroups || !RegOpenKeyEx(HKEY_CURRENT_USER,
  1265. szAnsiProgramGroups,
  1266. 0,
  1267. DELETE | KEY_READ | KEY_WRITE, &hkey))){
  1268. HMENU hMenu = GetSubMenu(GetMenu(hwndProgman), 1);
  1269. AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
  1270. LoadString(hAppInstance, IDS_ANSIGROUPSMENU, szMessage, CharSizeOf(szMessage));
  1271. AppendMenu(hMenu, MF_STRING | MF_ENABLED, IDM_ANSIGROUPS, szMessage);
  1272. if (hkey) {
  1273. RegCloseKey(hkey);
  1274. }
  1275. }
  1276. /* The main frame window's been created, shown, and filled.
  1277. * It's time to read the various group files, by enumerating group#
  1278. * lines in PROGMAN.INI
  1279. */
  1280. LoadAllGroups();
  1281. /*
  1282. * Restriction key is no longer needed.
  1283. */
  1284. if (hkeyPMRestrict) {
  1285. RegCloseKey(hkeyPMRestrict);
  1286. hkeyPMRestrict = NULL;
  1287. }
  1288. RCFErrExit:
  1289. //
  1290. // We've got the Ansi groups, reset this value.
  1291. //
  1292. bUseANSIGroups = FALSE;
  1293. RegCloseKey(hkeyAnsiProgramGroups);
  1294. hkeyAnsiProgramGroups = NULL;
  1295. ShowCursor(FALSE);
  1296. SetCursor(hCursor);
  1297. ShowWindow(hwndMDIClient,SW_SHOWNORMAL);
  1298. }
  1299. /****************************************************************************
  1300. *
  1301. * FUNCTION: ParseReserved(LPTSTR lpReserved, LPDWORD lpDdeId, LPDWORD lpHotKey)
  1302. *
  1303. * PURPOSE: Parses the lpReserved field of the StartupInfo structure to
  1304. * get the Progman's new instance DDE id and its Hot key.
  1305. * The lpReserved field is a string of thee following format:
  1306. * "dde.%d,hotkey.%d"
  1307. *
  1308. * Returns the dde id and hotkey.
  1309. *
  1310. * COMMENTS: This is to be compatible with Win3.1 by allowing users to
  1311. * set a hotkey for Progman, and to allow them to change
  1312. * Progman's icon and window title (see SetProgmanProperties in
  1313. * pmwprocs.c)
  1314. *
  1315. *
  1316. * HISTORY: 08-28-92 JohanneC Created.
  1317. *
  1318. ****************************************************************************/
  1319. void ParseReserved(LPTSTR lpReserved, LPDWORD lpDdeId, LPDWORD lpHotKey)
  1320. {
  1321. TCHAR *pch, *pchT, ch;
  1322. //
  1323. // The string will be of the format "dde.%d,hotkey.%d"
  1324. //
  1325. //
  1326. // Get the DDE id.
  1327. //
  1328. if ((pch = wcsstr(lpReserved, TEXT("dde."))) != NULL) {
  1329. pch += 4;
  1330. pchT = pch;
  1331. while (*pchT >= TEXT('0') && *pchT <= TEXT('9'))
  1332. pchT++;
  1333. ch = *pchT;
  1334. *pchT = 0;
  1335. *lpDdeId = MyAtoi(pch);
  1336. *pchT = ch;
  1337. }
  1338. //
  1339. // Get the hot key.
  1340. //
  1341. if ((pch = wcsstr(lpReserved, TEXT("hotkey."))) != NULL) {
  1342. pch += 7;
  1343. pchT = pch;
  1344. while (*pchT >= TEXT('0') && *pchT <= TEXT('9'))
  1345. pchT++;
  1346. ch = *pchT;
  1347. *pchT = 0;
  1348. *lpHotKey = MyAtoi(pch);
  1349. *pchT = ch;
  1350. }
  1351. }
  1352. /*** IsHandleReallyProgman --
  1353. *
  1354. *
  1355. * BOOL IsHandleReallyProgman (HWND hProgman, LPTSTR lpClassName)
  1356. *
  1357. * ENTRY - HWND hProgman
  1358. *
  1359. * EXIT - BOOL TRUE if it is progman
  1360. * FALSE if not
  1361. *
  1362. * SYNOPSIS - ??
  1363. *
  1364. * WARNINGS -
  1365. * EFFECTS -
  1366. *
  1367. */
  1368. BOOL IsHandleReallyProgman(HWND hwndProgman)
  1369. {
  1370. //
  1371. // Test to see if we found Progman or Explorer.
  1372. //
  1373. if ((GetClassLong (hwndProgman, GCL_STYLE) == 0) &&
  1374. (GetClassLongPtr (hwndProgman, GCLP_HICON) != 0) &&
  1375. (GetClassLongPtr (hwndProgman, GCLP_MENUNAME) != 0)) {
  1376. return TRUE;
  1377. }
  1378. return FALSE;
  1379. }
  1380. /*** AppInit --
  1381. *
  1382. *
  1383. * BOOL APIENTRY AppInit(HANDLE hInstance, HANDLE hPrevInstance,
  1384. * LPTSTR lpszCmdLine, int nCmdShow)
  1385. *
  1386. * ENTRY - HANDLE hInstance
  1387. * HANDLE hPrevInstance
  1388. * LPTSTR lpszCmdLine
  1389. * int nCmdSHow
  1390. *
  1391. * EXIT - BOOL xxx - (FALSE == ERROR)
  1392. *
  1393. * SYNOPSIS - ??
  1394. *
  1395. * WARNINGS -
  1396. * EFFECTS -
  1397. *
  1398. */
  1399. BOOL APIENTRY AppInit(HANDLE hInstance, LPTSTR lpszCmdLine, int nCmdShow)
  1400. {
  1401. WORD ret;
  1402. WNDCLASS wndClass;
  1403. TCHAR szClass[16];
  1404. TCHAR szBuffer[MAX_PATH];
  1405. LOGFONT lf;
  1406. TCHAR szText[MAXMESSAGELEN+1];
  1407. STARTUPINFO si;
  1408. HWND hwndPrev;
  1409. INT nTempCmdShow = nCmdShow;
  1410. #ifdef DEBUG_PROGMAN_DDE
  1411. {
  1412. TCHAR szDebug[300];
  1413. wsprintf (szDebug, TEXT("%d PROGMAN: Enter AppInit\r\n"),
  1414. GetTickCount());
  1415. OutputDebugString(szDebug);
  1416. }
  1417. #endif
  1418. //
  1419. // Preserve this instance's module handle.
  1420. //
  1421. hAppInstance = hInstance;
  1422. //
  1423. // Specify the shutdown order of the progman process.
  1424. // 2 means Porgman will shutdown before taskman (level = 1) and
  1425. // ntsd or windbg (level = 0)
  1426. //
  1427. SetProcessShutdownParameters(2,0);
  1428. #ifndef MYDEBUG
  1429. LoadString(hAppInstance, IDS_PMCLASS, szClass, CharSizeOf(szClass));
  1430. if (hwndPrev = FindWindow(szClass, NULL)) {
  1431. bDisableDDE = TRUE; // Only 1 "PROGMAN" should respond to dde
  1432. if (IsHandleReallyProgman(hwndPrev)) {
  1433. DWORD dwDdeId = 0;
  1434. DWORD dwHotKey = 0;
  1435. LONG lExiting;
  1436. GetStartupInfo(&si);
  1437. if (si.lpReserved) {
  1438. ParseReserved(si.lpReserved, &dwDdeId, &dwHotKey);
  1439. }
  1440. PostMessage(hwndPrev, WM_EXECINSTANCE, (WPARAM)dwDdeId, dwHotKey);
  1441. //
  1442. // Need to check the other progman to see if it is exiting currently.
  1443. // If so, then we will continue. GetWindowLong returns 0 as a
  1444. // failure case and as the "Not exiting" case (1 if we are exiting),
  1445. // so we need to confirm that the last error is also
  1446. // zero.
  1447. //
  1448. lExiting = GetWindowLong (hwndPrev, GWL_EXITING);
  1449. if (lExiting != 1) {
  1450. return FALSE;
  1451. }
  1452. }
  1453. }
  1454. #endif
  1455. /*
  1456. * Compute general constants.
  1457. */
  1458. dyBorder = GetSystemMetrics(SM_CYBORDER);
  1459. hItemIcon = LoadIcon(hAppInstance, (LPTSTR) MAKEINTRESOURCE(ITEMICON));
  1460. if (!hItemIcon) {
  1461. return FALSE;
  1462. }
  1463. /*
  1464. * Load the accelerator table.
  1465. */
  1466. hAccel = LoadAccelerators(hAppInstance, (LPTSTR) MAKEINTRESOURCE(PMACCELS));
  1467. if (!hAccel)
  1468. return FALSE;
  1469. cxIcon = GetSystemMetrics(SM_CXICON);
  1470. cyIcon = GetSystemMetrics(SM_CYICON);
  1471. cxOffset = 2 * GetSystemMetrics(SM_CXBORDER);
  1472. cyOffset = 2 * GetSystemMetrics(SM_CYBORDER);
  1473. cxIconSpace = cxIcon + 2 * cxOffset;
  1474. cyIconSpace = cyIcon + 2 * cyOffset;
  1475. SystemParametersInfo(SPI_ICONHORIZONTALSPACING, 0, (PVOID)(LPINT)&cxArrange, FALSE);
  1476. SystemParametersInfo(SPI_ICONVERTICALSPACING, 0, (PVOID)(LPINT)&cyArrange, FALSE);
  1477. SystemParametersInfo(SPI_GETICONTITLEWRAP, 0, (PVOID)(LPWORD)&bIconTitleWrap, FALSE);
  1478. SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), (PVOID)(LPLOGFONT)&lf, FALSE);
  1479. // lhb tracks check this out !!!! save this one for later! 1/21/93
  1480. //lf.lfCharSet = ANSI_CHARSET ;
  1481. //lstrcpy (lf.lfFaceName, TEXT("Lucida Sans Unicode"));
  1482. hFontTitle = CreateFontIndirect(&lf);
  1483. if (!hFontTitle)
  1484. return FALSE;
  1485. hIconGlobal = LoadIcon(hAppInstance,(LPTSTR) MAKEINTRESOURCE(WORDICON));
  1486. if (!hIconGlobal) {
  1487. return FALSE;
  1488. }
  1489. /*
  1490. * Remember the original directory.
  1491. */
  1492. GetCurrentDirectory(MAXITEMPATHLEN+1, szOriginalDirectory);
  1493. //
  1494. // Set Progman's working directory to system32 directory instead of the
  1495. // windows directory. johannec 5-4-93 bug 8364
  1496. //
  1497. //GetWindowsDirectory(szWindowsDirectory, MAXITEMPATHLEN+1);
  1498. GetSystemDirectory(szWindowsDirectory, MAXITEMPATHLEN+1);
  1499. /*
  1500. * Make sure drive letter is upper case.
  1501. */
  1502. CharUpperBuff(szWindowsDirectory, 1);
  1503. bInNtSetup = FALSE;
  1504. if (lpszCmdLine && *lpszCmdLine &&
  1505. !lstrcmpi(lpszCmdLine, TEXT("/NTSETUP"))) {
  1506. //
  1507. // Progman was started from ntsetup.exe, so it can be exited
  1508. // without causing NT Windows to exit.
  1509. //
  1510. bExitWindows = FALSE;
  1511. bInNtSetup = TRUE;
  1512. *lpszCmdLine = 0;
  1513. }
  1514. else {
  1515. HKEY hkeyWinlogon;
  1516. DWORD dwType;
  1517. DWORD cbBuffer;
  1518. LPTSTR lpt;
  1519. /* Check if we should be the shell by looking at shell= line for WInlogon
  1520. */
  1521. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1522. TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"),
  1523. 0,
  1524. KEY_READ,
  1525. &hkeyWinlogon) == ERROR_SUCCESS) {
  1526. cbBuffer = sizeof(szBuffer);
  1527. if (RegQueryValueEx(hkeyWinlogon,
  1528. TEXT("Shell"),
  1529. 0,
  1530. &dwType,
  1531. (LPBYTE)szBuffer,
  1532. &cbBuffer) == ERROR_SUCCESS) {
  1533. CharLower(szBuffer);
  1534. lpt = szBuffer;
  1535. while (lpt = wcsstr(lpt, szProgman)) {
  1536. //
  1537. // we probably found progman
  1538. //
  1539. lpt += lstrlen(szProgman);
  1540. if (*lpt == TEXT(' ') || *lpt == TEXT('.') || *lpt == TEXT(',') || !*lpt)
  1541. bExitWindows = TRUE;
  1542. }
  1543. }
  1544. else {
  1545. //
  1546. // assume that progman is the shell.
  1547. //
  1548. bExitWindows = TRUE;
  1549. }
  1550. RegCloseKey(hkeyWinlogon);
  1551. }
  1552. else {
  1553. //
  1554. // assume that progman is the shell.
  1555. //
  1556. bExitWindows = TRUE;
  1557. }
  1558. }
  1559. if (lpszCmdLine && *lpszCmdLine) {
  1560. nCmdShow = SW_SHOWMINNOACTIVE;
  1561. }
  1562. /*
  1563. * call private api to mark task man as a system app. This causes
  1564. * it to be killed after all other non-system apps during shutdown.
  1565. */
  1566. // MarkProcess(MP_SYSTEMAPP);
  1567. /*
  1568. * Load these strings now. If we need them later,
  1569. * we won't be able to load them at that time.
  1570. */
  1571. LoadString(hAppInstance, IDS_OOMEXITTITLE, szOOMExitTitle, CharSizeOf(szOOMExitTitle));
  1572. LoadString(hAppInstance, IDS_OOMEXITMSG, szOOMExitMsg, CharSizeOf(szOOMExitMsg));
  1573. LoadString(hAppInstance, IDS_PMCLASS, szClass, CharSizeOf(szClass));
  1574. SetCurrentDirectory(szWindowsDirectory);
  1575. SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); // Bounce errors to us, not fs.
  1576. // Set global exit flag.
  1577. fExiting = FALSE;
  1578. uiHelpMessage = RegisterWindowMessage(TEXT("ShellHelp"));
  1579. uiBrowseMessage = RegisterWindowMessage(HELPMSGSTRING);
  1580. uiActivateShellWindowMessage = RegisterWindowMessage(TEXT("ACTIVATESHELLWINDOW"));
  1581. uiConsoleWindowMessage = RegisterWindowMessage(TEXT("ConsoleProgmanHandle"));
  1582. uiSaveSettingsMessage = RegisterWindowMessage(TEXT("SaveSettings")); // for UPEDIT.exe : User Profile Editor
  1583. hhkMsgFilter = SetWindowsHook(WH_MSGFILTER, MessageFilter);
  1584. if (hhkMsgFilter == 0) {
  1585. GetLastError();
  1586. }
  1587. /*
  1588. * Register the Frame window class.
  1589. */
  1590. wndClass.lpszClassName = szClass;
  1591. wndClass.style = 0;
  1592. wndClass.lpfnWndProc = ProgmanWndProc;
  1593. wndClass.cbClsExtra = 0;
  1594. wndClass.cbWndExtra = sizeof(LONG);
  1595. wndClass.hInstance = hAppInstance;
  1596. wndClass.hIcon = hProgmanIcon = LoadIcon(hAppInstance, (LPTSTR) MAKEINTRESOURCE(PROGMANICON));
  1597. wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
  1598. wndClass.hbrBackground = NULL;
  1599. wndClass.lpszMenuName = (LPTSTR) MAKEINTRESOURCE(PROGMANMENU);
  1600. if (!RegisterClass(&wndClass))
  1601. return(FALSE);
  1602. /*
  1603. * Register the Program Group window class.
  1604. */
  1605. LoadString(hAppInstance, IDS_GROUPCLASS, szClass, 16);
  1606. wndClass.lpszClassName = szClass;
  1607. wndClass.style = CS_DBLCLKS;
  1608. wndClass.lpfnWndProc = GroupWndProc;
  1609. /*wndClass.cbClsExtra = 0;*/
  1610. wndClass.cbWndExtra = sizeof(PGROUP); /* <== PGROUP */
  1611. /*wndClass.hInstance = hAppInstance;*/
  1612. wndClass.hIcon = NULL;
  1613. /*wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);*/
  1614. wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  1615. wndClass.lpszMenuName = NULL;
  1616. if (!RegisterClass(&wndClass))
  1617. return(FALSE);
  1618. {
  1619. //
  1620. // Set the working set size to 300k.
  1621. //
  1622. QUOTA_LIMITS QuotaLimits;
  1623. NTSTATUS status;
  1624. status = NtQueryInformationProcess( NtCurrentProcess(),
  1625. ProcessQuotaLimits,
  1626. &QuotaLimits,
  1627. sizeof(QUOTA_LIMITS),
  1628. NULL );
  1629. if (NT_SUCCESS(status)) {
  1630. QuotaLimits.MinimumWorkingSetSize = 400 * 1024;
  1631. QuotaLimits.MaximumWorkingSetSize = 508 * 1024;
  1632. NtSetInformationProcess( NtCurrentProcess(),
  1633. ProcessQuotaLimits,
  1634. &QuotaLimits,
  1635. sizeof(QUOTA_LIMITS) );
  1636. }
  1637. }
  1638. hGroupIcon = LoadIcon(hAppInstance, (LPTSTR) MAKEINTRESOURCE(PERSGROUPICON));
  1639. hCommonGrpIcon = LoadIcon(hAppInstance, (LPTSTR) MAKEINTRESOURCE(COMMGROUPICON));
  1640. if (!RegisterHotKeyClass((HANDLE)hAppInstance))
  1641. return FALSE;
  1642. RegisterDDEClasses((HANDLE)hAppInstance);
  1643. /*
  1644. * Initialize the security descriptor for the registry keys that
  1645. * will be added to the user's personal profile.
  1646. */
  1647. pSecurityAttributes = &SecurityAttributes;
  1648. if (!InitializeSecurityAttributes(pSecurityAttributes, TRUE))
  1649. pSecurityAttributes = NULL;
  1650. /*
  1651. * Initialize the security descriptor for the registry keys that
  1652. * will be added to the local machine program groups. Only
  1653. * Administrators, Power Users and Server Operators
  1654. * have all access to these keys, other users have only read access.
  1655. */
  1656. pAdminSecAttr = &AdminSecAttr;
  1657. if (!InitializeSecurityAttributes(pAdminSecAttr, FALSE))
  1658. pAdminSecAttr = NULL;
  1659. /*
  1660. * Test if the current user is an admin. If so, ignore restrictions
  1661. * from the profile.
  1662. */
  1663. UserIsAdmin = TestUserForAdmin();
  1664. /*
  1665. * Read in the Group/Item data structures and create the windows.
  1666. */
  1667. #ifdef DEBUG_PROGMAN_DDE
  1668. {
  1669. TCHAR szDebug[300];
  1670. wsprintf (szDebug, TEXT("%d PROGMAN: Before ReadConfigFile\r\n"),
  1671. GetTickCount());
  1672. OutputDebugString(szDebug);
  1673. }
  1674. #endif
  1675. ReadConfigFile(nCmdShow);
  1676. #ifdef DEBUG_PROGMAN_DDE
  1677. {
  1678. TCHAR szDebug[300];
  1679. wsprintf (szDebug, TEXT("%d PROGMAN: After ReadConfigFile\r\n"),
  1680. GetTickCount());
  1681. OutputDebugString(szDebug);
  1682. }
  1683. #endif
  1684. if (hwndProgman == NULL)
  1685. return FALSE;
  1686. /*
  1687. * NOTE: the nCmdShow stuff from here down is bogus
  1688. *
  1689. * Do load/run lines, then the command line, then the startup group...
  1690. */
  1691. if (bExitWindows)
  1692. DoRunEquals(&nCmdShow);
  1693. /* Process the Command Line */
  1694. if (lpszCmdLine && *lpszCmdLine) {
  1695. WORD cbText;
  1696. TCHAR szFilename[MAXITEMPATHLEN+1];
  1697. lstrcpy(szPathField, lpszCmdLine);
  1698. // win foo.bar is done relative to the original directory.
  1699. SetCurrentDirectory(szOriginalDirectory);
  1700. GetDirectoryFromPath(szPathField, szDirField);
  1701. // now kernel converts the DOS cmd line to Ansi for us!
  1702. GetFilenameFromPath(szPathField, szFilename);
  1703. ret = ExecProgram(szFilename, szDirField, NULL, FALSE, 0, 0, 0);
  1704. if (ret) {
  1705. szText[0] = TEXT('\'');
  1706. lstrcpy(&szText[1],szPathField);
  1707. cbText = (WORD)lstrlen(szText);
  1708. LoadString(hAppInstance,IDS_CMDLINEERR,&szText[cbText],CharSizeOf(szText)-cbText);
  1709. MyMessageBox(NULL, IDS_APPTITLE, ret, szText, MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
  1710. } else
  1711. nCmdShow = SW_SHOWMINNOACTIVE;
  1712. SetCurrentDirectory(szWindowsDirectory);
  1713. }
  1714. /*
  1715. * See if we have a startup group last.
  1716. */
  1717. #ifndef MYDEBUG
  1718. if (bExitWindows || GetAsyncKeyState(VK_CONTROL) < 0)
  1719. #endif
  1720. HandleStartupGroup(nTempCmdShow);
  1721. /*
  1722. * create an event for monitoring the ProgramGroups key.
  1723. */
  1724. InitializeGroupKeyNotification();
  1725. if (bInitialArrange) {
  1726. PostMessage(hwndMDIClient, WM_MDIICONARRANGE, 0, 0L);
  1727. PostMessage(hwndProgman, WM_COMMAND, IDM_SAVENOW, 0L);
  1728. }
  1729. #ifdef DEBUG_PROGMAN_DDE
  1730. {
  1731. TCHAR szDebug[300];
  1732. wsprintf (szDebug, TEXT("%d PROGMAN: Leave AppInit\r\n"),
  1733. GetTickCount());
  1734. OutputDebugString(szDebug);
  1735. }
  1736. #endif
  1737. return TRUE;
  1738. }