1: /*
     2:  ============================================================================
     3:  xoblite™ -> an advanced "extended shell" for Microsoft® Windows® 11
     4:  Copyright © 2002-2026 Karl Henrik Henriksson [qwilk/@xoblite]
     5:  Copyright © 2001-2004 The Blackbox for Windows Development Team
     6:  http://xoblite.net/ + https://github.com/xoblite/
     7:  ============================================================================
     8: 
     9:   Blackbox for Windows is free software, released under the
    10:   GNU General Public License (GPL version 2 or later), with an extension
    11:   that allows linking of proprietary modules under a controlled interface.
    12:   What this means is that plugins etc. are allowed to be released
    13:   under any license the author wishes. Please note, however, that the
    14:   original Blackbox gradient math code used in Blackbox for Windows
    15:   is available under the BSD license.
    16: 
    17:   http://www.fsf.org/licenses/gpl.html
    18:   http://www.fsf.org/licenses/gpl-faq.html#LinkingOverControlledInterface
    19:   http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
    20: 
    21:   This program is distributed in the hope that it will be useful,
    22:   but WITHOUT ANY WARRANTY; without even the implied warranty of
    23:   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    24:   GNU General Public License for more details.
    25: 
    26:   For additional license information, please read the included license.html.
    27: 
    28:  ============================================================================
    29: */
    30: 
    31: #pragma warning(disable: 4996) // "'GetVersionExA' was declared deprecated" 
    32: 
    33: #include "Blackbox.h" 
    34: 
    35: BImage *pBImage;
    36: Console* pConsole;
    37: Desktop* pDesktop;
    38: Dock* pDock;
    39: Hotkeys* pHotkeys;
    40: Menu* pMenu;
    41: MenuCommon* pMenuCommon;
    42: MessageManager* pMessageManager;
    43: PluginManager* pPluginManager;
    44: PopupDialog* pPopupDialog;
    45: PreviewItem* pPreviewItem;
    46: Settings* pSettings;
    47: Taskbar* pTaskbar;
    48: Toolbar *pToolbar;
    49: Tooltips* pTooltips;
    50: Wallpaper* pWallpaper;
    51: Workspaces *pWorkspaces;
    52: 
    53: #include <gdiplus.h> 
    54: using namespace Gdiplus;
    55: GdiplusStartupInput gdiplusStartupInput;
    56: ULONG_PTR gdiplusToken;
    57: 
    58: //====================
    59: 
    60: const char szMainClass[] = "xoblite";
    61: HINSTANCE hMainInstance = NULL;
    62: HWND hMainWnd = NULL;
    63: HANDLE hMutex;
    64: 
    65: //HANDLE hShellReadyEvent;
    66: 
    67: NOTIFYICONDATA xobIconData;
    68: 
    69: static UINT WM_TASKBARCREATED_MESSAGE;
    70: 
    71: bool pausedRestart = false;
    72: int shutdownState;
    73: bool exitInProgress = false;
    74: 
    75: bool debugLogoff = false;
    76: bool debugReboot = false;
    77: bool debugShutdown = false;
    78: 
    79: int sessionDuration = 0;
    80: 
    81: //====================
    82: 
    83: HMODULE hShell32Module = NULL;
    84: 
    85: typedef void (__stdcall *MSWINSHUTDOWNPROC)(HWND);
    86: MSWINSHUTDOWNPROC MSWinShutdown = NULL;
    87: typedef void (__stdcall *RUNDLGPROC)(HWND, HICON, LPCSTR, LPCSTR, LPCSTR, int);
    88: RUNDLGPROC RunDlg = NULL;
    89: //typedef void (__stdcall *STTWTYPE)(HWND, int);
    90: //STTWTYPE BBSwitchToThisWindow;
    91: 
    92: typedef BOOL(WINAPI* LPFN_ISWOW64PROCESS2) (HANDLE, USHORT*, USHORT*);
    93: typedef BOOL(WINAPI* LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
    94: 
    95: typedef BOOL (WINAPI *LPFN_WOW64_DISABLE_REDIRECTION)(PVOID);
    96: LPFN_WOW64_DISABLE_REDIRECTION BBWow64DisableRedirection;
    97: typedef BOOL (WINAPI *LPFN_WOW64_REVERT_REDIRECTION)(PVOID);
    98: LPFN_WOW64_REVERT_REDIRECTION BBWow64RevertRedirection;
    99: 
   100: typedef BOOL (WINAPI *LPFN_SHUTDOWN_BLOCK_REASON_CREATE)(HWND, LPCWSTR);
   101: LPFN_SHUTDOWN_BLOCK_REASON_CREATE BBShutdownBlockReasonCreate;
   102: 
   103: //FARPROC (__stdcall *RegisterShellHook) (HWND, DWORD) = NULL; // Legacy legacy shell hook...
   104: 
   105: // ############################################################
   106: // ##### Experimental stuff, not otherwise enabled yet... #####
   107: // ##### (cf. useLegacyShellHook boolean setting below)   #####
   108: // ############################################################
   109: HMODULE hShellHookDLL = NULL;
   110: typedef bool (*PrepareShellHookFunc)(HWND, unsigned int, bool);
   111: PrepareShellHookFunc PrepareShellHook;
   112: typedef bool (*ShellHookStartFunc)(HWND, unsigned int, bool);
   113: ShellHookStartFunc StartShellHook;
   114: typedef bool (*ShellHookStopFunc)();
   115: ShellHookStopFunc StopShellHook;
   116: HOOKPROC ShellHookProcInDLL;
   117: // ############################################################
   118: 
   119: HHOOK shellHook = NULL;
   120: unsigned int WM_SHELLHOOKMESSAGE = 0;
   121: bool useLegacyShellHook = true;
   122: 
   123: #define ID_HOTKEY 0 
   124: 
   125: #ifndef ENDSESSION_CLOSEAPP 
   126: #define ENDSESSION_CLOSEAPP 0x00000001 
   127: #endif 
   128: #ifndef ENDSESSION_CRITICAL 
   129: #define ENDSESSION_CRITICAL 0x40000000 
   130: #endif 
   131: 
   132: bool somethingIsFullscreen = false;
   133: uint8_t lastFullscreenCheckStatus = 0;
   134: #ifndef QUNS_APP 
   135: #define QUNS_APP 7 
   136: #endif 
   137: 
   138: //===========================================================================
   139: 
   140: int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
   141: {
   142:     hMainInstance = hInstance;
   143: 
   144:     // Extract switches...
   145:     char option[MAX_LINE_LENGTH], extra[MAX_LINE_LENGTH];
   146:     char* tokens[1];
   147:     tokens[0] = option;
   148:     option[0] = extra[0] = '\0';
   149:     BBTokenize(lpCmdLine, tokens, 1, extra);
   150: 
   151:     //====================
   152: 
   153:     if (strnlen_s(option, sizeofArray(option))) // -> Switches included when calling the .exe -> Let's parse them instead of launching the regular way!
   154:     {
   155:         if ((!_stricmp(option, "-broam") || !_stricmp(option, "-exec")) && extra[0] == '@') // Support for sending bro@ms (i.e. using Blackbox.exe as a command line tool)
   156:         {
   157:             HWND xobhwnd = FindWindow(szMainClass, NULL);
   158:             if (xobhwnd)
   159:             {
   160:                 COPYDATASTRUCT cds;
   161:                 cds.dwData = BB_BROADCAST;
   162:                 cds.cbData = MAX_LINE_LENGTH;
   163:                 cds.lpData = &extra;
   164:                 SendMessage(xobhwnd, WM_COPYDATA, NULL, (LPARAM)(&cds));
   165:             }       
   166:             return 0;
   167:         }
   168:         else if (strchr(option, ':')) // Support for double clicking on .style files (nb. ...because filesystem paths always include a colon... :) )
   169:         {
   170:             if (strnlen_s(extra, sizeofArray(extra))) strcat_s(option, sizeofArray(option), extra);
   171:             if (!FileExists(option)) return 1;
   172: 
   173:             HWND xobhwnd = FindWindow(szMainClass, NULL);
   174:             if (xobhwnd)
   175:             {
   176:                 COPYDATASTRUCT cds;
   177:                 cds.dwData = BB_SETSTYLE;
   178:                 cds.cbData = MAX_LINE_LENGTH;
   179:                 cds.lpData = &option;
   180:                 SendMessage(xobhwnd, WM_COPYDATA, NULL, (LPARAM)(&cds));
   181:             }       
   182:             return 0;
   183:         }
   184:     }
   185: 
   186:     //====================
   187: 
   188:     // Check if Blackbox is already running...
   189:     hMutex = CreateMutex(NULL, false, "Blackbox");
   190:     if (GetLastError() == ERROR_ALREADY_EXISTS)
   191:     {
   192:         MessageBox(0, "Previously running instance of xoblite/Blackbox detected!\n(please quit that one first, then try to launch this one again)   ", "xoblite", MB_OK | MB_SETFOREGROUND | MB_ICONSTOP);
   193:         CloseHandle(hMutex);
   194:         return 1;
   195:     }
   196: 
   197:     //====================
   198: 
   199:     // Get addresses to undocumented Windows API calls...
   200:     hShell32Module = GetModuleHandle("SHELL32.DLL");
   201:     if (!hShell32Module) hShell32Module = LoadLibrary("SHELL32.DLL");
   202:     MSWinShutdown = (MSWINSHUTDOWNPROC)(GetProcAddress(hShell32Module, (LPCSTR)MAKELPARAM(0x3C, 0)));
   203:     RunDlg = (RUNDLGPROC)GetProcAddress(hShell32Module, (LPCSTR)MAKELPARAM(61, 0));
   204: //  RegisterShellHook = (FARPROC(__stdcall*) (HWND, DWORD))GetProcAddress(hShell32Module, (LPCSTR)((long)0xb5));
   205: 
   206:     //hUser32Module = GetModuleHandle("USER32.DLL");
   207:     //if (!hUser32Module) hUser32Module = LoadLibrary("USER32.DLL");
   208:     //BBSwitchToThisWindow = (STTWTYPE)GetProcAddress(GetModuleHandle("USER32.DLL"), "SwitchToThisWindow");
   209: 
   210:     //====================
   211: 
   212:     // Hide minimized windows...
   213:     MINIMIZEDMETRICS mm;
   214:     ZeroMemory(&mm, sizeof(MINIMIZEDMETRICS));
   215:     mm.cbSize = sizeof(MINIMIZEDMETRICS);
   216:     SystemParametersInfo(SPI_GETMINIMIZEDMETRICS, sizeof(MINIMIZEDMETRICS), &mm, false);
   217:     mm.iArrange |= ARW_HIDE;
   218:     SystemParametersInfo(SPI_SETMINIMIZEDMETRICS, sizeof(MINIMIZEDMETRICS), &mm, false);
   219: 
   220:     //====================
   221: 
   222:     // Set up the xoblite main class...
   223:     WNDCLASS wc;
   224:     ZeroMemory(&wc, sizeof(wc));
   225:     wc.hInstance = hMainInstance;
   226:     wc.lpfnWndProc = MainWndProc;
   227:     wc.lpszClassName = szMainClass;
   228: 
   229:     if (!RegisterClass(&wc))
   230:     {
   231:         MBoxErrorValue("Error registering xoblite class!");
   232:         Log("Error registering xoblite class!", NULL);
   233:         CloseHandle(hMutex);
   234:         return 1;
   235:     }
   236: 
   237:     // Set up the xoblite main window... (nb. this is only used for misc message handling, not as a UI element in itself)
   238:     hMainWnd = CreateWindowEx(
   239:         WS_EX_TOOLWINDOW | WS_EX_ACCEPTFILES | WS_EX_NOACTIVATE,    // window style
   240:         szMainClass,                                                // window class
   241:         NULL,                                                       // window name
   242:         WS_POPUP,                                                   // window parameters
   243:         0,                                                          // x position
   244:         0,                                                          // y position
   245:         0,                                                          // window width
   246:         0,                                                          // window height
   247:         NULL,                                                       // owner window
   248:         NULL,                                                       // no menu
   249:         hMainInstance,                                              // hInstance assigned by the system
   250:         NULL                                                        // no window creation data
   251:     );
   252: 
   253:     if (!hMainWnd)
   254:     {
   255:         MBoxErrorValue("Error creating the xoblite main window!");
   256:         Log("Error creating the xoblite main window!", NULL);
   257:         UnregisterClass(szMainClass, hMainInstance);
   258:         CloseHandle(hMutex);
   259:         return 1;
   260:     }
   261: 
   262:     //====================
   263: 
   264:     // Initialize the xoblite message manager and settings...
   265:     // (nb. these need to be started *before* all other subsystems
   266:     // - see startBlackbox() etc below - as they are used by all of them)
   267:     pMessageManager = new MessageManager;
   268:     pSettings = new Settings;
   269:     pSettings->accessLock = false;
   270: 
   271:     //====================
   272: 
   273:     // Are we running alongside Explorer? (check for the systray window class,
   274:     // however note that this will also lock on to e.g. a stand alone systray plugin,
   275:     // so we need to do this before starting the rest of the shell...)
   276:     if (FindWindow("Shell_TrayWnd", NULL) != NULL) pSettings->underExplorer = true;
   277:     else pSettings->underExplorer = false;
   278: 
   279:     // Check and save OS version as a single integer for easier lookup later...
   280:     // Win95 -> 0400, Win98 -> 0410, WinME -> 0490, WinNT4 -> 1400,
   281:     // Win2k -> 1500, WinXP/32bit -> 1501, WinXP/64bit (and Server2003 & WHS) -> 1502,
   282:     // WinVista (and Server2008) -> 1600, Win7 (and Server2008R2) -> 1601,
   283:     // Win8 (and Server2012) -> 1602, Win81 (and Server2012R2) -> 1603
   284:     OSVERSIONINFO osInfo;
   285:     ZeroMemory(&osInfo, sizeof(osInfo));
   286:     osInfo.dwOSVersionInfoSize = sizeof(osInfo);
   287:     GetVersionEx(&osInfo);
   288:     pSettings->operatingSystemVersion = (osInfo.dwMajorVersion*100) + osInfo.dwMinorVersion;
   289:     if (osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) pSettings->operatingSystemVersion += 1000;
   290: 
   291:     // Check whether we're running under 64-bit Windows, and if possible on which CPU/machine architecture...
   292:     // (nb. ...we're only shipping 32-bit x86 binaries currently, but maybe in the future we'll add e.g. 64-bit ARM64 builds if such machines take off...)
   293:     pSettings->machineArchitecture = IMAGE_FILE_MACHINE_UNKNOWN;
   294:     pSettings->runningUnderWOW64 = FALSE;
   295: 
   296:     LPFN_ISWOW64PROCESS2 BBIsWow64Process2 = (LPFN_ISWOW64PROCESS2)GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process2");
   297:     if (BBIsWow64Process2 != NULL)
   298:     {
   299:         USHORT is64bit = 0;
   300:         BBIsWow64Process2(GetCurrentProcess(), &is64bit, &pSettings->machineArchitecture);
   301:         if (is64bit == IMAGE_FILE_MACHINE_UNKNOWN) pSettings->runningUnderWOW64 = TRUE;
   302:     }
   303:     else
   304:     {
   305:         LPFN_ISWOW64PROCESS BBIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle("kernel32"), "IsWow64Process");
   306:         if (BBIsWow64Process != NULL) BBIsWow64Process(GetCurrentProcess(), &pSettings->runningUnderWOW64);
   307:         else pSettings->runningUnderWOW64 = FALSE;
   308:         pSettings->machineArchitecture = IMAGE_FILE_MACHINE_UNKNOWN; // Note: IsWow64Process does not provide information about the CPU architecture, only the WoW64-or-not status.
   309:     }
   310: 
   311:     // Get system calls to enable/disable filesystem redirection under 64-bit Windows...
   312:     // -> "Wow64DisableWow64FsRedirection disables file system redirection for the calling thread. File system redirection is enabled by default."
   313:     // -> "Wow64RevertWow64FsRedirection restores file system redirection for the calling thread."
   314:     BBWow64DisableRedirection = (LPFN_WOW64_DISABLE_REDIRECTION)GetProcAddress(GetModuleHandle("kernel32"),"Wow64DisableWow64FsRedirection");
   315:     BBWow64RevertRedirection = (LPFN_WOW64_REVERT_REDIRECTION)GetProcAddress(GetModuleHandle("kernel32"),"Wow64RevertWow64FsRedirection");
   316: 
   317:     // Provide seed for pseudorandom number generation... (used by e.g. @xoblite Random <Style/Wallpaper> )
   318:     srand((unsigned int)time(NULL));
   319: 
   320:     //====================
   321: 
   322:     // Initialize a Shell Hook to receive continuous information regarding Windows task handling activities etc...
   323: 
   324:     WM_SHELLHOOKMESSAGE = RegisterWindowMessage("SHELLHOOK"); // Note: This is used by both the newer (via xShellHook.dll) and legacy (in core .exe) shell hook
   325:                                                               // implementations to communicate information to the taskbar etc via the internal *box message bus.
   326: /*
   327:     if (!useLegacyShellHook)
   328:     {
   329:         hShellHookDLL = LoadLibrary("xShellHook.dll");
   330: 
   331:         if (hShellHookDLL != NULL) // -> xShellHook.dll found!
   332:         {
   333:             PrepareShellHook = (PrepareShellHookFunc)(GetProcAddress(hShellHookDLL, "PrepareShellHook"));
   334:             StartShellHook = (ShellHookStartFunc)(GetProcAddress(hShellHookDLL, "StartShellHook"));
   335:             StopShellHook = (ShellHookStopFunc)(GetProcAddress(hShellHookDLL, "StopShellHook"));
   336:             ShellHookProcInDLL = (HOOKPROC)GetProcAddress(hShellHookDLL, "ShellHookProc");
   337: 
   338:             if (StartShellHook != NULL)
   339:             {
   340:                 StartShellHook(hMainWnd, WM_SHELLHOOKMESSAGE, pSettings->debugLogging); // (...where the DLL in turn calls SetWindowsHookEx() etc.)
   341:     //          PrepareShellHook(hMainWnd, WM_SHELLHOOKMESSAGE, pSettings->debugLogging);
   342:     //          shellHook = SetWindowsHookEx(WH_SHELL, ShellHookProcInDLL, hShellHookDLL, 0);
   343:                 useLegacyShellHook = false;
   344:             }
   345:             else
   346:             {
   347:                 FreeLibrary(hShellHookDLL);
   348:                 hShellHookDLL = NULL;
   349:             }
   350:         }
   351:     }
   352: */
   353:     if (useLegacyShellHook || (hShellHookDLL == NULL)) // -> Fall back to the legacy RegisterShellHookWindow() function... (e.g. because xShellHook.dll was not found or otherwise disabled)
   354:     {
   355: /*
   356:         if (RegisterShellHook)
   357:         {
   358:             // This was an undocumented older legacy call, at some point seemingly replaced by the slightly more documented but nowadays
   359:             // also to be considered legacy RegisterShellHookWindow() as per below... (this kept here only for historic reference)
   360:             // (cf. https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registershellhookwindow )
   361: 
   362:             RegisterShellHook(NULL, true);
   363:             if (osInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) RegisterShellHook(hMainWnd, 1);
   364:             else RegisterShellHook(hMainWnd, 3);
   365:         }
   366: */
   367:         useLegacyShellHook = (bool)RegisterShellHookWindow(hMainWnd);
   368:     }
   369: 
   370:     //====================
   371: 
   372:     // Hide the Explorer desktop icons...
   373:     HideDesktopIcons(true);
   374: 
   375:     // Start GDI+... (used by e.g. the menu PreviewItem, for any image-instead-of-gradient use per element, etc)
   376:     GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
   377: 
   378:     // Start all xoblite subsystems...
   379:     startBlackbox();
   380:     MakeSticky(hMainWnd);
   381:     SetForegroundWindow(hMainWnd);
   382: 
   383:     //####################
   384:     //####################
   385:     //####################
   386: 
   387:     // Retrieve messages from the message queue for any window
   388:     // that belongs to this thread until we recieve WM_QUIT...
   389:     BOOL value;
   390:     MSG msg;
   391: 
   392:     while ((value = GetMessage(&msg, NULL, 0, 0 )) != 0)
   393:     {
   394:         if (value == -1) break;
   395:         else
   396:         {
   397:             TranslateMessage(&msg); 
   398:             DispatchMessage(&msg); 
   399:         }
   400:     }
   401: 
   402:     //####################
   403:     //####################
   404:     //####################
   405: 
   406:     // Stop all xoblite subsystems...
   407:     // (nb. this is now done *before* exiting the message queue; see elsewhere below)
   408:     // exitBlackbox();
   409: 
   410:     // Shutdown GDI+...
   411:     GdiplusShutdown(gdiplusToken);
   412: 
   413:     // Show the Explorer desktop icons...
   414:     HideDesktopIcons(false);
   415: 
   416:     // Release the shell hook...
   417:     if (useLegacyShellHook)
   418:     {
   419:         // if (RegisterShellHook) RegisterShellHook(hMainWnd, 0); // Older undocumented legacy shell hook (kept here only for historic reference, cf. similar comments above)
   420:         DeregisterShellHookWindow(hMainWnd);
   421:     }
   422: /*
   423:     else if (hShellHookDLL != NULL)
   424:     {
   425:         if (StopShellHook != NULL) StopShellHook();
   426: //      UnhookWindowsHookEx(shellHook);
   427:         FreeLibrary(hShellHookDLL);
   428:     }
   429: */
   430:     DestroyWindow(hMainWnd);
   431:     UnregisterClass(szMainClass, hMainInstance);
   432:     CloseHandle(hMutex);
   433: 
   434:     bool debugLogging = pSettings->debugLogging;
   435:     if (pSettings) delete pSettings;
   436:     if (pMessageManager) delete pMessageManager;
   437: 
   438:     if (debugLogging)
   439:     {
   440:         if (debugShutdown && debugReboot) Log("xoblite", "Exiting properly (External Shutdown/Reboot)");
   441:         else if (debugShutdown) Log("xoblite", "Exiting properly (Shutdown)");
   442:         else if (debugReboot) Log("xoblite", "Exiting properly (Reboot)");
   443:         else if (debugLogoff) Log("xoblite", "Exiting properly (Logoff)");
   444:         else Log("xoblite", "Exiting properly (Quit)");
   445:     }
   446: 
   447:     return 0;
   448: }
   449: 
   450: //===========================================================================
   451: // Function: startBlackbox
   452: // Purpose: ...
   453: //===========================================================================
   454: 
   455: void startBlackbox()
   456: {
   457:     // Get the paths to the default xoblite.rc or blackbox.rc/extensions.rc...
   458:     pSettings->GetShellFolders();
   459: 
   460:     //====================
   461: 
   462:     // Read only those settings from the default .rc
   463:     // that are required to set the correct theme at startup...
   464:     strcpy_s(pSettings->themesFolder, sizeofArray(pSettings->themesFolder), ReadString(pSettings->xobrcDefaultFile, "xoblite.themesFolder:", "$Blackbox$\\themes"));
   465:     if (strchr(pSettings->themesFolder, '\"')) StrRemoveEncap(pSettings->themesFolder);
   466:     if (strchr(pSettings->themesFolder, '$')) ReplaceShellFolders(pSettings->themesFolder);
   467:     if (strchr(pSettings->themesFolder, '%')) ReplaceEnvVars(pSettings->themesFolder);
   468:     strcpy_s(pSettings->selectedTheme, sizeofArray(pSettings->selectedTheme), ReadString(pSettings->xobrcDefaultFile, "xoblite.selected.theme:", "[Default]"));
   469:     if (!_stricmp(pSettings->selectedTheme, "<Default>")) strcpy_s(pSettings->selectedTheme, sizeofArray(pSettings->selectedTheme), "[Default]"); // (changed to avoid similarity to editable string/integer menu items, as it is also shown in the Themes menu)
   470: 
   471:     if (!_stricmp(pSettings->selectedTheme, "[Default]")) // -> Use the default theme...
   472:     {
   473:         SetTheme(pSettings->SF_blackboxPath, true);
   474:     }
   475:     else // -> Set a specific theme...
   476:     {
   477:         char themePath[MAX_PATH];
   478:         strcpy_s(themePath, sizeofArray(themePath), pSettings->themesFolder);
   479:         strcat_s(themePath, sizeofArray(themePath), "\\");
   480:         strcat_s(themePath, sizeofArray(themePath), pSettings->selectedTheme);
   481:         SetTheme(themePath, true);
   482:     }
   483: 
   484:     //====================
   485: 
   486:     // Read configuration settings and style parameters for the chosen theme...
   487:     pSettings->ReadConfiguration();
   488:     pSettings->ReadStyle();
   489:     RegisterThemeFonts();
   490: 
   491:     // Set time locale if configured...
   492:     if (strnlen_s(pSettings->timeDateLocale, sizeofArray(pSettings->timeDateLocale)) > 0) setlocale(LC_TIME, pSettings->timeDateLocale);
   493:     else setlocale(LC_TIME, ""); // Not configured -> Set the time locale to the user default obtained from the operating system...
   494: 
   495:     // Should we hide the Explorer taskbar etc already on startup?
   496:     if (pSettings->underExplorer && pSettings->explorerHidden) HideExplorer(true);
   497: 
   498:     //====================
   499: 
   500:     // ####################################################################
   501:     // ##### Note: The order things are started below is important!!! #####
   502:     // ####################################################################
   503: 
   504:     pBImage = new BImage;
   505:     pDesktop = new Desktop(hMainInstance);
   506:     pConsole = new Console(hMainInstance);
   507: 
   508:     // Display welcome message in the console...
   509:     SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_SHELL_MESSAGE, (LPARAM)"Welcome to xoblite.");
   510:     SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_PLAIN_MESSAGE, (LPARAM)" http://xoblite.net/");
   511:     SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_PLAIN_MESSAGE, (LPARAM)" https://github.com/xoblite/");
   512: 
   513:     // Set time stamp for beginning of session...
   514:     Log("----------------------------------------", "");
   515:     SessionTimeStamp(true);
   516: /*
   517:     if (pSettings->debugLogging)
   518:     {
   519:         char msg[255];
   520:         sprintf_s(msg, sizeofArray(msg), "Operating system: %s ", GetOSInfo());
   521:         if (pSettings->runningUnderWOW64) strcat_s(msg, sizeofArray(msg), "(64-bit).");
   522:         else strcat_s(msg, sizeofArray(msg), "(32-bit).");
   523:         SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_REGULAR_MESSAGE, (LPARAM)msg);
   524: 
   525: //      char msg[255];
   526: //      sprintf_s(msg, sizeofArray(msg), "Time locale set to %s.", setlocale(LC_TIME, NULL));
   527: //      SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_REGULAR_MESSAGE, (LPARAM)msg);
   528:     }
   529: */
   530: /*
   531:     if (useLegacyShellHook) SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_ERROR_MESSAGE, (LPARAM)"xShellHook .DLL not found (or disabled) -> Falling back to legacy shell hook implementation.");
   532:     else if (hShellHookDLL != NULL) SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)"xShellHook .DLL found -> Using alternative new shell hook implementation.");
   533:     if (pSettings->debugLogging)
   534:     {
   535:         if (hShellHookDLL != NULL)
   536:         {
   537:             // SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)"DEBUG -> xShellHook.dll loaded.");
   538:             if (PrepareShellHook != NULL) SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INDENTED_MESSAGE, (LPARAM)"... PrepareShellHook() function found.");
   539:             if (StartShellHook != NULL) SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INDENTED_MESSAGE, (LPARAM)"... StartShellHook() function found.");
   540:             if (StopShellHook != NULL) SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INDENTED_MESSAGE, (LPARAM)"... StopShellHook() function found.");
   541:             if (ShellHookProcInDLL != NULL) SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INDENTED_MESSAGE, (LPARAM)"... ShellHookProc() function found.");
   542:         }
   543:     }
   544: */
   545:     pWorkspaces = new Workspaces(hMainInstance);
   546:     pMenuCommon = new MenuCommon;
   547:     pPreviewItem = new PreviewItem(hMainInstance);
   548:     pDock = new Dock(hMainInstance);
   549:     pTooltips = new Tooltips();
   550:     pTaskbar = new Taskbar();
   551: 
   552:     pPluginManager = new PluginManager(hMainInstance);
   553:     pToolbar = new Toolbar(hMainInstance);
   554:     pPopupDialog = new PopupDialog(hMainInstance);
   555: 
   556:     pMenuCommon->Initialize(hMainInstance);
   557:     pTaskbar->InitializeTaskList(); // Enumerate tasks for the taskbar...
   558: 
   559:     pHotkeys = new Hotkeys(hMainInstance);
   560: 
   561:     if (pSettings->underExplorer)
   562:     {
   563:         // Add the xoblite icon to the system tray... =]
   564:         ZeroMemory(&xobIconData, sizeof(NOTIFYICONDATA));
   565:         xobIconData.cbSize = sizeof(NOTIFYICONDATA); // Older Windows versions -> NOTIFYICONDATA_V3_SIZE
   566:         xobIconData.hIcon = LoadIcon(hMainInstance, MAKEINTRESOURCE(IDI_XOBLITE));
   567: //      LoadIconMetric(hMainInstance, MAKEINTRESOURCE(IDI_XOBLITE), LIM_SMALL, &(xobIconData.hIcon));
   568:         strcpy_s(xobIconData.szTip, sizeofArray(xobIconData.szTip), "xoblite");
   569:         xobIconData.hWnd = GetBBWnd();
   570:         xobIconData.uID = 0;
   571:         xobIconData.uVersion = NOTIFYICON_VERSION_4; // // Older Windows versions -> 3
   572:         xobIconData.uCallbackMessage = BB_TRAYICONMESSAGE;
   573:         xobIconData.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
   574:         Shell_NotifyIcon(NIM_ADD, &xobIconData);
   575: 
   576:     }
   577: 
   578:     WM_TASKBARCREATED_MESSAGE = RegisterWindowMessage(TEXT("TaskbarCreated"));
   579: 
   580: //  SendMessage(GetDesktopWindow(), 0x400, 0, 0); // ...hmm, not quite sure what this did anymore...?! ;)
   581: 
   582:     // Show/hide the plugins based on the related xoblite.rc setting...
   583:     if (pSettings->pluginsHidden) SendMessage(hMainWnd, BB_BROADCAST, 0, (LPARAM)"@BBHidePlugins");
   584:     else SendMessage(hMainWnd, BB_BROADCAST, 0, (LPARAM)"@BBShowPlugins");
   585: 
   586:     // Finally, as a "security precausion" we move the xoblite desktop window to the bottom...
   587:     SetWindowPos(pDesktop->hDesktopWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSENDCHANGING);
   588: 
   589:     // Execute the current style's rootCommand...
   590:     _beginthread(ExecuteRootCommand, 0, NULL);
   591: 
   592:     PlaySoundFX(SFX_STARTUP);
   593: 
   594:     if (pSettings->debugLogging) Log("xoblite", "All subsystems started successfully.");
   595: 
   596:     //====================
   597: 
   598:     // Check if the Blackbox font pack is installed, and if not display a warning message...
   599:     HFONT checkPackFont = CreateFont(12, 0, 0, 0, FW_NORMAL, false, false, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, "mints-strong");
   600:     if (checkPackFont)
   601:     {
   602:         HDC temphdc = CreateCompatibleDC(NULL);
   603:         HGDIOBJ oldfont = SelectObject(temphdc, checkPackFont);
   604:         char createdFontName[33];
   605:         GetTextFace(temphdc, 32, createdFontName);
   606:         if (_stricmp(createdFontName, "mints-strong"))
   607:         {
   608:             SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)"The Blackbox font pack does not seem to be installed. Get it from the xoblite website! -> http://xoblite.net/");
   609:         }
   610: 
   611:         DeleteObject(checkPackFont);
   612:         DeleteObject(SelectObject(temphdc, oldfont));
   613:         DeleteDC(temphdc);
   614:     }
   615: 
   616:     //====================
   617: /*
   618:     if (pSettings->debugLogging) // ### DEPRECATED (read: old boundary failsafe introduced by BlackboxZero, nowadays outgrown [>300 bytes] anyway...) ###
   619:     {
   620:         char msg[255];
   621:         sprintf_s(msg, sizeofArray(msg), "Debug: Size of StyleItem struct -> %d bytes.", sizeof(StyleItem));
   622:         SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
   623:     }
   624: */
   625:     //====================
   626: 
   627:     // Set a 1 second recurring timer to check for applications entering/exiting fullscreen...
   628:     // (i.e. to hide/show the xoblite core UI elements when this happens; see WM_TIMER handling in MainWndProc() below)
   629:     SetTimer(GetBBWnd(), CHECK_FOR_FULLSCREEN_TIMER, 1000, (TIMERPROC)NULL);
   630: 
   631:     // Once everything else is up and running, we first wait another 3 seconds, then perform a check for updates...
   632:     SetTimer(GetBBWnd(), CHECK_FOR_UPDATES_DELAY_TIMER, 3000, (TIMERPROC)NULL);
   633: }
   634: 
   635: //===========================================================================
   636: // Function: exitBlackbox
   637: // Purpose: ...
   638: //===========================================================================
   639: 
   640: void exitBlackbox()
   641: {
   642:     // Just a security precausion... ;)
   643:     if (exitInProgress) return;
   644:     else exitInProgress = true;
   645: 
   646:     // Set time stamp for end of session...
   647:     SessionTimeStamp(false);
   648: 
   649:     ClearSticky();
   650: 
   651:     DestroyRunBox(); // ...just in case the user left the run box open upon exit...
   652: 
   653:     pSettings->accessLock = true;
   654: 
   655:     if (pSettings->underExplorer) Shell_NotifyIcon(NIM_DELETE, &xobIconData);
   656: 
   657:     if (pHotkeys) delete pHotkeys;
   658:     if (pPopupDialog) delete pPopupDialog;
   659:     if (pToolbar) delete pToolbar;
   660:     if (pPluginManager) delete pPluginManager;
   661:     if (pTaskbar) delete pTaskbar;
   662:     if (pTooltips) delete pTooltips;
   663:     if (pDock) delete pDock;
   664:     if (pPreviewItem) delete pPreviewItem;
   665:     if (pMenuCommon) delete pMenuCommon;
   666:     if (pWorkspaces) delete pWorkspaces;
   667:     if (pConsole) delete pConsole;
   668:     if (pDesktop) delete pDesktop;
   669:     if (pBImage) delete pBImage;
   670: 
   671:     UnregisterThemeFonts();
   672: 
   673:     if (pSettings->underExplorer)
   674:     {
   675:         Shell_NotifyIcon(NIM_DELETE, &xobIconData);
   676:         DestroyIcon(xobIconData.hIcon);
   677:     }
   678: 
   679:     if (pSettings->underExplorer && pSettings->explorerHidden) ShowExplorer();
   680: 
   681: //  if (pSettings->debugLogging) Log("xoblite", "exitBlackbox() completed successfully.");
   682: }
   683: 
   684: //===========================================================================
   685: // Functions: restartBlackboxStop / restartBlackboxStart
   686: // Purpose: Restarts applicable xoblite subsystems
   687: // (optionally with a "wait for user" pause in between stop and restart)
   688: //===========================================================================
   689: 
   690: void restartBlackboxStop()
   691: {
   692:     // Disable dock transparency (for some reason this needs to be 
   693:     // done to avoid visual artifacts) and hide the dock window...
   694:     if (pDock)
   695:     {
   696:         SetTransparency(pDock->hDockWnd, 255);
   697:         ShowWindow(pDock->hDockWnd, SW_HIDE);
   698:     }
   699: 
   700:     // Unload all plugins...
   701:     if (pPluginManager) delete pPluginManager;
   702: 
   703:     // Shall we pause the restart to let the user do something before continuing?
   704:     if ((GetAsyncKeyState(VK_SHIFT) & 0x8000) || pausedRestart)
   705:     {
   706:         MessageBox(GetBBWnd(), "Restart paused, press OK to continue...   ", "xoblite", MB_OK | MB_ICONINFORMATION | MB_TOPMOST);
   707:         pausedRestart = false;
   708:     }
   709: }
   710: 
   711: //===========================================================================
   712: 
   713: void restartBlackboxStart()
   714: {
   715:     int existingWorkspaces = pSettings->numberOfWorkspaces;
   716: 
   717:     // Stop applicable subsystems...
   718:     if (pHotkeys) delete pHotkeys;
   719:     if (pPreviewItem) delete pPreviewItem;
   720:     if (pMenuCommon) delete pMenuCommon;
   721: 
   722:     // Read configuration settings and style parameters...
   723:     pSettings->ReadConfiguration();
   724:     pSettings->ReadStyle();
   725: 
   726:     // Set time locale if configured...
   727:     if (strnlen_s(pSettings->timeDateLocale, sizeofArray(pSettings->timeDateLocale)) > 0) setlocale(LC_TIME, pSettings->timeDateLocale);
   728:     else setlocale(LC_TIME, ""); // Not configured -> Reset the time locale to the user default obtained from the operating system...
   729:     pToolbar->GetClockText(true);
   730: /*
   731:     if (pSettings->debugLogging)
   732:     {
   733:         char msg[255];
   734:         sprintf_s(msg, sizeofArray(msg), "Time locale set to %s.", setlocale(LC_TIME, NULL));
   735:         SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_REGULAR_MESSAGE, (LPARAM)msg);
   736:     }
   737: */
   738:     //====================
   739: 
   740:     if (existingWorkspaces != pSettings->numberOfWorkspaces)
   741:     {
   742: //      if (pWorkspaces) delete pWorkspaces;
   743: //      pWorkspaces = new Workspaces(hMainInstance);
   744:         pWorkspaces->GatherWindows();
   745:         if (pSettings->currentWorkspace > (pSettings->numberOfWorkspaces - 1))
   746:         {
   747:             pWorkspaces->SwitchToWorkspace(pSettings->numberOfWorkspaces - 1);
   748:         }
   749:     }
   750: 
   751:     pWorkspaces->UpdateWorkspaceNames();
   752: 
   753:     //====================
   754: 
   755:     // Start applicable subsystems again...
   756:     pMenuCommon = new MenuCommon();
   757:     pMenuCommon->Initialize(hMainInstance);
   758:     pPreviewItem = new PreviewItem(hMainInstance);
   759:     pPluginManager = new PluginManager(hMainInstance);
   760:     pHotkeys = new Hotkeys(hMainInstance);
   761: 
   762:     // Update toolbar+dock+console size, position and alpha transparency...
   763:     pToolbar->UpdatePosition();
   764:     pDock->UpdateDockWindow();
   765:     pConsole->UpdatePosition();
   766:     pPopupDialog->UpdatePopupDialog();
   767: 
   768:     // Show/hide the toolbar, console and plugins based on their applicable .rc settings...
   769:     ShowWindow(pToolbar->hToolbarWnd, pSettings->toolbarHidden ? SW_HIDE : SW_SHOWNOACTIVATE);
   770:     ShowWindow(pConsole->hConsoleWnd, pSettings->consoleHidden ? SW_HIDE : SW_SHOWNOACTIVATE);
   771:     if (pSettings->pluginsHidden) SendMessage(hMainWnd, BB_BROADCAST, 0, (LPARAM)"@BBHidePlugins");
   772:     else SendMessage(hMainWnd, BB_BROADCAST, 0, (LPARAM)"@BBShowPlugins");
   773: 
   774:     // Force update of any external system tray plugins... (nb. as of xoblite bb5, the internal systray has been discontinued, but keeping this "just in case"... ;))
   775:     PostMessage(hMainWnd, BB_TRAYUPDATE, NULL, (LPARAM)TRAYICON_REFRESH);
   776: 
   777:     // Ask the desktop to update...
   778:     pDesktop->GetClockText(true);
   779:     pDesktop->UpdateDesktopWindow();
   780:     // Finally, as a "security precausion" we move the xoblite desktop window to the bottom...
   781:     SetWindowPos(pDesktop->hDesktopWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSENDCHANGING);
   782:     // ...and move the console->dock->toolbar, if not hidden, to the top...
   783:     if (!pSettings->consoleHidden) SetForegroundWindow(pConsole->hConsoleWnd);
   784:     if (!pSettings->dockHidden) SetForegroundWindow(pDock->hDockWnd);
   785:     if (!pSettings->toolbarHidden) SetForegroundWindow(pToolbar->hToolbarWnd);
   786: 
   787:     // Should we hide or show the Explorer taskbar etc? (i.e. if the related setting has changed)
   788:     if (pSettings->underExplorer && pSettings->explorerHidden) HideExplorer(true);
   789:     else ShowExplorer();
   790: 
   791:     // Start Designer Mode (i.e. load the xDesignerGUI.dll privileged plugin) again if it was enabled before the core restart...
   792:     if (pSettings->designerModeEnabled)
   793:     {
   794:         char xDGUIpath[MAX_PATH];
   795:         sprintf_s(xDGUIpath, sizeofArray(xDGUIpath), "%s\\%s", pSettings->SF_blackboxPath, "xDesignerGUI.dll");
   796:         if (!pPluginManager->IsPluginLoaded("xDesignerGUI.dll")) pPluginManager->LoadPlugin(xDGUIpath);
   797:     }
   798: 
   799:     //====================
   800: 
   801:     _beginthread(ExecuteRootCommand, 0, NULL);
   802: }
   803: 
   804: //===========================================================================
   805: // Function: MainWndProc
   806: // Purpose: xoblite main window process (nb. non-visible window)
   807: //===========================================================================
   808: 
   809: LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
   810: {
   811:     switch (uMsg)
   812:     {
   813:         //====================
   814: 
   815:         case WM_HELP:
   816:         {
   817:             BBExecute(GetDesktopWindow(), NULL, "http://xoblite.net/shell/", "", "", SW_SHOWNORMAL, true);
   818:             return TRUE;
   819:         }
   820: 
   821:         //====================
   822: 
   823:         case WM_HOTKEY:
   824:         {
   825:             if (pHotkeys) pHotkeys->ExecuteHotkey((int)wParam);
   826:         }
   827:         break;
   828: 
   829:         //====================
   830: 
   831:         case WM_QUERYENDSESSION:
   832:         {
   833:             if (lParam & ENDSESSION_CRITICAL)
   834:             {
   835:                 if (lParam & ENDSESSION_LOGOFF) debugLogoff = true;
   836:                 else debugShutdown = debugReboot = true;
   837:                 if (pSettings->debugLogging) Log("xoblite", "WM_QUERYENDSESSION | SYSTEM/CRITICAL");
   838:                 return TRUE;
   839:             }
   840:             else if (debugLogoff || debugReboot || debugShutdown)
   841:             {
   842:                 if (pSettings->debugLogging)
   843:                 {
   844:                     if (debugLogoff) Log("xoblite", "WM_QUERYENDSESSION | XOBLITE/LOGOFF");
   845:                     else if (debugReboot) Log("xoblite", "WM_QUERYENDSESSION | XOBLITE/REBOOT");
   846:                     else Log("xoblite", "WM_QUERYENDSESSION | XOBLITE/SHUTDOWN");
   847:                 }
   848:                 return TRUE;
   849:             }
   850:             else
   851:             {
   852:                 if (pSettings->debugLogging)
   853:                 {
   854:                     if (lParam & ENDSESSION_CLOSEAPP) Log("xoblite", "WM_QUERYENDSESSION | SYSTEM/CLOSEAPP");
   855:                     else if (lParam & ENDSESSION_LOGOFF) Log("xoblite", "WM_QUERYENDSESSION | SYSTEM/LOGOFF");
   856:                     else Log("xoblite", "WM_QUERYENDSESSION | SYSTEM/SHUTDOWN_or_REBOOT");
   857:                 }
   858: /*
   859:                 if (pSettings->debugLogging)
   860:                 {
   861:                     if (MessageBox(GetBBWnd(), "Windows has requested a logoff/reboot/shutdown.   \n\nAre you sure you want to quit?   \n", "xoblite", MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND | MB_TOPMOST) != IDYES)
   862:                     {
   863:                         Log("xoblite", "WM_QUERYENDSESSION | === BLOCKED BY USER ===");
   864:                         return FALSE;
   865:                     }
   866:                 }
   867: */
   868:             }
   869: 
   870:             if (lParam & ENDSESSION_LOGOFF) debugLogoff = true;
   871:             else debugShutdown = debugReboot = true;
   872: //          PostMessage(hMainWnd, WM_CLOSE, 0, 0);
   873:             return TRUE;
   874:         }
   875: 
   876:         case WM_ENDSESSION:
   877:         {
   878:             if ((wParam == TRUE) && pSettings->debugLogging) Log("xoblite", "WM_ENDSESSION");
   879: //          exitBlackbox();
   880:             return 0;
   881:         }
   882: 
   883:         //====================
   884: 
   885:         case WM_SYSCOMMAND:
   886:         case WM_KEYDOWN:
   887:         {
   888:             if (wParam == SC_CLOSE)
   889:             {
   890:                 if (pSettings->debugLogging) Log("xoblite", "SC_CLOSE");
   891:                 PostMessage(GetBBWnd(), BB_SHUTDOWN, 255, 0); // Open the standard Windows shutdown menu...
   892:                 return 0;
   893:             }
   894:             else return DefWindowProc(hWnd, uMsg, wParam, lParam);
   895:         }
   896: 
   897:         //====================
   898: 
   899:         case WM_CLOSE:
   900:         case BB_QUIT:
   901:         {
   902:             if (pSettings->debugLogging && (uMsg==WM_CLOSE)) Log("xoblite", "SC_CLOSE");
   903:             exitBlackbox();
   904:             PostQuitMessage(0);
   905:         }
   906:         break;
   907: 
   908:         //====================
   909: 
   910:         case BB_SHUTDOWN:
   911:         {
   912:             switch (wParam)
   913:             {
   914:                 case 0: // Shutdown
   915:                     ShutdownWindows(0, ((int)lParam == 1));
   916:                 break;
   917:                 case 1: // Reboot
   918:                     ShutdownWindows(1, ((int)lParam == 1));
   919:                 break;
   920:                 case 2: // Log off
   921:                     ShutdownWindows(2, ((int)lParam == 1));
   922:                 break;
   923:                 case 3: // Hibernate (a.k.a. "safe sleep" and "suspend to disk")
   924:                     ShutdownWindows(3, ((int)lParam == 1));
   925:                 break;
   926:                 case 4: // Standby (a.k.a. "sleep" and "suspend to RAM")
   927:                     ShutdownWindows(4, ((int)lParam == 1));
   928:                 break;
   929:                 case 5: // LockWorkstation
   930: //                  BBExecute(GetDesktopWindow(), NULL, "rundll32.exe", "user32.dll,LockWorkStation", NULL, SW_HIDE, false);
   931:                     LockWorkStation();
   932:                     PlaySoundFX(SFX_LOCK_WORKSTATION);
   933:                 break;
   934:                 default: // Standard Windows shutdown menu (does not work from the xoblite main menu)
   935:                     MSWinShutdown(hMainWnd);
   936:                 break;
   937:             }
   938:             return 0;
   939:         }
   940: 
   941:         //====================
   942: 
   943:         case BB_RESTART:
   944:         {
   945:             if (exitInProgress) // Restart after a failed shutdown/reboot/etc attempt...
   946:             {
   947:                 exitInProgress = false;
   948:                 startBlackbox();
   949:             }
   950:             else if (!pausedRestart) // Regular restart...
   951:             {
   952:                 // Lock the dock to avoid repeated SLIT_REMOVE/ADD
   953:                 // messages from plugins when restarting...
   954:                 pDock->ReconfigureLock(true);
   955:                 if (wParam) pausedRestart = true;
   956:                 restartBlackboxStop();
   957:                 restartBlackboxStart();
   958:                 SendMessage(pDesktop->hDesktopWnd, BB_RECONFIGURE, 0, 0);
   959:             }
   960:         }
   961:         break;
   962: 
   963:         //====================
   964: 
   965:         case BB_SETTHEME: // Introducing xoblite *THEMES*! :D
   966:         {
   967:             if (lParam != 0)
   968:             {
   969:                 char themePath[MAX_LINE_LENGTH];
   970:                 strcpy_s(themePath, sizeofArray(themePath), (LPCSTR)lParam);
   971:                 SetTheme(themePath, false);
   972:             }
   973:         }
   974:         break;
   975: 
   976:         //====================
   977: 
   978:         case BB_SETSTYLE:
   979:         {
   980:             // Load a new style or refresh the current one?
   981:             if (lParam != 0)
   982:             {
   983:                 char style[MAX_LINE_LENGTH];
   984:                 strcpy_s(style, sizeofArray(style), (LPCSTR)lParam);
   985:                 if (strchr(style, '\"')) StrRemoveEncap(style);
   986:                 if (strchr(style, '$')) ReplaceShellFolders(style);
   987:                 if (strchr(style, '%')) ReplaceEnvVars(style);
   988: 
   989:                 if (!FileExists(style))
   990:                 {
   991:                     MBoxErrorFile(style);
   992:                     break;
   993:                 }
   994:                 stylePath(style); // Save the new style path to blackbox.rc etc.
   995:             }
   996: 
   997:             // Read the new style settings...
   998:             pSettings->ReadStyle();
   999: 
  1000:             // Show style change message in the console...
  1001:             char msg[MAX_LINE_LENGTH], a1[MAX_LINE_LENGTH], a2[MAX_LINE_LENGTH]; // , a3[MAX_LINE_LENGTH];
  1002:             strcpy_s(a1, sizeofArray(a1), ReadString(pSettings->styleFile, "style.name:", "[Style name not specified]"));
  1003:             strcpy_s(a2, sizeofArray(a2), ReadString(pSettings->styleFile, "style.author:", "[Author not specified]"));
  1004: //          strcpy_s(a3, sizeofArray(a3), ReadString(pSettings->styleFile, "style.wallpaper:", ""));
  1005: //          if (strnlen_s(a3, sizeofArray(a3))) sprintf_s(msg, sizeofArray(msg), "Applying \"%s\" by %s... (suggested wallpaper -> %s )", a1, a2, a3);
  1006: //          else sprintf_s(msg, sizeofArray(msg), "Applying \"%s\" by %s...", a1, a2);
  1007:             sprintf_s(msg, sizeofArray(msg), "Applying \"%s\" by %s...", a1, a2);
  1008:             SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_REGULAR_MESSAGE, (LPARAM)msg);
  1009: 
  1010:             // Update global menu settings (item heights, fonts...)
  1011:             pMenuCommon->Configure();
  1012: 
  1013:             // Temporarily lock the dock to avoid repeated SLIT_UPDATE messages from plugins... (i.e. repeated repaints of the dock window)
  1014:             pDock->ReconfigureLock(true);
  1015: 
  1016:             // Reconfigure...
  1017:             SendMessage(GetBBWnd(), BB_RECONFIGURE, 0, 0);
  1018: 
  1019:             // As a "security precausion", we also move the desktop window to the bottom...
  1020: //          SetWindowPos(pDesktop->hDesktopWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSENDCHANGING);
  1021:             SetWindowPos(pDesktop->hDesktopWnd, GetDesktopWindow(), 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSENDCHANGING);
  1022: 
  1023:             // Finally, we execute the rootCommand (nb. only "bsetbg" or "bsetroot", now internally parsed, allowed!) in a separate thread...
  1024:             if (!wParam && !pSettings->disableRootCommands) _beginthread(ExecuteRootCommand, 0, NULL);
  1025: 
  1026:             pSettings->Statistics.changedStyle++; // Update statistics...
  1027:         }
  1028:         break;
  1029: 
  1030:         //====================
  1031: 
  1032:         case WM_DISPLAYCHANGE:
  1033:         {
  1034:             if (!pSettings->disableRootCommands) _beginthread(ExecuteRootCommand, 0, NULL); // Refresh the desktop wallpaper by re-running the current style's rootCommand...
  1035:         }
  1036:         break;
  1037: 
  1038:         //====================
  1039: 
  1040:         case WM_DPICHANGED:
  1041:         {
  1042:             int dpiValue = (int)LOWORD(wParam);
  1043:             int scaleFactor = 0;
  1044: 
  1045:             switch (dpiValue)
  1046:             {
  1047:                 case 384: { scaleFactor = 400; } break; // 384 DPI -> 400%
  1048:                 case 336: { scaleFactor = 350; } break; // 336 DPI -> 350%
  1049:                 case 288: { scaleFactor = 300; } break; // 288 DPI -> 300%
  1050:                 case 240: { scaleFactor = 250; } break; // 240 DPI -> 250%
  1051:                 case 216: { scaleFactor = 225; } break; // 216 DPI -> 225%
  1052:                 case 192: { scaleFactor = 200; } break; // 192 DPI -> 200%
  1053:                 case 168: { scaleFactor = 175; } break; // 168 DPI -> 175%
  1054:                 case 144: { scaleFactor = 150; } break; // 144 DPI -> 150%
  1055:                 case 120: { scaleFactor = 125; } break; // 120 DPI -> 125%
  1056:                 case 96: { scaleFactor = 100; } break; // 96 DPI -> 100%
  1057:                 default: break; // Unknown DPI value
  1058:             }
  1059: 
  1060:             char msg[350];
  1061:             if (scaleFactor > 0) sprintf_s(msg, sizeofArray(msg), "Windows UI scaling factor has changed to %d%%. xoblite HiDPI scaling factor is set to %dx. ", scaleFactor, pSettings->scalingFactorHiDPI);
  1062:             else sprintf_s(msg, sizeofArray(msg), "Windows UI scaling resolution has changed to %d DPI. xoblite HiDPI scaling factor is set to %dx. ", dpiValue, pSettings->scalingFactorHiDPI);
  1063:             SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
  1064: 
  1065:             return 0;
  1066:         }
  1067: 
  1068:         //====================
  1069: 
  1070:         case BB_EDITFILE:
  1071:         {
  1072:             switch (wParam)
  1073:             {
  1074:                 case 0: // Open the current style file for editing
  1075:                     BBExecute(GetDesktopWindow(), NULL, pSettings->preferredEditor, pSettings->styleFile, NULL, SW_SHOWNORMAL, false);
  1076:                 break;
  1077:                 case 1: // Open the current menu.rc file for editing
  1078:                     BBExecute(GetDesktopWindow(), NULL, pSettings->preferredEditor, pSettings->menuFile, NULL, SW_SHOWNORMAL, false);
  1079:                 break;
  1080:                 case 2: // Open the current plugins.rc file for editing
  1081:                     BBExecute(GetDesktopWindow(), NULL, pSettings->preferredEditor, pSettings->pluginsFile, NULL, SW_SHOWNORMAL, false);
  1082:                 break;
  1083:                 case 3: // Open the current theme's xoblite.rc (or if used, legacy extensions.rc) file for editing
  1084:                     BBExecute(GetDesktopWindow(), NULL, pSettings->preferredEditor, pSettings->xobrcFile, NULL, SW_SHOWNORMAL, false);
  1085:                 break;
  1086:                 case 4: // Open the default xoblite.rc (or if used, legacy blackbox.rc) file for editing
  1087:                     BBExecute(GetDesktopWindow(), NULL, pSettings->preferredEditor, pSettings->xobrcDefaultFile, NULL, SW_SHOWNORMAL, false);
  1088:                 break;
  1089:                 default:
  1090:                 break;
  1091:             }
  1092:             return 0;
  1093:         }
  1094:         break;
  1095: 
  1096:         //====================
  1097: 
  1098:         case BB_TOGGLEPLUGINS:
  1099:         {
  1100:             if (pSettings->pluginsHidden)
  1101:             {
  1102:                 SendMessage(hMainWnd, BB_BROADCAST, 0, (LPARAM)"@BBShowPlugins");
  1103:                 pSettings->pluginsHidden = false;
  1104:             }
  1105:             else
  1106:             {
  1107:                 SendMessage(hMainWnd, BB_BROADCAST, 0, (LPARAM)"@BBHidePlugins");
  1108:                 pSettings->pluginsHidden = true;
  1109:             }
  1110: 
  1111:             // Move the console->dock->toolbar, if not hidden, back to the top... (i.e. so they're not covered by any non-alwaysontop plugins)
  1112:             if (!pSettings->consoleHidden) SetForegroundWindow(pConsole->hConsoleWnd);
  1113:             if (!pSettings->dockHidden) SetForegroundWindow(pDock->hDockWnd);
  1114:             if (!pSettings->toolbarHidden) SetForegroundWindow(pToolbar->hToolbarWnd);
  1115: 
  1116:             WriteBool(pSettings->xobrcFile, "xoblite.plugins.hidden:", pSettings->pluginsHidden);
  1117:         }
  1118:         break;
  1119: 
  1120:         //====================
  1121: 
  1122:         case BB_RUN: // This is called e.g. from a menu [run] item...
  1123:         {
  1124:             if ((int)lParam == 1) BBSmartExecute("@xoblite Run"); // -> The xoblite super-powered run box... (i.e. this includes support for bro@ms, @script as well as regular commands, but lacks a "Browse..." function etc)
  1125:             else RunDlg( NULL, NULL, NULL, NULL, NULL, 0 ); // -> The regular Windows run dialog... (i.e. this lacks support for bro@ms and @script of course, but has a "Browse..." function etc)
  1126:         }
  1127:         break;
  1128: 
  1129:         case WM_CTLCOLOREDIT: // Used by the xoblite run box edit window... (nb. for menu string item edit windows this is handled by the item's parent menu)
  1130:         {
  1131:             // SetTextColor((HDC)wParam, pSettings->Toolbar->TextColor);
  1132:             // SetBkColor((HDC)wParam, pSettings->Toolbar->Color);
  1133:             SetTextColor((HDC)wParam, 0x000000);
  1134:             SetBkColor((HDC)wParam, 0xffffff);
  1135:             return (LRESULT)GetStockObject(NULL_BRUSH);
  1136:         }
  1137:         break;
  1138: 
  1139:         //====================
  1140: 
  1141:         case BB_REGISTERMESSAGE:
  1142:         {
  1143:             UINT *msgArray = (UINT*)lParam;
  1144:             for (int size = 0; msgArray[size] != 0; size++)
  1145:             {
  1146:                 pMessageManager->AddMessage(msgArray[size], (HWND)wParam);
  1147:             }
  1148:             break;
  1149:         }
  1150: 
  1151:         case BB_UNREGISTERMESSAGE:
  1152:         {
  1153:             UINT *msgArray = (UINT*)lParam;
  1154:             for (int size = 0; msgArray[size] != 0; size++)
  1155:             {
  1156:                 pMessageManager->RemoveMessage(msgArray[size], (HWND)wParam);
  1157:             }
  1158:             break;
  1159:         }
  1160: 
  1161:         //====================
  1162: 
  1163:         case WM_COPYDATA: // Used by Blackbox.exe -broam <string>
  1164:         {
  1165:             PCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT)lParam;
  1166:             if (pcds->dwData == BB_BROADCAST) SendMessage(GetBBWnd(), BB_BROADCAST, 0, (LPARAM)pcds->lpData);
  1167:             else if (pcds->dwData == BB_SETSTYLE) PostMessage(GetBBWnd(), BB_SETSTYLE, 0, (LPARAM)pcds->lpData);
  1168:             break;
  1169:         }
  1170: 
  1171:         //====================
  1172: 
  1173:         case WM_DROPFILES:
  1174:         {
  1175:             // Forward any drag'n'drop messages to the Desktop for parsing...
  1176:             if (pDesktop) return PostMessage(pDesktop->hDesktopWnd, WM_DROPFILES, wParam, lParam);
  1177:         }
  1178:         break;
  1179: 
  1180:         //====================
  1181: 
  1182:         case WM_TIMER:
  1183:         {
  1184:             // CHECK_EXPLORER_HIDDEN_TIMER:
  1185:             // -> Timer to check whether the Explorer taskbar has gone visible again,
  1186:             // despite having been previously hidden... (read: I'm not 100% sure why/when
  1187:             // this happens yet, so continuously checking is more "foolproof" for now ;) )
  1188:             if (wParam == CHECK_EXPLORER_HIDDEN_TIMER)
  1189:             {
  1190:                 if (pSettings->explorerHidden)
  1191:                 {
  1192:                     if (pSettings->underExplorer && IsWindowVisible(FindWindow("Shell_TrayWnd", NULL)))
  1193:                     {
  1194:                         HideExplorer(true);
  1195:                         HideDesktopIcons(true);
  1196:                     }
  1197:                 }
  1198: 
  1199:                 return 0;
  1200:             }
  1201: 
  1202:             // SESSION_DURATION_TIMER:
  1203:             // -> Timer to measure the length of the session in minutes...
  1204:             // (used to calculate the duration of the session when it ends)
  1205:             else if (wParam == SESSION_DURATION_TIMER)
  1206:             {
  1207:                 sessionDuration++;
  1208:                 return 0;
  1209:             }
  1210: 
  1211:             // CHECK_FOR_FULLSCREEN_TIMER:
  1212:             // -> Timer to recurringly check for applications entering/exiting fullscreen,
  1213:             //    and to hide/show the xoblite core UI elements when this happens...
  1214:             else if (wParam == CHECK_FOR_FULLSCREEN_TIMER)
  1215:             {
  1216:                 if (!pSettings->fullscreenDetection) return 0;
  1217: 
  1218:                 char msg[MAX_LINE_LENGTH], windowText[MAX_LINE_LENGTH];
  1219: 
  1220:                 HWND window = NULL;
  1221:                 if (pTaskbar) window = pTaskbar->GetActiveWindow(); // First we check if the application window being focused is visible on the taskbar...
  1222:                 if (window == NULL) window = GetForegroundWindow(); // ...then fallback in case of a non-taskbar (i.e. normal taskbar IsAppWindow() checks failed) application window being focused.
  1223:                 if (window == NULL) return 0;
  1224:                 if (IsIconic(window)) return 0;
  1225: 
  1226:                 GetWindowText(window, windowText, sizeof(windowText));
  1227:                 if (!_stricmp(windowText, "Program Manager")) return 0;
  1228: //              if (strlen(windowText) == 0) return 0;
  1229: 
  1230:                 RECT r;
  1231:                 GetWindowRect(window, &r);
  1232:                 int windowWidth = r.right - r.left;
  1233:                 int windowHeight = r.bottom - r.top;
  1234: 
  1235:                 int fullscreenWidth = GetSystemMetrics(SM_CXSCREEN);
  1236:                 int fullscreenHeight = GetSystemMetrics(SM_CYSCREEN);
  1237: 
  1238:                 QUERY_USER_NOTIFICATION_STATE quns;
  1239:                 SHQueryUserNotificationState(&quns);
  1240: 
  1241:                 // Note: For reasons yet to be understood, the QUNS_BUSY state (and/or the related do-not-disturb focus mode handling by Windows) is not fully
  1242:                 // reliable and can lead to ping-pong hide/show scenarios; hence not relied upon below, in favour of simple window-vs-screen size match checking.
  1243: 
  1244: //              if (((windowWidth == fullscreenWidth) && (windowHeight == fullscreenHeight)) || (quns == QUNS_RUNNING_D3D_FULL_SCREEN) || (quns == QUNS_PRESENTATION_MODE))
  1245:                 if ((!pSettings->explorerHidden && (windowWidth == fullscreenWidth) && (windowHeight == fullscreenHeight)) || (quns == QUNS_RUNNING_D3D_FULL_SCREEN) || (quns == QUNS_PRESENTATION_MODE))
  1246:                 {
  1247:                     if (!somethingIsFullscreen)
  1248:                     {
  1249:                         somethingIsFullscreen = true;
  1250:                         pDesktop->FullscreenDetected(true);
  1251:                         pToolbar->FullscreenDetected(true);
  1252:                         pDock->FullscreenDetected(true);
  1253:                         pConsole->FullscreenDetected(true);
  1254: 
  1255:                         if (pSettings->debugLogging)
  1256:                         {
  1257:                             sprintf_s(msg, sizeofArray(msg), "DEBUG -> Blackbox::MainWndProc -> \"%s\" has entered fullscreen mode.", windowText);
  1258:                             switch (quns)
  1259:                             {
  1260:                                 case QUNS_RUNNING_D3D_FULL_SCREEN:  { strcat_s(msg, sizeofArray(msg), " | QUNS_RUNNING_D3D_FULL_SCREEN"); break; }
  1261:                                 case QUNS_PRESENTATION_MODE:        { strcat_s(msg, sizeofArray(msg), " | QUNS_PRESENTATION_MODE"); break; }
  1262:                                 default:                            { strcat_s(msg, sizeofArray(msg), " | WINDOW_SIZE_MATCH"); break; }
  1263:                             }
  1264:                             SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
  1265:                             Log(msg, "");
  1266: 
  1267:                         }
  1268: //                      else SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INDENTED_MESSAGE, (LPARAM)"...suspending xoblite core UI elements, following an application having entered fullscreen mode.");
  1269:                     }
  1270:                 }
  1271:                 else
  1272:                 {
  1273:                     if (somethingIsFullscreen)
  1274:                     {
  1275:                         somethingIsFullscreen = false;
  1276:                         pDesktop->FullscreenDetected(false);
  1277:                         pToolbar->FullscreenDetected(false);
  1278:                         pDock->FullscreenDetected(false);
  1279:                         pConsole->FullscreenDetected(false);
  1280: 
  1281:                         if (pSettings->debugLogging)
  1282:                         {
  1283:                             sprintf_s(msg, sizeofArray(msg), "DEBUG -> Blackbox::MainWndProc -> \"%s\" has exited fullscreen mode.", windowText);
  1284:                             SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
  1285:                             Log(msg, "");
  1286:                         }
  1287: //                      else SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INDENTED_MESSAGE, (LPARAM)"...resuming xoblite core UI elements, following an application having exited fullscreen mode.");
  1288:                     }
  1289:                 }
  1290: /*
  1291:                 QUERY_USER_NOTIFICATION_STATE quns;
  1292:                 SHQueryUserNotificationState(&quns);
  1293:                 switch (quns)
  1294:                 {
  1295: //                  case QUNS_BUSY: // Note: For reasons yet to be understood, the QUNS_BUSY state (and/or the Windows do-not-disturb focus mode handling) is not fully reliable and can lead to ping-pong hide/show scenarios :( -> FFS?
  1296:                     case QUNS_RUNNING_D3D_FULL_SCREEN:
  1297:                     case QUNS_PRESENTATION_MODE:
  1298:                     {
  1299:                         if ((uint8_t)quns != lastFullscreenCheckStatus)
  1300:                         {
  1301:                             if (pSettings->debugLogging)
  1302:                             {
  1303:                                 switch (quns)
  1304:                                 {
  1305: //                                  case QUNS_BUSY:                     { strcpy_s(qunsModeText, sizeofArray(qunsModeText), "QUNS_BUSY"); break; }                          // -> "A full-screen application is running or Presentation Settings are applied."
  1306:                                     case QUNS_RUNNING_D3D_FULL_SCREEN:  { strcpy_s(qunsModeText, sizeofArray(qunsModeText), "QUNS_RUNNING_D3D_FULL_SCREEN"); break; }       // -> "A full-screen (exclusive mode) Direct3D application is running."
  1307:                                     case QUNS_PRESENTATION_MODE:        { strcpy_s(qunsModeText, sizeofArray(qunsModeText), "QUNS_PRESENTATION_MODE"); break; }             // -> "The user has activated Windows presentation settings to block notifications and pop-up messages."
  1308:                                     default: { break; }
  1309:                                 }
  1310: 
  1311:                                 sprintf_s(msg, sizeofArray(msg), "DEBUG -> Blackbox::MainWndProc -> The application \"%s\" has entered fullscreen mode. | %s", windowText, qunsModeText);
  1312:                                 SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
  1313:                                 Log("xoblite", msg);
  1314:                             }
  1315: 
  1316:                             if (!somethingIsFullscreen)
  1317:                             {
  1318:                                 somethingIsFullscreen = true;
  1319:                                 pDesktop->FullscreenDetected(true);
  1320:                                 pToolbar->FullscreenDetected(true);
  1321:                                 pDock->FullscreenDetected(true);
  1322:                                 pConsole->FullscreenDetected(true);
  1323:                                 SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INDENTED_MESSAGE, (LPARAM)"...suspending xoblite core UI elements, following an application having entered fullscreen mode.");
  1324:                             }
  1325: 
  1326:                             lastFullscreenCheckStatus = (uint8_t)quns;
  1327:                         }
  1328: 
  1329:                         break;
  1330:                     }
  1331: 
  1332:                     default:
  1333:                     {
  1334:                         if ((uint8_t)quns != lastFullscreenCheckStatus)
  1335:                         {
  1336:                             if (pSettings->debugLogging)
  1337:                             {
  1338:                                 switch (quns)
  1339:                                 {
  1340:                                     case QUNS_NOT_PRESENT:              { strcpy_s(qunsModeText, sizeofArray(qunsModeText), "QUNS_NOT_PRESENT"); break; }                   // -> "A screen saver is displayed, the machine is locked, or a nonactive Fast User Switching session is in progress."
  1341:                                     case QUNS_BUSY:                     { strcpy_s(qunsModeText, sizeofArray(qunsModeText), "QUNS_BUSY"); break; }                          // -> "A full-screen application is running or Presentation Settings are applied."
  1342: //                                  case QUNS_RUNNING_D3D_FULL_SCREEN:  { strcpy_s(qunsModeText, sizeofArray(qunsModeText), "QUNS_RUNNING_D3D_FULL_SCREEN"); break; }       // -> "A full-screen (exclusive mode) Direct3D application is running."
  1343: //                                  case QUNS_PRESENTATION_MODE:        { strcpy_s(qunsModeText, sizeofArray(qunsModeText), "QUNS_PRESENTATION_MODE"); break; }             // -> "The user has activated Windows presentation settings to block notifications and pop-up messages."
  1344:                                     case QUNS_ACCEPTS_NOTIFICATIONS:    { strcpy_s(qunsModeText, sizeofArray(qunsModeText), "QUNS_ACCEPTS_NOTIFICATIONS"); break; }         // -> "None of the other states are found, notifications can be freely sent."
  1345:                                     case QUNS_QUIET_TIME:               { strcpy_s(qunsModeText, sizeofArray(qunsModeText), "QUNS_QUIET_TIME"); break; }                    // -> "The current user is in "quiet time", which is the first hour after a new user logs into his or her account for the first time."
  1346:                                     case QUNS_APP:                      { strcpy_s(qunsModeText, sizeofArray(qunsModeText), "QUNS_APP"); break; }                           // -> "A Windows Store app is running."
  1347:                                     default:                            { sprintf_s(qunsModeText, sizeofArray(qunsModeText), "UNKNOWN QUNS VALUE (%d)", quns); break; }
  1348:                                 }
  1349: 
  1350:                                 sprintf_s(msg, sizeofArray(msg), "DEBUG -> Blackbox::MainWndProc -> The system's user notification state has changed. | %s / %s", qunsModeText, windowText);
  1351:                                 SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
  1352:                                 Log("xoblite", msg);
  1353:                             }
  1354: 
  1355:                             if (somethingIsFullscreen)
  1356:                             {
  1357:                                 somethingIsFullscreen = false;
  1358:                                 pDesktop->FullscreenDetected(false);
  1359:                                 pToolbar->FullscreenDetected(false);
  1360:                                 pDock->FullscreenDetected(false);
  1361:                                 pConsole->FullscreenDetected(false);
  1362:                                 SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INDENTED_MESSAGE, (LPARAM)"...resuming xoblite core UI elements, following an application having exited fullscreen mode.");
  1363:                             }
  1364: 
  1365:                             lastFullscreenCheckStatus = (uint8_t)quns;
  1366:                         }
  1367: 
  1368:                         break;
  1369:                     }
  1370:                 }
  1371: */
  1372:                 return 0;
  1373:             }
  1374: 
  1375:             // CHECK_FOR_UPDATES_DELAY_TIMER:
  1376:             // -> On first launch, and when resuming from sleep/hibernate,
  1377:             // we perform a check for updates, but only after a certain delay
  1378:             // to allow all other things as well as the user to warm up first... ;)
  1379:             else if (wParam == CHECK_FOR_UPDATES_DELAY_TIMER)
  1380:             {
  1381:                 KillTimer(GetBBWnd(), CHECK_FOR_UPDATES_DELAY_TIMER);
  1382:                 CheckForUpdates();
  1383:                 return 0;
  1384:             }
  1385: 
  1386:             return 0;
  1387:         }
  1388: 
  1389:         //====================
  1390: 
  1391:         case BB_BROADCAST:
  1392:         {
  1393:             char broam[MAX_LINE_LENGTH];
  1394:             strcpy_s(broam, sizeofArray(broam), (LPCSTR)lParam);
  1395:             if (ExecuteBroam(broam, hMainInstance)) return 0;
  1396:         }
  1397: 
  1398:         //====================
  1399: 
  1400:         case BB_TRAYICONMESSAGE:
  1401:         {
  1402:             switch (LOWORD(lParam))
  1403:             {
  1404:                 case WM_LBUTTONUP:
  1405:                 {
  1406:                     if ((GetAsyncKeyState(VK_CONTROL) & 0x8000) && pWorkspaces) pWorkspaces->NextWorkspace();
  1407:                     else if (pToolbar)
  1408:                     {
  1409: //                      pToolbar->UpdatePosition();
  1410:                         SetWindowPos(pToolbar->hToolbarWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
  1411:                         SetForegroundWindow(pToolbar->hToolbarWnd);
  1412:                         PlaySoundFX(SFX_MENU_CLICK);
  1413:                     }
  1414:                     break;
  1415:                 }
  1416: 
  1417:                 case WM_RBUTTONDOWN:
  1418:                 {
  1419:                     if ((GetAsyncKeyState(VK_CONTROL) & 0x8000) && pWorkspaces) pWorkspaces->PreviousWorkspace();
  1420:                     else if (pTaskbar) pTaskbar->MinimizeAllWindows();
  1421:                     break;
  1422:                 }
  1423: 
  1424:                 case WM_MOUSEWHEEL: // TEMPORARY "FOR TESTING" PLACEHOLDER
  1425:                 {
  1426:                     PlaySoundFX(SFX_MENU_NAVIGATE);
  1427:                     break;
  1428:                 }
  1429: 
  1430:                 default: { break; }
  1431:             }
  1432:         }
  1433: 
  1434:         //====================
  1435: 
  1436:         default:
  1437:         {
  1438:             if (uMsg == WM_TASKBARCREATED_MESSAGE)
  1439:             {
  1440:                 if (pSettings->underExplorer)
  1441:                 {
  1442:                     // The Explorer system tray has been recreated (e.g. due to Explorer crashing), so we need to re-add the xoblite icon to the system tray...
  1443:                     DestroyIcon(xobIconData.hIcon);
  1444:                     ZeroMemory(&xobIconData, sizeof(NOTIFYICONDATA));
  1445:                     xobIconData.cbSize = sizeof(NOTIFYICONDATA); // Older Windows versions -> NOTIFYICONDATA_V3_SIZE
  1446:                     xobIconData.hIcon = LoadIcon(hMainInstance, MAKEINTRESOURCE(IDI_XOBLITE));
  1447: //                  LoadIconMetric(hMainInstance, MAKEINTRESOURCE(IDI_XOBLITE), LIM_SMALL, &(xobIconData.hIcon));
  1448:                     strcpy_s(xobIconData.szTip, sizeofArray(xobIconData.szTip), "xoblite");
  1449:                     xobIconData.hWnd = GetBBWnd();
  1450:                     xobIconData.uID = 0;
  1451:                     xobIconData.uVersion = NOTIFYICON_VERSION_4; // // Older Windows versions -> 3
  1452:                     xobIconData.uCallbackMessage = BB_TRAYICONMESSAGE;
  1453:                     xobIconData.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
  1454:                     Shell_NotifyIcon(NIM_ADD, &xobIconData);
  1455:                 }
  1456:                 return 0;
  1457:             }
  1458: 
  1459:             //====================
  1460: 
  1461:             if (pMessageManager)
  1462:             {
  1463:                 unsigned int shellMessage = uMsg;
  1464:                 WPARAM replaceParam = wParam;
  1465: 
  1466:                 if (shellMessage == WM_SHELLHOOKMESSAGE)
  1467:                 {
  1468:                     if (wParam == HSHELL_WINDOWCREATED) shellMessage = BB_ADDTASK;
  1469:                     else if (wParam == HSHELL_WINDOWDESTROYED) shellMessage = BB_REMOVETASK;
  1470:                     else if (wParam == HSHELL_ACTIVATESHELLWINDOW) shellMessage = BB_ACTIVATESHELLWINDOW;
  1471:                     else if (wParam == HSHELL_WINDOWACTIVATED) shellMessage = BB_ACTIVETASK;
  1472:                     else if (wParam == HSHELL_RUDEAPPACTIVATED)
  1473:                     {
  1474:                         // Could there be a better way to support fullscreen windows?
  1475:                         // (e.g. unloading everything or disable alwaysontop elements)
  1476:                         shellMessage = BB_ACTIVETASK;
  1477: /*
  1478:                         if (pTaskbar)
  1479:                         {
  1480:                             HWND window = (HWND)lParam;
  1481:                             if (pTaskbar->FindTask(window) >= 0) shellMessage = BB_ACTIVETASK;
  1482:                             else shellMessage = BB_ADDTASK;
  1483:                         }
  1484:                         else shellMessage = BB_ACTIVETASK;
  1485: 
  1486:                         if (pSettings->debugLogging && pTaskbar)
  1487:                         {
  1488:                             char msg[MAX_LINE_LENGTH], windowText[MAX_LINE_LENGTH], windowClass[MAX_LINE_LENGTH];
  1489:                             GetWindowText((HWND)lParam, windowText, sizeof(windowText));
  1490:                             if (!strnlen_s(windowText, sizeofArray(windowText))) strcpy_s(windowText, sizeofArray(windowText), "NULL");
  1491:                             GetClassName((HWND)lParam, windowClass, sizeof(windowClass));
  1492:                             if (!strnlen_s(windowClass, sizeofArray(windowClass))) strcpy_s(windowClass, sizeofArray(windowClass), "NULL");
  1493:                             sprintf_s(msg, sizeofArray(msg), "WM_SHELLHOOKMESSAGE -> HSHELL_RUDEAPPACTIVATED -> %s | %s | Already on taskbar: ", windowText, windowClass);
  1494:                             HWND window = (HWND)lParam;
  1495:                             if (pTaskbar->FindTask(window) >= 0) strcat_s(msg, sizeofArray(msg), "Yes");
  1496:                             else strcat_s(msg, sizeofArray(msg), "No");
  1497: 
  1498:                             SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
  1499:                             Log("xoblite", msg);
  1500:                         }
  1501: */
  1502:                     }
  1503:                     else if (wParam == HSHELL_GETMINRECT) shellMessage = BB_MINMAXTASK;
  1504:                     else if (wParam == HSHELL_REDRAW) shellMessage = BB_REDRAW;
  1505:                     else if (wParam == HSHELL_FLASH)
  1506:                     {
  1507:                         // Insert flashing code here...
  1508:                         shellMessage = BB_REDRAW;
  1509:                         pTaskbar->flashingHwnd = (HWND)lParam;
  1510:                     }
  1511:                     else // -> Unsupported HSHELL message received!
  1512:                     {
  1513: /*
  1514:                         if (pSettings->debugLogging)
  1515:                         {
  1516:                             char msg[MAX_LINE_LENGTH], windowText[MAX_LINE_LENGTH], windowClass[MAX_LINE_LENGTH];
  1517:                             GetWindowText((HWND)lParam, windowText, sizeof(windowText));
  1518:                             if (!strnlen_s(windowText, sizeofArray(windowText))) strcpy_s(windowText, sizeofArray(windowText), "NULL");
  1519:                             GetClassName((HWND)lParam, windowClass, sizeof(windowClass));
  1520:                             if (!strnlen_s(windowClass, sizeofArray(windowClass))) strcpy_s(windowClass, sizeofArray(windowClass), "NULL");
  1521: 
  1522:                             if (wParam == HSHELL_TASKMAN) strcpy_s(msg, sizeofArray(msg), "Unsupported HSHELL message -> HSHELL_TASKMAN");
  1523:                             else if (wParam == HSHELL_LANGUAGE) strcpy_s(msg, sizeofArray(msg), "Unsupported HSHELL message -> HSHELL_LANGUAGE");
  1524:                             else if (wParam == HSHELL_SYSMENU) strcpy_s(msg, sizeofArray(msg), "Unsupported HSHELL message -> HSHELL_SYSMENU");
  1525:                             else if (wParam == HSHELL_ENDTASK) sprintf_s(msg, sizeofArray(msg), "Unsupported HSHELL message -> HSHELL_ENDTASK -> %s | %s", windowText, windowClass);
  1526:                             else if (wParam == HSHELL_ACCESSIBILITYSTATE) strcpy_s(msg, sizeofArray(msg), "Unsupported HSHELL message -> HSHELL_ACCESSIBILITYSTATE");
  1527:                             else if (wParam == HSHELL_APPCOMMAND) strcpy_s(msg, sizeofArray(msg), "Unsupported HSHELL message -> HSHELL_APPCOMMAND");
  1528:                             else if (wParam == HSHELL_WINDOWREPLACED) sprintf_s(msg, sizeofArray(msg), "Unsupported HSHELL message -> HSHELL_WINDOWREPLACED -> %s | %s", windowText, windowClass);
  1529:                             else if (wParam == HSHELL_WINDOWREPLACING) sprintf_s(msg, sizeofArray(msg), "Unsupported HSHELL message -> HSHELL_WINDOWREPLACING -> %s | %s", windowText, windowClass);
  1530:                             else if (wParam == HSHELL_MONITORCHANGED) sprintf_s(msg, sizeofArray(msg), "Unsupported HSHELL message -> HSHELL_MONITORCHANGED -> %s | %s", windowText, windowClass);
  1531:                             else sprintf_s(msg, sizeofArray(msg), "Unknown HSHELL message -> 0x%lx -> %s | %s", (LONG)wParam, windowText, windowClass);
  1532: 
  1533:                             SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
  1534:                             Log("xoblite", msg);
  1535:                         }
  1536: */
  1537:                         return DefWindowProc(hWnd, uMsg, wParam, lParam);
  1538:                     }
  1539: 
  1540:                     replaceParam = (WPARAM)lParam; // Replacement wParam set to the hwnd
  1541:                 }
  1542: 
  1543:                 //====================
  1544: 
  1545:                 if (pMessageManager->HandlerExists(shellMessage))
  1546:                 {
  1547:                     LRESULT lResult;
  1548:                     if (pMessageManager->SendMessage(shellMessage, replaceParam, lParam, &lResult)) return lResult;
  1549:                 }
  1550:             }
  1551: 
  1552:             return DefWindowProc(hWnd, uMsg, wParam, lParam);
  1553:         }
  1554: 
  1555:         //====================
  1556:     }
  1557: 
  1558:     return DefWindowProc(hWnd, uMsg, wParam, lParam);
  1559: }
  1560: 
  1561: //===========================================================================
  1562: // Function: ShellHookProc
  1563: // Purpose: WH_SHELL hook procedure (see SetWindowsHookEx etc above)
  1564: //===========================================================================
  1565: 
  1566: LRESULT CALLBACK ShellHookProc(int nCode, WPARAM wParam, LPARAM lParam)
  1567: {
  1568:     if (nCode < 0)
  1569:     {
  1570:         if (pSettings->debugLogging) Log("DEBUG -> ShellHookProc -> nCode < 0 (i.e. \"do not process this message\")", "");
  1571:         return CallNextHookEx(shellHook, nCode, wParam, lParam);
  1572:     }
  1573: 
  1574:     if (pSettings->debugLogging)
  1575:     {
  1576:         char msg[MAX_LINE_LENGTH];
  1577:         switch (nCode)
  1578:         {
  1579:             case HSHELL_WINDOWCREATED: { strcpy_s(msg, sizeofArray(msg), "DEBUG -> ShellHookProc -> HSHELL_WINDOWCREATED"); break; }
  1580:             case HSHELL_WINDOWDESTROYED: { strcpy_s(msg, sizeofArray(msg), "DEBUG -> ShellHookProc -> HSHELL_WINDOWDESTROYED"); break; }
  1581:             case HSHELL_ACTIVATESHELLWINDOW: { strcpy_s(msg, sizeofArray(msg), "DEBUG -> ShellHookProc -> HSHELL_ACTIVATESHELLWINDOW"); break; }
  1582:             case HSHELL_WINDOWACTIVATED: { strcpy_s(msg, sizeofArray(msg), "DEBUG -> ShellHookProc -> HSHELL_WINDOWACTIVATED"); break; }
  1583:             case HSHELL_GETMINRECT: { strcpy_s(msg, sizeofArray(msg), "DEBUG -> ShellHookProc -> HSHELL_GETMINRECT"); break; }
  1584:             case HSHELL_REDRAW: { strcpy_s(msg, sizeofArray(msg), "DEBUG -> ShellHookProc -> HSHELL_REDRAW"); break; }
  1585:             case HSHELL_TASKMAN: { strcpy_s(msg, sizeofArray(msg), "DEBUG -> ShellHookProc -> HSHELL_TASKMAN"); break; }
  1586:             case HSHELL_LANGUAGE: { strcpy_s(msg, sizeofArray(msg), "DEBUG -> ShellHookProc -> HSHELL_LANGUAGE"); break; }
  1587: 
  1588:             case HSHELL_ACCESSIBILITYSTATE: { strcpy_s(msg, sizeofArray(msg), "DEBUG -> ShellHookProc -> HSHELL_ACCESSIBILITYSTATE"); break; }
  1589:             case HSHELL_APPCOMMAND: { strcpy_s(msg, sizeofArray(msg), "DEBUG -> ShellHookProc -> HSHELL_APPCOMMAND"); break; }
  1590:             case HSHELL_WINDOWREPLACED: { strcpy_s(msg, sizeofArray(msg), "DEBUG -> ShellHookProc -> HSHELL_WINDOWREPLACED"); break; }
  1591: 
  1592:             default: { sprintf_s(msg, sizeofArray(msg), "DEBUG -> ShellHookProc -> Unknown HSHELL message -> 0x%lx", (LONG)nCode); break; }
  1593:         }
  1594:         strcat_s(msg, sizeofArray(msg), " -> Forwarding to the *box internal message bus for further processing.");
  1595:         PostMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
  1596:         Log("xoblite", msg);
  1597:     }
  1598: 
  1599:     if (pMessageManager) PostMessage(GetBBWnd(), WM_SHELLHOOKMESSAGE, (WPARAM)nCode, (LPARAM)wParam);
  1600: 
  1601:     return CallNextHookEx(shellHook, nCode, wParam, lParam);
  1602: /*
  1603:     if (pMessageManager)
  1604:     {
  1605:         unsigned int shellMessage = nCode;
  1606:         WPARAM replaceParam = wParam;
  1607: 
  1608:         //====================
  1609: 
  1610:         if (nCode == HSHELL_WINDOWCREATED) shellMessage = BB_ADDTASK;
  1611:         else if (nCode == HSHELL_WINDOWDESTROYED) shellMessage = BB_REMOVETASK;
  1612:         else if (nCode == HSHELL_ACTIVATESHELLWINDOW) shellMessage = BB_ACTIVATESHELLWINDOW;
  1613:         else if (nCode == HSHELL_WINDOWACTIVATED) shellMessage = BB_ACTIVETASK;
  1614:         else if (nCode == HSHELL_RUDEAPPACTIVATED)
  1615:         {
  1616:             // Could there be a better way to support fullscreen windows?
  1617:             // (e.g. unloading everything or disable alwaysontop elements)
  1618:             shellMessage = BB_ACTIVETASK;
  1619: 
  1620: //          if (pTaskbar)
  1621: //          {
  1622: //              HWND window = (HWND)lParam;
  1623: //              if (pTaskbar->FindTask(window) >= 0) shellMessage = BB_ACTIVETASK;
  1624: //              else shellMessage = BB_ADDTASK;
  1625: //          }
  1626: //          else shellMessage = BB_ACTIVETASK;
  1627: //
  1628: //          if (pSettings->debugLogging && pTaskbar)
  1629: //          {
  1630: //              char msg[MAX_LINE_LENGTH], windowText[MAX_LINE_LENGTH], windowClass[MAX_LINE_LENGTH];
  1631: //              GetWindowText((HWND)lParam, windowText, sizeof(windowText));
  1632: //              if (!strnlen_s(windowText, sizeofArray(windowText))) strcpy_s(windowText, sizeofArray(windowText), "NULL");
  1633: //              GetClassName((HWND)lParam, windowClass, sizeof(windowClass));
  1634: //              if (!strnlen_s(windowClass, sizeofArray(windowClass))) strcpy_s(windowClass, sizeofArray(windowClass),"NULL");
  1635: //              sprintf_s(msg, sizeofArray(msg), "WM_SHELLHOOKMESSAGE -> HSHELL_RUDEAPPACTIVATED -> %s | %s | Already on taskbar: ", windowText, windowClass);
  1636: //              HWND window = (HWND)lParam;
  1637: //              if (pTaskbar->FindTask(window) >= 0) strcat_s(msg, sizeofArray(msg), "Yes");
  1638: //              else strcat_s(msg, sizeofArray(msg), "No");
  1639: //
  1640: //              SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
  1641: //              Log("xoblite", msg);
  1642: //          }
  1643:         }
  1644:         else if (nCode == HSHELL_GETMINRECT) shellMessage = BB_MINMAXTASK;
  1645:         else if (nCode == HSHELL_REDRAW) shellMessage = BB_REDRAW;
  1646:         else if (nCode == HSHELL_FLASH)
  1647:         {
  1648:             // Insert flashing code here...
  1649:             shellMessage = BB_REDRAW;
  1650:             pTaskbar->flashingHwnd = (HWND)lParam;
  1651:         }
  1652:         else // -> Unsupported HSHELL message received!
  1653:         {
  1654:             if (pSettings->debugLogging)
  1655:             {
  1656:                 char msg[MAX_LINE_LENGTH], windowText[MAX_LINE_LENGTH], windowClass[MAX_LINE_LENGTH];
  1657:                 GetWindowText((HWND)wParam, windowText, sizeof(windowText));
  1658:                 if (!strnlen_s(windowText, sizeofArray(windowText))) strcpy_s(windowText, sizeofArray(windowText), "NULL");
  1659:                 GetClassName((HWND)wParam, windowClass, sizeof(windowClass));
  1660:                 if (!strnlen_s(windowClass, sizeofArray(windowText))) strcpy_s(windowClass, sizeofArray(windowClass), "NULL");
  1661: 
  1662:                 if (nCode == HSHELL_TASKMAN) strcpy_s(msg, sizeofArray(msg), "Unsupported HSHELL message -> HSHELL_TASKMAN");
  1663:                 else if (nCode == HSHELL_LANGUAGE) strcpy_s(msg, sizeofArray(msg), "Unsupported HSHELL message -> HSHELL_LANGUAGE");
  1664:                 else if (nCode == HSHELL_SYSMENU) strcpy_s(msg, sizeofArray(msg), "Unsupported HSHELL message -> HSHELL_SYSMENU");
  1665:                 else if (nCode == HSHELL_ENDTASK) sprintf_s(msg, sizeofArray(msg), "Unsupported HSHELL message -> HSHELL_ENDTASK -> %s | %s", windowText, windowClass);
  1666:                 else if (nCode == HSHELL_ACCESSIBILITYSTATE) strcpy_s(msg, sizeofArray(msg), "Unsupported HSHELL message -> HSHELL_ACCESSIBILITYSTATE");
  1667:                 else if (nCode == HSHELL_APPCOMMAND) strcpy_s(msg, sizeofArray(msg), "Unsupported HSHELL message -> HSHELL_APPCOMMAND");
  1668:                 else if (nCode == HSHELL_WINDOWREPLACED) sprintf_s(msg, sizeofArray(msg), "Unsupported HSHELL message -> HSHELL_WINDOWREPLACED -> %s | %s", windowText, windowClass);
  1669:                 else if (nCode == HSHELL_WINDOWREPLACING) sprintf_s(msg, sizeofArray(msg), "Unsupported HSHELL message -> HSHELL_WINDOWREPLACING -> %s | %s", windowText, windowClass);
  1670:                 else if (nCode == HSHELL_MONITORCHANGED) sprintf_s(msg, sizeofArray(msg), "Unsupported HSHELL message -> HSHELL_MONITORCHANGED -> %s | %s", windowText, windowClass);
  1671:                 else sprintf_s(msg, sizeofArray(msg), "Unknown HSHELL message -> 0x%lx -> %s | %s", (LONG)nCode, windowText, windowClass);
  1672: 
  1673:                 SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_INFORMATION_MESSAGE, (LPARAM)msg);
  1674:                 Log("xoblite", msg);
  1675:             }
  1676: 
  1677:             return CallNextHookEx(shellHook, nCode, wParam, lParam);
  1678:         }
  1679: 
  1680:         //====================
  1681: 
  1682:         if (pMessageManager->HandlerExists(shellMessage))
  1683:         {
  1684:             if (pSettings->debugLogging) Log("DEBUG -> In ShellHookProc, about to pMessageManager->SendMessage...", "");
  1685: 
  1686:             LRESULT lResult;
  1687:             if (pMessageManager->SendMessage(shellMessage, wParam, lParam, &lResult)) return lResult;
  1688:         }
  1689:     }
  1690: 
  1691:     return CallNextHookEx(shellHook, nCode, wParam, lParam);
  1692: */
  1693: }
  1694: 
  1695: //===========================================================================
  1696: // Function: ExecuteRootCommand
  1697: // Purpose: ...
  1698: //===========================================================================
  1699: 
  1700: void ExecuteRootCommand(void *)
  1701: {
  1702:     if (!pSettings->disableRootCommands)
  1703:     {
  1704:         if (!(GetAsyncKeyState(VK_CONTROL) & 0x8000)) // -> Do not run the rootCommand if the control key is held down...
  1705:         {
  1706:             char temp[MAX_LINE_LENGTH] = "", param[32];
  1707: 
  1708:             if (pSettings->wallpaperPerWorkspace && (pSettings->currentWorkspace > 0))
  1709:             {
  1710:                 sprintf_s(param, sizeofArray(param), "rootCommand%d:", (pSettings->currentWorkspace + 1));
  1711:                 strcpy_s(temp, sizeofArray(temp), ReadString(stylePath(), param, ""));
  1712:             }
  1713: 
  1714:             if (strnlen_s(temp, sizeofArray(temp)) == 0) strcpy_s(temp, sizeofArray(temp), ReadString(stylePath(), "rootCommand:", ""));
  1715: 
  1716:             if (strnlen_s(temp, sizeofArray(temp)) > 0)
  1717:             {
  1718:                 strcpy_s(pSettings->rootCommand, sizeofArray(pSettings->rootCommand), temp);
  1719:                 pWallpaper->ExecuteRootCommand();
  1720:             }
  1721:         }
  1722:     }
  1723:     else SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, NULL, SPIF_SENDCHANGE); // Trigger desktop repaint under Windows Vista (...iirc?)
  1724: 
  1725:     _endthread();
  1726: }
  1727: 
  1728: //===========================================================================
  1729: // Functions: ShutdownWindows / ShutdownThread
  1730: // Purpose: ...
  1731: //===========================================================================
  1732: 
  1733: void ShutdownWindows(int state, bool skipAsking) // 0=Shutdown, 1=Reboot, 2=Logoff, 3=Hibernate, 4=Standby/Suspend
  1734: {
  1735:     if (!skipAsking)
  1736:     {
  1737:         PlaySoundFX(SFX_MENU_CLICK);
  1738: 
  1739:         if (state == 0) SendMessage(GetBBWnd(), BB_POPUPMESSAGE, (WPARAM)"Are you sure you want to shut down your computer?", (LPARAM)"@xoblite System Shutdown");
  1740:         else if (state == 1) SendMessage(GetBBWnd(), BB_POPUPMESSAGE, (WPARAM)"Are you sure you want to reboot your computer?", (LPARAM)"@xoblite System Reboot");
  1741:         else if (state == 2) SendMessage(GetBBWnd(), BB_POPUPMESSAGE, (WPARAM)"Are you sure you want to log off?", (LPARAM)"@xoblite System LogOff");
  1742:         else if (state == 3) SendMessage(GetBBWnd(), BB_POPUPMESSAGE, (WPARAM)"Are you sure you want to hibernate?", (LPARAM)"@xoblite System Hibernate");
  1743:         else if (state == 4) SendMessage(GetBBWnd(), BB_POPUPMESSAGE, (WPARAM)"Are you sure you want to standby?", (LPARAM)"@xoblite System Standby");
  1744:         else return;
  1745:     }
  1746:     else
  1747:     {
  1748:         if (state < 3)
  1749:         {
  1750:             // To avoid a hanging Blackbox.exe due to e.g. slow unloading
  1751:             // plugins or certain hooks we perform the shell exit procedure
  1752:             // before initiating shutdown/reboot/logoff. Note that we can
  1753:             // always startBlackbox() again if the shutdown fails! (see below)
  1754:             exitBlackbox();
  1755:         }
  1756:         else
  1757:         {
  1758:             // Hibernate or standby -> Set time stamp for end of session...
  1759:             SessionTimeStamp(false);
  1760:         }
  1761: 
  1762:         // Run the shutdown functions in their own thread...
  1763:         shutdownState = state;
  1764:         _beginthread(ShutdownThread, 0, NULL);
  1765:     }
  1766: }
  1767: 
  1768: //===========================================================================
  1769: 
  1770: void ShutdownThread(void *) // Supporting function to ShutdownWindows() (see above)
  1771: {
  1772:     // Log off?
  1773:     if (shutdownState == 2)
  1774:     {
  1775:         if (!ExitWindowsEx(EWX_LOGOFF, SHTDN_REASON_FLAG_PLANNED))
  1776:         {
  1777:             MBoxErrorValue("Log off failed");
  1778:             PostMessage(GetBBWnd(), BB_RESTART, 0, 0);
  1779:         }
  1780:         else
  1781:         {
  1782:             debugLogoff = true;
  1783: //          PostMessage(hMainWnd, WM_CLOSE, 0, 0);
  1784:             PostQuitMessage(0);
  1785:         }
  1786: 
  1787:         _endthread();
  1788:     }
  1789: 
  1790:     //====================
  1791: 
  1792:     HANDLE hToken = NULL; 
  1793:     TOKEN_PRIVILEGES tkp; 
  1794:         
  1795:     OSVERSIONINFO osInfo;
  1796:     ZeroMemory(&osInfo, sizeof(osInfo));
  1797:     osInfo.dwOSVersionInfoSize = sizeof(osInfo);
  1798:     GetVersionEx(&osInfo);
  1799: 
  1800:     // Under WinNT/2k/XP we need to adjust priviliges to be able to shutdown/reboot/hibernate/standby...
  1801:     if (osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
  1802:     {
  1803:         // Get a token for this process...
  1804:         if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
  1805:         {
  1806:             MBoxErrorValue("OpenProcessToken failed");
  1807:             PostMessage(GetBBWnd(), BB_RESTART, 0, 0);
  1808:             _endthread();
  1809:         }
  1810: 
  1811:         // Get the LUID for the shutdown privilege... 
  1812:         LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid); 
  1813:         tkp.PrivilegeCount = 1;  // one privilege to set    
  1814:         tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 
  1815: 
  1816:         // Get the shutdown privileges for this process...
  1817:         AdjustTokenPrivileges(hToken, false, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0); 
  1818:         if (GetLastError() != ERROR_SUCCESS)
  1819:         {
  1820:             MBoxErrorValue("AdjustTokenPrivileges failed");
  1821:             PostMessage(GetBBWnd(), BB_RESTART, 0, 0);
  1822:             _endthread();
  1823:         }
  1824:     }
  1825:     
  1826:     //====================
  1827: 
  1828:     if (shutdownState == 0) // Shutdown?
  1829:     {
  1830:         if (!ExitWindowsEx(EWX_SHUTDOWN | EWX_POWEROFF, SHTDN_REASON_FLAG_PLANNED))
  1831:         {
  1832:             MBoxErrorValue("Shutdown failed!");
  1833:             PostMessage(GetBBWnd(), BB_RESTART, 0, 0);
  1834:         }
  1835:         else
  1836:         {
  1837:             debugShutdown = true;
  1838: //          PostMessage(hMainWnd, WM_CLOSE, 0, 0);
  1839:             PostQuitMessage(0);
  1840:         }
  1841:     }
  1842:     else if (shutdownState == 1) // Reboot?
  1843:     {
  1844:         if (!ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_FLAG_PLANNED))
  1845:         {
  1846:             MBoxErrorValue("Reboot failed!");
  1847:             // As the (un)installer may initiate a reboot we need to check
  1848:             // if the reboot was initiated by the (un)installer before
  1849:             // attempting to restart the shell... (see ShutdownWindows above)
  1850:             PostMessage(GetBBWnd(), BB_RESTART, 0, 0);
  1851:         }
  1852:         else
  1853:         {
  1854:             debugReboot = true;
  1855: //          PostMessage(hMainWnd, WM_CLOSE, 0, 0);
  1856:             PostQuitMessage(0);
  1857:         }
  1858:     }
  1859:     else if (shutdownState == 3) // Hibernate? (a.k.a. "safe sleep" and "suspend to disk")
  1860:     {
  1861:         if (!SetSystemPowerState(FALSE, FALSE)) MBoxErrorValue("Hibernate failed!");
  1862: //      ZeroMemory(&pSettings->Statistics, sizeof(pSettings->Statistics)); // Reset statistics...
  1863:         Sleep(3000); // Allow system clock some time to update after waking up... (note that we're running in a separate thread)
  1864:         SessionTimeStamp(true); // Begin new session...
  1865:         SetTimer(GetBBWnd(), CHECK_FOR_UPDATES_DELAY_TIMER, 3000, (TIMERPROC)NULL); // Wait 3 seconds, then perform a check for updates...
  1866:     }
  1867:     else if (shutdownState == 4) // Standby? (a.k.a. "sleep" and "suspend to RAM")
  1868:     {
  1869:         if (!SetSystemPowerState(TRUE, FALSE)) MBoxErrorValue("Standby failed!");
  1870: //      ZeroMemory(&pSettings->Statistics, sizeof(pSettings->Statistics)); // Reset statistics...
  1871:         Sleep(3000); // Allow system clock some time to update after waking up... (note that we're running in a separate thread)
  1872:         SessionTimeStamp(true); // Begin new session...
  1873:         SetTimer(GetBBWnd(), CHECK_FOR_UPDATES_DELAY_TIMER, 3000, (TIMERPROC)NULL); // Wait 3 seconds, then perform a check for updates...
  1874:     }
  1875: 
  1876:     // Disable shutdown privilege...
  1877:     tkp.Privileges[0].Attributes = 0; 
  1878:     AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);
  1879: 
  1880:     _endthread();
  1881: }
  1882: 
  1883: //===========================================================================
  1884: // Function: HideDesktopIcons
  1885: // Purpose: ...
  1886: //===========================================================================
  1887: 
  1888: bool desktopIconsPreviouslyHidden = false;
  1889: 
  1890: void HideDesktopIcons(bool hide)
  1891: {
  1892:     HWND window = FindWindow("Progman", "Program Manager");
  1893:     if (window != NULL)
  1894:     {
  1895:         window = FindWindowEx(window, NULL, "SHELLDLL_DefView", "");
  1896:         if (window != NULL)
  1897:         {
  1898:             window = FindWindowEx(window, NULL, "SysListView32", "FolderView");
  1899:             if (window != NULL)
  1900:             {
  1901:                 if (hide)
  1902:                 {
  1903:                     if (IsWindowVisible(window))
  1904:                     {
  1905:                         ShowWindow(window, SW_HIDE);
  1906:                         desktopIconsPreviouslyHidden = true;
  1907:                     }
  1908:                 }
  1909:                 else if (desktopIconsPreviouslyHidden) ShowWindow(window, SW_SHOWNOACTIVATE);
  1910:                 return;
  1911:             }
  1912:         }
  1913:     }
  1914: /*
  1915:     window = FindWindow("", "WorkerW");
  1916:     if (window != NULL)
  1917:     {
  1918:         window = FindWindowEx(window, NULL, "SHELLDLL_DefView", "");
  1919:         if (window != NULL)
  1920:         {
  1921:             window = FindWindowEx(window, NULL, "SysListView32", "FolderView");
  1922:             if (window != NULL)
  1923:             {
  1924:                 if (hide) ShowWindow(window, SW_HIDE);
  1925:                 else ShowWindow(window, SW_SHOWNOACTIVATE);
  1926:                 return;
  1927:             }
  1928:         }
  1929:     }
  1930: */
  1931: }
  1932: 
  1933: //===========================================================================
  1934: // Function: SessionTimeStamp
  1935: // Purpose: ...
  1936: //===========================================================================
  1937: 
  1938: void SessionTimeStamp(bool beginSession)
  1939: {
  1940:     time_t systemSessionTime;
  1941:     struct tm *localSessionTime;
  1942:     char timeStampString[MAX_LINE_LENGTH], msg[MAX_LINE_LENGTH];
  1943: 
  1944:     time(&systemSessionTime);
  1945:     localSessionTime = localtime(&systemSessionTime);
  1946: 
  1947:     //====================
  1948: 
  1949:     _locale_t timestampLocale = _create_locale(LC_TIME, "en-US"); // -> Always use en-US format for the console timestamp...
  1950:     if (strstr(pSettings->toolbarClockFormat, "%p"))
  1951:     {
  1952:         // 12-hour clock including the current locale's AM/PM indicator
  1953:         _strftime_l(timeStampString, MAX_LINE_LENGTH, "%a %#d %b at %I:%M %p", localSessionTime, timestampLocale);
  1954:     }
  1955:     else
  1956:     {
  1957:         // 24-hour clock
  1958:         _strftime_l(timeStampString, MAX_LINE_LENGTH, "%a %#d %b at %H:%M", localSessionTime, timestampLocale);
  1959:     }
  1960:     _free_locale(timestampLocale);
  1961: 
  1962:     //====================
  1963: 
  1964:     if (beginSession)
  1965:     {
  1966:         sessionDuration = 0;
  1967:         SetTimer(GetBBWnd(), SESSION_DURATION_TIMER, 60000, (TIMERPROC)NULL);
  1968:         sprintf_s(msg, sizeofArray(msg), "Session begins %s.", timeStampString);
  1969:     }
  1970:     else
  1971:     {
  1972:         KillTimer(GetBBWnd(), SESSION_DURATION_TIMER);
  1973:         int durHours = sessionDuration / 60;
  1974:         int durMinutes = sessionDuration % 60;
  1975: //      sprintf_s(msg, sizeofArray(msg), "Session ends %s (duration %d hour(s) %d minute(s)).", timeStampString, durHours, durMinutes);
  1976:         sprintf_s(msg, sizeofArray(msg), "Session ends %s (duration %d:%02d).", timeStampString, durHours, durMinutes);
  1977:     }
  1978: 
  1979:     SendMessage(GetBBWnd(), BB_CONSOLEMESSAGE, (WPARAM)CONSOLE_REGULAR_MESSAGE, (LPARAM)msg);
  1980:     Log("TimeStamp", msg);
  1981: }
  1982: 
  1983: //===========================================================================
  1984: 
  1985: void CheckForUpdates()
  1986: {
  1987:     if (pPluginManager && _stricmp(pSettings->checkedForUpdates, "*Disabled*")) _beginthread(periodicCheckForUpdates, 0, NULL);
  1988: }
  1989: 
  1990: //===========================================================================
  1991: 



syntax highlighting by

w e b c p p
web c plus plus