/*
 ============================================================================
 xoblite -> an alternative shell based on Blackbox for Windows
 Copyright © 2002-2005 Karl-Henrik Henriksson [qwilk]
 Copyright © 2001-2004 The Blackbox for Windows Development Team
 http://xoblite.net/ - #bb4win on irc.freenode.net
 ============================================================================

  Blackbox for Windows is free software, released under the
  GNU General Public License (GPL version 2 or later), with an extension
  that allows linking of proprietary modules under a controlled interface.
  What this means is that plugins etc. are allowed to be released
  under any license the author wishes. Please note, however, that the
  original Blackbox gradient math code used in Blackbox for Windows
  is available under the BSD license.

  http://www.fsf.org/licenses/gpl.html
  http://www.fsf.org/licenses/gpl-faq.html#LinkingOverControlledInterface
  http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.

  For additional license information, please read the included license.html

 ============================================================================
*/

#pragma comment(linker, "/opt:nowin98") 

#include "BBApi.h" 
#include "BImage.h" 
#include "Settings.h" 
#include "Desk.h" 
#include "Menu/MenuMaker.h" 
#include "Menu/Menu.h" 
#include "Toolbar.h" 
#include "TrayManager.h" 
#include "Systembar.h" 
#include "Workspaces.h" 
#include "Slit.h" 
#include "PluginManager.h" 
#include "MessageManager.h" 
#include "resource.h" 
#include <process.h> 
#include <windows.h> 
#include <commdlg.h> 
#include <time.h> 
#include <shlobj.h> 

BImage *pBImage;
Settings *pSettings;
MenuMaker* pMenuMaker;
Menu* pMenu;
Desk *pDesk;
Slit *pSlit;
PluginManager *pPluginManager;
Toolbar *pToolbar;
TrayManager *pTrayManager;
Systembar *pSystembar;
Workspaces *pWorkspaces;
MessageManager *pMessageManager;

//====================

LRESULT CALLBACK MainWndProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

void startBlackbox();
void exitBlackbox();
void restartBlackboxStop();
void restartBlackboxStart();

void ExecuteScript(void *param);
void ExecuteRootCommand(void *);

void ShutdownWindows(int state);
void ShutdownThread(void *);

bool IsFirstRunThisSession();
void RunStartupStuff (void *underExplorer);
void RunEntriesIn (HKEY key, LPCSTR path, bool deleteEntry);
void RunFolderContents(LPCSTR szParams);

void installBlackbox();
void uninstallBlackbox();
int checkPath();

void HideExplorer();
void ShowExplorer();
BOOL CALLBACK ExplorerEnumWindowsProc(HWND hwnd, LPARAM lParam);

//====================

const char szMainClass[] = "xoblite";

HINSTANCE hMainInstance = NULL;
HWND hMainWnd = NULL;
HANDLE hMutex;

bool switchNoStartup = false;
bool pauseRestart = false;
int shutdownState;
bool shutdownInMainThread = false;
bool exitInProgress = false;
HANDLE hShellReadyEvent;

bool debugLogoff = false, debugReboot = false, debugShutdown = false;

HMODULE hShell32Module = NULL;
typedef void (__stdcall *MSWINSHUTDOWNPROC)(HWND);
MSWINSHUTDOWNPROC MSWinShutdown = NULL;
typedef void (__stdcall *RUNDLGPROC)(HWND, HICON, LPCSTR, LPCSTR, LPCSTR, int);
RUNDLGPROC RunDlg = NULL;
typedef void (__stdcall *STTWTYPE)(HWND, int);
STTWTYPE BBSwitchToThisWindow;

HMODULE hShDocVwModule = NULL;
void (__stdcall *ShellDDEInit_shdocvw)(bool bInit) = 0;

FARPROC (__stdcall *RegisterShellHook) (HWND, DWORD) = NULL;
unsigned int WM_ShellHook = 0;

#ifndef REGSTR_PATH_EXPLORER 
#define REGSTR_PATH_EXPLORER TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer") 
#endif 

#define ID_HOTKEY 0 

//===========================================================================

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
        hMainInstance = hInstance;

        // Extract switches...
        char option[MAX_LINE_LENGTH], extra[MAX_LINE_LENGTH];
        char* tokens[1];
        tokens[0] = option;
        option[0] = extra[0] = '\0';
        BBTokenize(lpCmdLine, tokens, 1, extra);

        //====================

        if ((!stricmp(option, "-about")) || (!stricmp(option, "-help")))
        {
                char msg[MAX_LINE_LENGTH], buffer[MAX_LINE_LENGTH];
                ULONG *size = 0;
                void *value;
                UINT bytes;

                DWORD number = GetFileVersionInfoSize("Blackbox.exe", size);
                GetFileVersionInfo("Blackbox.exe", NULL, number, (LPVOID)buffer);
                 // Make sure the correct version encoding is used (currently "000004b0" = language neutral)
                VerQueryValue(buffer, TEXT("\\StringFileInfo\\000004b0\\FileVersion"), &value, &bytes);

                strcpy(msg, "xoblite ");
                strcat(msg, (LPCSTR)value);
                strcat(msg,
                                "\n\n© 2002-2005 Karl-Henrik Henriksson [qwilk]\n"
                                "© 2001-2004 The Blackbox for Windows Development Team\n\n"
                                "Contains a slightly modified version of the BImage rendering engine\n"
                                "used in the original \"Blackbox\" window manager for the X Window System   \n"
                                "© 1997-2000 Bradley T Hughes, 2001-2002 Sean 'Shaleh' Perry\n\n"
                                "Switches:\n\n"
                                "-about\t\tShow this information\n"
                                "-install\t\tInstall xoblite as your default shell\n"
                                "-uninstall\t\tUninstall xoblite\n"
                                "-nostartup\tDo not run startup programs (overrides extensions.rc)   \n"
                                "-broam <...>\tSend the specified broadcast message (\"bro@m\")   \n\n"
                                "More information about xoblite can be found in the documentation...   \n\n"
                                "http://xoblite.net/                              #bb4win on irc.freenode.net   ");

                MSGBOXPARAMS msgbox;
                ZeroMemory(&msgbox, sizeof(msgbox));
                msgbox.cbSize = sizeof(msgbox);
                msgbox.hwndOwner = GetBBWnd();
                msgbox.hInstance = hMainInstance;
                msgbox.lpszText = msg;
                msgbox.lpszCaption = "About xoblite...";
                msgbox.dwStyle = MB_OK | MB_SETFOREGROUND | MB_USERICON;
                msgbox.lpszIcon = MAKEINTRESOURCE(IDI_XOBLITE);
//              msgbox.dwContextHelpId = 0;
//              msgbox.lpfnMsgBoxCallback = NULL;
//              msgbox.dwLanguageId = LANG_NEUTRAL;
                MessageBoxIndirect(&msgbox);

                return 0;
        }
        else if (!stricmp(option, "-install"))
        {
                shutdownInMainThread = true;
                installBlackbox();
                return 0;
        }
        else if (!stricmp(option, "-uninstall"))
        {
                shutdownInMainThread = true;
                uninstallBlackbox();
                return 0;
        }
        else if (!stricmp(option, "-broam") && extra[0] == '@')
        {
                HWND xobhwnd = FindWindow(szMainClass, NULL);
                if (xobhwnd)
                {
                        COPYDATASTRUCT cds;
                        cds.dwData = BB_BROADCAST;
                        cds.cbData = MAX_LINE_LENGTH;
                        cds.lpData = &extra;
                        SendMessage(xobhwnd, WM_COPYDATA, NULL, (LPARAM)(&cds));
                }               
                return 0;
        }
        else if (!stricmp(option, "-nostartup"))
        {
                switchNoStartup = true;
        }
        else if (strchr(option, ':')) // Support for double clicking on .style files (paths always include a colon... <g>)
        {
                if (strlen(extra)) strcat(option, extra);
                if (!FileExists(option)) return 1;

                HWND xobhwnd = FindWindow(szMainClass, NULL);
                if (xobhwnd)
                {
                        COPYDATASTRUCT cds;
                        cds.dwData = BB_SETSTYLE;
                        cds.cbData = MAX_LINE_LENGTH;
                        cds.lpData = &option;
                        SendMessage(xobhwnd, WM_COPYDATA, NULL, (LPARAM)(&cds));
                }               
                return 0;
        }

        //====================

        // Tell the WinXP Welcome screen to close...
        // (fix courtesy of Nicolas Escuder / LiteStep 0.24.7 RC3)
        hShellReadyEvent = OpenEvent(EVENT_MODIFY_STATE, false, "msgina: ShellReadyEvent");
