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 } 1207