diff --git a/Sandboxie/common/my_version.h b/Sandboxie/common/my_version.h index 76fe97ff..cc410258 100644 --- a/Sandboxie/common/my_version.h +++ b/Sandboxie/common/my_version.h @@ -25,7 +25,7 @@ #define STR(X) STR2(X) #define VERSION_MJR 5 -#define VERSION_MIN 69 +#define VERSION_MIN 70 #define VERSION_REV 0 #define VERSION_UPD 0 diff --git a/Sandboxie/core/dll/callsvc.c b/Sandboxie/core/dll/callsvc.c index c14f1923..1d101d8a 100644 --- a/Sandboxie/core/dll/callsvc.c +++ b/Sandboxie/core/dll/callsvc.c @@ -1,6 +1,6 @@ /* * Copyright 2004-2020 Sandboxie Holdings, LLC - * Copyright 2020 David Xanatos, xanasoft.com + * Copyright 2020-2023 David Xanatos, xanasoft.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/Sandboxie/core/dll/file_pipe.c b/Sandboxie/core/dll/file_pipe.c index 0dd7408a..d9b0467a 100644 --- a/Sandboxie/core/dll/file_pipe.c +++ b/Sandboxie/core/dll/file_pipe.c @@ -1152,17 +1152,11 @@ _FX NTSTATUS File_NtFsControlFile( handle = File_GetProxyPipe(FileHandle, NULL); if (! handle) { - status = STATUS_BAD_INITIAL_PC; - if (IoControlCode == FSCTL_SET_REPARSE_POINT) { - BOOLEAN BoxReparsTarget = SbieApi_QueryConfBool(NULL, L"BoxReparsTarget", FALSE); - if(BoxReparsTarget) { - - status = File_SetReparsePoint( - FileHandle, InputBuffer, InputBufferLength); - SetLastError(LastError); - } + status = File_SetReparsePoint( + FileHandle, InputBuffer, InputBufferLength); + SetLastError(LastError); } else if (IoControlCode == FSCTL_PIPE_WAIT) { @@ -1178,7 +1172,8 @@ _FX NTSTATUS File_NtFsControlFile( else status = STATUS_ACCESS_DENIED; - } + } else + status = STATUS_BAD_INITIAL_PC; if (status == STATUS_BAD_INITIAL_PC) { diff --git a/Sandboxie/core/dll/gui.c b/Sandboxie/core/dll/gui.c index 3c2d78a6..7311f00c 100644 --- a/Sandboxie/core/dll/gui.c +++ b/Sandboxie/core/dll/gui.c @@ -416,18 +416,7 @@ _FX BOOLEAN Gui_Init(HMODULE module) GUI_IMPORT___(ClipCursor); GUI_IMPORT___(GetClipCursor); GUI_IMPORT___(GetCursorPos); - GUI_IMPORT___(SetCursorPos); - - GUI_IMPORT___(SetTimer); - HMODULE temp = module; - module = Dll_Kernel32; - GUI_IMPORT___(Sleep); - GUI_IMPORT___(SleepEx); - GUI_IMPORT___(GetTickCount); - GUI_IMPORT___(GetTickCount64); - GUI_IMPORT___(QueryUnbiasedInterruptTime); - GUI_IMPORT___(QueryPerformanceCounter); - module = temp; + GUI_IMPORT___(SetCursorPos); GUI_IMPORT___(SetTimer); GUI_IMPORT___(MsgWaitForMultipleObjects); diff --git a/Sandboxie/core/dll/guimisc.c b/Sandboxie/core/dll/guimisc.c index cfda5d57..7ef60407 100644 --- a/Sandboxie/core/dll/guimisc.c +++ b/Sandboxie/core/dll/guimisc.c @@ -285,7 +285,7 @@ _FX BOOLEAN Gui_InitMisc(HMODULE module) __sys_GetThreadDpiAwarenessContext = (P_GetThreadDpiAwarenessContext) Ldr_GetProcAddrNew(DllName_user32, L"GetThreadDpiAwarenessContext","GetThreadDpiAwarenessContext"); - HMODULE current = module; + if (SbieApi_QueryConfBool(NULL, L"BlockInterferePower", FALSE)) { SBIEDLL_HOOK_GUI(ShutdownBlockReasonCreate); @@ -1703,45 +1703,3 @@ _FX void Gui_SwitchToThisWindow(HWND hWnd, BOOL fAlt) return; __sys_SwitchToThisWindow(hWnd, fAlt); } - -_FX DWORD Gui_GetTickCount() { - return __sys_GetTickCount() * SbieApi_QueryConfNumber(NULL, L"AddTickSpeed", 1) / SbieApi_QueryConfNumber(NULL,L"LowTickSpeed", 1); -} - -_FX ULONGLONG Gui_GetTickCount64() { - return __sys_GetTickCount64() * SbieApi_QueryConfNumber(NULL, L"AddTickSpeed", 1) / SbieApi_QueryConfNumber(NULL, L"LowTickSpeed", 1); -} - -_FX BOOL Gui_QueryUnbiasedInterruptTime( - PULONGLONG UnbiasedTime -) { - BOOL rtn = __sys_QueryUnbiasedInterruptTime(UnbiasedTime); - *UnbiasedTime *= SbieApi_QueryConfNumber(NULL, L"AddTickSpeed", 1) / SbieApi_QueryConfNumber(NULL, L"LowTickSpeed", 1); - return rtn; -} - -_FX void Gui_Sleep(DWORD dwMiSecond) { - __sys_Sleep(dwMiSecond * SbieApi_QueryConfNumber(NULL, L"AddSleepSpeed", 1) / SbieApi_QueryConfNumber(NULL, L"LowSleepSpeed", 1)); -} - -_FX DWORD Gui_SleepEx(DWORD dwMiSecond, BOOL bAlert) { - return __sys_SleepEx(dwMiSecond * SbieApi_QueryConfNumber(NULL, L"AddSleepSpeed", 1) / SbieApi_QueryConfNumber(NULL, L"LowSleepSpeed", 1),bAlert); -} - -_FX BOOL Gui_QueryPerformanceCounter( - LARGE_INTEGER* lpPerformanceCount -) { - BOOL rtn = __sys_QueryPerformanceCounter(lpPerformanceCount); - lpPerformanceCount->QuadPart = lpPerformanceCount->QuadPart*SbieApi_QueryConfNumber(NULL, L"AddTickSpeed", 1)/ SbieApi_QueryConfNumber(NULL, L"LowTickSpeed", 1); - return rtn; -} - -_FX UINT_PTR Gui_SetTimer( - HWND hWnd, - UINT_PTR nIDEvent, - UINT uElapse, - TIMERPROC lpTimerFunc -) -{ - return __sys_SetTimer(hWnd, nIDEvent, uElapse * SbieApi_QueryConfNumber(NULL, L"AddTimerSpeed", 1) / SbieApi_QueryConfNumber(NULL, L"LowTimerSpeed", 1), lpTimerFunc); -} diff --git a/Sandboxie/core/svc/GuiServer.cpp b/Sandboxie/core/svc/GuiServer.cpp index fd7a2351..dd2416a2 100644 --- a/Sandboxie/core/svc/GuiServer.cpp +++ b/Sandboxie/core/svc/GuiServer.cpp @@ -34,6 +34,9 @@ #include #include #include "misc.h" +#include +#include +#include "sbieiniserver.h" #define PATTERN XPATTERN extern "C" { @@ -906,9 +909,17 @@ bool GuiServer::QueueCallbackSlave2(void) args.rpl_len = rpl_len; args.rpl_buf = rpl_buf; + HDESK prev_desk; + HDESK local_desktop = SwitchToCallerDesktop(args.pid, &prev_desk); + status = (this->*SlaveFuncPtr)(&args); if (status == 0) rpl_len = args.rpl_len; + + if (local_desktop) { + SetThreadDesktop(prev_desk); + CloseDesktop(local_desktop); + } } } } @@ -1583,19 +1594,12 @@ ULONG GuiServer::GetWindowStationSlave(SlaveArgs *args) local_winsta = GetProcessWindowStation(); WCHAR deskname[128] = { 0 }; - /*SbieApi_QueryConfAsIs(boxname, L"SandboxDesktopName", 0, deskname, sizeof(deskname)); - if(*value) - local_desktop = OpenDesktop(value, 0, FALSE, GENERIC_ALL); - else*/ if (SbieApi_QueryConfBool(boxname, L"UseSandboxDesktop", FALSE)) { wsprintf(deskname, L"%s_%s_Session_%d_Desktop", //_%08X", SANDBOXIE, boxname, m_SessionId); //GetTickCount()); - local_desktop = OpenDesktop(deskname, 0, FALSE, GENERIC_ALL); - if (!local_desktop) - local_desktop = CreateDesktop(deskname, NULL, NULL, 0, GENERIC_ALL, NULL); - + local_desktop = CreateBoxedDesktop(session_id, deskname); close_desktop = TRUE; } else local_desktop = GetThreadDesktop(GetCurrentThreadId()); @@ -1710,6 +1714,166 @@ finish: } +//--------------------------------------------------------------------------- +// CreateBoxedDesktop +//--------------------------------------------------------------------------- + +struct SDeskStartParam +{ + ULONG session_id; + const wchar_t* desk_name; + HDESK local_desktop; +}; + +ULONG GuiServer__StartupWorker(void* _Param) +{ + SDeskStartParam* pParam = (SDeskStartParam*)_Param; + + ULONG status = 0; + const ULONG TOKEN_RIGHTS = TOKEN_QUERY | TOKEN_DUPLICATE + | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID + | TOKEN_ADJUST_GROUPS | TOKEN_ASSIGN_PRIMARY; + HANDLE hOldToken = NULL; + HANDLE hNewToken = NULL; + //void *env = NULL; + //WCHAR cmdline[MAX_PATH]; + BOOL ok = TRUE; + + // + // set thread desktop and check if explorer is already running + // + + SetThreadDesktop(pParam->local_desktop); + + if (FindWindowW(L"Shell_TrayWnd", 0)) + return 0; + + // + // get the user token + // + + if (ok) { + ok = WTSQueryUserToken(pParam->session_id, &hOldToken); + if (! ok) + status = 0x72000000 | GetLastError(); + } + + if (ok) { + ok = DuplicateTokenEx( + hOldToken, TOKEN_RIGHTS, NULL, SecurityAnonymous, + TokenPrimary, &hNewToken); + if (! ok) + status = 0x73000000 | GetLastError(); + } + + // + // create the new shell process + // + + //ok = CreateEnvironmentBlock(&env, hNewToken, FALSE); + //if (! ok) + // status = 0x75000000 | GetLastError(); + + if (ok) { + + //GetSystemWindowsDirectoryW(cmdline, MAX_PATH); + //wcscat_s(cmdline, MAX_PATH, L"\\Explorer.exe"); + + //STARTUPINFO si; + //PROCESS_INFORMATION pi; + + //memzero(&si, sizeof(STARTUPINFO)); + //si.cb = sizeof(STARTUPINFO); + //si.dwFlags = STARTF_USESHOWWINDOW; + //si.lpDesktop = (wchar_t*)pParam->desk_name; + + //ok = CreateProcessAsUser( + // hNewToken, NULL, cmdline, NULL, NULL, FALSE, + // CREATE_UNICODE_ENVIRONMENT, env, NULL, &si, &pi); + + //if (! ok) + // status = 0x76000000 | GetLastError(); + //else { + + // CloseHandle(pi.hThread); + // CloseHandle(pi.hProcess); + //} + + SbieIniServer::RunSbieCtrl(hOldToken, pParam->desk_name); + + for (int i = 0; i++ < 10 && !FindWindowW(L"Shell_TrayWnd", 0); Sleep(1000)); // wait 10 seconds + } + + if (hNewToken) + CloseHandle(hNewToken); + if (hOldToken) + CloseHandle(hOldToken); + //if (env) + // DestroyEnvironmentBlock(env); + + return 0; +} + + +HDESK GuiServer::CreateBoxedDesktop(ULONG session_id, const wchar_t* desk_name) +{ + HDESK local_desktop = OpenDesktop(desk_name, 0, FALSE, GENERIC_ALL); + if (!local_desktop) + local_desktop = CreateDesktop(desk_name, NULL, NULL, 0, GENERIC_ALL, NULL); + if (local_desktop) { + + SDeskStartParam* pParam = (SDeskStartParam*)HeapAlloc(GetProcessHeap(), 0, sizeof(SDeskStartParam)); + pParam->session_id = session_id; + pParam->desk_name = desk_name; + pParam->local_desktop = local_desktop; + + HANDLE hThread = CreateThread(NULL, 0, GuiServer__StartupWorker, (void *)pParam, 0, NULL); + WaitForSingleObject(hThread, 20 * 1000); + CloseHandle(hThread); + + HeapFree(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, pParam); + } + return local_desktop; +} + + +//--------------------------------------------------------------------------- +// SwitchToCallerDesktop +//--------------------------------------------------------------------------- + + +HDESK GuiServer::SwitchToCallerDesktop(ULONG pid, HDESK* prev_desk) +{ + ULONG status; + WCHAR boxname[BOXNAME_COUNT]; + ULONG session_id; + WCHAR deskname[128] = { 0 }; + HDESK local_desktop = NULL; + + status = SbieApi_QueryProcess((HANDLE)(ULONG_PTR)pid, boxname, NULL, NULL, &session_id); + if (!NT_SUCCESS(status)) + return NULL; + + if (SbieApi_QueryConfBool(boxname, L"UseSandboxDesktop", FALSE)) { + + wsprintf(deskname, L"%s_%s_Session_%d_Desktop", //_%08X", + SANDBOXIE, boxname, m_SessionId); //GetTickCount()); + } + else + return NULL; + + if (prev_desk) *prev_desk = GetThreadDesktop(GetCurrentThreadId()); + local_desktop = OpenDesktop(deskname, 0, FALSE, GENERIC_ALL); + if (local_desktop) { + + if (!SetThreadDesktop(local_desktop)) + SbieApi_LogEx(session_id, 2340, L"[%d]", GetLastError()); + } + + return local_desktop; +} + + //--------------------------------------------------------------------------- // CreateConsoleSlave //--------------------------------------------------------------------------- diff --git a/Sandboxie/core/svc/GuiServer.h b/Sandboxie/core/svc/GuiServer.h index 49993d23..41d38ea4 100644 --- a/Sandboxie/core/svc/GuiServer.h +++ b/Sandboxie/core/svc/GuiServer.h @@ -74,6 +74,10 @@ protected: bool QueueCallbackSlave2(void); + HDESK CreateBoxedDesktop(ULONG session_id, const wchar_t* deskname); + + HDESK SwitchToCallerDesktop(ULONG pid, HDESK* prev_desk); + HANDLE GetJobObjectForAssign(const WCHAR *boxname); HANDLE GetJobObjectForGrant(ULONG pid); diff --git a/Sandboxie/core/svc/sbieiniserver.cpp b/Sandboxie/core/svc/sbieiniserver.cpp index 89ab9104..6f367be6 100644 --- a/Sandboxie/core/svc/sbieiniserver.cpp +++ b/Sandboxie/core/svc/sbieiniserver.cpp @@ -486,6 +486,11 @@ ULONG SbieIniServer::CheckRequest(MSG_HEADER *msg) bool SbieIniServer::SetUserSettingsSectionName(HANDLE hToken) +{ + return SetUserSettingsSectionName(hToken, m_username, m_sectionname); +} + +bool SbieIniServer::SetUserSettingsSectionName(HANDLE hToken, WCHAR* m_username, WCHAR* m_sectionname) { union { TOKEN_USER user; @@ -493,8 +498,6 @@ bool SbieIniServer::SetUserSettingsSectionName(HANDLE hToken) WCHAR value[4]; } info; - m_admin = FALSE; - // // if the UserSettings_Portable section exists, use that // @@ -521,7 +524,7 @@ bool SbieIniServer::SetUserSettingsSectionName(HANDLE hToken) if (! ok) return false; - ULONG username_len = sizeof(m_username) / sizeof(WCHAR) - 4; + ULONG username_len = 256 - 4; // ULONG username_len = sizeof(m_username) / sizeof(WCHAR) - 4; WCHAR domain[256]; ULONG domain_len = sizeof(domain) / sizeof(WCHAR) - 4; SID_NAME_USE use; @@ -533,7 +536,7 @@ bool SbieIniServer::SetUserSettingsSectionName(HANDLE hToken) if (! ok || ! m_username[0]) return false; - m_username[sizeof(m_username) / sizeof(WCHAR) - 4] = L'\0'; + m_username[username_len] = L'\0'; //m_username[sizeof(m_username) / sizeof(WCHAR) - 4] = L'\0'; _wcslwr(m_username); // @@ -2245,7 +2248,6 @@ MSG_HEADER *SbieIniServer::RunSbieCtrl(MSG_HEADER *msg, HANDLE idProcess, bool i NTSTATUS status = STATUS_UNSUCCESSFUL; HANDLE hToken = NULL; BOOL ok = TRUE; - WCHAR ctrlCmd[128] = { 0 }; // // get token from caller session or caller process. note that on @@ -2309,14 +2311,42 @@ MSG_HEADER *SbieIniServer::RunSbieCtrl(MSG_HEADER *msg, HANDLE idProcess, bool i } } + if (ok) + { + if(isSandboxed || msg->length <= sizeof(MSG_HEADER)) + status = RunSbieCtrl(hToken, NULL); + else + status = RunSbieCtrl(hToken, NULL, (WCHAR*)((UCHAR*)msg + sizeof(MSG_HEADER)), (msg->length - sizeof(MSG_HEADER)) / sizeof(WCHAR)); + } + + // + // finish + // + + if (hToken) + CloseHandle(hToken); + + return SHORT_REPLY(status); +} + +NTSTATUS SbieIniServer::RunSbieCtrl(HANDLE hToken, const WCHAR* DeskName, const WCHAR* CtrlCmd, size_t CtrlCmdLen) +{ + NTSTATUS status = STATUS_UNSUCCESSFUL; + BOOL ok = TRUE; + + WCHAR ctrlCmd[128] = { 0 }; + // // get the agent binary name // - if (isSandboxed) { + if (!CtrlCmd) { + + WCHAR m_username[256]; + WCHAR m_sectionname[128]; const WCHAR* _Setting2 = SBIECTRL_ L"AutoStartAgent"; - bool ok2 = SetUserSettingsSectionName(hToken); + bool ok2 = SetUserSettingsSectionName(hToken, m_username, m_sectionname); if (ok2) { SbieApi_QueryConfAsIs( m_sectionname, _Setting2, 0, ctrlCmd, sizeof(ctrlCmd) - 2); @@ -2327,11 +2357,10 @@ MSG_HEADER *SbieIniServer::RunSbieCtrl(MSG_HEADER *msg, HANDLE idProcess, bool i m_sectionname, _Setting2, 0, ctrlCmd, sizeof(ctrlCmd) - 2); } - } else if (msg->length > sizeof(MSG_HEADER)) { + } else if (CtrlCmdLen > 0) { - ULONG len = (ULONG)(msg->length - sizeof(MSG_HEADER)); - memcpy(ctrlCmd, (UCHAR*)msg + sizeof(MSG_HEADER), len); - ctrlCmd[len / sizeof(WCHAR)] = L'\0'; + memcpy(ctrlCmd, CtrlCmd, CtrlCmdLen * sizeof(WCHAR)); + ctrlCmd[CtrlCmdLen] = L'\0'; } // @@ -2370,6 +2399,10 @@ MSG_HEADER *SbieIniServer::RunSbieCtrl(MSG_HEADER *msg, HANDLE idProcess, bool i memzero(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_FORCEOFFFEEDBACK; + if (DeskName) { + si.dwFlags |= STARTF_USESHOWWINDOW; + si.lpDesktop = (wchar_t*)DeskName; + } ok = CreateProcessAsUser( hToken, NULL, CmdLine, NULL, NULL, FALSE, @@ -2391,14 +2424,7 @@ MSG_HEADER *SbieIniServer::RunSbieCtrl(MSG_HEADER *msg, HANDLE idProcess, bool i } } - // - // finish - // - - if (hToken) - CloseHandle(hToken); - - return SHORT_REPLY(status); + return status; } diff --git a/Sandboxie/core/svc/sbieiniserver.h b/Sandboxie/core/svc/sbieiniserver.h index bba3ec02..a88e46c7 100644 --- a/Sandboxie/core/svc/sbieiniserver.h +++ b/Sandboxie/core/svc/sbieiniserver.h @@ -62,6 +62,8 @@ protected: bool SetUserSettingsSectionName(HANDLE hToken); + static bool SetUserSettingsSectionName(HANDLE hToken, WCHAR* m_username, WCHAR* m_sectionname); + bool UserCanEdit(HANDLE hToken); #ifdef NEW_INI_MODE @@ -107,6 +109,9 @@ protected: MSG_HEADER *RC4Crypt(MSG_HEADER *msg, HANDLE idProcess, bool isSandboxed); +public: + + static NTSTATUS RunSbieCtrl(HANDLE hToken, const WCHAR* DeskName, const WCHAR* CtrlCmd = NULL, size_t CtrlCmdLen = 0); protected: @@ -122,7 +127,6 @@ protected: WCHAR m_line[1500]; //BOOLEAN m_insertbom; #endif - BOOLEAN m_admin; HANDLE m_hLockFile; ULONG m_session_id; diff --git a/Sandboxie/msgs/Sbie-English-1033.txt b/Sandboxie/msgs/Sbie-English-1033.txt index bf804213..81d2414b 100644 --- a/Sandboxie/msgs/Sbie-English-1033.txt +++ b/Sandboxie/msgs/Sbie-English-1033.txt @@ -767,6 +767,10 @@ SBIE2337 Failed to start program: %2 SBIE2338 Encountered unsupported architecture in process: %2 . +2340;pop;err;01 +SBIE2340 Desktop worker failed to switch to caller Desktop: %2 +. + # 2398;txt;01 # SBIE2398 Service suffers exception ... at address ... # . @@ -921,7 +925,7 @@ Programs . 3198;txt;01 -Do you want to start a new program in the %2 sandbox? +Do you want to start a new program into the sandbox %2? You received this message because you set AlertBeforeStart=y. . diff --git a/SandboxiePlus/MiscHelpers/Common/TreeViewEx.h b/SandboxiePlus/MiscHelpers/Common/TreeViewEx.h index 2b62a88b..b1d4ec2f 100644 --- a/SandboxiePlus/MiscHelpers/Common/TreeViewEx.h +++ b/SandboxiePlus/MiscHelpers/Common/TreeViewEx.h @@ -293,6 +293,17 @@ private slots: } protected: + void mouseDoubleClickEvent(QMouseEvent* event) override + { + QModelIndex index = indexAt(event->pos()); + if (!index.isValid()) { + emit doubleClicked(index); + return; + } + + QTreeView::mouseDoubleClickEvent(event); + } + QMenu* m_pMenu; QMap m_Columns; QSet m_FixedColumns; diff --git a/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.cpp b/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.cpp index 09e824a8..8cca1131 100644 --- a/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.cpp +++ b/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.cpp @@ -823,4 +823,11 @@ SB_STATUS CSandBox::ImBoxMount(const QString& Password, bool bProtect, bool bAut SB_STATUS CSandBox::ImBoxUnmount() { return m_pAPI->ImBoxUnmount(this); +} + +SB_STATUS CSandBox::SwitchToDesktop() +{ + if (m_Desktop.isEmpty()) + return SB_OK; // nothign to do + return m_pAPI->SwitchToDesktop(m_Desktop); } \ No newline at end of file diff --git a/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.h b/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.h index 5b7e3ddb..038c0da4 100644 --- a/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.h +++ b/SandboxiePlus/QSbieAPI/Sandboxie/SandBox.h @@ -84,6 +84,10 @@ public: virtual SB_STATUS ImBoxMount(const QString& Password = QString(), bool bProtect = false, bool bAutoUnmount = false); virtual SB_STATUS ImBoxUnmount(); + // Desktop Manager + virtual QString GetDesktop() const { return m_Desktop; } + virtual SB_STATUS SwitchToDesktop(); + class CSbieAPI* Api() { return m_pAPI; } protected: @@ -101,6 +105,8 @@ protected: QString m_RegPath; QString m_IpcPath; QString m_Mount; + + QString m_Desktop; bool m_IsEnabled; diff --git a/SandboxiePlus/QSbieAPI/SbieAPI.cpp b/SandboxiePlus/QSbieAPI/SbieAPI.cpp index 393f2ef8..bbe7bbea 100644 --- a/SandboxiePlus/QSbieAPI/SbieAPI.cpp +++ b/SandboxiePlus/QSbieAPI/SbieAPI.cpp @@ -2626,6 +2626,84 @@ SB_RESULT(QVariantMap) CSbieAPI::ImBoxQuery(const QString& Root) return CSbieResult(Info); } +/////////////////////////////////////////////////////////////////////////////// +// Desktop Manager +// + +BOOL CALLBACK CSbieAPI__EnumDesktopsProc(LPWSTR lpszDesktop, LPARAM lParam) +{ + CSbieAPI::TDesktopMap* pDesktops = (CSbieAPI::TDesktopMap*)lParam; + QString Name = QString::fromWCharArray(lpszDesktop); // Sandboxie_[BoxName]_Session_[Num]_Desktop + QStringList Names = Name.split("_"); + if (Names.count() > 3 && Names[0] == "Sandboxie" && Names[2] == "Session") + pDesktops->insert(Names[1].toLower(), Name); + return TRUE; +} + +SB_RESULT(CSbieAPI::TDesktopMap) CSbieAPI::EnumBoxDesktops() +{ + TDesktopMap Desktops; + + HWINSTA hWinSta = GetProcessWindowStation(); + if (hWinSta == NULL) + return SB_ERR(STATUS_UNSUCCESSFUL); + + // Enumerate all desktops associated with the current window station + if (!EnumDesktopsW(hWinSta, CSbieAPI__EnumDesktopsProc, (LPARAM)&Desktops)) + return SB_ERR(STATUS_UNSUCCESSFUL); + + foreach(const CSandBoxPtr & pBox, m_SandBoxes) + pBox->m_Desktop = Desktops.value(pBox->m_Name.toLower()); + + return CSbieResult(Desktops); +} + +SB_STATUS CSbieAPI::SwitchToDesktop(const QString& Desktop) +{ + BOOL ok = FALSE; + + HDESK hDesktop = OpenDesktop(Desktop.toStdWString().c_str(), 0, FALSE, DESKTOP_SWITCHDESKTOP); + if (hDesktop != NULL) + { + ok = SwitchDesktop(hDesktop); + + CloseDesktop(hDesktop); + } + + if(!ok) + return SB_ERR(STATUS_UNSUCCESSFUL); + return SB_OK; +} + +QString CSbieAPI__GetDesktopName(HDESK hDesktop) +{ + wchar_t desktopName[MAX_PATH]; + DWORD neededLength = sizeof(desktopName); + if (!GetUserObjectInformationW(hDesktop, UOI_NAME, desktopName, neededLength, &neededLength)) + return QString(); + + return QString::fromWCharArray(desktopName); +} + +QString CSbieAPI::GetCurrentDesktopName() +{ + HDESK hDesktop = GetThreadDesktop(GetCurrentThreadId()); + if (hDesktop == NULL) + return QString(); + return CSbieAPI__GetDesktopName(hDesktop); +} + +bool CSbieAPI::IsCurrentDesktopActive() +{ + QString CurrentDesktop = CSbieAPI::GetCurrentDesktopName(); + QString ActiveDesktop; + HDESK hInputDesktop = OpenInputDesktop(0, FALSE, DESKTOP_READOBJECTS | DESKTOP_SWITCHDESKTOP); + if (hInputDesktop) { + ActiveDesktop = CSbieAPI__GetDesktopName(hInputDesktop); + CloseDesktop(hInputDesktop); + } + return CurrentDesktop.compare(ActiveDesktop, Qt::CaseInsensitive) == 0; +} /////////////////////////////////////////////////////////////////////////////// // Monitor diff --git a/SandboxiePlus/QSbieAPI/SbieAPI.h b/SandboxiePlus/QSbieAPI/SbieAPI.h index c1b83e4f..a029e342 100644 --- a/SandboxiePlus/QSbieAPI/SbieAPI.h +++ b/SandboxiePlus/QSbieAPI/SbieAPI.h @@ -140,6 +140,13 @@ public: virtual SB_RESULT(QVariantMap) ImBoxQuery(const QString& Root = QString()); //virtual SB_STATUS ImBoxUpdate( // todo + // Desktop Manager + typedef QMultiMap TDesktopMap; + virtual SB_RESULT(TDesktopMap) EnumBoxDesktops(); + virtual SB_STATUS SwitchToDesktop(const QString& Desktop); + static QString GetCurrentDesktopName(); + static bool IsCurrentDesktopActive(); + // Monitor virtual SB_STATUS EnableMonitor(bool Enable); virtual bool IsMonitoring(); diff --git a/SandboxiePlus/SandMan/Helpers/WinHelper.cpp b/SandboxiePlus/SandMan/Helpers/WinHelper.cpp index 6ad737b8..c55d9819 100644 --- a/SandboxiePlus/SandMan/Helpers/WinHelper.cpp +++ b/SandboxiePlus/SandMan/Helpers/WinHelper.cpp @@ -169,4 +169,27 @@ QString GetProductVersion(const QString &filePath) } } return QString(); +} + +bool KillProcessById(DWORD processId) +{ + bool ok = false; + HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, processId); + if (hProcess && hProcess != INVALID_HANDLE_VALUE) { + if (TerminateProcess(hProcess, 0)) + ok = true; + CloseHandle(hProcess); + } + return ok; +} + +bool KillProcessByWnd(const QString& WndName) +{ + HWND hwnd = FindWindowW(WndName.toStdWString().c_str(), 0); + if (hwnd) { + DWORD processId; + if (GetWindowThreadProcessId(hwnd, &processId)) + return KillProcessById(processId); + } + return false; } \ No newline at end of file diff --git a/SandboxiePlus/SandMan/Helpers/WinHelper.h b/SandboxiePlus/SandMan/Helpers/WinHelper.h index 734ee44a..ba64a00b 100644 --- a/SandboxiePlus/SandMan/Helpers/WinHelper.h +++ b/SandboxiePlus/SandMan/Helpers/WinHelper.h @@ -8,4 +8,6 @@ bool PickWindowsIcon(QWidget* pParent, QString& Path, quint32& Index); void ProtectWindow(void* hWnd); -QString GetProductVersion(const QString& filePath); \ No newline at end of file +QString GetProductVersion(const QString& filePath); + +bool KillProcessByWnd(const QString& WndName); \ No newline at end of file diff --git a/SandboxiePlus/SandMan/SandMan.cpp b/SandboxiePlus/SandMan/SandMan.cpp index 43fcdb41..94a53ea7 100644 --- a/SandboxiePlus/SandMan/SandMan.cpp +++ b/SandboxiePlus/SandMan/SandMan.cpp @@ -115,7 +115,7 @@ CSandMan* theGUI = NULL; extern QString g_PendingMessage; -CSandMan::CSandMan(QWidget *parent) +CSandMan::CSandMan(const QString& BoxDesktop, bool bAutoRun, QWidget *parent) : QMainWindow(parent) { #if defined(Q_OS_WIN) @@ -126,6 +126,8 @@ CSandMan::CSandMan(QWidget *parent) CArchive::Init(); + m_BoxDesktop = BoxDesktop; + theGUI = this; m_DarkTheme = false; @@ -181,6 +183,7 @@ CSandMan::CSandMan(QWidget *parent) connect(theAPI, SIGNAL(StatusChanged()), this, SLOT(OnStatusChanged())); connect(theAPI, SIGNAL(BoxAdded(const CSandBoxPtr&)), this, SLOT(OnBoxAdded(const CSandBoxPtr&))); + connect(theAPI, SIGNAL(BoxOpened(const CSandBoxPtr&)), this, SLOT(OnBoxOpened(const CSandBoxPtr&))); connect(theAPI, SIGNAL(BoxClosed(const CSandBoxPtr&)), this, SLOT(OnBoxClosed(const CSandBoxPtr&))); connect(theAPI, SIGNAL(BoxCleaned(CSandBoxPlus*)), this, SLOT(OnBoxCleaned(CSandBoxPlus*))); @@ -256,7 +259,7 @@ CSandMan::CSandMan(QWidget *parent) m_BoxColors[CSandBoxPlus::eOpen] = qRgb(255,255,255); m_BoxColors[CSandBoxPlus::ePrivate] = qRgb(56,56,56); - CreateTrayIcon(); + CreateTrayIcon(bAutoRun); LoadState(); @@ -284,7 +287,6 @@ CSandMan::CSandMan(QWidget *parent) m_uTimerID = startTimer(1000); - bool bAutoRun = QApplication::arguments().contains("-autorun"); if (!bAutoRun && g_PendingMessage.isEmpty()) SafeShow(this); @@ -537,6 +539,8 @@ void CSandMan::CreateMenus(bool bAdvanced) //m_pUpdateCore = NULL; } + m_pDefaultDesktop = m_pMenuFile->addAction(CSandMan::GetIcon("Monitor"), tr("Return to Default Desktop"), this, SLOT(OnDefaultDesktop())); + if (m_BoxDesktop.isEmpty()) m_pDefaultDesktop->setEnabled(false); m_pMenuFile->addSeparator(); m_pRestart = m_pMenuFile->addAction(CSandMan::GetIcon("Shield9"), tr("Restart As Admin"), this, SLOT(OnRestartAsAdmin())); m_pExit = m_pMenuFile->addAction(CSandMan::GetIcon("Exit"), tr("Exit"), this, SLOT(OnExit())); @@ -694,6 +698,8 @@ void CSandMan::CreateOldMenus() m_pSetupWizard = NULL; //m_pUpdateCore = NULL; } + m_pDefaultDesktop = m_pMenuFile->addAction(CSandMan::GetIcon("Monitor"), tr("Return to Default Desktop"), this, SLOT(OnDefaultDesktop())); + if (m_BoxDesktop.isEmpty()) m_pDefaultDesktop->setEnabled(false); m_pRestart = m_pMenuFile->addAction(CSandMan::GetIcon("Shield9"), tr("Restart As Admin"), this, SLOT(OnRestartAsAdmin())); m_pExit = m_pMenuFile->addAction(CSandMan::GetIcon("Exit"), tr("Exit"), this, SLOT(OnExit())); @@ -866,6 +872,8 @@ QList CSandMan::GetAvailableToolBarActions() ToolBarAction{ "CheckForUpdates", m_pUpdate }, ToolBarAction{ "About", m_pAbout }, ToolBarAction{ "", nullptr }, // separator + ToolBarAction{ "pApp", m_pDefaultDesktop }, + ToolBarAction{ "", nullptr }, // separator ToolBarAction{ "RestartAsAdmin", m_pRestart }, ToolBarAction{ "Exit", m_pExit }, ToolBarAction{ "", nullptr }, // separator @@ -1300,24 +1308,35 @@ void CSandMan::CheckForUpdates(bool bManual) m_pUpdater->CheckForUpdates(bManual); } -#include "SandManTray.cpp" +void CSandMan::OnDefaultDesktop() +{ + theAPI->SwitchToDesktop("Default"); +} void CSandMan::OnRestartAsAdmin() { theAPI->Disconnect(); + Restart(true); + OnExit(); +} + +void CSandMan::Restart(bool AsAdmin) +{ WCHAR buf[255] = { 0 }; GetModuleFileNameW(NULL, buf, 255); SHELLEXECUTEINFO se; memset(&se, 0, sizeof(SHELLEXECUTEINFO)); se.cbSize = sizeof(SHELLEXECUTEINFO); - se.lpVerb = L"runas"; + if(AsAdmin) + se.lpVerb = L"runas"; se.lpFile = buf; - se.nShow = SW_HIDE; + se.nShow = SW_SHOWNORMAL; se.fMask = 0; ShellExecuteEx(&se); - OnExit(); } +#include "SandManTray.cpp" + void CSandMan::OnExit() { m_bExit = true; @@ -1353,7 +1372,17 @@ void CSandMan::closeEvent(QCloseEvent *e) emit Closed(); - if (IsFullyPortable() && theAPI->IsConnected()) + if (!m_BoxDesktop.isEmpty()) + { + auto pBoxEx = theAPI->GetBoxByName(m_BoxDesktop).objectCast(); + if (pBoxEx) pBoxEx->TerminateAll(); + theAPI->SwitchToDesktop("Default"); + if (!KillProcessByWnd("Shell_TrayWnd")) { + e->ignore(); + return; + } + } + else if (IsFullyPortable() && theAPI->IsConnected()) { int PortableStop = theConf->GetInt("Options/PortableStop", -1); if (PortableStop == -1) @@ -1716,14 +1745,24 @@ bool CSandMan::RunSandboxed(const QStringList& Commands, QString BoxName, const SB_RESULT(quint32) CSandMan::RunStart(const QString& BoxName, const QString& Command, CSbieAPI::EStartFlags Flags, const QString& WorkingDir, QProcess* pProcess) { auto pBoxEx = theAPI->GetBoxByName(BoxName).objectCast(); - if (pBoxEx && pBoxEx->UseImageFile() && pBoxEx->GetMountRoot().isEmpty()) { - + if (pBoxEx && pBoxEx->UseImageFile() && pBoxEx->GetMountRoot().isEmpty()) + { SB_STATUS Status = ImBoxMount(pBoxEx, true); if (Status.IsError()) return Status; } - return theAPI->RunStart(BoxName, Command, Flags, WorkingDir, pProcess); + auto Res = theAPI->RunStart(BoxName, Command, Flags, WorkingDir, pProcess); + + if (!Res.IsError() && pBoxEx->GetBool("UseSandboxDesktop", false) && theConf->GetBool("Options/AutoDesktopSwitch", true)) + { + QTimer::singleShot(1000, this, [pBoxEx]() { + theAPI->EnumBoxDesktops(); + pBoxEx->SwitchToDesktop(); + }); + } + + return Res; } SB_STATUS CSandMan::ImBoxMount(const CSandBoxPtr& pBox, bool bAutoUnmount) @@ -2121,6 +2160,7 @@ finish: void CSandMan::UpdateProcesses() { theAPI->UpdateProcesses(KeepTerminated() ? -1 : 1500, ShowAllSessions()); // keep for 1.5 sec + theAPI->EnumBoxDesktops(); } void CSandMan::OnBoxAdded(const CSandBoxPtr& pBox) @@ -2297,8 +2337,19 @@ void CSandMan::OnStartMenuChanged() } } +void CSandMan::OnBoxOpened(const CSandBoxPtr& pBox) +{ +} + void CSandMan::OnBoxClosed(const CSandBoxPtr& pBox) { + if (!m_BoxDesktop.isEmpty()) + { + if (!theAPI->IsCurrentDesktopActive()) + OnExit(); + return; + } + foreach(const QString & Value, pBox->GetTextList("OnBoxTerminate", true, false, true)) { QString Value2 = pBox->Expand(Value); CSbieProgressPtr pProgress = CSbieUtils::RunCommand(Value2, true); diff --git a/SandboxiePlus/SandMan/SandMan.h b/SandboxiePlus/SandMan/SandMan.h index 04a8df18..c23dc587 100644 --- a/SandboxiePlus/SandMan/SandMan.h +++ b/SandboxiePlus/SandMan/SandMan.h @@ -39,7 +39,7 @@ class CSandMan : public QMainWindow Q_OBJECT public: - CSandMan(QWidget *parent = Q_NULLPTR); + CSandMan(const QString& BoxDesktop, bool bAutoRun, QWidget *parent = Q_NULLPTR); virtual ~CSandMan(); CSbieTemplatesEx* GetCompat() { return m_SbieTemplates; } @@ -79,6 +79,7 @@ public: bool IsShowHidden() { return m_pShowHidden && m_pShowHidden->isChecked(); } bool KeepTerminated(); bool ShowAllSessions() { return m_pShowAllSessions && m_pShowAllSessions->isChecked(); } + const QString& GetBoxDesktop() const { return m_BoxDesktop; } bool IsSilentMode(); bool IsDisableRecovery() {return IsSilentMode() || m_pDisableRecovery && m_pDisableRecovery->isChecked();} bool IsDisableMessages() {return IsSilentMode() || m_pDisableMessages && m_pDisableMessages->isChecked();} @@ -119,6 +120,8 @@ public: void SaveMessageLog(QIODevice* pFile); + static void Restart(bool AsAdmin = false); + signals: void DrivesChanged(); @@ -154,6 +157,7 @@ protected: bool m_bConnectPending; bool m_bStopPending; CBoxBorder* m_pBoxBorder; + QString m_BoxDesktop; CSbieTemplatesEx* m_SbieTemplates; CScriptManager* m_SbieScripts; @@ -226,6 +230,7 @@ public slots: void OnCancelAsync(); void OnBoxAdded(const CSandBoxPtr& pBox); + void OnBoxOpened(const CSandBoxPtr& pBox); void OnBoxClosed(const CSandBoxPtr& pBox); void OnBoxCleaned(CSandBoxPlus* pBoxEx); @@ -262,6 +267,7 @@ private slots: void OnDisableForce2(); void OnDisablePopUp(); void OnMaintenance(); + void OnDefaultDesktop(); void OnViewMode(QAction* action); void OnAlwaysTop(); @@ -311,7 +317,7 @@ private: void CreateToolBar(bool bRebuild); void CreateLabel(); void CreateView(int iViewMode); - void CreateTrayIcon(); + void CreateTrayIcon(bool bAutoRun); void CreateTrayMenu(); void CreateBoxMenu(QMenu* pMenu, int iOffset = 0, int iSysTrayFilter = 0); @@ -371,7 +377,6 @@ private: QHBoxLayout* m_pMenuLayout; QMenu* m_pMenuFile; - QAction* m_pRestart; QAction* m_pRunBoxed; QAction* m_pNewBox; QAction* m_pNewGroup; @@ -401,6 +406,8 @@ private: QAction* m_pImDiskCpl; QAction* m_pUninstallAll; QAction* m_pSetupWizard; + QAction* m_pDefaultDesktop; + QAction* m_pRestart; QAction* m_pExit; QMenu* m_pMenuView; diff --git a/SandboxiePlus/SandMan/SandManTray.cpp b/SandboxiePlus/SandMan/SandManTray.cpp index dd546d5b..0737a180 100644 --- a/SandboxiePlus/SandMan/SandManTray.cpp +++ b/SandboxiePlus/SandMan/SandManTray.cpp @@ -18,7 +18,7 @@ public: bool CTrayBoxesItemDelegate::m_Hold = false; -void CSandMan::CreateTrayIcon() +void CSandMan::CreateTrayIcon(bool bAutoRun) { m_pTrayIcon = new QSystemTrayIcon(GetTrayIcon(), this); m_pTrayIcon->setToolTip(GetTrayText()); @@ -30,8 +30,6 @@ void CSandMan::CreateTrayIcon() CreateTrayMenu(); - bool bAutoRun = QApplication::arguments().contains("-autorun"); - if(g_PendingMessage.isEmpty()){ m_pTrayIcon->show(); // Note: qt bug; hide does not work if not showing first :/ if(!bAutoRun && theConf->GetInt("Options/SysTrayIcon", 1) == 0) @@ -125,6 +123,11 @@ void CSandMan::CreateTrayMenu() //m_pTrayMenu->addAction(pBoxWidget); //m_pTrayMenu->addSeparator(); + if (m_pDefaultDesktop->isEnabled()) { + m_pTrayMenu->addAction(m_pDefaultDesktop); + m_pTrayMenu->addSeparator(); + } + m_pTrayMenu->addAction(m_pExit); } diff --git a/SandboxiePlus/SandMan/Views/SbieView.cpp b/SandboxiePlus/SandMan/Views/SbieView.cpp index de200d62..af73205c 100644 --- a/SandboxiePlus/SandMan/Views/SbieView.cpp +++ b/SandboxiePlus/SandMan/Views/SbieView.cpp @@ -197,6 +197,8 @@ void CSbieView::CreateMenu() m_iMenuRun = m_pMenuRun->actions().count(); m_pMenuEmptyBox = m_pMenuBox->addAction(CSandMan::GetIcon("EmptyAll"), tr("Terminate All Programs"), this, SLOT(OnSandBoxAction())); m_pMenuBox->addSeparator(); + m_pMenuSwitchDesk = m_pMenuBox->addAction(CSandMan::GetIcon("Monitor"), tr("Switch to Isoalted Desktop"), this, SLOT(OnSandBoxAction())); + m_pMenuBox->addSeparator(); m_pMenuContent = m_pMenuBox->addMenu(CSandMan::GetIcon("Compatibility"), tr("Box Content")); m_pMenuBrowse = m_pMenuContent->addAction(CSandMan::GetIcon("Folder"), tr("Browse Files"), this, SLOT(OnSandBoxAction())); m_pMenuContent->addSeparator(); @@ -327,6 +329,7 @@ void CSbieView::CreateOldMenu() m_pMenuBox->addSeparator(); m_pMenuEmptyBox = m_pMenuBox->addAction(CSandMan::GetIcon("EmptyAll"), tr("Terminate Programs"), this, SLOT(OnSandBoxAction())); + m_pMenuSwitchDesk = m_pMenuBox->addAction(CSandMan::GetIcon("Monitor"), tr("Switch to Isoalted Desktop"), this, SLOT(OnSandBoxAction())); m_pMenuMount = m_pMenuBox->addAction(CSandMan::GetIcon("LockOpen"), tr("Mount Box Image"), this, SLOT(OnSandBoxAction())); m_pMenuUnmount = m_pMenuBox->addAction(CSandMan::GetIcon("LockClosed"), tr("Unmount Box Image"), this, SLOT(OnSandBoxAction())); m_pMenuRecover = m_pMenuBox->addAction(CSandMan::GetIcon("Recover"), tr("Quick Recover"), this, SLOT(OnSandBoxAction())); @@ -416,6 +419,8 @@ void CSbieView::CreateTrayMenu() m_pMenuTray->addMenu(m_pMenuRun); m_pMenuTray->addAction(m_pMenuEmptyBox); m_pMenuTray->addSeparator(); + m_pMenuTray->addAction(m_pMenuSwitchDesk); + m_pMenuTray->addSeparator(); m_pMenuTray->addAction(m_pMenuBrowse); m_pMenuTray->addAction(m_pMenuExplore); m_pMenuTray->addAction(m_pMenuRegEdit); @@ -477,7 +482,16 @@ QString CSbieView__SerializeGroup(QMap& m_Groups, const QS void CSbieView::Refresh() { - QList Added = m_pSbieModel->Sync(theAPI->GetAllBoxes(), m_Groups, theGUI->IsShowHidden()); + QMap Boxes; + if (!theGUI->GetBoxDesktop().isEmpty() +#ifdef _DEBUG + && !theGUI->ShowAllSessions() +#endif + ) + Boxes.insert(theGUI->GetBoxDesktop().toLower(), theAPI->GetBoxByName(theGUI->GetBoxDesktop())); + else + Boxes = theAPI->GetAllBoxes(); + QList Added = m_pSbieModel->Sync(Boxes, m_Groups, theGUI->IsShowHidden()); if (m_pSbieModel->IsTree()) { @@ -628,6 +642,7 @@ bool CSbieView::UpdateMenu(bool bAdvanced, const CSandBoxPtr &pBox, int iSandBox m_pMenuCleanUp->setEnabled(iSandBoxeCount > 0); if (m_pMenuContent) m_pMenuContent->setEnabled(iSandBoxeCount > 0); m_pMenuEmptyBox->setEnabled(iSandBoxeCount > 0); + m_pMenuSwitchDesk->setEnabled(iSandBoxeCount == 1 && !pBoxEx->GetDesktop().isEmpty()); m_pMenuBrowse->setEnabled(iSandBoxeCount == 1); m_pMenuExplore->setEnabled(iSandBoxeCount == 1); @@ -1551,6 +1566,10 @@ void CSbieView::OnSandBoxAction(QAction* Action, const QList& SandB foreach(const CSandBoxPtr& pBox, SandBoxes) Results.append(pBox->TerminateAll()); } + else if (Action == m_pMenuSwitchDesk) + { + Results.append(SandBoxes.first()->SwitchToDesktop()); + } else if (Action == m_pMenuMkLink) { if (theConf->GetInt("Options/InfoMkLink", -1) == -1) @@ -1759,6 +1778,12 @@ void CSbieView::ShowBrowse(const CSandBoxPtr& pBox) void CSbieView::OnDoubleClicked(const QModelIndex& index) { + if (!index.isValid()) { + if (!theGUI->GetBoxDesktop().isEmpty() && theConf->GetBool("Options/QuickDesktopSwitch", true)) + theAPI->SwitchToDesktop("Default"); + return; + } + QModelIndex ModelIndex = m_pSortProxy->mapToSource(index); CSandBoxPtr pBox = m_pSbieModel->GetSandBox(ModelIndex); if (pBox.isNull()) @@ -1774,6 +1799,11 @@ void CSbieView::OnDoubleClicked(const QModelIndex& index) return; } + if (!pBox->GetDesktop().isEmpty() && theConf->GetBool("Options/QuickDesktopSwitch", true) && theGUI->GetBoxDesktop().compare(pBox->GetName(), Qt::CaseInsensitive) != 0) { + pBox->SwitchToDesktop(); + return; + } + //if (index.column() != CSbieModel::eName) // return; @@ -2207,7 +2237,7 @@ void CSbieView::ClearUserUIConfig(const QMap AllBoxes) void CSbieView::SaveBoxGrouping() { - if (!theAPI->IsConnected()) + if (!theAPI->IsConnected() || !theGUI->GetBoxDesktop().isEmpty()) return; theAPI->GetUserSettings()->SetRefreshOnChange(false); diff --git a/SandboxiePlus/SandMan/Views/SbieView.h b/SandboxiePlus/SandMan/Views/SbieView.h index cb0ce534..cbb67f6d 100644 --- a/SandboxiePlus/SandMan/Views/SbieView.h +++ b/SandboxiePlus/SandMan/Views/SbieView.h @@ -186,6 +186,7 @@ private: QAction* m_pMenuOptions; QAction* m_pMenuSnapshots; QAction* m_pMenuEmptyBox; + QAction* m_pMenuSwitchDesk; QMenu* m_pMenuContent; QAction* m_pMenuExplore; QAction* m_pMenuBrowse; diff --git a/SandboxiePlus/SandMan/main.cpp b/SandboxiePlus/SandMan/main.cpp index ce5d1baa..adf8e478 100644 --- a/SandboxiePlus/SandMan/main.cpp +++ b/SandboxiePlus/SandMan/main.cpp @@ -32,6 +32,8 @@ int main(int argc, char *argv[]) // use a shared setting location when used in a business environment for easier administration theConf = new CSettings(ConfDir, "Sandboxie-Plus"); + QString AppID = "SandMan"; + #ifndef _DEBUG InitMiniDumpWriter(QString("SandMan-v%1").arg(CSandMan::GetVersion()).toStdWString().c_str() , QString(theConf->GetConfigDir()).replace("/", "\\").toStdWString().c_str()); #endif @@ -60,8 +62,37 @@ int main(int argc, char *argv[]) QApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton); #endif - QtSingleApplication app(argc, argv); - app.setQuitOnLastWindowClosed(false); + QString BoxDesktop; + QString CurDesk = CSbieAPI::GetCurrentDesktopName(); + QStringList CurDeskNames = CurDesk.split("_"); + if (CurDeskNames.length() >= 3 && CurDeskNames[0] == "Sandboxie" && CurDeskNames[2] == "Session") + BoxDesktop = CurDeskNames[1]; + + if (!BoxDesktop.isEmpty()) + { + for (int i = 1; i < argc; i++) + { + if (stricmp(argv[i], "-autorun") != 0) + continue; + + WCHAR cmdline[MAX_PATH]; + GetSystemWindowsDirectoryW(cmdline, MAX_PATH); + wcscat_s(cmdline, MAX_PATH, L"\\Explorer.exe"); + QStringList StartArgs; + StartArgs << "/Box:" + BoxDesktop; + StartArgs << "/fcp"; + StartArgs << QString::fromWCharArray(cmdline); + QProcess::startDetached(AppDir + "\\start.exe", StartArgs); + + CSandMan::Restart(); + return 0; + } + + AppID.append("_" + BoxDesktop); + } + + QtSingleApplication* pApp = new QtSingleApplication(AppID, argc, argv); + pApp->setQuitOnLastWindowClosed(false); //InitConsole(false); @@ -165,30 +196,34 @@ int main(int argc, char *argv[]) return -1; } + bool bAutoRun = pApp->arguments().contains("-autorun"); + if (!g_PendingMessage.isEmpty()) { - if(app.sendMessage(g_PendingMessage)) + if(pApp->sendMessage(g_PendingMessage)) return 0; - app.disableSingleApp(); // we start to do one job and exit, don't interfere with starting a regular instance + pApp->disableSingleApp(); // we start to do one job and exit, don't interfere with starting a regular instance } else { - if (app.arguments().contains("-autorun") && app.isRunning()) + if (bAutoRun && pApp->isRunning()) return 0; - if (app.sendMessage("ShowWnd")) + if (pApp->sendMessage("ShowWnd")) return 0; } //QThreadPool::globalInstance()->setMaxThreadCount(theConf->GetInt("Options/MaxThreadPool", 10)); - CSandMan* pWnd = new CSandMan(); + CSandMan* pWnd = new CSandMan(BoxDesktop, bAutoRun); - QObject::connect(&app, SIGNAL(messageReceived(const QString&)), pWnd, SLOT(OnMessage(const QString&)), Qt::QueuedConnection); + QObject::connect(pApp, SIGNAL(messageReceived(const QString&)), pWnd, SLOT(OnMessage(const QString&)), Qt::QueuedConnection); - int ret = app.exec(); + int ret = pApp->exec(); delete pWnd; delete theConf; theConf = NULL; + delete pApp; + return ret; } diff --git a/SandboxiePlus/version.h b/SandboxiePlus/version.h index 41c411ee..fa0e93c4 100644 --- a/SandboxiePlus/version.h +++ b/SandboxiePlus/version.h @@ -1,7 +1,7 @@ #pragma once #define VERSION_MJR 1 -#define VERSION_MIN 14 +#define VERSION_MIN 15 #define VERSION_REV 0 #define VERSION_UPD 0