//      hShellReadyEvent = OpenEvent(EVENT_MODIFY_STATE, 1, "Global\\msgina: ShellReadyEvent");
//      hShellReadyEvent = OpenEvent(EVENT_MODIFY_STATE, 1, "Globalmsgina: ShellReadyEvent");
//      hShellReadyEvent = OpenEvent(EVENT_MODIFY_STATE, 1, "Globalmsgina: ReturnToWelcome");

        if (hShellReadyEvent != NULL)
        {
                SetEvent(hShellReadyEvent);
                CloseHandle(hShellReadyEvent);
        }

        //====================

        // Check if Blackbox is already running...
        hMutex = CreateMutex(NULL, false, "Blackbox");
        if (GetLastError() == ERROR_ALREADY_EXISTS)
        {
                MessageBox(0, "Previous instance of xoblite/Blackbox detected!   ", "xoblite", MB_OK | MB_SETFOREGROUND | MB_ICONSTOP);
                CloseHandle(hMutex);
                return 0;
        }

        //====================

        // Get addresses to undocumented Windows API calls...
        hShell32Module = GetModuleHandle("SHELL32.DLL");
        if (!hShell32Module) hShell32Module = LoadLibrary("SHELL32.DLL");
        MSWinShutdown = (MSWINSHUTDOWNPROC)(GetProcAddress(hShell32Module, (LPCSTR)MAKELPARAM(0x3C, 0)));
        RunDlg = (RUNDLGPROC)GetProcAddress(hShell32Module, (LPCSTR)MAKELPARAM(61, 0));
        //hUser32Module = GetModuleHandle("USER32.DLL");
        //if (!hUser32Module) hUser32Module = LoadLibrary("USER32.DLL");
        BBSwitchToThisWindow = (STTWTYPE)GetProcAddress(GetModuleHandle("USER32.DLL"), "SwitchToThisWindow");

        //====================

        // Hide minimized windows...
        MINIMIZEDMETRICS mm;
        ZeroMemory(&mm, sizeof(MINIMIZEDMETRICS));
        mm.cbSize = sizeof(MINIMIZEDMETRICS);
        SystemParametersInfo(SPI_GETMINIMIZEDMETRICS, sizeof(MINIMIZEDMETRICS), &mm, false);
        mm.iArrange |= ARW_HIDE; // ARW_HIDE == 8
        SystemParametersInfo(SPI_SETMINIMIZEDMETRICS, sizeof(MINIMIZEDMETRICS), &mm, false);

        //====================

        // Set up the main class...
        WNDCLASS wc;
        ZeroMemory(&wc, sizeof(wc));
        wc.hInstance = hMainInstance;
        wc.lpfnWndProc = MainWndProc;
        wc.lpszClassName = szMainClass;
        if (!RegisterClass(&wc))
        {
                MBoxErrorValue("Error registering xoblite class");
                Log("Error registering xoblite class", NULL);
                CloseHandle(hMutex);
                return 1;
        }

        // Set up the main window...
        hMainWnd = CreateWindowEx(
                       WS_EX_TOOLWINDOW,
                       szMainClass,
                       NULL,
                       WS_POPUP,
                       0, 0, 0, 0,
                       NULL,
                       NULL,
                       hMainInstance,
                       NULL);

        if (!hMainWnd)
        {
                MBoxErrorValue("Error creating the xoblite window");
                Log("Error creating the xoblite window", NULL);
                UnregisterClass(szMainClass, hMainInstance);
                CloseHandle(hMutex);
                return 1;
        }

        //====================

        // RegisterShellHook initialization...
        RegisterShellHook = (FARPROC (__stdcall *) (HWND, DWORD))GetProcAddress(hShell32Module, (LPCSTR)((long)0xb5));
        WM_ShellHook = RegisterWindowMessage("SHELLHOOK");

        if (RegisterShellHook)
        {
                OSVERSIONINFO osInfo;
                osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
                GetVersionEx(&osInfo);

                RegisterShellHook(NULL, true);

                if(osInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
                        RegisterShellHook(hMainWnd, 1);
                else
                        RegisterShellHook(hMainWnd, 3);
        }

        //====================

        // Initialize message manager and settings...
        pMessageManager = new MessageManager;
        pSettings = new Settings;
        pSettings->accessLock = false;

        // Are we running on top of Explorer? (check for the systray window class,
        // however unfortunately this will also lock on to a stand alone systray)
        if (FindWindow("Shell_TrayWnd", NULL)) pSettings->underExplorer = true;
        else pSettings->underExplorer = false;

        // Check OS version...
        OSVERSIONINFO osInfo;
        ZeroMemory(&osInfo, sizeof(osInfo));
        osInfo.dwOSVersionInfoSize = sizeof(osInfo);
        GetVersionEx(&osInfo);
        if (osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT && osInfo.dwMajorVersion == 5) pSettings->usingWin2kXP = true;
        else pSettings->usingWin2kXP = false;

        // Make our main window a Blackbox sticky window...
        MakeSticky(hMainWnd);

        // Start Blackbox elements...
        startBlackbox();

        SetForegroundWindow(hMainWnd);

        //====================

        // If -nostartup switch was used or if running on top of Explorer, do not run startup items...
        // Please note that startup items must be run after the Blackbox SysTray has launched to get tray icons...
        if (IsFirstRunThisSession() && !switchNoStartup && pSettings->runStartupApps && !pSettings->underExplorer)
                _beginthread(RunStartupStuff, 0, (LPVOID)pSettings->underExplorer);

        //====================

        // Initialize the Microsoft DDE server...
        // (using an undocumented API, courtesy of Tim DeWolf and the GeoShell Development Team)
        if (!pSettings->underExplorer && FindWindow("Progman", NULL) == NULL)
        {
                hShDocVwModule = LoadLibrary("SHDOCVW.DLL");
                if (hShDocVwModule) ShellDDEInit_shdocvw = (void (__stdcall *)(bool)) GetProcAddress(hShDocVwModule, (LPSTR) 118);

                if (ShellDDEInit_shdocvw) ShellDDEInit_shdocvw(true);
                // else MessageBox(NULL, "Unable to start shell DDE...   ", "xoblite", MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND);
                else SendMessage(GetBBWnd(), BB_SETTOOLBARLABEL, 0, (LPARAM)"xoblite -> Unable to start shell DDE...");
        }

        //====================

        // Retrieve messages from the message queue for any window
        // that belongs to this thread until we recieve WM_QUIT...
        BOOL value;
        MSG msg;

        while ((value = GetMessage(&msg, NULL, 0, 0 )) != 0)
        {
                if (value == -1) break;
                else
                {
                        TranslateMessage(&msg); 
                        DispatchMessage(&msg); 
                }
        }

        //====================

        // Shutdown the DDE server...
        if (ShellDDEInit_shdocvw) ShellDDEInit_shdocvw(false);
        if (hShDocVwModule) FreeLibrary(hShDocVwModule);

        //====================

        // exitBlackbox(); // This is now done before exiting the message queue...

        if (RegisterShellHook) RegisterShellHook(hMainWnd, 0);

        DestroyWindow(hMainWnd);
        UnregisterClass(szMainClass, hMainInstance);
        CloseHandle(hMutex);

        bool debugLogging = pSettings->debugLogging;

        if (pSettings) delete pSettings;
        if (pMessageManager) delete pMessageManager;

        //====================
/*
        if (returnToLogon)
        {
                // Return to the WinXP Welcome screen...
                hShellReadyEvent = OpenEvent(EVENT_MODIFY_STATE, 1, "Global\\msgina: ReturnToWelcome");

                if (hShellReadyEvent != NULL)
                {
                        SetEvent(hShellReadyEvent);
                        CloseHandle(hShellReadyEvent);
                }
        }
*/
        //====================

        if (debugLogging)
        {
                if (debugShutdown && debugReboot) Log("xoblite", "Exiting properly (External Shutdown/Reboot)");
                else if (debugShutdown) Log("xoblite", "Exiting properly (Shutdown)");
                else if (debugReboot) Log("xoblite", "Exiting properly (Reboot)");
                else if (debugLogoff) Log("xoblite", "Exiting properly (Logoff)");
        }

        return 0;
}

//===========================================================================

void startBlackbox()
{
        pSettings->GetShellFolders();

        //====================

        // Read only those settings from the default extensions.rc
        // that are required to set the correct theme at startup...
        strcpy(pSettings->themesFolder, ReadString(pSettings->extrcDefaultFile, "xoblite.themesFolder:", "$Blackbox$\\themes"));
        if (strchr(pSettings->themesFolder, '\"')) StrRemoveEncap(pSettings->themesFolder);
        if (strchr(pSettings->themesFolder, '$')) ReplaceShellFolders(pSettings->themesFolder);
        if (strchr(pSettings->themesFolder, '%')) ReplaceEnvVars(pSettings->themesFolder);
        strcpy(pSettings->selectedTheme, ReadString(pSettings->extrcDefaultFile, "xoblite.selected.theme:", "<Default>"));

        // Should we switch to a theme other than the default?
        if (stricmp(pSettings->selectedTheme, "<Default>"))
        {
                char path[MAX_PATH];

                strcpy(pSettings->SF_currentThemePath, pSettings->themesFolder);
                strcat(pSettings->SF_currentThemePath, "\\");
                strcat(pSettings->SF_currentThemePath, pSettings->selectedTheme);

                // Make sure it is a valid theme...
                strcpy(path, pSettings->SF_currentThemePath);
                strcat(path, "\\blackbox.rc");
                if (FileExists(path))
                {
                        pSettings->usingDefaultTheme = false;

                        bbrcPath(path);
                        strcpy(path, pSettings->SF_currentThemePath);
                        strcat(path, "\\extensions.rc");
                        if (FileExists(path)) extensionsrcPath(path);
                        strcpy(path, pSettings->SF_currentThemePath);
                        strcat(path, "\\plugins.rc");
                        if (FileExists(path)) plugrcPath(path);
                }
                else
                {
                        strcpy(pSettings->SF_currentThemePath, pSettings->SF_blackboxPath); // Default theme
                        pSettings->usingDefaultTheme = true;
                }
        }

        //====================

        pSettings->ReadRCSettings();
        pSettings->ReadExtensionsRCSettings();
        pSettings->ReadStyleSettings();

        //====================

        // Please note that HideExplorer has to be performed *before* the
        // xoblite systray is created (since it checks for "Shell_TrayWnd")
        if (pSettings->underExplorer) HideExplorer();

        //====================

        // Note: Order is important!
        pBImage = new BImage;
        pDesk = new Desk(hMainInstance);
        pWorkspaces = new Workspaces(hMainInstance);
        pMenuMaker = new MenuMaker;
        pSlit = new Slit(hMainInstance);
//      pTrayManager = new TrayManager(hMainInstance, (pSettings->systrayDisabled || pSettings->underExplorer));
        pTrayManager = new TrayManager(hMainInstance, (pSettings->systrayDisabled));
        if (pSettings->systembarFirstInSlit)
        {
//              pSystembar = new Systembar(hMainInstance, (pSettings->systrayDisabled || pSettings->underExplorer));
                pSystembar = new Systembar(hMainInstance, (pSettings->systrayDisabled));
                pPluginManager = new PluginManager(hMainInstance);
        }
        else
        {
                pPluginManager = new PluginManager(hMainInstance);
//              pSystembar = new Systembar(hMainInstance, (pSettings->systrayDisabled || pSettings->underExplorer));
                pSystembar = new Systembar(hMainInstance, (pSettings->systrayDisabled));
        }
        pToolbar = new Toolbar(hMainInstance);

        if (!stricmp(pSettings->systembarPlacement, "DockedToToolbar")) pSystembar->UpdatePosition();

        pMenuMaker->Initialize(hMainInstance);
        pTrayManager->Initialize();
        pSystembar->Initialize(); // Enumerate windows for the taskbar...

        SystemParametersInfo(SPI_SETDOUBLECLICKTIME, pSettings->doubleClickInterval, NULL, SPIF_SENDCHANGE);
        SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, pSettings->opaqueMove, NULL, SPIF_SENDCHANGE);

        SendMessage(GetDesktopWindow(), 0x400, 0, 0);

        // Hide the plugins based on extensions.rc setting...
        if (pSettings->pluginsHidden) SendMessage(hMainWnd, BB_BROADCAST, 0, (LPARAM)"@BBHidePlugins");

        // Finally, as a "security precausion" we move the desktop window to the bottom...
        SetWindowPos(pDesk->hDesktopWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSENDCHANGING);

        //====================

        _beginthread(ExecuteRootCommand, 0, NULL);
}

