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