[DCOMLAUNCH] Add a DcomLaunch service stub
[reactos.git] / 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 StringCbPrintfW(caption, size, 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 StringCbPrintfW(buffer, sizeof(buffer),
586 L"%d %d %d %d %d",
587 WndPl.rcNormalPosition.left,
588 WndPl.rcNormalPosition.top,
589 WndPl.rcNormalPosition.right,
590 WndPl.rcNormalPosition.bottom,
591 WndPl.showCmd);
592
593 dwSize = wcslen(buffer) * sizeof(WCHAR);
594 RegSetValueExW(Globals.hKeyPMSettings, L"Window", 0, REG_SZ, (LPBYTE)buffer, dwSize);
595
596 return TRUE;
597 }
598
599
600 /***********************************************************************
601 *
602 * WinMain
603 */
604
605 INT WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, INT nCmdShow)
606 {
607 MSG msg;
608 INITCOMMONCONTROLSEX icex;
609
610 /*
611 * Set our shutdown parameters: we want to shutdown the very last,
612 * but before any TaskMgr instance (which has a shutdown level of 1).
613 */
614 SetProcessShutdownParameters(2, 0);
615
616 Globals.hInstance = hInstance;
617 Globals.hGroups = NULL;
618 Globals.hActiveGroup = NULL;
619
620 /* Load Program Manager's settings */
621 MAIN_LoadSettings();
622
623 /* Load the default icons */
624 Globals.hDefaultIcon = LoadIconW(NULL, MAKEINTRESOURCEW(IDI_WINLOGO));
625 Globals.hMainIcon = LoadIconW(Globals.hInstance, MAKEINTRESOURCEW(IDI_APPICON));
626 Globals.hPersonalGroupIcon = LoadIconW(Globals.hInstance, MAKEINTRESOURCEW(IDI_GROUP_PERSONAL_ICON));
627 Globals.hCommonGroupIcon = LoadIconW(Globals.hInstance, MAKEINTRESOURCEW(IDI_GROUP_COMMON_ICON));
628
629 /* Initialize the common controls */
630 icex.dwSize = sizeof(icex);
631 icex.dwICC = ICC_HOTKEY_CLASS | ICC_LISTVIEW_CLASSES; // | ICC_STANDARD_CLASSES;
632 InitCommonControlsEx(&icex);
633
634 /* Register the window classes */
635 if (!hPrevInstance) // FIXME: Unused on Win32!
636 {
637 if (!MAIN_RegisterMainWinClass()) goto Quit;
638 if (!GROUP_RegisterGroupWinClass()) goto Quit;
639 }
640
641 /* Set up the strings, the main window, the accelerators, the menu, and the MDI child window */
642 STRING_LoadStrings();
643 MAIN_CreateMainWindow();
644 Globals.hAccel = LoadAcceleratorsW(Globals.hInstance, MAKEINTRESOURCEW(IDA_ACCEL));
645 STRING_LoadMenus();
646 MAIN_CreateMDIWindow();
647
648 /* Load all the groups */
649 // MAIN_CreateGroups();
650 MAIN_LoadGroups();
651
652 /* Load the Startup group: start the initial applications */
653 MAIN_AutoStart();
654
655 /* Message loop */
656 while (GetMessageW(&msg, NULL, 0, 0))
657 {
658 if (!TranslateMDISysAccel(Globals.hMDIWnd, &msg) &&
659 !TranslateAcceleratorW(Globals.hMainWnd, Globals.hAccel, &msg))
660 {
661 TranslateMessage(&msg);
662 DispatchMessageW(&msg);
663 }
664 }
665
666 Quit:
667
668 /* Save the settings, close the registry keys and quit */
669
670 // MAIN_SaveSettings();
671 RegCloseKey(Globals.hKeyCommonGroups);
672 RegCloseKey(Globals.hKeyUnicodeGroups);
673 RegCloseKey(Globals.hKeyAnsiGroups);
674 RegCloseKey(Globals.hKeyPMUnicodeGroups);
675 RegCloseKey(Globals.hKeyPMAnsiGroups);
676 RegCloseKey(Globals.hKeyPMCommonGroups);
677 RegCloseKey(Globals.hKeyPMSettings);
678 RegCloseKey(Globals.hKeyProgMan);
679
680 return 0;
681 }
682
683 /***********************************************************************
684 *
685 * MAIN_CreateGroups
686 */
687
688 #if 0
689 static VOID MAIN_CreateGroups(VOID)
690 {
691 CHAR buffer[BUFFER_SIZE];
692 CHAR szPath[MAX_PATHNAME_LEN];
693 CHAR key[20], *ptr;
694
695 /* Initialize groups according the `Order' entry of `progman.ini' */
696 GetPrivateProfileStringA("Settings", "Order", "", buffer, sizeof(buffer), Globals.lpszIniFile);
697 ptr = buffer;
698 while (ptr < buffer + sizeof(buffer))
699 {
700 int num, skip, ret;
701 ret = sscanf(ptr, "%d%n", &num, &skip);
702 if (ret == 0)
703 MAIN_MessageBoxIDS_s(IDS_FILE_READ_ERROR_s, Globals.lpszIniFile, IDS_ERROR, MB_OK);
704 if (ret != 1) break;
705
706 sprintf(key, "Group%d", num);
707 GetPrivateProfileStringA("Groups", key, "", szPath,
708 sizeof(szPath), Globals.lpszIniFile);
709 if (!szPath[0]) continue;
710
711 GRPFILE_ReadGroupFile(szPath);
712
713 ptr += skip;
714 }
715 /* FIXME initialize other groups, not enumerated by `Order' */
716 }
717 #endif
718
719 static VOID MAIN_LoadGroups(VOID)
720 {
721 }
722
723 /***********************************************************************
724 *
725 * MAIN_AutoStart
726 */
727
728 static VOID MAIN_AutoStart(VOID)
729 {
730 LONG lRet;
731 DWORD dwSize;
732 DWORD dwType;
733
734 PROGGROUP* hGroup;
735 PROGRAM* hProgram;
736
737 WCHAR buffer[BUFFER_SIZE];
738
739 dwSize = sizeof(buffer);
740 lRet = RegQueryValueExW(Globals.hKeyPMSettings, L"Startup", NULL, &dwType, (LPBYTE)buffer, &dwSize);
741 if (lRet != ERROR_SUCCESS || dwType != REG_SZ)
742 return;
743
744 for (hGroup = Globals.hGroups; hGroup; hGroup = hGroup->hNext)
745 {
746 if (_wcsicmp(buffer, hGroup->hName) == 0)
747 {
748 for (hProgram = hGroup->hPrograms; hProgram; hProgram = hProgram->hNext)
749 PROGRAM_ExecuteProgram(hProgram);
750 }
751 }
752 }
753
754 /***********************************************************************
755 *
756 * MAIN_MainWndProc
757 */
758
759 static LRESULT CALLBACK MAIN_MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
760 {
761 switch (uMsg)
762 {
763 case WM_INITMENU:
764 {
765 PROGGROUP* hActiveGroup = GROUP_ActiveGroup();
766 if (hActiveGroup)
767 {
768 if (PROGRAM_ActiveProgram(hActiveGroup))
769 {
770 EnableMenuItem(Globals.hFileMenu, PM_OPEN, MF_ENABLED);
771 EnableMenuItem(Globals.hFileMenu, PM_MOVE, MF_ENABLED);
772 EnableMenuItem(Globals.hFileMenu, PM_COPY, MF_ENABLED);
773 EnableMenuItem(Globals.hFileMenu, PM_DELETE , MF_ENABLED);
774 EnableMenuItem(Globals.hFileMenu, PM_ATTRIBUTES, MF_ENABLED);
775 }
776 else
777 {
778 if (!hActiveGroup->hWnd || IsIconic(hActiveGroup->hWnd))
779 EnableMenuItem(Globals.hFileMenu, PM_OPEN, MF_ENABLED);
780 else
781 EnableMenuItem(Globals.hFileMenu, PM_OPEN, MF_GRAYED);
782
783 EnableMenuItem(Globals.hFileMenu, PM_MOVE, MF_GRAYED);
784 EnableMenuItem(Globals.hFileMenu, PM_COPY, MF_GRAYED);
785 EnableMenuItem(Globals.hFileMenu, PM_DELETE , MF_ENABLED);
786 EnableMenuItem(Globals.hFileMenu, PM_ATTRIBUTES, MF_ENABLED);
787 }
788 }
789 else
790 {
791 EnableMenuItem(Globals.hFileMenu, PM_OPEN, MF_GRAYED);
792 EnableMenuItem(Globals.hFileMenu, PM_MOVE, MF_GRAYED);
793 EnableMenuItem(Globals.hFileMenu, PM_COPY, MF_GRAYED);
794 EnableMenuItem(Globals.hFileMenu, PM_DELETE , MF_GRAYED);
795 EnableMenuItem(Globals.hFileMenu, PM_ATTRIBUTES, MF_GRAYED);
796 }
797
798 CheckMenuItem(Globals.hOptionMenu, PM_AUTO_ARRANGE,
799 MF_BYCOMMAND | (Globals.bAutoArrange ? MF_CHECKED : MF_UNCHECKED));
800 CheckMenuItem(Globals.hOptionMenu, PM_MIN_ON_RUN,
801 MF_BYCOMMAND | (Globals.bMinOnRun ? MF_CHECKED : MF_UNCHECKED));
802 CheckMenuItem(Globals.hOptionMenu, PM_SAVE_SETTINGS,
803 MF_BYCOMMAND | (Globals.bSaveSettings ? MF_CHECKED : MF_UNCHECKED));
804 break;
805 }
806
807 case WM_DESTROY:
808 if (Globals.bSaveSettings)
809 MAIN_SaveSettings();
810 PostQuitMessage(0);
811 break;
812
813 case WM_COMMAND:
814 if (LOWORD(wParam) < PM_FIRST_CHILD)
815 MAIN_MenuCommand(hWnd, LOWORD(wParam), lParam);
816 break;
817 }
818
819 return DefFrameProcW(hWnd, Globals.hMDIWnd, uMsg, wParam, lParam);
820 }
821
822
823 /***********************************************************************
824 *
825 * MAIN_MenuCommand
826 */
827
828 static VOID MAIN_MenuCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
829 {
830 #if 0
831 HLOCAL hActiveGroup = GROUP_ActiveGroup();
832 HLOCAL hActiveProgram = PROGRAM_ActiveProgram(hActiveGroup);
833 HWND hActiveGroupWnd = GROUP_GroupWnd(hActiveGroup);
834
835 switch(wParam)
836 {
837 /* Menu File */
838 case PM_NEW:
839 switch (DIALOG_New((hActiveGroupWnd && !IsIconic(hActiveGroupWnd)) ?
840 PM_NEW_PROGRAM : PM_NEW_GROUP))
841 {
842 case PM_NEW_PROGRAM:
843 if (hActiveGroup) PROGRAM_NewProgram(hActiveGroup);
844 break;
845
846 case PM_NEW_GROUP:
847 GROUP_NewGroup();
848 break;
849 }
850 break;
851
852
853 case PM_DELETE:
854 if (hActiveProgram)
855 {
856 if (DIALOG_Delete(IDS_DELETE_PROGRAM_s, PROGRAM_ProgramName(hActiveProgram)))
857 PROGRAM_DeleteProgram(hActiveProgram, TRUE);
858 }
859 else if (hActiveGroup)
860 {
861 if (DIALOG_Delete(IDS_DELETE_GROUP_s, GROUP_GroupName(hActiveGroup)))
862 GROUP_DeleteGroup(hActiveGroup);
863 }
864 break;
865
866
867
868 case PM_SAVE_SETTINGS:
869 Globals.bSaveSettings = !Globals.bSaveSettings;
870 CheckMenuItem(Globals.hOptionMenu, PM_SAVE_SETTINGS,
871 MF_BYCOMMAND | (Globals.bSaveSettings ?
872 MF_CHECKED : MF_UNCHECKED));
873 WritePrivateProfileStringA("Settings", "SaveSettings",
874 Globals.bSaveSettings ? "1" : "0",
875 Globals.lpszIniFile);
876 WritePrivateProfileStringA(NULL,NULL,NULL,Globals.lpszIniFile); /* flush it */
877 break;
878
879
880 case PM_ARRANGE:
881
882 if (hActiveGroupWnd && !IsIconic(hActiveGroupWnd))
883 ArrangeIconicWindows(hActiveGroupWnd);
884 else
885 SendMessageW(Globals.hMDIWnd, WM_MDIICONARRANGE, 0, 0);
886 break;
887
888 }
889
890
891
892
893 #endif
894
895 DWORD Value;
896
897 PROGGROUP* hActiveGroup;
898 PROGRAM* hActiveProgram;
899 HWND hActiveGroupWnd;
900
901 hActiveGroup = GROUP_ActiveGroup();
902 hActiveProgram = PROGRAM_ActiveProgram(hActiveGroup);
903 hActiveGroupWnd = (hActiveGroup ? hActiveGroup->hWnd : NULL);
904
905 switch (wParam)
906 {
907 /* Menu File */
908
909 case PM_NEW:
910 {
911 BOOL Success;
912 INT nResult;
913
914 if (!hActiveGroupWnd || IsIconic(hActiveGroupWnd))
915 Success = DIALOG_New(PM_NEW_GROUP, &nResult);
916 else
917 Success = DIALOG_New(PM_NEW_PROGRAM, &nResult);
918 if (!Success)
919 break;
920
921 if (nResult & 1)
922 {
923 GROUPFORMAT format;
924 BOOL bIsCommonGroup;
925
926 format = (nResult & 0xC) >> 2;
927 bIsCommonGroup = (nResult & 2) != 0;
928 GROUP_NewGroup(format, bIsCommonGroup);
929 }
930 else if (hActiveGroup)
931 {
932 PROGRAM_NewProgram(hActiveGroup);
933 }
934
935 break;
936 }
937
938 case PM_OPEN:
939 if (hActiveProgram)
940 PROGRAM_ExecuteProgram(hActiveProgram);
941 else if (hActiveGroupWnd)
942 OpenIcon(hActiveGroupWnd);
943 break;
944
945 case PM_MOVE:
946 case PM_COPY:
947 if (hActiveProgram)
948 PROGRAM_CopyMoveProgram(hActiveProgram, wParam == PM_MOVE);
949 break;
950
951 case PM_DELETE:
952 {
953 if (hActiveProgram)
954 {
955 if (DIALOG_Delete(IDS_DELETE_PROGRAM_s, hActiveProgram->hName))
956 PROGRAM_DeleteProgram(hActiveProgram, TRUE);
957 }
958 else if (hActiveGroup && DIALOG_Delete(IDS_DELETE_GROUP_s, hActiveGroup->hName))
959 {
960 GROUP_DeleteGroup(hActiveGroup);
961 }
962 break;
963 }
964
965 case PM_ATTRIBUTES:
966 if (hActiveProgram)
967 PROGRAM_ModifyProgram(hActiveProgram);
968 else if (hActiveGroup)
969 GROUP_ModifyGroup(hActiveGroup);
970 break;
971
972 case PM_EXECUTE:
973 DIALOG_Execute();
974 break;
975
976 case PM_EXIT:
977 // MAIN_SaveSettings();
978 PostQuitMessage(0);
979 break;
980
981
982 /* Menu Options */
983
984 case PM_AUTO_ARRANGE:
985 Globals.bAutoArrange = !Globals.bAutoArrange;
986 CheckMenuItem(Globals.hOptionMenu, PM_AUTO_ARRANGE,
987 MF_BYCOMMAND | (Globals.bAutoArrange ? MF_CHECKED : MF_UNCHECKED));
988 Value = Globals.bAutoArrange;
989 RegSetValueExW(Globals.hKeyPMSettings, L"AutoArrange", 0, REG_DWORD, (LPBYTE)&Value, sizeof(Value));
990 break;
991
992 case PM_MIN_ON_RUN:
993 Globals.bMinOnRun = !Globals.bMinOnRun;
994 CheckMenuItem(Globals.hOptionMenu, PM_MIN_ON_RUN,
995 MF_BYCOMMAND | (Globals.bMinOnRun ? MF_CHECKED : MF_UNCHECKED));
996 Value = Globals.bMinOnRun;
997 RegSetValueExW(Globals.hKeyPMSettings, L"MinOnRun", 0, REG_DWORD, (LPBYTE)&Value, sizeof(Value));
998 break;
999
1000 case PM_SAVE_SETTINGS:
1001 Globals.bSaveSettings = !Globals.bSaveSettings;
1002 CheckMenuItem(Globals.hOptionMenu, PM_SAVE_SETTINGS,
1003 MF_BYCOMMAND | (Globals.bSaveSettings ? MF_CHECKED : MF_UNCHECKED));
1004 Value = Globals.bSaveSettings;
1005 RegSetValueExW(Globals.hKeyPMSettings, L"SaveSettings", 0, REG_DWORD, (LPBYTE)&Value, sizeof(Value));
1006 break;
1007
1008 case PM_SAVE_SETTINGS_NOW:
1009 MAIN_SaveSettings();
1010 break;
1011
1012
1013 /* Menu Windows */
1014
1015 case PM_OVERLAP:
1016 SendMessageW(Globals.hMDIWnd, WM_MDICASCADE, 0, 0);
1017 break;
1018
1019 case PM_SIDE_BY_SIDE:
1020 SendMessageW(Globals.hMDIWnd, WM_MDITILE, MDITILE_VERTICAL, 0);
1021 break;
1022
1023 case PM_ARRANGE:
1024 if (!hActiveGroupWnd || IsIconic(hActiveGroupWnd))
1025 SendMessageW(Globals.hMDIWnd, WM_MDIICONARRANGE, 0, 0);
1026 else
1027 SendMessageA(hActiveGroup->hListView, LVM_ARRANGE, 0, 0);
1028 break;
1029
1030
1031 /* Menu Help */
1032
1033 case PM_CONTENTS:
1034 if (!WinHelpW(Globals.hMainWnd, L"progman.hlp", HELP_CONTENTS, 0))
1035 MAIN_MessageBoxIDS(IDS_WINHELP_ERROR, IDS_ERROR, MB_OK);
1036 break;
1037
1038 case PM_ABOUT:
1039 ShellAboutW(hWnd, szTitle, NULL, Globals.hMainIcon);
1040 break;
1041
1042 default:
1043 MAIN_MessageBoxIDS(IDS_NOT_IMPLEMENTED, IDS_ERROR, MB_OK);
1044 break;
1045 }
1046
1047 }
1048
1049 /***********************************************************************
1050 *
1051 * MAIN_RegisterMainWinClass
1052 */
1053
1054 static ATOM MAIN_RegisterMainWinClass(VOID)
1055 {
1056 WNDCLASSW wndClass;
1057
1058 wndClass.style = CS_HREDRAW | CS_VREDRAW;
1059 wndClass.lpfnWndProc = MAIN_MainWndProc;
1060 wndClass.cbClsExtra = 0;
1061 wndClass.cbWndExtra = 0;
1062 wndClass.hInstance = Globals.hInstance;
1063 wndClass.hIcon = Globals.hMainIcon;
1064 wndClass.hCursor = LoadCursorW(NULL, MAKEINTRESOURCEW(IDC_ARROW));
1065 wndClass.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
1066 wndClass.lpszMenuName = NULL;
1067 wndClass.lpszClassName = STRING_MAIN_WIN_CLASS_NAME;
1068
1069 return RegisterClassW(&wndClass);
1070 }
1071
1072 /***********************************************************************
1073 *
1074 * MAIN_CreateMainWindow
1075 */
1076
1077 static VOID MAIN_CreateMainWindow(VOID)
1078 {
1079 INT left, top, right, bottom;
1080 INT width, height;
1081 INT nCmdShow;
1082 WCHAR buffer[100];
1083
1084 LONG lRet;
1085 DWORD dwSize;
1086 DWORD dwType;
1087
1088 Globals.hMDIWnd = NULL;
1089 Globals.hMainMenu = NULL;
1090
1091 /* Get the geometry of the main window */
1092 dwSize = sizeof(buffer);
1093 lRet = RegQueryValueExW(Globals.hKeyPMSettings, L"Window", NULL, &dwType, (LPBYTE)buffer, &dwSize);
1094 if (lRet != ERROR_SUCCESS || dwType != REG_SZ)
1095 buffer[0] = '\0';
1096
1097 if (swscanf(buffer, L"%d %d %d %d %d", &left, &top, &right, &bottom, &nCmdShow) == 5)
1098 {
1099 width = right - left;
1100 height = bottom - top;
1101 }
1102 else
1103 {
1104 left = top = width = height = CW_USEDEFAULT;
1105 nCmdShow = SW_SHOWNORMAL;
1106 }
1107
1108 /* Create the main window */
1109 Globals.hMainWnd =
1110 CreateWindowW(STRING_MAIN_WIN_CLASS_NAME,
1111 szTitle,
1112 WS_OVERLAPPEDWINDOW, // /* | WS_CLIPSIBLINGS | WS_CLIPCHILDREN */
1113 left, top, width, height,
1114 NULL, NULL,
1115 Globals.hInstance,
1116 NULL);
1117
1118 MAIN_SetMainWindowTitle();
1119 ShowWindow(Globals.hMainWnd, nCmdShow);
1120 UpdateWindow(Globals.hMainWnd);
1121 }
1122
1123 /***********************************************************************
1124 *
1125 * MAIN_CreateMDIWindow
1126 */
1127
1128 static VOID MAIN_CreateMDIWindow(VOID)
1129 {
1130 CLIENTCREATESTRUCT ccs;
1131 RECT rect;
1132
1133 /* Get the geometry of the MDI window */
1134 GetClientRect(Globals.hMainWnd, &rect);
1135
1136 ccs.hWindowMenu = Globals.hWindowsMenu;
1137 ccs.idFirstChild = PM_FIRST_CHILD;
1138
1139 /* Create MDI Window */
1140 Globals.hMDIWnd =
1141 CreateWindowW(WC_MDICLIENT, NULL, WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL, // WS_CHILDWINDOW | ...
1142 rect.left, rect.top,
1143 rect.right - rect.left, rect.bottom - rect.top,
1144 Globals.hMainWnd, 0,
1145 Globals.hInstance, &ccs);
1146
1147 /* Reset the background of the MDI client window (default: COLOR_APPWORKSPACE + 1) */
1148 SetClassLongPtrW(Globals.hMDIWnd, GCLP_HBRBACKGROUND, (COLOR_WINDOW + 1));
1149
1150 ShowWindow(Globals.hMDIWnd, SW_SHOW);
1151 UpdateWindow(Globals.hMDIWnd);
1152 }
1153
1154 /**********************************************************************/
1155 /***********************************************************************
1156 *
1157 * MAIN_MessageBoxIDS
1158 */
1159 INT MAIN_MessageBoxIDS(UINT ids_text, UINT ids_title, WORD type)
1160 {
1161 WCHAR text[MAX_STRING_LEN];
1162 WCHAR title[MAX_STRING_LEN];
1163
1164 LoadStringW(Globals.hInstance, ids_text , text , ARRAYSIZE(text));
1165 LoadStringW(Globals.hInstance, ids_title, title, ARRAYSIZE(title));
1166
1167 return MessageBoxW(Globals.hMainWnd, text, title, type);
1168 }
1169
1170 /***********************************************************************
1171 *
1172 * MAIN_MessageBoxIDS_s
1173 */
1174 INT MAIN_MessageBoxIDS_s(UINT ids_text, LPCWSTR str, UINT ids_title, WORD type)
1175 {
1176 WCHAR text[MAX_STRING_LEN];
1177 WCHAR title[MAX_STRING_LEN];
1178 WCHAR newtext[MAX_STRING_LEN + MAX_PATHNAME_LEN];
1179
1180 LoadStringW(Globals.hInstance, ids_text , text , ARRAYSIZE(text));
1181 LoadStringW(Globals.hInstance, ids_title, title, ARRAYSIZE(title));
1182 wsprintfW(newtext, text, str);
1183
1184 return MessageBoxW(Globals.hMainWnd, newtext, title, type);
1185 }
1186
1187 /***********************************************************************
1188 *
1189 * MAIN_ReplaceString
1190 */
1191
1192 VOID MAIN_ReplaceString(LPWSTR* string, LPWSTR replace)
1193 {
1194 LPWSTR newstring;
1195
1196 newstring = Alloc(HEAP_ZERO_MEMORY, (wcslen(replace) + 1) * sizeof(WCHAR));
1197 if (newstring)
1198 {
1199 wcscpy(newstring, replace);
1200 *string = newstring;
1201 }
1202 else
1203 {
1204 MAIN_MessageBoxIDS(IDS_OUT_OF_MEMORY, IDS_ERROR, MB_OK);
1205 }
1206 }