//===========================================================================

void exitBlackbox()
{
        // Just a security precausion... ;)
        if (exitInProgress) return;
        else exitInProgress = true;

        // Save toolbar and systembar widths to the blackbox/extensions.rc...
        if (pToolbar->saveWidthOnRestart) WriteInt(bbrcPath(), "session.screen0.toolbar.widthPercent:", pSettings->toolbarWidthPercent);
        if (pSystembar->saveWidthOnRestart) WriteInt(pSettings->extrcFile, "xoblite.systembar.widthPercent:", pSettings->systembarWidthPercent);

        ClearSticky();

        pSettings->accessLock = true;

        if (pSystembar) delete pSystembar;
//      if (pTrayManager) delete pTrayManager; // Moved to make quit appear snappier... <g>
        if (pPluginManager) delete pPluginManager;
        if (pSlit) delete pSlit;
        if (pMenuMaker) delete pMenuMaker;
        if (pToolbar) delete pToolbar;
        if (pWorkspaces) delete pWorkspaces;
        if (pDesk) delete pDesk;
        if (pTrayManager) delete pTrayManager;
        if (pBImage) delete pBImage;

        if (pSettings->underExplorer) ShowExplorer();
}

//===========================================================================

void restartBlackboxStop()
{
        // Save toolbar and systembar widths to the blackbox/extensions.rc...
        if (pToolbar->saveWidthOnRestart) WriteInt(bbrcPath(), "session.screen0.toolbar.widthPercent:", pSettings->toolbarWidthPercent);
        if (pSystembar->saveWidthOnRestart) WriteInt(pSettings->extrcFile, "xoblite.systembar.widthPercent:", pSettings->systembarWidthPercent);
        pToolbar->saveWidthOnRestart = pSystembar->saveWidthOnRestart = false;

        // Disable slit transparency (for some reason this needs to be 
        // done to avoid visual artifacts) and hide the slit window...
        SetTransparency(pSlit->hSlitWnd, 255);
        ShowWindow(pSlit->hSlitWnd, SW_HIDE);

        // Undock from slit if currently docked...
        if (pSystembar->DockedToSlit)
        {
                SendMessage(pSlit->hSlitWnd, SLIT_REMOVE, NULL, (LPARAM)pSystembar->hSystembarWnd);
                ShowWindow(pSystembar->hSystembarWnd, SW_HIDE);
                pSystembar->DockedToSlit = false;
        }

        if (pPluginManager) delete pPluginManager;
        if (pMenuMaker) delete pMenuMaker;

        //====================

        if ((GetAsyncKeyState(VK_SHIFT) & 0x8000) || pauseRestart)
        {
                MessageBox(GetBBWnd(), "Restart paused, press OK to continue...   ", "xoblite", MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND);// | MB_TOPMOST);
                pauseRestart = false;
        }
}

//===========================================================================

void restartBlackboxStart()
{
        int existingWorkspaces = pSettings->workspaces;

        pSettings->ReadRCSettings();
        pSettings->ReadExtensionsRCSettings();
        pSettings->ReadStyleSettings();

        //====================

        if (existingWorkspaces != pSettings->workspaces)
        {
//              if (pWorkspaces) delete pWorkspaces;
//              pWorkspaces = new Workspaces(hMainInstance);
                pWorkspaces->GatherWindows();
                if (pWorkspaces->currentScreen > pSettings->workspaces - 1)
                        pWorkspaces->switchToDesktop(pSettings->workspaces-1);
        }

        pWorkspaces->flushNames();

        //====================
/*
        // *** NOTE: Disabled since it messes up the slit
        // if the systembar is docked, needs rewrite... ***

        if (!pSettings->underExplorer)
        {
                // If the systrayDisabled setting in extensions.rc differs from the current state...
                if (pSettings->systrayDisabled && !DisableTray)
                {
                        // Restarting COM too often is not a very good idea,
                        // so for now we only allow the enabled->disabled direction,
                        // not vice versa...
                        DisableTray = true;

                        // ...then exit Systembar and TrayManager...
                        if (pSystembar) delete pSystembar;
                        if (pTrayManager) delete pTrayManager;
                        // ...and relaunch them with the updated DisableTray setting...
                        pTrayManager = new TrayManager(hMainInstance, DisableTray);
                        pSystembar = new Systembar(hMainInstance, DisableTray);
                        if (!DisableTray) pTrayManager->Initialize();
                        pSystembar->Initialize(); // Enumerate windows for the taskbar...
                }
        }
*/
        //====================

        pMenuMaker = new MenuMaker();
        pMenuMaker->Initialize(hMainInstance);

        if (pSettings->systembarFirstInSlit)
        {
                // We need to do this to make sure the systembar is leftmost in the slit...
                if (!stricmp(pSettings->systembarPlacement, "DockedToSlit"))
                {
                        ShowWindow(pSystembar->hSystembarWnd, SW_SHOWNOACTIVATE);
                        SendMessage(pSlit->hSlitWnd, SLIT_ADD, NULL, (LPARAM)pSystembar->hSystembarWnd);
                        pSystembar->DockedToSlit = true;
                }

                pPluginManager = new PluginManager(hMainInstance);
        }
        else
        {
                // We need to do this to make sure the systembar is rightmost in the slit...
                pPluginManager = new PluginManager(hMainInstance);

                if (!stricmp(pSettings->systembarPlacement, "DockedToSlit"))
                {
                        ShowWindow(pSystembar->hSystembarWnd, SW_SHOWNOACTIVATE);
                        SendMessage(pSlit->hSlitWnd, SLIT_ADD, NULL, (LPARAM)pSystembar->hSystembarWnd);
                        pSystembar->DockedToSlit = true;
                }
        }

        // Update toolbar+systembar+slit size and position...
        pToolbar->UpdatePosition();
        pSystembar->UpdatePosition();
        pSlit->GetSettings();
        pSlit->UpdatePluginPositions(); // Note: Will also show the slit if !pSettings->slitHidden
        // Show/hide the toolbar, systembar and plugins based on extensions.rc settings...
        ShowWindow(pToolbar->hToolbarWnd, pSettings->toolbarHidden ? SW_HIDE : SW_SHOWNOACTIVATE);
        if (!pSystembar->DockedToSlit) ShowWindow(pSystembar->hSystembarWnd, pSettings->systembarHidden ? SW_HIDE : SW_SHOWNOACTIVATE);
        if (pSettings->pluginsHidden) SendMessage(hMainWnd, BB_BROADCAST, 0, (LPARAM)"@BBHidePlugins");
        // Force update of any external system tray plugins...
        PostMessage(hMainWnd, BB_TRAYUPDATE, NULL, (LPARAM)TRAYICON_REFRESH);
        // Finally, as a "security precausion" we move the desktop window to the bottom...
        SetWindowPos(pDesk->hDesktopWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSENDCHANGING);

        //====================

        _beginthread(ExecuteRootCommand, 0, NULL);
}

//===========================================================================

