PageRenderTime 51ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/reactos/base/shell/progman/main.c

https://gitlab.com/dj-tech/reactos
C | 1205 lines | 870 code | 212 blank | 123 comment | 116 complexity | bcb0e5036488747534e0d4fa41f576e3 MD5 | raw file
  1. /*
  2. * Program Manager
  3. *
  4. * Copyright 1996 Ulrich Schmid
  5. * Copyright 2002 Sylvain Petreolle
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  20. */
  21. /*
  22. * PROJECT: ReactOS Program Manager
  23. * COPYRIGHT: GPL - See COPYING in the top level directory
  24. * FILE: base/shell/progman/main.c
  25. * PURPOSE: ProgMan entry point & MDI window
  26. * PROGRAMMERS: Ulrich Schmid
  27. * Sylvain Petreolle
  28. * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
  29. */
  30. #include "progman.h"
  31. #include <shellapi.h>
  32. #define WC_MDICLIENTA "MDICLIENT"
  33. #define WC_MDICLIENTW L"MDICLIENT"
  34. #ifdef UNICODE
  35. #define WC_MDICLIENT WC_MDICLIENTW
  36. #else
  37. #define WC_MDICLIENT WC_MDICLIENTA
  38. #endif
  39. GLOBALS Globals;
  40. static VOID MAIN_LoadGroups(VOID);
  41. static VOID MAIN_MenuCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
  42. static ATOM MAIN_RegisterMainWinClass(VOID);
  43. static VOID MAIN_CreateMainWindow(VOID);
  44. static VOID MAIN_CreateMDIWindow(VOID);
  45. static VOID MAIN_AutoStart(VOID);
  46. #define BUFFER_SIZE 1024
  47. /*
  48. * Memory management functions
  49. */
  50. PVOID
  51. Alloc(IN DWORD dwFlags,
  52. IN SIZE_T dwBytes)
  53. {
  54. return HeapAlloc(GetProcessHeap(), dwFlags, dwBytes);
  55. }
  56. BOOL
  57. Free(IN PVOID lpMem)
  58. {
  59. return HeapFree(GetProcessHeap(), 0, lpMem);
  60. }
  61. PVOID
  62. ReAlloc(IN DWORD dwFlags,
  63. IN PVOID lpMem,
  64. IN SIZE_T dwBytes)
  65. {
  66. return HeapReAlloc(GetProcessHeap(), dwFlags, lpMem, dwBytes);
  67. }
  68. PVOID
  69. AppendToBuffer(IN PVOID pBuffer,
  70. IN PSIZE_T pdwBufferSize,
  71. IN PVOID pData,
  72. IN SIZE_T dwDataSize)
  73. {
  74. PVOID pTmp;
  75. SIZE_T dwBufferSize;
  76. dwBufferSize = dwDataSize + *pdwBufferSize;
  77. if (pBuffer)
  78. pTmp = ReAlloc(0, pBuffer, dwBufferSize);
  79. else
  80. pTmp = Alloc(0, dwBufferSize);
  81. if (!pTmp)
  82. return NULL;
  83. memcpy((PVOID)((ULONG_PTR)pTmp + *pdwBufferSize), pData, dwDataSize);
  84. *pdwBufferSize = dwBufferSize;
  85. return pTmp;
  86. }
  87. /*
  88. * Debugging helpers
  89. */
  90. VOID
  91. PrintStringV(IN LPCWSTR szStr,
  92. IN va_list args)
  93. {
  94. WCHAR Buffer[4096];
  95. _vsnwprintf(Buffer, ARRAYSIZE(Buffer), szStr, args);
  96. MessageBoxW(Globals.hMainWnd, Buffer, L"Information", MB_OK);
  97. }
  98. VOID
  99. PrintString(IN LPCWSTR szStr, ...)
  100. {
  101. va_list args;
  102. va_start(args, szStr);
  103. PrintStringV(szStr, args);
  104. va_end(args);
  105. }
  106. VOID
  107. PrintResourceString(IN UINT uID, ...)
  108. {
  109. WCHAR Buffer[4096];
  110. va_list args;
  111. va_start(args, uID);
  112. LoadStringW(Globals.hInstance, uID, Buffer, ARRAYSIZE(Buffer));
  113. PrintStringV(Buffer, args);
  114. va_end(args);
  115. }
  116. VOID
  117. PrintWin32Error(IN LPWSTR Message, IN DWORD ErrorCode)
  118. {
  119. LPWSTR lpMsgBuf;
  120. FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  121. NULL, ErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  122. (LPWSTR)&lpMsgBuf, 0, NULL);
  123. PrintString(L"%s: %s\n", Message, lpMsgBuf);
  124. LocalFree(lpMsgBuf);
  125. }
  126. int ShowLastWin32Error(VOID)
  127. {
  128. DWORD dwError;
  129. LPWSTR lpMsgBuf = NULL;
  130. WCHAR Buffer[4096];
  131. dwError = GetLastError();
  132. FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  133. NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  134. (LPWSTR)&lpMsgBuf, 0, NULL);
  135. _snwprintf(Buffer, ARRAYSIZE(Buffer), L"Error %d: %s\n", dwError, lpMsgBuf);
  136. LocalFree(lpMsgBuf);
  137. return MessageBoxW(Globals.hMainWnd, Buffer, L"Error", MB_OK);
  138. }
  139. /* Copied and adapted from dll/win32/userenv/environment.c!GetUserAndDomainName */
  140. static
  141. BOOL
  142. GetUserAndDomainName(OUT LPWSTR* UserName,
  143. OUT LPWSTR* DomainName)
  144. {
  145. BOOL bRet = TRUE;
  146. HANDLE hToken;
  147. DWORD cbTokenBuffer = 0;
  148. PTOKEN_USER pUserToken;
  149. LPWSTR lpUserName = NULL;
  150. LPWSTR lpDomainName = NULL;
  151. DWORD cbUserName = 0;
  152. DWORD cbDomainName = 0;
  153. SID_NAME_USE SidNameUse;
  154. /* Get the process token */
  155. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
  156. return FALSE;
  157. /* Retrieve token's information */
  158. if (!GetTokenInformation(hToken, TokenUser, NULL, 0, &cbTokenBuffer))
  159. {
  160. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  161. {
  162. CloseHandle(hToken);
  163. return FALSE;
  164. }
  165. }
  166. pUserToken = Alloc(HEAP_ZERO_MEMORY, cbTokenBuffer);
  167. if (!pUserToken)
  168. {
  169. CloseHandle(hToken);
  170. return FALSE;
  171. }
  172. if (!GetTokenInformation(hToken, TokenUser, pUserToken, cbTokenBuffer, &cbTokenBuffer))
  173. {
  174. Free(pUserToken);
  175. CloseHandle(hToken);
  176. return FALSE;
  177. }
  178. CloseHandle(hToken);
  179. /* Retrieve the domain and user name */
  180. if (!LookupAccountSidW(NULL,
  181. pUserToken->User.Sid,
  182. NULL,
  183. &cbUserName,
  184. NULL,
  185. &cbDomainName,
  186. &SidNameUse))
  187. {
  188. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  189. {
  190. bRet = FALSE;
  191. goto done;
  192. }
  193. }
  194. lpUserName = Alloc(HEAP_ZERO_MEMORY, cbUserName * sizeof(WCHAR));
  195. if (lpUserName == NULL)
  196. {
  197. bRet = FALSE;
  198. goto done;
  199. }
  200. lpDomainName = Alloc(HEAP_ZERO_MEMORY, cbDomainName * sizeof(WCHAR));
  201. if (lpDomainName == NULL)
  202. {
  203. bRet = FALSE;
  204. goto done;
  205. }
  206. if (!LookupAccountSidW(NULL,
  207. pUserToken->User.Sid,
  208. lpUserName,
  209. &cbUserName,
  210. lpDomainName,
  211. &cbDomainName,
  212. &SidNameUse))
  213. {
  214. bRet = FALSE;
  215. goto done;
  216. }
  217. *UserName = lpUserName;
  218. *DomainName = lpDomainName;
  219. done:
  220. if (bRet == FALSE)
  221. {
  222. if (lpUserName != NULL)
  223. Free(lpUserName);
  224. if (lpDomainName != NULL)
  225. Free(lpDomainName);
  226. }
  227. Free(pUserToken);
  228. return bRet;
  229. }
  230. static
  231. VOID
  232. MAIN_SetMainWindowTitle(VOID)
  233. {
  234. LPWSTR caption;
  235. SIZE_T size;
  236. LPWSTR lpDomainName = NULL;
  237. LPWSTR lpUserName = NULL;
  238. if (GetUserAndDomainName(&lpUserName, &lpDomainName) && lpUserName && lpDomainName)
  239. {
  240. size = (256 + 3 + wcslen(lpDomainName) + wcslen(lpUserName) + 1) * sizeof(WCHAR);
  241. caption = Alloc(HEAP_ZERO_MEMORY, size);
  242. if (caption)
  243. {
  244. swprintf(caption, L"%s - %s\\%s", szTitle, lpDomainName, lpUserName);
  245. SetWindowTextW(Globals.hMainWnd, caption);
  246. Free(caption);
  247. }
  248. else
  249. {
  250. SetWindowTextW(Globals.hMainWnd, szTitle);
  251. }
  252. }
  253. else
  254. {
  255. SetWindowTextW(Globals.hMainWnd, szTitle);
  256. }
  257. if (lpUserName) Free(lpUserName);
  258. if (lpDomainName) Free(lpDomainName);
  259. }
  260. static
  261. BOOL
  262. MAIN_LoadSettings(VOID)
  263. {
  264. LPWSTR lpszTmp;
  265. LPWSTR lpszSection;
  266. LONG lRet;
  267. WCHAR dummy[2];
  268. LPWSTR lpszKeyValue;
  269. const LPCWSTR lpszIniFile = L"progman.ini";
  270. WCHAR szWinDir[MAX_PATH];
  271. LPWSTR lpszKey;
  272. DWORD Value;
  273. HKEY hKey;
  274. BOOL bIsIniMigrated;
  275. DWORD dwSize;
  276. LPWSTR lpszSections;
  277. LPWSTR lpszData;
  278. DWORD dwRet;
  279. DWORD dwType;
  280. LPWSTR lpszValue;
  281. bIsIniMigrated = FALSE;
  282. lpszSections = NULL;
  283. lpszData = NULL;
  284. /* Try to create/open the Program Manager user key */
  285. if (RegCreateKeyExW(HKEY_CURRENT_USER,
  286. L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Program Manager",
  287. 0,
  288. NULL,
  289. REG_OPTION_NON_VOLATILE,
  290. KEY_READ | KEY_WRITE,
  291. NULL,
  292. &Globals.hKeyProgMan,
  293. NULL) != ERROR_SUCCESS)
  294. {
  295. return FALSE;
  296. }
  297. /*
  298. * TODO: Add the explanation for the migration...
  299. */
  300. dwSize = sizeof(Value);
  301. lRet = RegQueryValueExW(Globals.hKeyProgMan, L"IniMigrated", NULL, &dwType, (LPBYTE)&Value, &dwSize);
  302. if (lRet != ERROR_SUCCESS || dwType != REG_DWORD)
  303. Value = 0;
  304. bIsIniMigrated = !!Value;
  305. if (bIsIniMigrated)
  306. {
  307. /* The migration was already done, just load the settings */
  308. goto LoadSettings;
  309. }
  310. /* Perform the migration */
  311. bIsIniMigrated = TRUE;
  312. dwSize = ARRAYSIZE(dummy);
  313. SetLastError(0);
  314. GetPrivateProfileSectionW(L"Settings", dummy, dwSize, lpszIniFile);
  315. if (GetLastError() == ERROR_FILE_NOT_FOUND)
  316. goto MigrationDone;
  317. SetLastError(0);
  318. GetPrivateProfileSectionW(L"Groups", dummy, dwSize, lpszIniFile);
  319. if (GetLastError() == ERROR_FILE_NOT_FOUND)
  320. goto MigrationDone;
  321. GetWindowsDirectoryW(szWinDir, ARRAYSIZE(szWinDir));
  322. // NOTE: GCC complains we cannot use the "\u2022" (UNICODE Code Point) notation for specifying the bullet character,
  323. // because it's only available in C++ or in C99. On the contrary MSVC is fine with it.
  324. // Instead we use a hex specification for the character: "\x2022".
  325. // Note also that the character "\x07" gives also a bullet, but a larger one.
  326. PrintString(
  327. L"The Program Manager has detected the presence of a legacy settings file PROGMAN.INI in the directory '%s' "
  328. L"and is going to migrate its contents into the current-user Program Manager settings registry key:\n"
  329. L"HKCU\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Program Manager"
  330. L"\n\n"
  331. L"\x2022 The migration operation will potentially overwrite all the existing current-user Program Manager settings in the registry by those stored in the PROGMAN.INI file.\n"
  332. L"\n"
  333. L"\x2022 The migration is done once, so that, at the next launch of the Program Manager, the new migrated settings are directly used.\n"
  334. L"\n"
  335. L"\x2022 It is possible to trigger later the migration by manually deleting the registry value \"IniMigrated\" under the current-user Program Manager settings registry key (specified above).\n"
  336. L"\n"
  337. L"Would you like to migrate its contents into the registry?",
  338. szWinDir);
  339. for (dwSize = BUFFER_SIZE; ; dwSize += BUFFER_SIZE)
  340. {
  341. lpszSections = Alloc(0, dwSize * sizeof(WCHAR));
  342. dwRet = GetPrivateProfileSectionNamesW(lpszSections, dwSize, lpszIniFile);
  343. if (dwRet < dwSize - 2)
  344. break;
  345. Free(lpszSections);
  346. }
  347. lpszSection = lpszSections;
  348. while (*lpszSection)
  349. {
  350. lRet = RegCreateKeyExW(Globals.hKeyProgMan,
  351. lpszSection,
  352. 0,
  353. NULL,
  354. REG_OPTION_NON_VOLATILE,
  355. KEY_WRITE,
  356. NULL,
  357. &hKey,
  358. NULL);
  359. if (lRet == ERROR_SUCCESS)
  360. {
  361. for (dwSize = BUFFER_SIZE; ; dwSize += BUFFER_SIZE)
  362. {
  363. lpszData = Alloc(0, dwSize * sizeof(WCHAR));
  364. dwRet = GetPrivateProfileSectionW(lpszSection, lpszData, dwSize, lpszIniFile);
  365. if (dwRet < dwSize - 2)
  366. break;
  367. Free(lpszData);
  368. }
  369. lpszKeyValue = lpszData;
  370. while (*lpszKeyValue)
  371. {
  372. lpszKey = lpszKeyValue;
  373. lpszValue = wcschr(lpszKeyValue, L'=');
  374. lpszKeyValue += (wcslen(lpszKeyValue) + 1);
  375. if (lpszValue)
  376. {
  377. *lpszValue = '\0';
  378. ++lpszValue;
  379. Value = wcstoul(lpszValue, &lpszTmp, 0);
  380. if (lpszTmp - lpszValue >= wcslen(lpszValue))
  381. {
  382. lpszValue = (LPWSTR)&Value;
  383. dwSize = sizeof(Value);
  384. dwType = REG_DWORD;
  385. }
  386. else
  387. {
  388. dwSize = wcslen(lpszValue) * sizeof(WCHAR);
  389. dwType = REG_SZ;
  390. }
  391. }
  392. else
  393. {
  394. dwSize = 0;
  395. dwType = REG_DWORD;
  396. }
  397. lRet = RegSetValueExW(hKey, lpszKey, 0, dwType, (LPBYTE)lpszValue, dwSize);
  398. }
  399. Free(lpszData);
  400. RegCloseKey(hKey);
  401. lpszSection += (wcslen(lpszSection) + 1);
  402. }
  403. }
  404. Free(lpszSections);
  405. MigrationDone:
  406. Value = TRUE;
  407. RegSetValueExW(Globals.hKeyProgMan, L"IniMigrated", 0, REG_DWORD, (LPBYTE)&Value, sizeof(Value));
  408. LoadSettings:
  409. /* Create the necessary registry keys for the Program Manager and load its settings from the registry */
  410. lRet = RegCreateKeyExW(Globals.hKeyProgMan,
  411. L"Settings",
  412. 0,
  413. NULL,
  414. REG_OPTION_NON_VOLATILE,
  415. KEY_READ | KEY_WRITE,
  416. NULL,
  417. &Globals.hKeyPMSettings,
  418. NULL);
  419. lRet = RegCreateKeyExW(Globals.hKeyProgMan,
  420. L"Common Groups",
  421. 0,
  422. NULL,
  423. REG_OPTION_NON_VOLATILE,
  424. KEY_READ | KEY_WRITE,
  425. NULL,
  426. &Globals.hKeyPMCommonGroups,
  427. NULL);
  428. lRet = RegCreateKeyExW(Globals.hKeyProgMan,
  429. L"Groups",
  430. 0,
  431. NULL,
  432. REG_OPTION_NON_VOLATILE,
  433. KEY_READ | KEY_WRITE,
  434. NULL,
  435. &Globals.hKeyPMAnsiGroups,
  436. NULL);
  437. lRet = RegCreateKeyExW(Globals.hKeyProgMan,
  438. L"UNICODE Groups",
  439. 0,
  440. NULL,
  441. REG_OPTION_NON_VOLATILE,
  442. KEY_READ | KEY_WRITE,
  443. NULL,
  444. &Globals.hKeyPMUnicodeGroups,
  445. NULL);
  446. lRet = RegCreateKeyExW(HKEY_CURRENT_USER,
  447. L"Program Groups",
  448. 0,
  449. NULL,
  450. REG_OPTION_NON_VOLATILE,
  451. KEY_READ | KEY_WRITE,
  452. NULL,
  453. &Globals.hKeyAnsiGroups,
  454. NULL);
  455. lRet = RegCreateKeyExW(HKEY_CURRENT_USER,
  456. L"UNICODE Program Groups",
  457. 0,
  458. NULL,
  459. REG_OPTION_NON_VOLATILE,
  460. KEY_READ | KEY_WRITE,
  461. NULL,
  462. &Globals.hKeyUnicodeGroups,
  463. NULL);
  464. lRet = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
  465. L"SOFTWARE\\Program Groups",
  466. 0,
  467. NULL,
  468. REG_OPTION_NON_VOLATILE,
  469. KEY_READ | KEY_WRITE,
  470. NULL,
  471. &Globals.hKeyCommonGroups,
  472. NULL);
  473. dwSize = sizeof(Globals.bAutoArrange);
  474. RegQueryValueExW(Globals.hKeyPMSettings, L"AutoArrange", NULL, &dwType, (LPBYTE)&Globals.bAutoArrange, &dwSize);
  475. dwSize = sizeof(Globals.bMinOnRun);
  476. RegQueryValueExW(Globals.hKeyPMSettings, L"MinOnRun", NULL, &dwType, (LPBYTE)&Globals.bMinOnRun, &dwSize);
  477. dwSize = sizeof(Globals.bSaveSettings);
  478. RegQueryValueExW(Globals.hKeyPMSettings, L"SaveSettings", NULL, &dwType, (LPBYTE)&Globals.bSaveSettings, &dwSize);
  479. return TRUE;
  480. }
  481. static
  482. BOOL
  483. MAIN_SaveSettings(VOID)
  484. {
  485. WINDOWPLACEMENT WndPl;
  486. DWORD dwSize;
  487. WCHAR buffer[100];
  488. WndPl.length = sizeof(WndPl);
  489. GetWindowPlacement(Globals.hMainWnd, &WndPl);
  490. swprintf(buffer, L"%d %d %d %d %d",
  491. WndPl.rcNormalPosition.left,
  492. WndPl.rcNormalPosition.top,
  493. WndPl.rcNormalPosition.right,
  494. WndPl.rcNormalPosition.bottom,
  495. WndPl.showCmd);
  496. dwSize = wcslen(buffer) * sizeof(WCHAR);
  497. RegSetValueExW(Globals.hKeyPMSettings, L"Window", 0, REG_SZ, (LPBYTE)buffer, dwSize);
  498. return TRUE;
  499. }
  500. /***********************************************************************
  501. *
  502. * WinMain
  503. */
  504. INT WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, INT nCmdShow)
  505. {
  506. MSG msg;
  507. INITCOMMONCONTROLSEX icex;
  508. /*
  509. * Set our shutdown parameters: we want to shutdown the very last,
  510. * but before any TaskMgr instance (which has a shutdown level of 1).
  511. */
  512. SetProcessShutdownParameters(2, 0);
  513. Globals.hInstance = hInstance;
  514. Globals.hGroups = NULL;
  515. Globals.hActiveGroup = NULL;
  516. /* Load Program Manager's settings */
  517. MAIN_LoadSettings();
  518. /* Load the default icons */
  519. Globals.hDefaultIcon = LoadIconW(NULL, MAKEINTRESOURCEW(IDI_WINLOGO));
  520. Globals.hMainIcon = LoadIconW(Globals.hInstance, MAKEINTRESOURCEW(IDI_APPICON));
  521. Globals.hPersonalGroupIcon = LoadIconW(Globals.hInstance, MAKEINTRESOURCEW(IDI_GROUP_PERSONAL_ICON));
  522. Globals.hCommonGroupIcon = LoadIconW(Globals.hInstance, MAKEINTRESOURCEW(IDI_GROUP_COMMON_ICON));
  523. /* Initialize the common controls */
  524. icex.dwSize = sizeof(icex);
  525. icex.dwICC = ICC_HOTKEY_CLASS | ICC_LISTVIEW_CLASSES; // | ICC_STANDARD_CLASSES;
  526. InitCommonControlsEx(&icex);
  527. /* Register the window classes */
  528. if (!hPrevInstance) // FIXME: Unused on Win32!
  529. {
  530. if (!MAIN_RegisterMainWinClass()) goto Quit;
  531. if (!GROUP_RegisterGroupWinClass()) goto Quit;
  532. }
  533. /* Set up the strings, the main window, the accelerators, the menu, and the MDI child window */
  534. STRING_LoadStrings();
  535. MAIN_CreateMainWindow();
  536. Globals.hAccel = LoadAcceleratorsW(Globals.hInstance, MAKEINTRESOURCEW(IDA_ACCEL));
  537. STRING_LoadMenus();
  538. MAIN_CreateMDIWindow();
  539. /* Load all the groups */
  540. // MAIN_CreateGroups();
  541. MAIN_LoadGroups();
  542. /* Load the Startup group: start the initial applications */
  543. MAIN_AutoStart();
  544. /* Message loop */
  545. while (GetMessageW(&msg, NULL, 0, 0))
  546. {
  547. if (!TranslateMDISysAccel(Globals.hMDIWnd, &msg) &&
  548. !TranslateAcceleratorW(Globals.hMainWnd, Globals.hAccel, &msg))
  549. {
  550. TranslateMessage(&msg);
  551. DispatchMessageW(&msg);
  552. }
  553. }
  554. Quit:
  555. /* Save the settings, close the registry keys and quit */
  556. // MAIN_SaveSettings();
  557. RegCloseKey(Globals.hKeyCommonGroups);
  558. RegCloseKey(Globals.hKeyUnicodeGroups);
  559. RegCloseKey(Globals.hKeyAnsiGroups);
  560. RegCloseKey(Globals.hKeyPMUnicodeGroups);
  561. RegCloseKey(Globals.hKeyPMAnsiGroups);
  562. RegCloseKey(Globals.hKeyPMCommonGroups);
  563. RegCloseKey(Globals.hKeyPMSettings);
  564. RegCloseKey(Globals.hKeyProgMan);
  565. return 0;
  566. }
  567. /***********************************************************************
  568. *
  569. * MAIN_CreateGroups
  570. */
  571. #if 0
  572. static VOID MAIN_CreateGroups(VOID)
  573. {
  574. CHAR buffer[BUFFER_SIZE];
  575. CHAR szPath[MAX_PATHNAME_LEN];
  576. CHAR key[20], *ptr;
  577. /* Initialize groups according the `Order' entry of `progman.ini' */
  578. GetPrivateProfileStringA("Settings", "Order", "", buffer, sizeof(buffer), Globals.lpszIniFile);
  579. ptr = buffer;
  580. while (ptr < buffer + sizeof(buffer))
  581. {
  582. int num, skip, ret;
  583. ret = sscanf(ptr, "%d%n", &num, &skip);
  584. if (ret == 0)
  585. MAIN_MessageBoxIDS_s(IDS_FILE_READ_ERROR_s, Globals.lpszIniFile, IDS_ERROR, MB_OK);
  586. if (ret != 1) break;
  587. sprintf(key, "Group%d", num);
  588. GetPrivateProfileStringA("Groups", key, "", szPath,
  589. sizeof(szPath), Globals.lpszIniFile);
  590. if (!szPath[0]) continue;
  591. GRPFILE_ReadGroupFile(szPath);
  592. ptr += skip;
  593. }
  594. /* FIXME initialize other groups, not enumerated by `Order' */
  595. }
  596. #endif
  597. static VOID MAIN_LoadGroups(VOID)
  598. {
  599. }
  600. /***********************************************************************
  601. *
  602. * MAIN_AutoStart
  603. */
  604. static VOID MAIN_AutoStart(VOID)
  605. {
  606. LONG lRet;
  607. DWORD dwSize;
  608. DWORD dwType;
  609. PROGGROUP* hGroup;
  610. PROGRAM* hProgram;
  611. WCHAR buffer[BUFFER_SIZE];
  612. dwSize = sizeof(buffer);
  613. lRet = RegQueryValueExW(Globals.hKeyPMSettings, L"Startup", NULL, &dwType, (LPBYTE)buffer, &dwSize);
  614. if (lRet != ERROR_SUCCESS || dwType != REG_SZ)
  615. return;
  616. for (hGroup = Globals.hGroups; hGroup; hGroup = hGroup->hNext)
  617. {
  618. if (_wcsicmp(buffer, hGroup->hName) == 0)
  619. {
  620. for (hProgram = hGroup->hPrograms; hProgram; hProgram = hProgram->hNext)
  621. PROGRAM_ExecuteProgram(hProgram);
  622. }
  623. }
  624. }
  625. /***********************************************************************
  626. *
  627. * MAIN_MainWndProc
  628. */
  629. static LRESULT CALLBACK MAIN_MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  630. {
  631. switch (uMsg)
  632. {
  633. case WM_INITMENU:
  634. {
  635. PROGGROUP* hActiveGroup = GROUP_ActiveGroup();
  636. if (hActiveGroup)
  637. {
  638. if (PROGRAM_ActiveProgram(hActiveGroup))
  639. {
  640. EnableMenuItem(Globals.hFileMenu, PM_OPEN, MF_ENABLED);
  641. EnableMenuItem(Globals.hFileMenu, PM_MOVE, MF_ENABLED);
  642. EnableMenuItem(Globals.hFileMenu, PM_COPY, MF_ENABLED);
  643. EnableMenuItem(Globals.hFileMenu, PM_DELETE , MF_ENABLED);
  644. EnableMenuItem(Globals.hFileMenu, PM_ATTRIBUTES, MF_ENABLED);
  645. }
  646. else
  647. {
  648. if (!hActiveGroup->hWnd || IsIconic(hActiveGroup->hWnd))
  649. EnableMenuItem(Globals.hFileMenu, PM_OPEN, MF_ENABLED);
  650. else
  651. EnableMenuItem(Globals.hFileMenu, PM_OPEN, MF_GRAYED);
  652. EnableMenuItem(Globals.hFileMenu, PM_MOVE, MF_GRAYED);
  653. EnableMenuItem(Globals.hFileMenu, PM_COPY, MF_GRAYED);
  654. EnableMenuItem(Globals.hFileMenu, PM_DELETE , MF_ENABLED);
  655. EnableMenuItem(Globals.hFileMenu, PM_ATTRIBUTES, MF_ENABLED);
  656. }
  657. }
  658. else
  659. {
  660. EnableMenuItem(Globals.hFileMenu, PM_OPEN, MF_GRAYED);
  661. EnableMenuItem(Globals.hFileMenu, PM_MOVE, MF_GRAYED);
  662. EnableMenuItem(Globals.hFileMenu, PM_COPY, MF_GRAYED);
  663. EnableMenuItem(Globals.hFileMenu, PM_DELETE , MF_GRAYED);
  664. EnableMenuItem(Globals.hFileMenu, PM_ATTRIBUTES, MF_GRAYED);
  665. }
  666. CheckMenuItem(Globals.hOptionMenu, PM_AUTO_ARRANGE,
  667. MF_BYCOMMAND | (Globals.bAutoArrange ? MF_CHECKED : MF_UNCHECKED));
  668. CheckMenuItem(Globals.hOptionMenu, PM_MIN_ON_RUN,
  669. MF_BYCOMMAND | (Globals.bMinOnRun ? MF_CHECKED : MF_UNCHECKED));
  670. CheckMenuItem(Globals.hOptionMenu, PM_SAVE_SETTINGS,
  671. MF_BYCOMMAND | (Globals.bSaveSettings ? MF_CHECKED : MF_UNCHECKED));
  672. break;
  673. }
  674. case WM_DESTROY:
  675. if (Globals.bSaveSettings)
  676. MAIN_SaveSettings();
  677. PostQuitMessage(0);
  678. break;
  679. case WM_COMMAND:
  680. if (LOWORD(wParam) < PM_FIRST_CHILD)
  681. MAIN_MenuCommand(hWnd, LOWORD(wParam), lParam);
  682. break;
  683. }
  684. return DefFrameProcW(hWnd, Globals.hMDIWnd, uMsg, wParam, lParam);
  685. }
  686. /***********************************************************************
  687. *
  688. * MAIN_MenuCommand
  689. */
  690. static VOID MAIN_MenuCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
  691. {
  692. #if 0
  693. HLOCAL hActiveGroup = GROUP_ActiveGroup();
  694. HLOCAL hActiveProgram = PROGRAM_ActiveProgram(hActiveGroup);
  695. HWND hActiveGroupWnd = GROUP_GroupWnd(hActiveGroup);
  696. switch(wParam)
  697. {
  698. /* Menu File */
  699. case PM_NEW:
  700. switch (DIALOG_New((hActiveGroupWnd && !IsIconic(hActiveGroupWnd)) ?
  701. PM_NEW_PROGRAM : PM_NEW_GROUP))
  702. {
  703. case PM_NEW_PROGRAM:
  704. if (hActiveGroup) PROGRAM_NewProgram(hActiveGroup);
  705. break;
  706. case PM_NEW_GROUP:
  707. GROUP_NewGroup();
  708. break;
  709. }
  710. break;
  711. case PM_DELETE:
  712. if (hActiveProgram)
  713. {
  714. if (DIALOG_Delete(IDS_DELETE_PROGRAM_s, PROGRAM_ProgramName(hActiveProgram)))
  715. PROGRAM_DeleteProgram(hActiveProgram, TRUE);
  716. }
  717. else if (hActiveGroup)
  718. {
  719. if (DIALOG_Delete(IDS_DELETE_GROUP_s, GROUP_GroupName(hActiveGroup)))
  720. GROUP_DeleteGroup(hActiveGroup);
  721. }
  722. break;
  723. case PM_SAVE_SETTINGS:
  724. Globals.bSaveSettings = !Globals.bSaveSettings;
  725. CheckMenuItem(Globals.hOptionMenu, PM_SAVE_SETTINGS,
  726. MF_BYCOMMAND | (Globals.bSaveSettings ?
  727. MF_CHECKED : MF_UNCHECKED));
  728. WritePrivateProfileStringA("Settings", "SaveSettings",
  729. Globals.bSaveSettings ? "1" : "0",
  730. Globals.lpszIniFile);
  731. WritePrivateProfileStringA(NULL,NULL,NULL,Globals.lpszIniFile); /* flush it */
  732. break;
  733. case PM_ARRANGE:
  734. if (hActiveGroupWnd && !IsIconic(hActiveGroupWnd))
  735. ArrangeIconicWindows(hActiveGroupWnd);
  736. else
  737. SendMessageW(Globals.hMDIWnd, WM_MDIICONARRANGE, 0, 0);
  738. break;
  739. }
  740. #endif
  741. DWORD Value;
  742. PROGGROUP* hActiveGroup;
  743. PROGRAM* hActiveProgram;
  744. HWND hActiveGroupWnd;
  745. hActiveGroup = GROUP_ActiveGroup();
  746. hActiveProgram = PROGRAM_ActiveProgram(hActiveGroup);
  747. hActiveGroupWnd = (hActiveGroup ? hActiveGroup->hWnd : NULL);
  748. switch (wParam)
  749. {
  750. /* Menu File */
  751. case PM_NEW:
  752. {
  753. BOOL Success;
  754. INT nResult;
  755. if (!hActiveGroupWnd || IsIconic(hActiveGroupWnd))
  756. Success = DIALOG_New(PM_NEW_GROUP, &nResult);
  757. else
  758. Success = DIALOG_New(PM_NEW_PROGRAM, &nResult);
  759. if (!Success)
  760. break;
  761. if (nResult & 1)
  762. {
  763. GROUPFORMAT format;
  764. BOOL bIsCommonGroup;
  765. format = (nResult & 0xC) >> 2;
  766. bIsCommonGroup = (nResult & 2) != 0;
  767. GROUP_NewGroup(format, bIsCommonGroup);
  768. }
  769. else if (hActiveGroup)
  770. {
  771. PROGRAM_NewProgram(hActiveGroup);
  772. }
  773. break;
  774. }
  775. case PM_OPEN:
  776. if (hActiveProgram)
  777. PROGRAM_ExecuteProgram(hActiveProgram);
  778. else if (hActiveGroupWnd)
  779. OpenIcon(hActiveGroupWnd);
  780. break;
  781. case PM_MOVE:
  782. case PM_COPY:
  783. if (hActiveProgram)
  784. PROGRAM_CopyMoveProgram(hActiveProgram, wParam == PM_MOVE);
  785. break;
  786. case PM_DELETE:
  787. {
  788. if (hActiveProgram)
  789. {
  790. if (DIALOG_Delete(IDS_DELETE_PROGRAM_s, hActiveProgram->hName))
  791. PROGRAM_DeleteProgram(hActiveProgram, TRUE);
  792. }
  793. else if (hActiveGroup && DIALOG_Delete(IDS_DELETE_GROUP_s, hActiveGroup->hName))
  794. {
  795. GROUP_DeleteGroup(hActiveGroup);
  796. }
  797. break;
  798. }
  799. case PM_ATTRIBUTES:
  800. if (hActiveProgram)
  801. PROGRAM_ModifyProgram(hActiveProgram);
  802. else if (hActiveGroup)
  803. GROUP_ModifyGroup(hActiveGroup);
  804. break;
  805. case PM_EXECUTE:
  806. DIALOG_Execute();
  807. break;
  808. case PM_EXIT:
  809. // MAIN_SaveSettings();
  810. PostQuitMessage(0);
  811. break;
  812. /* Menu Options */
  813. case PM_AUTO_ARRANGE:
  814. Globals.bAutoArrange = !Globals.bAutoArrange;
  815. CheckMenuItem(Globals.hOptionMenu, PM_AUTO_ARRANGE,
  816. MF_BYCOMMAND | (Globals.bAutoArrange ? MF_CHECKED : MF_UNCHECKED));
  817. Value = Globals.bAutoArrange;
  818. RegSetValueExW(Globals.hKeyPMSettings, L"AutoArrange", 0, REG_DWORD, (LPBYTE)&Value, sizeof(Value));
  819. break;
  820. case PM_MIN_ON_RUN:
  821. Globals.bMinOnRun = !Globals.bMinOnRun;
  822. CheckMenuItem(Globals.hOptionMenu, PM_MIN_ON_RUN,
  823. MF_BYCOMMAND | (Globals.bMinOnRun ? MF_CHECKED : MF_UNCHECKED));
  824. Value = Globals.bMinOnRun;
  825. RegSetValueExW(Globals.hKeyPMSettings, L"MinOnRun", 0, REG_DWORD, (LPBYTE)&Value, sizeof(Value));
  826. break;
  827. case PM_SAVE_SETTINGS:
  828. Globals.bSaveSettings = !Globals.bSaveSettings;
  829. CheckMenuItem(Globals.hOptionMenu, PM_SAVE_SETTINGS,
  830. MF_BYCOMMAND | (Globals.bSaveSettings ? MF_CHECKED : MF_UNCHECKED));
  831. Value = Globals.bSaveSettings;
  832. RegSetValueExW(Globals.hKeyPMSettings, L"SaveSettings", 0, REG_DWORD, (LPBYTE)&Value, sizeof(Value));
  833. break;
  834. case PM_SAVE_SETTINGS_NOW:
  835. MAIN_SaveSettings();
  836. break;
  837. /* Menu Windows */
  838. case PM_OVERLAP:
  839. SendMessageW(Globals.hMDIWnd, WM_MDICASCADE, 0, 0);
  840. break;
  841. case PM_SIDE_BY_SIDE:
  842. SendMessageW(Globals.hMDIWnd, WM_MDITILE, MDITILE_VERTICAL, 0);
  843. break;
  844. case PM_ARRANGE:
  845. if (!hActiveGroupWnd || IsIconic(hActiveGroupWnd))
  846. SendMessageW(Globals.hMDIWnd, WM_MDIICONARRANGE, 0, 0);
  847. else
  848. SendMessageA(hActiveGroup->hListView, LVM_ARRANGE, 0, 0);
  849. break;
  850. /* Menu Help */
  851. case PM_CONTENTS:
  852. if (!WinHelpW(Globals.hMainWnd, L"progman.hlp", HELP_CONTENTS, 0))
  853. MAIN_MessageBoxIDS(IDS_WINHELP_ERROR, IDS_ERROR, MB_OK);
  854. break;
  855. case PM_ABOUT:
  856. ShellAboutW(hWnd, szTitle, NULL, Globals.hMainIcon);
  857. break;
  858. default:
  859. MAIN_MessageBoxIDS(IDS_NOT_IMPLEMENTED, IDS_ERROR, MB_OK);
  860. break;
  861. }
  862. }
  863. /***********************************************************************
  864. *
  865. * MAIN_RegisterMainWinClass
  866. */
  867. static ATOM MAIN_RegisterMainWinClass(VOID)
  868. {
  869. WNDCLASSW wndClass;
  870. wndClass.style = CS_HREDRAW | CS_VREDRAW;
  871. wndClass.lpfnWndProc = MAIN_MainWndProc;
  872. wndClass.cbClsExtra = 0;
  873. wndClass.cbWndExtra = 0;
  874. wndClass.hInstance = Globals.hInstance;
  875. wndClass.hIcon = Globals.hMainIcon;
  876. wndClass.hCursor = LoadCursorW(NULL, MAKEINTRESOURCEW(IDC_ARROW));
  877. wndClass.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
  878. wndClass.lpszMenuName = NULL;
  879. wndClass.lpszClassName = STRING_MAIN_WIN_CLASS_NAME;
  880. return RegisterClassW(&wndClass);
  881. }
  882. /***********************************************************************
  883. *
  884. * MAIN_CreateMainWindow
  885. */
  886. static VOID MAIN_CreateMainWindow(VOID)
  887. {
  888. INT left, top, right, bottom;
  889. INT width, height;
  890. INT nCmdShow;
  891. WCHAR buffer[100];
  892. LONG lRet;
  893. DWORD dwSize;
  894. DWORD dwType;
  895. Globals.hMDIWnd = NULL;
  896. Globals.hMainMenu = NULL;
  897. /* Get the geometry of the main window */
  898. dwSize = sizeof(buffer);
  899. lRet = RegQueryValueExW(Globals.hKeyPMSettings, L"Window", NULL, &dwType, (LPBYTE)buffer, &dwSize);
  900. if (lRet != ERROR_SUCCESS || dwType != REG_SZ)
  901. buffer[0] = '\0';
  902. if (swscanf(buffer, L"%d %d %d %d %d", &left, &top, &right, &bottom, &nCmdShow) == 5)
  903. {
  904. width = right - left;
  905. height = bottom - top;
  906. }
  907. else
  908. {
  909. left = top = width = height = CW_USEDEFAULT;
  910. nCmdShow = SW_SHOWNORMAL;
  911. }
  912. /* Create the main window */
  913. Globals.hMainWnd =
  914. CreateWindowW(STRING_MAIN_WIN_CLASS_NAME,
  915. szTitle,
  916. WS_OVERLAPPEDWINDOW, // /* | WS_CLIPSIBLINGS | WS_CLIPCHILDREN */
  917. left, top, width, height,
  918. NULL, NULL,
  919. Globals.hInstance,
  920. NULL);
  921. MAIN_SetMainWindowTitle();
  922. ShowWindow(Globals.hMainWnd, nCmdShow);
  923. UpdateWindow(Globals.hMainWnd);
  924. }
  925. /***********************************************************************
  926. *
  927. * MAIN_CreateMDIWindow
  928. */
  929. static VOID MAIN_CreateMDIWindow(VOID)
  930. {
  931. CLIENTCREATESTRUCT ccs;
  932. RECT rect;
  933. /* Get the geometry of the MDI window */
  934. GetClientRect(Globals.hMainWnd, &rect);
  935. ccs.hWindowMenu = Globals.hWindowsMenu;
  936. ccs.idFirstChild = PM_FIRST_CHILD;
  937. /* Create MDI Window */
  938. Globals.hMDIWnd =
  939. CreateWindowW(WC_MDICLIENT, NULL, WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL, // WS_CHILDWINDOW | ...
  940. rect.left, rect.top,
  941. rect.right - rect.left, rect.bottom - rect.top,
  942. Globals.hMainWnd, 0,
  943. Globals.hInstance, &ccs);
  944. /* Reset the background of the MDI client window (default: COLOR_APPWORKSPACE + 1) */
  945. SetClassLongPtrW(Globals.hMDIWnd, GCLP_HBRBACKGROUND, (COLOR_WINDOW + 1));
  946. ShowWindow(Globals.hMDIWnd, SW_SHOW);
  947. UpdateWindow(Globals.hMDIWnd);
  948. }
  949. /**********************************************************************/
  950. /***********************************************************************
  951. *
  952. * MAIN_MessageBoxIDS
  953. */
  954. INT MAIN_MessageBoxIDS(UINT ids_text, UINT ids_title, WORD type)
  955. {
  956. WCHAR text[MAX_STRING_LEN];
  957. WCHAR title[MAX_STRING_LEN];
  958. LoadStringW(Globals.hInstance, ids_text , text , ARRAYSIZE(text));
  959. LoadStringW(Globals.hInstance, ids_title, title, ARRAYSIZE(title));
  960. return MessageBoxW(Globals.hMainWnd, text, title, type);
  961. }
  962. /***********************************************************************
  963. *
  964. * MAIN_MessageBoxIDS_s
  965. */
  966. INT MAIN_MessageBoxIDS_s(UINT ids_text, LPCWSTR str, UINT ids_title, WORD type)
  967. {
  968. WCHAR text[MAX_STRING_LEN];
  969. WCHAR title[MAX_STRING_LEN];
  970. WCHAR newtext[MAX_STRING_LEN + MAX_PATHNAME_LEN];
  971. LoadStringW(Globals.hInstance, ids_text , text , ARRAYSIZE(text));
  972. LoadStringW(Globals.hInstance, ids_title, title, ARRAYSIZE(title));
  973. wsprintfW(newtext, text, str);
  974. return MessageBoxW(Globals.hMainWnd, newtext, title, type);
  975. }
  976. /***********************************************************************
  977. *
  978. * MAIN_ReplaceString
  979. */
  980. VOID MAIN_ReplaceString(LPWSTR* string, LPWSTR replace)
  981. {
  982. LPWSTR newstring;
  983. newstring = Alloc(HEAP_ZERO_MEMORY, (wcslen(replace) + 1) * sizeof(WCHAR));
  984. if (newstring)
  985. {
  986. wcscpy(newstring, replace);
  987. *string = newstring;
  988. }
  989. else
  990. {
  991. MAIN_MessageBoxIDS(IDS_OUT_OF_MEMORY, IDS_ERROR, MB_OK);
  992. }
  993. }