LRESULT CALLBACK MainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
        switch (uMsg)
        {
                //====================

                case WM_HOTKEY:
                {
                        if (wParam == ID_HOTKEY)
                        {
                                if (MessageBox(GetBBWnd(), "Are you sure you want to quit?   \n", "xoblite", MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND | MB_TOPMOST) == IDYES)
                                {
                                        exitBlackbox();
                                        PostQuitMessage(0);
                                }
                        }
                }
                break;

                //====================

                case WM_QUERYENDSESSION:
                {
                        if (lParam & ENDSESSION_LOGOFF) debugLogoff = true;
                        else debugShutdown = debugReboot = true;
                        PostMessage(hMainWnd, WM_CLOSE, 0, 0);
                        return TRUE;
                }

                case WM_ENDSESSION:
                {
//                      exitBlackbox();
                        return 0;
                }

                //====================

                case WM_SYSCOMMAND:
                case WM_KEYDOWN:
                {
                        if (wParam == SC_CLOSE)
                        {
                                // Standard Windows shutdown menu...
                                PostMessage(GetBBWnd(), BB_SHUTDOWN, 255, 0);
                                return 0;
                        }
                        else return DefWindowProc(hWnd, uMsg, wParam, lParam);
                }

                //====================

                case WM_CLOSE:
                case BB_QUIT:
                {
                        exitBlackbox();
                        PostQuitMessage(0);
                }
                break;

                //====================

                case BB_SHUTDOWN:
                {
                        switch (wParam)
                        {
                                case 0: // Shutdown
                                        ShutdownWindows(0);
                                break;
                                case 1: // Reboot
                                        ShutdownWindows(1);
                                break;
                                case 2: // Log off
                                        ShutdownWindows(2);
                                break;
                                case 3: // Hibernate
                                        ShutdownWindows(3);
                                break;
                                case 4: // Suspend
                                        ShutdownWindows(4);
                                break;
                                case 5: // LockWorkstation
                                        BBExecute(GetDesktopWindow(), NULL, "rundll32.exe", "user32.dll,LockWorkStation", NULL, SW_HIDE, false);
                                break;
                                default: // Standard Windows shutdown menu (does not work from the xoblite main menu)
                                        MSWinShutdown(hMainWnd);
                                break;
                        }
                        return 0;
                }

                //====================

                case BB_RESTART:
                {
                        // Lock the slit to avoid repeated SLIT_REMOVE/ADD messages from plugins...
                        pSlit->ReconfigureLock(true);
                        if (wParam) pauseRestart = true;
                        restartBlackboxStop();
                        restartBlackboxStart();
                }
                break;

                //====================

                case BB_SETTHEME: // Introducing xoblite *THEMES*! :D
                {
                        if (lParam != 0)
                        {
                                char path[MAX_LINE_LENGTH], theme[MAX_LINE_LENGTH];
                                strcpy(theme, (LPCSTR)lParam);
                                if (strchr(theme, '\"')) StrRemoveEncap(theme);
                                if (strchr(theme, '$')) ReplaceShellFolders(theme);
                                if (strchr(theme, '%')) ReplaceEnvVars(theme);
                                if (theme[strlen(theme)-1] == '\\') theme[strlen(theme)-1] = 0;

                                if (!stricmp(pSettings->SF_currentThemePath, theme))
                                {
                                        restartBlackboxStop();
                                        restartBlackboxStart();
                                        break;
                                }

                                //====================

                                // Make sure it is a valid theme...
                                bool validTheme = !stricmp(pSettings->SF_blackboxPath, theme);
                                if (!validTheme)
                                {
                                        strcpy(path, theme);
                                        strcat(path, "\\blackbox.rc");
                                        validTheme = FileExists(path);
                                }

                                //====================

                                if (validTheme)
                                {
                                        // Save settings, unload plugins etc...
                                        restartBlackboxStop();

                                        // Set the new theme path...
                                        strcpy(pSettings->SF_currentThemePath, theme);
                                        pSettings->usingDefaultTheme = !stricmp(pSettings->SF_blackboxPath, pSettings->SF_currentThemePath);

                                        if (pSettings->usingDefaultTheme)
                                        {
                                                // Reset config file paths to initiate a new
                                                // ConfigFileExists check for each of them...
                                                strcpy(pSettings->bbrcFile, "");
                                                bbrcPath();

                                                strcpy(pSettings->extrcFile, "");
                                                extensionsrcPath();
                                                strcpy(pSettings->extrcDefaultFile, pSettings->extrcFile);

                                                strcpy(pSettings->plugrcFile, "");
                                                plugrcPath();

                                                pSettings->writeProtection = false;
                                                strcpy(pSettings->selectedTheme, "<Default>");
                                                WriteString(pSettings->extrcDefaultFile, "xoblite.selected.theme:", pSettings->selectedTheme);
                                        }
                                        else
                                        {
                                                // Set the new theme's config file paths...
                                                strcpy(path, pSettings->SF_currentThemePath);
                                                strcat(path, "\\blackbox.rc");
                                                if (FileExists(path)) bbrcPath(path);
                                                strcpy(path, pSettings->SF_currentThemePath);
                                                strcat(path, "\\extensions.rc");
                                                if (FileExists(path)) extensionsrcPath(path);
                                                strcpy(path, pSettings->SF_currentThemePath);
                                                strcat(path, "\\plugins.rc");
                                                if (FileExists(path)) plugrcPath(path);

                                                pSettings->writeProtection = false;
                                                strcpy(pSettings->selectedTheme, &pSettings->SF_currentThemePath[strlen(pSettings->themesFolder)+1]);
                                                WriteString(pSettings->extrcDefaultFile, "xoblite.selected.theme:", pSettings->selectedTheme);
                                        }

                                        // Finally, we load the new theme settings...
                                        restartBlackboxStart();
                                }
                                else
                                {
                                        // The specified theme path wasn't valid!
                                        char msg[MAX_LINE_LENGTH];
                                        sprintf(msg, "%s   \n\ndoes not seem to be a valid theme path.   \nPlease check your menu configuration file.   ", (LPCSTR)lParam);
                                        MessageBox(GetBBWnd(), msg, "xoblite", MB_OK | MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
                                }
                        }
                }
                break;

                //====================

                case BB_SETSTYLE:
                {
                        // Load a new style or refresh the current one?
                        if (lParam != 0)
                        {
                                char style[MAX_LINE_LENGTH];
                                strcpy(style, (LPCSTR)lParam);
                                if (strchr(style, '\"')) StrRemoveEncap(style);
                                if (strchr(style, '$')) ReplaceShellFolders(style);
                                if (strchr(style, '%')) ReplaceEnvVars(style);

                                if (!FileExists(style))
                                {
                                        MBoxErrorFile(style);
                                        break;
                                }
                                stylePath(style); // Save the new style path to blackbox.rc etc.
                        }

                        if (pMenuMaker) delete pMenuMaker;

                        // Read the new style settings...
                        pSettings->ReadStyleSettings();
                        // Show style change message in the toolbar...
                        char temp[MAX_LINE_LENGTH], a1[MAX_LINE_LENGTH], a2[MAX_LINE_LENGTH];
                        strcpy(a1, ReadString(pSettings->styleFile, "style.name:", "[Style name not specified]"));
                        strcpy(a2, ReadString(pSettings->styleFile, "style.author:", "[Author not specified]"));
                        sprintf(temp, "Applying \"%s\" by %s...", a1, a2);
                        SendMessage(GetBBWnd(), BB_SETTOOLBARLABEL, 0, (LPARAM)temp);
                        // Lock the slit to avoid repeated SLIT_UPDATE messages from plugins...
                        pSlit->ReconfigureLock(true);
                        pSlit->GetSettings();
                        // Reconfigure...
                        SendMessage(GetBBWnd(), BB_RECONFIGURE, 0, 0);

                        pMenuMaker = new MenuMaker;
                        pMenuMaker->Initialize(hMainInstance);

                        // Finally, as a "security precausion" we move the desktop window to the bottom...
                        SetWindowPos(pDesk->hDesktopWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSENDCHANGING);

                        // Disable execution of the rootCommand if wParam != 0...
                        if (!wParam) _beginthread(ExecuteRootCommand, 0, NULL);
                }
                break;

                //====================

                case WM_DISPLAYCHANGE:
                {
                        _beginthread(ExecuteRootCommand, 0, NULL);
                }
                break;

                //====================

                case BB_EDITFILE:
                {
                        switch (wParam)
                        {
                                case 0:
                                        BBExecute(GetDesktopWindow(), NULL, pSettings->preferredEditor, pSettings->styleFile, NULL, SW_SHOWNORMAL, false);
                                break;
                                case 1:
                                        BBExecute(GetDesktopWindow(), NULL, pSettings->preferredEditor, pSettings->menuFile, NULL, SW_SHOWNORMAL, false);
                                break;
                                case 2:
                                        BBExecute(GetDesktopWindow(), NULL, pSettings->preferredEditor, plugrcPath(), NULL, SW_SHOWNORMAL, false);
                                break;
                                case 3:
                                        BBExecute(GetDesktopWindow(), NULL, pSettings->preferredEditor, pSettings->extrcFile, NULL, SW_SHOWNORMAL, false);
                                break;
                                case 4:
                                        BBExecute(GetDesktopWindow(), NULL, pSettings->preferredEditor, bbrcPath(), NULL, SW_SHOWNORMAL, false);
                                break;
                                default:
                                break;
                        }
                        return 0;
                }
                break;

                //====================

                case BB_TOGGLEPLUGINS:
                {
                        if (pSettings->pluginsHidden)
                        {
                                SendMessage(hMainWnd, BB_BROADCAST, 0, (LPARAM)"@BBShowPlugins");
                                pSettings->pluginsHidden = false;
                        }
                        else
                        {
                                SendMessage(hMainWnd, BB_BROADCAST, 0, (LPARAM)"@BBHidePlugins");
                                pSettings->pluginsHidden = true;
                        }

                        WriteBool(pSettings->extrcFile, "xoblite.plugins.hidden:", pSettings->pluginsHidden);
                }
                break;

                //====================

                case BB_RUN:
                        RunDlg( NULL, NULL, NULL, NULL, NULL, 0 );
                break;

                //====================

                case BB_REGISTERMESSAGE:
                {
                        UINT *msgArray = (UINT*)lParam;
                        for (int size = 0; msgArray[size] != 0; size++)
                        {
                                pMessageManager->AddMessage(msgArray[size], (HWND)wParam);
                        }
                        break;
                }

                case BB_UNREGISTERMESSAGE:
                {
                        UINT *msgArray = (UINT*)lParam;
                        for (int size = 0; msgArray[size] != 0; size++)
                        {
                                pMessageManager->RemoveMessage(msgArray[size], (HWND)wParam);
                        }
                        break;
                }

                //====================

                case WM_CREATE:
                        RegisterHotKey(hWnd, ID_HOTKEY, MOD_CONTROL | MOD_ALT, VK_F1);
                break;

                //====================

                case WM_COPYDATA: // Used by Blackbox.exe -broam <string>
                {
                        PCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT)lParam;
                        if (pcds->dwData == BB_BROADCAST) SendMessage(GetBBWnd(), BB_BROADCAST, 0, (LPARAM)pcds->lpData);
                        else if (pcds->dwData == BB_SETSTYLE) SendMessage(GetBBWnd(), BB_SETSTYLE, 0, (LPARAM)pcds->lpData);
                        break;
                }

                //====================

                case BB_BROADCAST: // xoblite core bro@ms
                {
                        char temp[MAX_LINE_LENGTH];
                        strcpy(temp, (LPCSTR)lParam);

                        if (!_strnicmp(temp, "@xoblite", 8))
                        {
                                static char msg[MAX_LINE_LENGTH];
                                char token1[MAX_LINE_LENGTH], token2[MAX_LINE_LENGTH], token3[MAX_LINE_LENGTH], extra[MAX_LINE_LENGTH];
                                LPSTR tokens[3];
                                tokens[0] = token1;
                                tokens[1] = token2;
                                tokens[2] = token3;

                                token1[0] = token2[0] = token3[0] = extra[0] = '\0';
                                BBTokenize (temp, tokens, 3, extra);

                                //====================

                                if (!_stricmp(token2, "CheckForUpdates"))
                                {
                                        bool silent = false;
                                        _beginthread(checkForUpdates, 0, &silent);
                                        return 0;
                                }

                                //====================

                                else if (!_stricmp(token2, "SetTheme"))
                                {
                                        PostMessage(hMainWnd, BB_SETTHEME, 0, (LPARAM)token3);
                                        return 0;
                                }
                                else if (!_stricmp(token2, "SetStyle"))
                                {
                                        PostMessage(hMainWnd, BB_SETSTYLE, 0, (LPARAM)token3);
                                        return 0;
                                }

                                //====================

                                else if (!_stricmp(token2, "LoadPlugin"))
                                {
                                        pPluginManager->loadPlugin(token3);
                                        return 0;
                                }
                                else if (!_stricmp(token2, "UnloadPlugin"))
                                {
                                        pPluginManager->unloadPlugin(token3, -1);
                                        return 0;
                                }

                                //====================

                                else if (!_stricmp(token2, "Toolbar"))
                                {
                                        if (!_stricmp(token3, "Hide") && !pSettings->toolbarHidden) PostMessage(GetBBWnd(), BB_TOGGLETOOLBAR, 0, 0);
                                        else if (!_stricmp(token3, "Show") && pSettings->toolbarHidden) PostMessage(GetBBWnd(), BB_TOGGLETOOLBAR, 0, 0);
                                        else if (!_stricmp(token3, "Toggle")) PostMessage(GetBBWnd(), BB_TOGGLETOOLBAR, 0, 0);
                                        else if (!_stricmp(token3, "Transparency"))
                                        {
                                                pSettings->toolbarTransparencyAlpha = atoi(extra);
                                                if (!pToolbar->ToolbarAutoHidden) SetTransparency(pToolbar->hToolbarWnd, pSettings->toolbarTransparencyAlpha);
                                                if (!stricmp(pSettings->systembarPlacement, "DockedToToolbar"))
                                                        SetTransparency(pSystembar->hSystembarWnd, pSettings->toolbarTransparencyAlpha);
                                                WriteInt(pSettings->extrcFile, "xoblite.toolbar.transparency.alpha:", pSettings->toolbarTransparencyAlpha);
                                        }

                                        return 0;
                                }

                                //====================

                                else if (!_stricmp(token2, "Systembar"))
                                {
                                        if (!_stricmp(token3, "Hide") && !pSettings->systembarHidden) PostMessage(GetBBWnd(), BB_TOGGLESYSTEMBAR, 0, 0);
                                        else if (!_stricmp(token3, "Show") && pSettings->systembarHidden) PostMessage(GetBBWnd(), BB_TOGGLESYSTEMBAR, 0, 0);
                                        else if (!_stricmp(token3, "Toggle")) PostMessage(GetBBWnd(), BB_TOGGLESYSTEMBAR, 0, 0);
                                        else if (!_stricmp(token3, "ToggleSysTray")) pSystembar->ToggleSysTray();
                                        else if (!_stricmp(token3, "TaskbarMode"))
                                        {
                                                if (!_stricmp(extra, "Bars")) pSystembar->ChangeTaskbarMode(1);
                                                else if (!_stricmp(extra, "Icons")) pSystembar->ChangeTaskbarMode(2);
                                                else pSystembar->ChangeTaskbarMode(3);
                                        }
                                        else if (!_stricmp(token3, "Transparency"))
                                        {
                                                pSettings->systembarTransparencyAlpha = atoi(extra);
                                                if (!IsInString(pSettings->systembarPlacement, "DockedTo")) SetTransparency(pSystembar->hSystembarWnd, pSettings->systembarTransparencyAlpha);
                                                WriteInt(pSettings->extrcFile, "xoblite.systembar.transparency.alpha:", pSettings->systembarTransparencyAlpha);
                                        }
                                        else if (!_stricmp(token3, "TaskbarSat"))
                                        {
                                                pSettings->taskbarSaturationValue = atoi(extra);
                                                InvalidateRect(pSystembar->hSystembarWnd, NULL, false);
                                                WriteInt(pSettings->extrcFile, "xoblite.taskbar.saturation:", pSettings->taskbarSaturationValue);
                                        }
                                        else if (!_stricmp(token3, "TaskbarHue"))
                                        {
                                                pSettings->taskbarHueIntensity = atoi(extra);
                                                InvalidateRect(pSystembar->hSystembarWnd, NULL, false);
                                                WriteInt(pSettings->extrcFile, "xoblite.taskbar.hue:", pSettings->taskbarHueIntensity);
                                        }
                                        else if (!_stricmp(token3, "SysTraySat"))
                                        {
                                                pSettings->systraySaturationValue = atoi(extra);
                                                InvalidateRect(pSystembar->hSystembarWnd, NULL, false);
                                                WriteInt(pSettings->extrcFile, "xoblite.systray.saturation:", pSettings->systraySaturationValue);
                                        }
                                        else if (!_stricmp(token3, "SysTrayHue"))
                                        {
                                                pSettings->systrayHueIntensity = atoi(extra);
                                                InvalidateRect(pSystembar->hSystembarWnd, NULL, false);
                                                WriteInt(pSettings->extrcFile, "xoblite.systray.hue:", pSettings->systrayHueIntensity);
                                        }

                                        return 0;
                                }

                                //====================

                                else if (!_stricmp(token2, "Slit"))
                                {
                                        if (!_stricmp(token3, "Hide") && !pSettings->slitHidden) PostMessage(GetBBWnd(), BB_TOGGLESLIT, 0, 0);
                                        else if (!_stricmp(token3, "Show") && pSettings->slitHidden) PostMessage(GetBBWnd(), BB_TOGGLESLIT, 0, 0);
                                        else if (!_stricmp(token3, "Toggle")) PostMessage(GetBBWnd(), BB_TOGGLESLIT, 0, 0);
                                        else if (!_stricmp(token3, "Transparency"))
                                        {
                                                pSettings->slitTransparencyAlpha = atoi(extra);
                                                if (!pSlit->SlitAutoHidden) SetTransparency(pSlit->hSlitWnd, pSettings->slitTransparencyAlpha);
                                                WriteInt(pSettings->extrcFile, "xoblite.slit.transparency.alpha:", pSettings->slitTransparencyAlpha);
                                        }

                                        return 0;
                                }

                                //====================

                                else if (!_stricmp(token2, "Menu"))
                                {
                                        if (!_stricmp(token3, "Transparency"))
                                        {
                                                pSettings->menuTransparencyAlpha = atoi(extra);
//                                              SetTransparency(pMenu->m_hWnd, pSettings->menuTransparencyAlpha);
                                                WriteInt(pSettings->extrcFile, "xoblite.menu.transparency.alpha:", pSettings->menuTransparencyAlpha);
                                        }
                                        else if (!_stricmp(token3, "SetRCPath"))
                                        {
                                                menuPath(extra);
                                                if (pMenuMaker) delete pMenuMaker;
                                                pMenuMaker = new MenuMaker();
                                                pMenuMaker->Initialize(hMainInstance);
                                        }

                                        return 0;
                                }

                                //====================

                                else if (!_stricmp(token2, "Plugins"))
                                {
                                        if (!_stricmp(token3, "Hide") && !pSettings->pluginsHidden) PostMessage(GetBBWnd(), BB_TOGGLEPLUGINS, 0, 0);
                                        else if (!_stricmp(token3, "Show") && pSettings->pluginsHidden) PostMessage(GetBBWnd(), BB_TOGGLEPLUGINS, 0, 0);
                                        else if (!_stricmp(token3, "Toggle")) PostMessage(GetBBWnd(), BB_TOGGLEPLUGINS, 0, 0);

                                        return 0;
                                }

                                //====================

                                else if (!_stricmp(token2, "ToggleForceFontShadows"))
                                {
                                        if (!pSettings->forceFontShadows) pSettings->forceFontShadows = true;
                                        else pSettings->forceFontShadows = false;
                                        WriteBool(pSettings->extrcFile, "xoblite.force.font.shadows:", pSettings->forceFontShadows);

                                        if (pSettings->forceFontShadows)
                                        {
                                                pSettings->MenuTitle->FontShadow = pSettings->MenuFrame->FontShadow = pSettings->MenuHilite->FontShadow = true;
                                                pSettings->ToolbarLabel->FontShadow = pSettings->ToolbarWindowLabel->FontShadow = pSettings->ToolbarClock->FontShadow = true;
                                                pSettings->ActiveTask->FontShadow = pSettings->InactiveTask->FontShadow = true;
                                                InvalidateRect(pToolbar->hToolbarWnd, NULL, false);
                                                InvalidateRect(pSystembar->hSystembarWnd, NULL, false);
                                                InvalidateRect(pSlit->hSlitWnd, NULL, false);
                                                if (pMenuMaker) pMenuMaker->Hide();
                                        }
                                        else PostMessage(GetBBWnd(), BB_SETSTYLE, 0, 0);

                                        return 0;
                                }

                                //====================

                                else if (!_stricmp(token2, "ToggleWriteProtection"))
                                {
                                        if (!pSettings->writeProtection)
                                        {
                                                WriteBool(pSettings->extrcFile, "xoblite.write.protection:", true);
                                                pSettings->writeProtection = true;
                                                MessageBox(GetBBWnd(), "Write protection enabled.   ", "xoblite", MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TOPMOST);
                                        }
                                        else
                                        {
                                                pSettings->writeProtection = false;
                                                WriteBool(pSettings->extrcFile, "xoblite.write.protection:", false);
                                                MessageBox(GetBBWnd(), "Write protection disabled.   ", "xoblite", MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TOPMOST);
                                        }

                                        if (pSettings->taskbarOnToolbar && pSystembar) InvalidateRect(pSystembar->hSystembarWnd, NULL, false);
                                        else if (pToolbar) InvalidateRect(pToolbar->hToolbarWnd, NULL, false);

                                        return 0;
                                }

                                //====================

                                else if (!_stricmp(token2, "Edit"))
                                {
                                        if (strchr(token3, '$')) ReplaceShellFolders(token3);
                                        if (strchr(token3, '%')) ReplaceEnvVars(token3);
                                        BBExecute(GetDesktopWindow(), NULL, pSettings->preferredEditor, token3, NULL, SW_SHOWNORMAL, false);

                                        return 0;
                                }

                                //====================

                                else if (!_stricmp(token2, "PausedRestart"))
                                {
                                        // BB_RESTART WPARAM set to 1 -> paused restart (xoblite only for now)
                                        PostMessage(GetBBWnd(), BB_RESTART, 1, 0);
                                        return 0;
                                }

                                //====================

                                else if (!_stricmp(token2, "MinimizeAll"))
                                {
                                        pSystembar->MinimizeAllWindows();
                                        return 0;
                                }
                                else if (!_stricmp(token2, "RestoreAll"))
                                {
                                        pSystembar->RestoreAllWindows();
                                        return 0;
                                }

                                //====================
                        }
                        else if (!_strnicmp(temp, "@Script", 7) && !pSettings->disableScriptSupport)
                        {
                                char token1[MAX_LINE_LENGTH], script[MAX_LINE_LENGTH];
                                LPSTR tokens[1];
                                tokens[0] = token1;

                                token1[0] = script[0] = '\0';
                                BBTokenize (temp, tokens, 1, script);

                                // Remove encapsulating [] brackets and execute the script...
                                script[strlen(script)-1] = '\0';
                                _beginthread(ExecuteScript, 0, &script[1]);

                                return 0;
                        }
                }

                //====================

                default:
                {
                        if (pMessageManager)
                        {
                                unsigned int msg = uMsg;

                                if (msg == WM_ShellHook)
                                {
                                        if (wParam == HSHELL_WINDOWCREATED) msg = BB_ADDTASK;
                                        else if (wParam == HSHELL_WINDOWDESTROYED) msg = BB_REMOVETASK;
                                        else if (wParam == HSHELL_ACTIVATESHELLWINDOW) msg = BB_ACTIVATESHELLWINDOW;
                                        else if (wParam == HSHELL_WINDOWACTIVATED) msg = BB_ACTIVETASK;
                                        else if (wParam == (HSHELL_WINDOWACTIVATED+0x8000))
                                        {
                                                // Could there be a better way to support fullscreen windows?
                                                // (e.g. unloading everything or disable alwaysontop elements)
                                                msg = BB_ACTIVETASK;
                                        }
                                        else if (wParam == HSHELL_GETMINRECT) msg = BB_MINMAXTASK;
                                        else if (wParam == HSHELL_REDRAW) msg = BB_REDRAW;
                                        else if (wParam == (HSHELL_REDRAW+0x8000))
                                        {
                                                // Insert flashing code here...
                                                msg = BB_REDRAW;
                                                pSystembar->flashingHwnd = (HWND)lParam;
                                        }
                                        wParam = lParam; // wParam set to the hwnd
                                }

                                if (pMessageManager->HandlerExists(msg))
                                {
                                        LRESULT lResult;
                                        if (pMessageManager->SendMessage(msg, wParam, lParam, &lResult)) return lResult;
                                }
                        }

                        return DefWindowProc(hWnd, uMsg, wParam, lParam);
                }

                //====================
        }

        return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

//===========================================================================

void ExecuteScript(void *param)
{
        char script[MAX_LINE_LENGTH], cmd[MAX_LINE_LENGTH];
        strcpy(script, (LPSTR)param);

        while (strlen(script))
        {
                strcpy(script, Tokenize(script, cmd, "|"));

                if (cmd[0] == '@') SendMessage(GetBBWnd(), BB_BROADCAST, 0, (LPARAM)cmd);
                else if (!_strnicmp(cmd, "Pause", 5)) Sleep(atoi(&cmd[6]));
                else
                {
                        if (strchr(cmd, '$')) ReplaceShellFolders(cmd);
                        if (strchr(cmd, '%')) ReplaceEnvVars(cmd);

                        char command[MAX_LINE_LENGTH], arguments[MAX_LINE_LENGTH], workingdir[MAX_LINE_LENGTH];
                        LPSTR tokens[1];
                        tokens[0] = command;
                        command[0] = arguments[0] = workingdir[0] = '\0';
                        BBTokenize (cmd, tokens, 1, arguments);
                        if (command[1] == ':')
                        {
                                strcpy(workingdir, command);
                                int nLen = strlen(workingdir) - 1;
                                while (nLen >0 && workingdir[nLen] != '\\') nLen--;
                                workingdir[nLen + 1] = 0;
                        }
                        BBExecute(GetDesktopWindow(), NULL, command, arguments, workingdir, SW_SHOWNORMAL, false);
                }
        }

        _endthread();
}

//===========================================================================

void ExecuteRootCommand(void *)
{
        if (!pSettings->disableRootCommands && !(GetAsyncKeyState(VK_CONTROL) & 0x8000)) // Is the control key held down?
        {
                if (strlen(pSettings->rootCommand))
                {
                        // Execute the style's rootCommand...
                        char command[MAX_LINE_LENGTH], arguments[MAX_LINE_LENGTH];
                        LPSTR tokens[1];
                        tokens[0] = command;
                        command[0] = arguments[0] = '\0';
                        BBTokenize (pSettings->rootCommand, tokens, 1, arguments);
                        // Since it's a rootCommand, we use the Blackbox directory as working directory...
                        char bbpath[MAX_LINE_LENGTH];
                        GetBlackboxPath(bbpath, sizeof(bbpath));
                        BBExecute(GetDesktopWindow(), NULL, command, arguments, bbpath, SW_SHOWNORMAL, true);
                }
        }

        _endthread();
}

//===========================================================================

void ShutdownWindows(int state) // 0=Shutdown, 1=Reboot, 2=Logoff, 3=Hibernate, 4=Suspend
{
        char message[MAX_LINE_LENGTH];
        if (state == 0) strcpy(message, "Are you sure you want to shut down your computer?");
        else if (state == 1) strcpy(message, "Are you sure you want to reboot your computer?");
        else if (state == 2) strcpy(message, "Are you sure you want to log off?");
        else if (state == 3) strcpy(message, "Are you sure you want to hibernate?");
        else if (state == 4) strcpy(message, "Are you sure you want to suspend?");
        else return;

        //====================

        if (MessageBox(GetBBWnd(), message, "xoblite", MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND | MB_TOPMOST) == IDYES)
        {
                // Run the shutdown functions in their own thread,
                // unless installing using the -install switch...
                shutdownState = state;
                if (shutdownInMainThread) ShutdownThread((LPVOID)shutdownState);
                else _beginthread(ShutdownThread, 0, NULL);
        }
}

//===========================================================================

void ShutdownThread(void *)
{
        // Log off?
        if (shutdownState == 2)
        {
                if (!ExitWindowsEx(EWX_LOGOFF, SHTDN_REASON_FLAG_PLANNED)) MBoxErrorValue("Log off failed");
                else
                {
                        debugLogoff = true;
                        PostMessage(hMainWnd, WM_CLOSE, 0, 0);
                }

                return;
        }

        //====================

        HANDLE hToken = NULL; 
        TOKEN_PRIVILEGES tkp; 
                
        OSVERSIONINFO osInfo;
        ZeroMemory(&osInfo, sizeof(osInfo));
        osInfo.dwOSVersionInfoSize = sizeof(osInfo);
        GetVersionEx(&osInfo);

        // Under WinNT/2k/XP we need to adjust priviliges to be able to shutdown/reboot/hibernate/suspend...
        if (osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
        {
                // Get a token for this process...
                if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
                {
                        MBoxErrorValue("OpenProcessToken failed");
                        return;
                }

                // Get the LUID for the shutdown privilege... 
                LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid); 
                tkp.PrivilegeCount = 1;  // one privilege to set    
                tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 

                // Get the shutdown privileges for this process...
                AdjustTokenPrivileges(hToken, false, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0); 
                if (GetLastError() != ERROR_SUCCESS)
                {
                        MBoxErrorValue("AdjustTokenPrivileges failed");
                        return;
                }
        }
        
        //====================

        if (shutdownState == 0) // Shutdown?
        {
                if (!ExitWindowsEx(EWX_SHUTDOWN | EWX_POWEROFF, SHTDN_REASON_FLAG_PLANNED)) MBoxErrorValue("Shutdown failed!");
                else
                {
                        debugShutdown = true;
                        PostMessage(hMainWnd, WM_CLOSE, 0, 0);
                }
        }
        else if (shutdownState == 1) // Reboot?
        {
                if (!ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_FLAG_PLANNED)) MBoxErrorValue("Reboot failed!");
                else
                {
                        debugReboot = true;
                        PostMessage(hMainWnd, WM_CLOSE, 0, 0);
                }
        }
        else if (shutdownState == 3) // Hibernate?
        {
                if (!SetSystemPowerState(FALSE, FALSE)) MBoxErrorValue("Hibernate failed!");
        }
        else if (shutdownState == 4) // Suspend?
        {
                if (!SetSystemPowerState(TRUE, FALSE)) MBoxErrorValue("Suspend failed!");
        }

        // Disable shutdown privilege...
        tkp.Privileges[0].Attributes = 0; 
        AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);

        if (!shutdownInMainThread) _endthread();
}

//===========================================================================

// IsFirstRunThisSession()
// from LiteStep's StartupRunner.cpp, slightly modified for xoblite
// Copyright © 1997-2004 The LiteStep Development Team
bool IsFirstRunThisSession()
{
        bool bReturn = false;
        HKEY hkExplorer;
        TCHAR tzSessionInfo[30];

        OSVERSIONINFO OsVersionInfo;
        OsVersionInfo.dwOSVersionInfoSize = sizeof(OsVersionInfo);
        GetVersionEx(&OsVersionInfo);

        // On NT systems, the SessionInfo subkey will be the AuthenticationID
        if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
        {
                HANDLE hToken;
                if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken) != 0)
                {
                        TOKEN_STATISTICS tsStats;
                        DWORD dwOutSize;

                        if (GetTokenInformation(hToken, TokenStatistics, &tsStats, sizeof(tsStats), &dwOutSize))
                        {
//                              StringCchPrintf(tzSessionInfo, 30, _T("SessionInfo\\%08x%08x"), tsStats.AuthenticationId.HighPart, tsStats.AuthenticationId.LowPart);
                                sprintf(tzSessionInfo, "SessionInfo\\%08x%08x", tsStats.AuthenticationId.HighPart, tsStats.AuthenticationId.LowPart);

                                // Create the SessionInfo and StartUpHasBeenRun keys
                                LONG lResult = RegCreateKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER, 0, NULL, REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, &hkExplorer, NULL);

                                if (lResult == ERROR_SUCCESS)
                                {
                                        HKEY hkSessionInfo;

                                        lResult = RegCreateKeyEx(hkExplorer, tzSessionInfo, 0, NULL, REG_OPTION_VOLATILE, KEY_WRITE, NULL, &hkSessionInfo, NULL);

                                        if (lResult == ERROR_SUCCESS)
                                        {
                                                DWORD dwDisposition;
                                                HKEY hkStartup;
                                                lResult = RegCreateKeyEx(hkSessionInfo, "StartupHasBeenRun", 0, NULL, REG_OPTION_VOLATILE, KEY_WRITE, NULL, &hkStartup, &dwDisposition);

                        RegCloseKey(hkStartup);

                        if (dwDisposition == REG_CREATED_NEW_KEY)
                                                {
                                                        bReturn = true;
                                                }
                                        }

                    RegCloseKey(hkSessionInfo);
                                }

                RegCloseKey(hkExplorer);
                        }
                }

        CloseHandle(hToken);
        }
        else
        {
                bReturn = true;
        }

        return bReturn;
}

//===========================================================================

void RunStartupStuff (void *underExplorer)
{
        if (!(BOOL)underExplorer)
        {
                const LPCSTR szRunOncePath = "Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce";
                const LPCSTR szRunPath = "Software\\Microsoft\\Windows\\CurrentVersion\\Run";
                char szPath[MAX_PATH];

                // Run one-time entries in HKLM and HKCU and delete them afterwards...
                RunEntriesIn (HKEY_LOCAL_MACHINE, szRunOncePath, true);
                RunEntriesIn (HKEY_CURRENT_USER, szRunOncePath, true);

                // Run regular HKLM entries...
                RunEntriesIn (HKEY_LOCAL_MACHINE, szRunPath, false);
                // Run regular HKCU entries...
                RunEntriesIn (HKEY_CURRENT_USER, szRunPath, false);

                // Run startup items...
                SHGetSpecialFolderPath(NULL, szPath, CSIDL_COMMON_STARTUP, 0);
                if (strlen(szPath)) RunFolderContents(szPath);
                SHGetSpecialFolderPath(NULL, szPath, CSIDL_STARTUP, 0);
                if (strlen(szPath)) RunFolderContents(szPath);
        }

        _endthread();
}

//====================

void RunEntriesIn (HKEY key, LPCTSTR path, bool deleteEntry)
{
        HKEY hKey = NULL;
        LONG lResult;

        lResult = RegOpenKeyEx(key, path, 0, KEY_ALL_ACCESS, &hKey);
        if (lResult == ERROR_SUCCESS)
        {
                char szNameBuffer[MAX_LINE_LENGTH], szValueBuffer[MAX_LINE_LENGTH];
                DWORD dwLoop, dwNameSize, dwValueSize;

                for (dwLoop = 0; ; ++dwLoop)
                {
                        dwNameSize = sizeof (szNameBuffer);
                        dwValueSize = sizeof (szValueBuffer);

                        lResult = RegEnumValue(hKey, dwLoop, szNameBuffer, &dwNameSize, NULL, NULL, (LPBYTE) szValueBuffer, &dwValueSize);

                        if (lResult == ERROR_NO_MORE_ITEMS) break;
                        if (lResult == ERROR_SUCCESS)
                        {
                                WinExec (szValueBuffer, SW_SHOWNORMAL);

                                if (deleteEntry)
                                {
                                        lResult = RegDeleteValue(hKey, szNameBuffer);
                                        if (lResult != ERROR_SUCCESS) break;
                                }
                        }
                        else break;
                }

                RegCloseKey (hKey);
        }
}

//====================

void RunFolderContents(LPCSTR szParams)
{
        char szDir[MAX_PATH], szPath[MAX_PATH];
        WIN32_FIND_DATA findData;
        HANDLE hSearch;

        strcpy(szPath, szParams);
        strcpy(szDir, szPath);
        if (szPath[strlen(szPath) - 1] != '\\') strcat(szPath, "\\");
        strcat(szPath, "*.*");

        if (strcmp(szPath, "\\*.*") != 0)
        {
                hSearch = FindFirstFile(szPath, &findData);

                while (hSearch != INVALID_HANDLE_VALUE)
                {
                        if (strcmp(findData.cFileName, ".") && strcmp(findData.cFileName, "..") && (!(findData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) && !(findData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)))
                        {
                                BBExecute(NULL, NULL, findData.cFileName, NULL, szDir, SW_SHOWNORMAL, false);
                        }

                        if (!FindNextFile(hSearch, &findData))
                        {
                                FindClose(hSearch);
                                hSearch = INVALID_HANDLE_VALUE;
                        }
                }
        }
}

//===========================================================================

void installBlackbox()
{
        if (MessageBox(GetDesktopWindow(), "Do you want to install xoblite as your default shell?   ", "xoblite", MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND | MB_TOPMOST) == IDYES)
        {
                bool shellInstalled = false;

                char szBlackbox[MAX_LINE_LENGTH] = "", szExplorer[MAX_LINE_LENGTH] = "explorer.exe", szDefault[MAX_LINE_LENGTH] = "";
                GetBlackboxPath(szBlackbox, MAX_LINE_LENGTH);
                strcat(szBlackbox, "Blackbox.exe");

                OSVERSIONINFO osInfo;
                ZeroMemory(&osInfo, sizeof(osInfo));
                osInfo.dwOSVersionInfoSize = sizeof(osInfo);
                GetVersionEx(&osInfo);

                //====================

                if (osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) // WindowsNT/2000/XP
                {
                        HKEY key, boot, fileManager;
                        DWORD result, dwData = 1;
                        char bootOption[MAX_LINE_LENGTH];
                        bool currentUser = false;

                        if (MessageBox(GetDesktopWindow(), "Do you want to install xoblite as the default shell for All Users?   \n(selecting \"No\" will install for the Current User only).", "xoblite", MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND | MB_TOPMOST) == IDYES)
                        {
                                strcpy(bootOption, "SYS:Microsoft\\Windows NT\\CurrentVersion\\Winlogon");
                                strcpy(szDefault, szBlackbox); // If installing for all users the HKLM shell setting should point to Blackbox...
                                currentUser = false;
                        }
                        else
                        {
                                strcpy(bootOption, "USR:Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon");
                                strcpy(szDefault, szExplorer); // If installing only for the current user the HKLM shell setting should point to Explorer...
                                currentUser = true;
                        }

                        //====================

                        // First we open the boot options registry key...
                        if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\IniFileMapping\\system.ini\\boot\0", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &boot, &result) == ERROR_SUCCESS)
                        {
                                // ...and set the "Shell" registry value that defines if the shell setting should
                                // be read from HKLM (for all users) or from HKCU (for the current user), see above...
                                if (RegSetValueEx(boot, "Shell\0", 0, REG_SZ, (LPBYTE)bootOption, lstrlen(bootOption) + 1) == ERROR_SUCCESS)
                                {
                                        //====================

                                        // Next we set the HKLM shell registry key (this needs to be done at all times!)
                                        if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\0", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, &result) == ERROR_SUCCESS)
                                        {
                                                if (RegSetValueEx(key, "Shell\0", 0, REG_SZ, (LPBYTE)szDefault, lstrlen(szDefault) + 1) == ERROR_SUCCESS)
                                                {
                                                        if (!currentUser)
                                                        {
                                                                shellInstalled = true;
                                                        }
                                                }
                                                else MessageBox(GetDesktopWindow(), "Installation unsuccessful!\nUnable to set the HKLM shell registry key.   ", "xoblite", MB_OK | MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);

                                                RegCloseKey(key);
                                        }
                                        else MessageBox(GetDesktopWindow(), "Installation unsuccessful!\nFailed to open the HKLM shell registry key.   ", "xoblite", MB_OK | MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);

                                        //====================

                                        if (currentUser)
                                        {
                                                // If installing for the current user only, we also need to set the HKCU shell registry key...
                                                if (RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\0", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, &result) == ERROR_SUCCESS)
                                                {
                                                        if (RegSetValueEx(key, "Shell\0", 0, REG_SZ, (LPBYTE)szBlackbox, lstrlen(szBlackbox) + 1) == ERROR_SUCCESS)
                                                        {
                                                                // ...as well as the DesktopProcess registry key that allows Explorer
                                                                // to be used as file manager while using an alternative shell...
                                                                if (RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\0", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &fileManager, &result) == ERROR_SUCCESS)
                                                                {
                                                                        if (RegSetValueEx(fileManager, "DesktopProcess\0", 0, REG_DWORD, (LPBYTE) &dwData, sizeof(DWORD)) == ERROR_SUCCESS)
                                                                        {
                                                                                shellInstalled = true;
                                                                        }
                                                                        else MessageBox(GetDesktopWindow(), "Installation unsuccessful!\nUnable to set the registry key that allows   \nExplorer to be used as file manager.", "xoblite", MB_OK | MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
                                                                }
                                                                else MessageBox(GetDesktopWindow(), "Installation unsuccessful!\nFailed to open the registry key that allows   \nExplorer to be used as file manager.", "xoblite", MB_OK | MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);

                                                                RegCloseKey(fileManager);
                                                        }
                                                        else MessageBox(GetDesktopWindow(), "Installation unsuccessful!\nUnable to set the HKCU shell registry key.   ", "xoblite", MB_OK | MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
                                                }
                                                else MessageBox(GetDesktopWindow(), "Installation unsuccessful!\nFailed to open the HKCU shell registry key.   ", "xoblite", MB_OK | MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);

                                                RegCloseKey(key);
                                        }

                                        //====================
                                }
                                else MessageBox(GetDesktopWindow(), "Installation unsuccessful!\nUnable to set the boot option registry key.   ", "xoblite", MB_OK | MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
                        }
                        else MessageBox(GetDesktopWindow(), "Installation unsuccessful!\nFailed to open the boot option registry key.   ", "xoblite",  MB_OK | MB_TOPMOST | MB_ICONERROR);

                        RegCloseKey(boot);
                }

                //====================

                else // Windows9x/ME
                {
                        char szWinDir[MAX_LINE_LENGTH];
                        GetWindowsDirectory(szWinDir, sizeof(szWinDir));
                        strcat(szWinDir, "\\SYSTEM.INI");

                        // To set Blackbox as shell in Windows9x/ME we simply need to modify the "Shell" parameter in system.ini...
                        if (WritePrivateProfileString("Boot", "Shell", szBlackbox, szWinDir) != 0)
                        {
                                shellInstalled = true;
                        }
                        else
                        {
                                char message[MAX_LINE_LENGTH];
                                strcpy(message, "Installation unsuccessful!\n\n");
                                strcat(message, "Unable to update ");
                                strcat(message, szWinDir);
                                strcat(message, "\nYou will need to manually add Shell=");
                                strcat(message, szBlackbox);
                                strcat(message, " to ");
                                strcat(message, szWinDir);
                                MessageBox(GetDesktopWindow(), message, "xoblite", MB_OK | MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
                        }
                }

                if (shellInstalled)
                {
                        if (MessageBox(GetDesktopWindow(), "Installation successful!\n\nYou need to restart your computer for the changes   \nto take effect. Do you want to restart now?", "xoblite", MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND | MB_TOPMOST) == IDYES)
                        {
                                ShutdownWindows(1);
                        }
                }

                //====================
        }
}

//===========================================================================

void uninstallBlackbox()
{
        if (MessageBox(NULL, "Do you want to uninstall xoblite?   ", "xoblite", MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND | MB_TOPMOST) == IDYES)
        {
                char szExplorer[MAX_LINE_LENGTH];
                strcpy(szExplorer, "explorer.exe");

                OSVERSIONINFO osInfo;
                ZeroMemory(&osInfo, sizeof(osInfo));
                osInfo.dwOSVersionInfoSize = sizeof(osInfo);
                GetVersionEx(&osInfo);

                //====================

                if (osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) // Windows NT/2000/XP
                {
                        HKEY key, boot, current;
                        DWORD result;
                        char bootOption[MAX_LINE_LENGTH];

                        strcpy(bootOption, "SYS:Microsoft\\Windows NT\\CurrentVersion\\Winlogon");

                        // First we open the boot options registry key...
                        if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\IniFileMapping\\system.ini\\boot\0", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &boot, &result) == ERROR_SUCCESS)
                        {
                                // ...and configure the system to read the shell setting from HKLM (ie. the same shell for all users)...
                                if (RegSetValueEx(boot, "Shell\0", 0, REG_SZ, (LPBYTE)bootOption, lstrlen(bootOption) + 1) == ERROR_SUCCESS)
                                {
                                        // Then we set Explorer as shell for all users...
                                        if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\0", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, &result) == ERROR_SUCCESS)
                                        {
                                                if (RegSetValueEx(key, "Shell\0", 0, REG_SZ, (LPBYTE)szExplorer, lstrlen(szExplorer) + 1) == ERROR_SUCCESS)
                                                {
                                                        // ...and delete the shell registry value for the current user...
                                                        if (RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\0", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &current, &result) == ERROR_SUCCESS)
                                                        {
                                                                RegDeleteValue(current, "Shell\0");
                                                                MessageBox(GetDesktopWindow(), "Uninstallation successful, you may now safely delete the xoblite directory.   ", "xoblite", MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TOPMOST);
                                                        }
                                                        else MessageBox(GetDesktopWindow(), "Failed to delete the HKCU shell registry key!   \nxoblite uninstallation did not complete.", "xoblite", MB_OK | MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);

                                                        RegCloseKey(current);
                                                }
                                                else MessageBox(GetDesktopWindow(), "Unable to set the HKLM shell registry key!   \nxoblite uninstallation did not complete.", "xoblite", MB_OK | MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
                                        }
                                        else MessageBox(GetDesktopWindow(), "Failed to open the HKLM shell registry key!   \nxoblite uninstallation did not complete.", "xoblite", MB_OK | MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);

                                        RegCloseKey(key);
                                }
                                else MessageBox(GetDesktopWindow(), "Unable to set the boot option registry key!   \nxoblite uninstallation did not complete.", "xoblite", MB_OK | MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);

                                RegCloseKey(boot);
                        }
                        else MessageBox(GetDesktopWindow(), "Failed to open the boot option registry key!   \nxoblite uninstallation did not complete.", "xoblite", MB_OK | MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
                }

                //====================

                else // Windows9x/ME
                {
                        char szWinDir[MAX_LINE_LENGTH];
                        GetWindowsDirectory(szWinDir, sizeof(szWinDir));
                        strcat(szWinDir, "\\SYSTEM.INI");

                        // Set the "Shell" parameter in system.ini back to Explorer...
                        if (WritePrivateProfileString("Boot", "Shell", szExplorer, szWinDir) != 0)
                        {
                                MessageBox(GetDesktopWindow(), "Uninstallation successful, you may now safely delete the xoblite directory.   ", "xoblite", MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TOPMOST);
                        }
                        else
                        {
                                char message[MAX_LINE_LENGTH];
                                strcpy(message, "xoblite uninstallation did not complete.\n\n");
                                strcat(message, "Unable to update ");
                                strcat(message, szWinDir);
                                strcat(message, "\nYou will need to manually add Shell=");
                                strcat(message, szExplorer);
                                strcat(message, " to ");
                                strcat(message, szWinDir);
                                MessageBox(GetDesktopWindow(), message, "xoblite", MB_OK | MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
                        }
                }

                //====================
        }
}

//===========================================================================

vector<HWND> ExplorerWndList;

void HideExplorer()
{
        HWND hwnd;

        ExplorerWndList.clear();

        hwnd = FindWindow("Shell_TrayWnd","");
        if (hwnd)
        {
                ShowWindow(hwnd, SW_HIDE);
                ExplorerWndList.push_back(hwnd);
        }
        else return;

        hwnd = FindWindow("Progman", "Program Manager");
        if (hwnd)
        {
                ShowWindow(hwnd, SW_HIDE);
                ExplorerWndList.push_back(hwnd);
        }

        EnumWindows(ExplorerEnumWindowsProc, 0);
}

//====================

void ShowExplorer()
{
        while (ExplorerWndList.size())
        {
                ShowWindow(ExplorerWndList.back(), SW_SHOWNOACTIVATE);
                ExplorerWndList.pop_back();
        }
}

//====================

BOOL CALLBACK ExplorerEnumWindowsProc(HWND hwnd, LPARAM lParam)
{
        char classname[MAX_LINE_LENGTH];
        GetClassName(hwnd, classname, MAX_LINE_LENGTH);
        if (!stricmp(classname, "BaseBar") && IsWindowVisible(hwnd))
        {
                ShowWindow(hwnd, SW_HIDE);
                ExplorerWndList.push_back(hwnd);
        }

        return true;
}

//===========================================================================





syntax highlighting by

w e b c p p
web c plus plus