Merge branch 'master' into next

This commit is contained in:
DavidXanatos 2022-06-17 08:59:09 +02:00
commit 51b03496a1
34 changed files with 1447 additions and 1135 deletions

View File

@ -18,6 +18,39 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [1.1.3 / 5.56.3] - 2022-06-??
### Fixed
- fixed issue with recovery window on delete [#1948](https://github.com/sandboxie-plus/Sandboxie/issues/1948)
## [1.1.2 / 5.56.2] - 2022-06-14
### Added
- added missing file recovery log from sbiectrl to sandman [#425](https://github.com/sandboxie-plus/Sandboxie/issues/425)
- Immediate recovery window will now auto close when all files are recovered [#1498](https://github.com/sandboxie-plus/Sandboxie/issues/1498)
- the Immediate recovery window of sandman is now by default alway on top like in sbiectrl this can be disabled with "Options/RecoveryOnTop=n" [#1465](https://github.com/sandboxie-plus/Sandboxie/issues/1465)
- added option to toggle Immediate recovery from the presets sub menu [#1653](https://github.com/sandboxie-plus/Sandboxie/issues/1653)
- added option to disable file recovery and or message pop up globally
- added per box refresh opzion [#1945](https://github.com/sandboxie-plus/Sandboxie/issues/1945)
### Changed
- desktop security workaround used for chrome, firefox and acrobat can now be enabled for all processes using "UseSbieDeskHack=y"
- inproved double click behavioure [#1935](https://github.com/sandboxie-plus/Sandboxie/issues/1935)
- box size info is refreshed on file recovery
### Fixed
- fixed issue with unnececery sandboxie config reloads introduced in 1.1.1
- fixed issue with recovery window focus [#1374](https://github.com/sandboxie-plus/Sandboxie/issues/1374)
- fixed issues with desktop objects introduced in 1.1.1 [#1934](https://github.com/sandboxie-plus/Sandboxie/issues/1934)
- fixed issues with edge startup boost using a gpo preset
## [1.1.1 / 5.56.1] - 2022-06-07 ## [1.1.1 / 5.56.1] - 2022-06-07
### Added ### Added
@ -1025,8 +1058,8 @@ Fixed issue with Windows 7
### Changed ### Changed
- replaced the Process List used by the driver with a much faster Hash Map implementation - replaced the Process List used by the driver with a much faster Hash Map implementation
-- Note: this change provides an almost static system call speed of 1.2µs regardless of the running process count -- Note: this change provides an almost static system call speed of 1.2µs regardless of the running process count
-- The old list, with 100 programs running required 4.5µs; with 200: 12µs; and with 300: 18µs per syscall -- The old list, with 100 programs running required 4.5µs; with 200: 12µs; and with 300: 18µs per syscall
-- Note: some of the slowdown was also affecting non-sandboxed applications due to how the driver handles certain callbacks -- Note: some of the slowdown was also affecting non-sandboxed applications due to how the driver handles certain callbacks
- replaced the per-process Thread List used by the driver with a much faster Hash Map implementation - replaced the per-process Thread List used by the driver with a much faster Hash Map implementation
- replaced configuration section list with a hash map to improve configuration performance, and increased line limit to 100000 - replaced configuration section list with a hash map to improve configuration performance, and increased line limit to 100000
@ -1653,7 +1686,7 @@ Fixed issue with Windows 7
- added text filter to templates view - added text filter to templates view
- added new compatibility templates: - added new compatibility templates:
-- Windows 10 core UI component: OpenIpcPath=\BaseNamedObjects\[CoreUI]-* solving issues with Chinese Input and Emojis [#120](https://github.com/sandboxie-plus/Sandboxie/issues/120) [#88](https://github.com/sandboxie-plus/Sandboxie/issues/88) -- Windows 10 core UI component: OpenIpcPath=\BaseNamedObjects\[CoreUI]-* solving issues with Chinese Input and Emojis [#120](https://github.com/sandboxie-plus/Sandboxie/issues/120) [#88](https://github.com/sandboxie-plus/Sandboxie/issues/88)
-- Firefox Quantum, access to Windows FontCachePort for compatibility with Windows 7 -- Firefox Quantum, access to Windows's FontCachePort for compatibility with Windows 7
- added experimental debug option "OriginalToken=y" which lets sandboxed processes retain their original unrestricted token - added experimental debug option "OriginalToken=y" which lets sandboxed processes retain their original unrestricted token
-- This option is comparable with "OpenToken=y" and is intended only for testing and debugging, it BREAKS most SECURITY guarantees (!) -- This option is comparable with "OpenToken=y" and is intended only for testing and debugging, it BREAKS most SECURITY guarantees (!)
- added debug option "NoSandboxieDesktop=y" it disables the desktop proxy mechanism - added debug option "NoSandboxieDesktop=y" it disables the desktop proxy mechanism

View File

@ -112,11 +112,8 @@ typedef BOOL (*P_SaferComputeTokenFromLevel)(
typedef ULONG (*P_GetEffectiveRightsFromAcl)( typedef ULONG (*P_GetEffectiveRightsFromAcl)(
PACL pacl, void *pTrustee, PACCESS_MASK pAccessRights); PACL pacl, void *pTrustee, PACCESS_MASK pAccessRights);
//typedef BOOL (*P_EnumWindowStations) (WINSTAENUMPROC lpEnumFunc, LPARAM lParam); typedef BOOL (*P_EnumWindowStations) (_In_ WINSTAENUMPROC lpEnumFunc, _In_ LPARAM lParam);
//typedef HANDLE (*P_OpenWindowStationW) (LPCWSTR lpszWinSta, BOOL fInherit, ACCESS_MASK dwDesiredAccess); typedef HANDLE (*P_OpenWindowStationW) (LPCWSTR lpszWinSta, BOOL fInherit, ACCESS_MASK dwDesiredAccess);
//
//typedef BOOL (*P_EnumDesktopsW) (HWINSTA hwinsta, DESKTOPENUMPROCW lpEnumFunc, LPARAM lParam);
//typedef HANDLE (*P_OpenDesktopW) (LPCWSTR lpszDesktop, DWORD dwFlags, BOOL fInherit, ACCESS_MASK dwDesiredAccess);
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -158,12 +155,8 @@ typedef ULONG (*P_GetEffectiveRightsFromAcl)(
P_SaferComputeTokenFromLevel __sys_SaferComputeTokenFromLevel = NULL; P_SaferComputeTokenFromLevel __sys_SaferComputeTokenFromLevel = NULL;
P_GetEffectiveRightsFromAcl __sys_GetEffectiveRightsFromAclW = NULL; P_GetEffectiveRightsFromAcl __sys_GetEffectiveRightsFromAclW = NULL;
P_EnumWindowStations __sys_EnumWindowStationsW = NULL;
//P_EnumWindowStations __sys_EnumWindowStationsW = NULL; P_OpenWindowStationW __sys_OpenWindowStationW = NULL;
//P_OpenWindowStationW __sys_OpenWindowStationW = NULL;
//extern P_EnumDesktopsW __sys_EnumDesktopsW;
//extern P_OpenDesktopW __sys_OpenDesktopW;
static HMODULE AdvApi_Module = NULL; static HMODULE AdvApi_Module = NULL;
@ -247,7 +240,7 @@ _FX BOOLEAN AdvApi_Init(HMODULE module)
// only hook SetSecurityInfo if this is Chrome. Outlook 2013 uses delayed loading and will cause infinite callbacks // only hook SetSecurityInfo if this is Chrome. Outlook 2013 uses delayed loading and will cause infinite callbacks
// Starting with Win 10, we only want to hook ntmarta!SetSecurityInfo. Do NOT hook advapi!SetSecurityInfo. Delay loading for advapi will cause infinite recursion. // Starting with Win 10, we only want to hook ntmarta!SetSecurityInfo. Do NOT hook advapi!SetSecurityInfo. Delay loading for advapi will cause infinite recursion.
// Note: the infinite recursion issue has been resolved int 5.43 // Note: the infinite recursion issue has been resolved int 5.43
if ((Dll_ImageType == DLL_IMAGE_GOOGLE_CHROME) || (Dll_ImageType == DLL_IMAGE_ACROBAT_READER)) { if ((Dll_ImageType == DLL_IMAGE_GOOGLE_CHROME) || (Dll_ImageType == DLL_IMAGE_MOZILLA_FIREFOX) || (Dll_ImageType == DLL_IMAGE_ACROBAT_READER) || Config_GetSettingsForImageName_bool(L"UseSbieDeskHack", FALSE)) {
SetSecurityInfo = __sys_SetSecurityInfo; SetSecurityInfo = __sys_SetSecurityInfo;
GetSecurityInfo = __sys_GetSecurityInfo; GetSecurityInfo = __sys_GetSecurityInfo;
SBIEDLL_HOOK(AdvApi_, SetSecurityInfo); SBIEDLL_HOOK(AdvApi_, SetSecurityInfo);
@ -496,8 +489,12 @@ _FX ULONG AdvApi_CreateRestrictedToken(
} }
/*HANDLE Sandboxie_WinSta = 0;
HANDLE Sandboxie_Desktop = 0; HANDLE Sandboxie_WinSta = 0;
BOOL CALLBACK myEnumWindowStationProc(
_In_ LPTSTR lpszWindowStation,
_In_ LPARAM lParam);
// Get Sandbox Dummy WindowStation Handle // Get Sandbox Dummy WindowStation Handle
BOOL CALLBACK myEnumWindowStationProc( BOOL CALLBACK myEnumWindowStationProc(
@ -514,37 +511,6 @@ BOOL CALLBACK myEnumWindowStationProc(
return TRUE; return TRUE;
} }
BOOL CALLBACK myEnumDesktopsProc(
_In_ LPTSTR lpszDesktop,
_In_ LPARAM lParam)
{
if ((!lpszDesktop) || (!__sys_OpenDesktopW)) {
return FALSE;
}
if (!_wcsnicmp(lpszDesktop, L"Sandbox", 7)) {
const ACCESS_MASK DESKTOP_ALL_ACCESS = 0x1FF; // see WinUser.h
Sandboxie_Desktop = __sys_OpenDesktopW(lpszDesktop, 0, FALSE, DESKTOP_ALL_ACCESS);
return FALSE;
}
return TRUE;
}
_FX VOID OpenWinSta()
{
if (!Sandboxie_WinSta) {
__sys_EnumWindowStationsW = (P_EnumWindowStations)Ldr_GetProcAddrNew(L"User32.dll", L"EnumWindowStationsW", "EnumWindowStationsW");
__sys_OpenWindowStationW = (P_OpenWindowStationW)Ldr_GetProcAddrNew(L"User32.dll", L"OpenWindowStationW", "OpenWindowStationW");
if (__sys_EnumWindowStationsW) {
__sys_EnumWindowStationsW(myEnumWindowStationProc, 0);
if (Sandboxie_WinSta) {
if (__sys_EnumDesktopsW)
__sys_EnumDesktopsW(Sandboxie_WinSta, myEnumDesktopsProc, 0);
}
}
}
}*/
// Chrome 52+ now needs to be able to create a WindowStation and Desktop for its sandbox // Chrome 52+ now needs to be able to create a WindowStation and Desktop for its sandbox
// GetSecurityInfo will fail when chrome tries to do a DACL read on the default WindowStation. // GetSecurityInfo will fail when chrome tries to do a DACL read on the default WindowStation.
@ -552,8 +518,6 @@ _FX VOID OpenWinSta()
// this will allow chrome to create the required WindowStation and Desktop. See comment in // this will allow chrome to create the required WindowStation and Desktop. See comment in
// GuiServer.cpp: GuiServer::GetWindowStationAndDesktopName. // GuiServer.cpp: GuiServer::GetWindowStationAndDesktopName.
extern HANDLE Sandboxie_WinSta;
_FX DWORD AdvApi_GetSecurityInfo( _FX DWORD AdvApi_GetSecurityInfo(
HANDLE handle, HANDLE handle,
SE_OBJECT_TYPE ObjectType, SE_OBJECT_TYPE ObjectType,
@ -568,7 +532,13 @@ _FX DWORD AdvApi_GetSecurityInfo(
rc = __sys_GetSecurityInfo(handle, ObjectType, SecurityInfo, psidOwner, psidGroup, pDacl, pSacl, ppSecurityDescriptor); rc = __sys_GetSecurityInfo(handle, ObjectType, SecurityInfo, psidOwner, psidGroup, pDacl, pSacl, ppSecurityDescriptor);
if (rc && ObjectType == SE_WINDOW_OBJECT && SecurityInfo == DACL_SECURITY_INFORMATION) { if (rc && ObjectType == SE_WINDOW_OBJECT && SecurityInfo == DACL_SECURITY_INFORMATION) {
//OpenWinSta(); __sys_EnumWindowStationsW = (P_EnumWindowStations)Ldr_GetProcAddrNew(L"User32.dll", L"EnumWindowStationsW", "EnumWindowStationsW");
__sys_OpenWindowStationW = (P_OpenWindowStationW)Ldr_GetProcAddrNew(L"User32.dll", L"OpenWindowStationW", "OpenWindowStationW");
if (!Sandboxie_WinSta) {
if (__sys_EnumWindowStationsW) {
rc = __sys_EnumWindowStationsW(myEnumWindowStationProc, 0);
}
}
rc = __sys_GetSecurityInfo(Sandboxie_WinSta, ObjectType, SecurityInfo, psidOwner, psidGroup, pDacl, pSacl, ppSecurityDescriptor); rc = __sys_GetSecurityInfo(Sandboxie_WinSta, ObjectType, SecurityInfo, psidOwner, psidGroup, pDacl, pSacl, ppSecurityDescriptor);
} }
return rc; return rc;
@ -731,7 +701,7 @@ _FX BOOLEAN Ntmarta_Init(HMODULE module)
#define GETPROC2(x,s) __sys_Ntmarta_##x##s = (P_##x) Ldr_GetProcAddrNew(DllName_ntmarta, L#x L#s,#x #s); #define GETPROC2(x,s) __sys_Ntmarta_##x##s = (P_##x) Ldr_GetProcAddrNew(DllName_ntmarta, L#x L#s,#x #s);
GETPROC2(GetSecurityInfo, ); GETPROC2(GetSecurityInfo, );
if ((Dll_ImageType == DLL_IMAGE_GOOGLE_CHROME) || (Dll_ImageType == DLL_IMAGE_ACROBAT_READER)) { if ((Dll_ImageType == DLL_IMAGE_GOOGLE_CHROME) || (Dll_ImageType == DLL_IMAGE_MOZILLA_FIREFOX) || (Dll_ImageType == DLL_IMAGE_ACROBAT_READER) || Config_GetSettingsForImageName_bool(L"UseSbieDeskHack", FALSE)) {
GetSecurityInfo = __sys_Ntmarta_GetSecurityInfo; GetSecurityInfo = __sys_Ntmarta_GetSecurityInfo;
if (GetSecurityInfo) if (GetSecurityInfo)
@ -784,7 +754,13 @@ _FX DWORD Ntmarta_GetSecurityInfo(
rc = __sys_Ntmarta_GetSecurityInfo(handle, ObjectType, SecurityInfo, psidOwner, psidGroup, pDacl, pSacl, ppSecurityDescriptor); rc = __sys_Ntmarta_GetSecurityInfo(handle, ObjectType, SecurityInfo, psidOwner, psidGroup, pDacl, pSacl, ppSecurityDescriptor);
if (rc && ObjectType == SE_WINDOW_OBJECT && SecurityInfo == DACL_SECURITY_INFORMATION) { if (rc && ObjectType == SE_WINDOW_OBJECT && SecurityInfo == DACL_SECURITY_INFORMATION) {
//OpenWinSta(); __sys_EnumWindowStationsW = (P_EnumWindowStations)Ldr_GetProcAddrNew(L"User32.dll", L"EnumWindowStationsW", "EnumWindowStationsW");
__sys_OpenWindowStationW = (P_OpenWindowStationW)Ldr_GetProcAddrNew(L"User32.dll", L"OpenWindowStationW", "OpenWindowStationW");
if (!Sandboxie_WinSta) {
if (__sys_EnumWindowStationsW) {
rc = __sys_EnumWindowStationsW(myEnumWindowStationProc, 0);
}
}
rc = __sys_Ntmarta_GetSecurityInfo(Sandboxie_WinSta, ObjectType, SecurityInfo, psidOwner, psidGroup, pDacl, pSacl, ppSecurityDescriptor); rc = __sys_Ntmarta_GetSecurityInfo(Sandboxie_WinSta, ObjectType, SecurityInfo, psidOwner, psidGroup, pDacl, pSacl, ppSecurityDescriptor);
} }
return rc; return rc;

View File

@ -41,6 +41,7 @@ static BOOLEAN DisableRecycleBin(void);
static BOOLEAN DisableWinRS(void); static BOOLEAN DisableWinRS(void);
static BOOLEAN DisableWerFaultUI(void); static BOOLEAN DisableWerFaultUI(void);
static BOOLEAN EnableMsiDebugging(void); static BOOLEAN EnableMsiDebugging(void);
static BOOLEAN DisableEdgeBoost(void);
static BOOLEAN Custom_EnableBrowseNewProcess(void); static BOOLEAN Custom_EnableBrowseNewProcess(void);
static BOOLEAN Custom_DisableBHOs(void); static BOOLEAN Custom_DisableBHOs(void);
static BOOLEAN Custom_OpenWith(void); static BOOLEAN Custom_OpenWith(void);
@ -87,6 +88,7 @@ _FX BOOLEAN CustomizeSandbox(void)
DisableWinRS(); DisableWinRS();
DisableWerFaultUI(); DisableWerFaultUI();
EnableMsiDebugging(); EnableMsiDebugging();
DisableEdgeBoost();
Custom_EnableBrowseNewProcess(); Custom_EnableBrowseNewProcess();
DeleteShellAssocKeys(0); DeleteShellAssocKeys(0);
Custom_DisableBHOs(); Custom_DisableBHOs();
@ -461,6 +463,44 @@ _FX BOOLEAN EnableMsiDebugging(void)
} }
//---------------------------------------------------------------------------
// DisableEdgeBoost
//
// Disable esge startup boost
//---------------------------------------------------------------------------
_FX BOOLEAN DisableEdgeBoost(void)
{
NTSTATUS status;
OBJECT_ATTRIBUTES objattrs;
UNICODE_STRING uni;
HANDLE hKeyRoot;
HANDLE hKeyEdge;
// Open HKLM
RtlInitUnicodeString(&uni, Custom_PrefixHKLM);
InitializeObjectAttributes(&objattrs, &uni, OBJ_CASE_INSENSITIVE, NULL, NULL);
if (NtOpenKey(&hKeyRoot, KEY_READ, &objattrs) == STATUS_SUCCESS)
{
// open/create WER parent key
RtlInitUnicodeString(&uni, L"SOFTWARE\\Policies\\Microsoft\\Edge");
InitializeObjectAttributes(&objattrs, &uni, OBJ_CASE_INSENSITIVE, hKeyRoot, NULL);
if (Key_OpenOrCreateIfBoxed(&hKeyEdge, KEY_ALL_ACCESS, &objattrs) == STATUS_SUCCESS)
{
DWORD StartupBoostEnabled = 0;
RtlInitUnicodeString(&uni, L"StartupBoostEnabled");
status = NtSetValueKey(hKeyEdge, &uni, 0, REG_DWORD, &StartupBoostEnabled, sizeof(StartupBoostEnabled));
NtClose(hKeyEdge);
}
NtClose(hKeyRoot);
}
return TRUE;
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Custom_OpenWith // Custom_OpenWith
// //

View File

@ -821,9 +821,6 @@ _FX BOOL DisallowWin32kSystemCallsIsOn()
extern P_NtSetInformationThread __sys_NtSetInformationThread; extern P_NtSetInformationThread __sys_NtSetInformationThread;
HANDLE Sandboxie_WinSta = NULL;
HANDLE Sandboxie_Desktop = NULL;
_FX BOOLEAN Gui_ConnectToWindowStationAndDesktop(HMODULE User32) _FX BOOLEAN Gui_ConnectToWindowStationAndDesktop(HMODULE User32)
{ {
static HDESK _ProcessDesktop = NULL; static HDESK _ProcessDesktop = NULL;
@ -903,9 +900,6 @@ _FX BOOLEAN Gui_ConnectToWindowStationAndDesktop(HMODULE User32)
errlvl = 2; errlvl = 2;
else { else {
Sandboxie_WinSta = (HANDLE)rpl->hsbie_winsta;
Sandboxie_Desktop = (HANDLE)rpl->hsbie_desk;
// //
// locate windowstation and desktop functions in user32 dll // locate windowstation and desktop functions in user32 dll
// //

View File

@ -175,7 +175,6 @@ static BOOLEAN Gui_D3D9_Loaded = FALSE;
static ULONG64 Gui_GetShellWindow_LastTicks = 0; static ULONG64 Gui_GetShellWindow_LastTicks = 0;
static BOOLEAN Winsta_Hack = FALSE;
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Gui_InitEnum // Gui_InitEnum
@ -578,18 +577,22 @@ _FX HDESK Gui_OpenDesktopA(
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
//Gui_CreateWindowStationW //Gui_CreateWindowStationW
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
extern HANDLE Sandboxie_WinSta;
_FX HANDLE Gui_CreateWindowStationW (void *lpwinsta, DWORD dwFlags, ACCESS_MASK dwDesiredAccess, LPSECURITY_ATTRIBUTES lpsa) {
_FX HANDLE Gui_CreateWindowStationW (void *lpwinsta, DWORD dwFlags, ACCESS_MASK dwDesiredAccess, LPSECURITY_ATTRIBUTES lpsa)
{
HANDLE myHandle = 0; HANDLE myHandle = 0;
myHandle = __sys_CreateWindowStationW(lpwinsta, dwFlags, dwDesiredAccess, lpsa); myHandle = __sys_CreateWindowStationW(lpwinsta, dwFlags, dwDesiredAccess, lpsa);
if (!myHandle) { if (myHandle)
if(Sandboxie_WinSta) return myHandle;
return Sandboxie_WinSta;
SbieApi_Log(2205, L"CreateWindowStation"); extern HANDLE Sandboxie_WinSta;
} if(Sandboxie_WinSta && ((Dll_ImageType == DLL_IMAGE_GOOGLE_CHROME) || (Dll_ImageType == DLL_IMAGE_MOZILLA_FIREFOX) || Config_GetSettingsForImageName_bool(L"UseSbieWndStation", TRUE)))
return myHandle; return Sandboxie_WinSta;
SbieApi_Log(2205, L"CreateWindowStation");
return 0;
} }
@ -598,22 +601,26 @@ _FX HANDLE Gui_CreateWindowStationW (void *lpwinsta, DWORD dwFlags, ACCESS_MASK
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
_FX HANDLE Gui_CreateWindowStationA (void *lpwinsta, DWORD dwFlags, ACCESS_MASK dwDesiredAccess, LPSECURITY_ATTRIBUTES lpsa) { _FX HANDLE Gui_CreateWindowStationA (void *lpwinsta, DWORD dwFlags, ACCESS_MASK dwDesiredAccess, LPSECURITY_ATTRIBUTES lpsa)
{
HANDLE myHandle = 0; HANDLE myHandle = 0;
myHandle = __sys_CreateWindowStationA(lpwinsta, dwFlags, dwDesiredAccess, lpsa); myHandle = __sys_CreateWindowStationA(lpwinsta, dwFlags, dwDesiredAccess, lpsa);
if (!myHandle) { if (myHandle)
if(Sandboxie_WinSta) return myHandle;
return Sandboxie_WinSta;
SbieApi_Log(2205, L"CreateWindowStation"); extern HANDLE Sandboxie_WinSta;
} if(Sandboxie_WinSta && ((Dll_ImageType == DLL_IMAGE_GOOGLE_CHROME) || (Dll_ImageType == DLL_IMAGE_MOZILLA_FIREFOX) || Config_GetSettingsForImageName_bool(L"UseSbieWndStation", TRUE)))
return myHandle; return Sandboxie_WinSta;
SbieApi_Log(2205, L"CreateWindowStation");
return 0;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Gui_CreateDesktopW // Gui_CreateDesktopW
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
extern HANDLE Sandboxie_Desktop;
_FX HDESK Gui_CreateDesktopW( _FX HDESK Gui_CreateDesktopW(
void *lpszDesktop, void *lpszDevice, void *DevMode, ULONG dwFlags, void *lpszDesktop, void *lpszDevice, void *DevMode, ULONG dwFlags,
@ -625,7 +632,7 @@ _FX HDESK Gui_CreateDesktopW(
if (rc) if (rc)
return rc; return rc;
if (!Config_GetSettingsForImageName_bool(L"UseSbieWndStation", TRUE) && (Dll_ImageType != DLL_IMAGE_GOOGLE_CHROME) && (Dll_ImageType != DLL_IMAGE_MOZILLA_FIREFOX)) if ((Dll_ImageType == DLL_IMAGE_GOOGLE_CHROME) || (Dll_ImageType == DLL_IMAGE_MOZILLA_FIREFOX) || (Dll_ImageType == DLL_IMAGE_ACROBAT_READER) || Config_GetSettingsForImageName_bool(L"UseSbieDeskHack", FALSE))
{ {
//Call the system CreateDesktopW without a security context. //Call the system CreateDesktopW without a security context.
//This works in tandem with the Ntmarta_GetSecurityInfo hook (see in advapi.c). //This works in tandem with the Ntmarta_GetSecurityInfo hook (see in advapi.c).
@ -635,12 +642,10 @@ _FX HDESK Gui_CreateDesktopW(
//the sandboxie restricted token by dropping the security context. This won't //the sandboxie restricted token by dropping the security context. This won't
//work without the GetSecurityInfo hook. //work without the GetSecurityInfo hook.
rc = __sys_CreateDesktopW(lpszDesktop, NULL, NULL, dwFlags, dwDesiredAccess, NULL); rc = __sys_CreateDesktopW(lpszDesktop, NULL, NULL, dwFlags, dwDesiredAccess, NULL);
if (rc) //if (rc)
return rc; return rc;
} }
if (Sandboxie_Desktop)
return Sandboxie_Desktop;
SbieApi_Log(2205, L"CreateDesktop"); SbieApi_Log(2205, L"CreateDesktop");
return CreateEvent(NULL, FALSE, FALSE, NULL); return CreateEvent(NULL, FALSE, FALSE, NULL);
} }
@ -661,15 +666,13 @@ _FX HDESK Gui_CreateDesktopA(
if (rc) if (rc)
return rc; return rc;
if (!Config_GetSettingsForImageName_bool(L"UseSbieWndStation", TRUE) && (Dll_ImageType != DLL_IMAGE_GOOGLE_CHROME) && (Dll_ImageType != DLL_IMAGE_MOZILLA_FIREFOX)) if ((Dll_ImageType == DLL_IMAGE_GOOGLE_CHROME) || (Dll_ImageType == DLL_IMAGE_MOZILLA_FIREFOX) || (Dll_ImageType == DLL_IMAGE_ACROBAT_READER) || Config_GetSettingsForImageName_bool(L"UseSbieDeskHack", FALSE))
{ {
rc = __sys_CreateDesktopA(lpszDesktop, NULL, NULL, dwFlags, dwDesiredAccess, NULL); rc = __sys_CreateDesktopA(lpszDesktop, NULL, NULL, dwFlags, dwDesiredAccess, NULL);
if (rc) //if (rc)
return rc; return rc;
} }
if (Sandboxie_Desktop)
return Sandboxie_Desktop;
SbieApi_Log(2205, L"CreateDesktop"); SbieApi_Log(2205, L"CreateDesktop");
return CreateEvent(NULL, FALSE, FALSE, NULL); return CreateEvent(NULL, FALSE, FALSE, NULL);
} }

View File

@ -2010,6 +2010,15 @@ _FX BOOLEAN Sxs_PreferExternal(THREAD_DATA *TlsData)
if (!TlsData->proc_image_path) if (!TlsData->proc_image_path)
return FALSE; return FALSE;
//
// KB5014019 breaks edge, it seams making edge start its child processes with
// PreferExternalManifest fixes the issue, but the main process must be loaded normally
// hence we have ExternalManifestHack that checks the parent and not the target
//
if (Config_GetSettingsForImageName_bool(L"ExternalManifestHack", FALSE))
return TRUE;
WCHAR *ptr1 = wcsrchr(TlsData->proc_image_path, L'\\'); WCHAR *ptr1 = wcsrchr(TlsData->proc_image_path, L'\\');
WCHAR value[16]; WCHAR value[16];

View File

@ -605,7 +605,7 @@ void GuiServer::RunSlave(const WCHAR *cmdline)
// create window station // create window station
// //
if (! pThis->GetWindowStationAndDesktopName(NULL, NULL, NULL)) if (! pThis->GetWindowStationAndDesktopName(NULL))
return; return;
// //
@ -1190,7 +1190,7 @@ HANDLE GuiServer::GetJobObject(const WCHAR *boxname)
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
bool GuiServer::GetWindowStationAndDesktopName(WCHAR *out_name, HANDLE* out_winsta, HANDLE* out_desk) bool GuiServer::GetWindowStationAndDesktopName(WCHAR *out_name)
{ {
static HWINSTA _hWinSta = NULL; static HWINSTA _hWinSta = NULL;
static HDESK _hDesk = NULL; static HDESK _hDesk = NULL;
@ -1205,8 +1205,6 @@ bool GuiServer::GetWindowStationAndDesktopName(WCHAR *out_name, HANDLE* out_wins
if (out_name) { if (out_name) {
wcscpy(out_name, _CombinedName); wcscpy(out_name, _CombinedName);
if (out_winsta) *out_winsta = _hWinSta;
if (out_desk) *out_desk = _hDesk;
return true; return true;
} }
@ -1275,8 +1273,6 @@ bool GuiServer::GetWindowStationAndDesktopName(WCHAR *out_name, HANDLE* out_wins
else { else {
if (out_winsta) *out_winsta = _hWinSta;
if (! SetProcessWindowStation(_hWinSta)) if (! SetProcessWindowStation(_hWinSta))
errlvl = 0x62; errlvl = 0x62;
else { else {
@ -1289,9 +1285,6 @@ bool GuiServer::GetWindowStationAndDesktopName(WCHAR *out_name, HANDLE* out_wins
const ACCESS_MASK DESKTOP_ALL_ACCESS = 0x1FF; // see WinUser.h const ACCESS_MASK DESKTOP_ALL_ACCESS = 0x1FF; // see WinUser.h
_hDesk = CreateDesktop(desktop_name, NULL, NULL, 0, _hDesk = CreateDesktop(desktop_name, NULL, NULL, 0,
DESKTOP_ALL_ACCESS | WRITE_OWNER, &sa); DESKTOP_ALL_ACCESS | WRITE_OWNER, &sa);
if (out_desk) *out_desk = _hDesk;
if (! _hDesk) if (! _hDesk)
errlvl = 0x63; errlvl = 0x63;
@ -1474,9 +1467,7 @@ ULONG GuiServer::GetWindowStationSlave(SlaveArgs *args)
GUI_GET_WINDOW_STATION_RPL *rpl = GUI_GET_WINDOW_STATION_RPL *rpl =
(GUI_GET_WINDOW_STATION_RPL *)args->rpl_buf; (GUI_GET_WINDOW_STATION_RPL *)args->rpl_buf;
HANDLE sbie_winsta; if (! GetWindowStationAndDesktopName(rpl->name)) {
HANDLE sbie_desk;
if (! GetWindowStationAndDesktopName(rpl->name, &sbie_winsta, &sbie_desk)) {
status = -1; status = -1;
errlvl = 0x73; errlvl = 0x73;
goto finish; goto finish;
@ -1533,22 +1524,6 @@ ULONG GuiServer::GetWindowStationSlave(SlaveArgs *args)
goto finish; goto finish;
} }
if (! DuplicateHandle(NtCurrentProcess(), sbie_winsta,
hProcess, (HANDLE *)&rpl->hsbie_winsta,
WINSTA_ALL_ACCESS | STANDARD_RIGHTS_REQUIRED, FALSE, 0)) {
status = GetLastError();
errlvl = 0x85;
goto finish;
}
if (! DuplicateHandle(NtCurrentProcess(), sbie_desk,
hProcess, (HANDLE *)&rpl->hsbie_desk,
0, FALSE, DUPLICATE_SAME_ACCESS)) {
status = GetLastError();
errlvl = 0x86;
goto finish;
}
#ifdef _WIN64 #ifdef _WIN64
// //

View File

@ -80,7 +80,7 @@ protected:
HANDLE GetJobObject(const WCHAR *boxname); HANDLE GetJobObject(const WCHAR *boxname);
bool GetWindowStationAndDesktopName(WCHAR *out_name, HANDLE* out_winsta, HANDLE* out_desk); bool GetWindowStationAndDesktopName(WCHAR *out_name);
protected: protected:

View File

@ -94,8 +94,6 @@ struct tagGUI_GET_WINDOW_STATION_RPL
ULONG64 hwinsta; ULONG64 hwinsta;
ULONG64 hdesk; ULONG64 hdesk;
WCHAR name[96]; WCHAR name[96];
ULONG64 hsbie_winsta;
ULONG64 hsbie_desk;
}; };
typedef struct tagGUI_GET_WINDOW_STATION_RPL GUI_GET_WINDOW_STATION_RPL; typedef struct tagGUI_GET_WINDOW_STATION_RPL GUI_GET_WINDOW_STATION_RPL;

View File

@ -643,7 +643,7 @@ Tmpl.Url=https://www.microsoft.com/en-us/edge
Tmpl.Scan=s Tmpl.Scan=s
Tmpl.ScanProduct=Microsoft Edge Tmpl.ScanProduct=Microsoft Edge
Tmpl.ScanService=edgeupdate Tmpl.ScanService=edgeupdate
PreferExternalManifest=msedge.exe,y ExternalManifestHack=msedge.exe,y
# #
# Vivaldi # Vivaldi

View File

@ -1145,6 +1145,7 @@ SB_STATUS CSbieAPI::ReloadBoxes(bool bForceUpdate)
{ {
pBox = CSandBoxPtr(NewSandBox(BoxName, this)); pBox = CSandBoxPtr(NewSandBox(BoxName, this));
m_SandBoxes.insert(BoxName.toLower(), pBox); m_SandBoxes.insert(BoxName.toLower(), pBox);
emit BoxAdded(pBox);
} }
UpdateBoxPaths(pBox); UpdateBoxPaths(pBox);
@ -1153,8 +1154,11 @@ SB_STATUS CSbieAPI::ReloadBoxes(bool bForceUpdate)
pBox->UpdateDetails(); pBox->UpdateDetails();
} }
foreach(const QString& BoxName, OldSandBoxes.keys()) foreach(const QString & BoxName, OldSandBoxes.keys()) {
m_SandBoxes.remove(BoxName); CSandBoxPtr pBox = m_SandBoxes.take(BoxName);
pBox->SetBoxPaths(QString(), QString(), QString());
emit BoxRemoved(pBox);
}
return SB_OK; return SB_OK;
} }
@ -1419,7 +1423,7 @@ SB_STATUS CSbieAPI::UpdateProcesses(bool bKeep, bool bAllSessions)
if (pBox->m_ActiveProcessCount == 0) { if (pBox->m_ActiveProcessCount == 0) {
pBox->m_ActiveProcessCount = 1; pBox->m_ActiveProcessCount = 1;
pBox->OpenBox(); pBox->OpenBox();
emit BoxOpened(pBox->GetName()); emit BoxOpened(pBox);
} }
pProcess->m_pBox = pBox.data(); pProcess->m_pBox = pBox.data();
@ -1459,7 +1463,7 @@ SB_STATUS CSbieAPI::UpdateProcesses(bool bKeep, bool bAllSessions)
pBox->m_ActiveProcessCount = ActiveProcessCount; pBox->m_ActiveProcessCount = ActiveProcessCount;
if (WasBoxClosed) { if (WasBoxClosed) {
pBox->CloseBox(); pBox->CloseBox();
emit BoxClosed(pBox->GetName()); emit BoxClosed(pBox);
} }
} }
} }
@ -2337,7 +2341,7 @@ CBoxedProcessPtr CSbieAPI::OnProcessBoxed(quint32 ProcessId, const QString& Path
if (pBox->m_ActiveProcessCount == 0) { if (pBox->m_ActiveProcessCount == 0) {
pBox->m_ActiveProcessCount = 1; pBox->m_ActiveProcessCount = 1;
pBox->OpenBox(); pBox->OpenBox();
emit BoxOpened(pBox->GetName()); emit BoxOpened(pBox);
} }
pProcess = CBoxedProcessPtr(NewBoxedProcess(ProcessId, pBox.data())); pProcess = CBoxedProcessPtr(NewBoxedProcess(ProcessId, pBox.data()));

View File

@ -158,8 +158,12 @@ signals:
void LogSbieMessage(quint32 MsgCode, const QStringList& MsgData, quint32 ProcessId); void LogSbieMessage(quint32 MsgCode, const QStringList& MsgData, quint32 ProcessId);
void ProcessBoxed(quint32 ProcessId, const QString& Path, const QString& Box, quint32 ParentId); void ProcessBoxed(quint32 ProcessId, const QString& Path, const QString& Box, quint32 ParentId);
void FileToRecover(const QString& BoxName, const QString& FilePath, const QString& BoxPath, quint32 ProcessId); void FileToRecover(const QString& BoxName, const QString& FilePath, const QString& BoxPath, quint32 ProcessId);
void BoxOpened(const QString& BoxName);
void BoxClosed(const QString& BoxName); void BoxAdded(const CSandBoxPtr& pBox);
void BoxOpened(const CSandBoxPtr& pBox);
void BoxClosed(const CSandBoxPtr& pBox);
void BoxRemoved(const CSandBoxPtr& pBox);
void NotAuthorized(bool bLoginRequired, bool &bRetry); void NotAuthorized(bool bLoginRequired, bool &bRetry);
void QueuedRequest(quint32 ClientPid, quint32 ClientTid, quint32 RequestId, const QVariantMap& Data); void QueuedRequest(quint32 ClientPid, quint32 ClientTid, quint32 RequestId, const QVariantMap& Data);

View File

@ -5,14 +5,11 @@
CBoxMonitor::CBoxMonitor() CBoxMonitor::CBoxMonitor()
{ {
m_bTerminate = false; m_bTerminate = false;
start();
} }
CBoxMonitor::~CBoxMonitor() CBoxMonitor::~CBoxMonitor()
{ {
m_bTerminate = true; Stop();
if (!wait(10 * 1000))
terminate();
} }
void CBoxMonitor::Notify(const wstring& strDirectory) void CBoxMonitor::Notify(const wstring& strDirectory)
@ -25,7 +22,7 @@ void CBoxMonitor::Notify(const wstring& strDirectory)
quint64 CBoxMonitor::CounDirSize(const QString& Directory, SBox* Box) quint64 CBoxMonitor::CounDirSize(const QString& Directory, SBox* Box)
{ {
quint64 TotalSize = 0; quint64 TotalSize = 0;
if (Box->pBox.isNull() || m_bTerminate) if (m_bTerminate || Box->pBox.isNull())
return TotalSize; return TotalSize;
QDir Dir(Directory); QDir Dir(Directory);
@ -44,6 +41,8 @@ void CBoxMonitor::run()
{ {
while (!m_bTerminate) while (!m_bTerminate)
{ {
Sleep(1000);
m_Mutex.lock(); m_Mutex.lock();
QList<QString> Keys = m_Boxes.keys(); QList<QString> Keys = m_Boxes.keys();
m_Mutex.unlock(); m_Mutex.unlock();
@ -62,12 +61,14 @@ void CBoxMonitor::run()
if (MinScanInterval > 30 * 60 * 1000) if (MinScanInterval > 30 * 60 * 1000)
MinScanInterval = 30 * 60 * 1000; MinScanInterval = 30 * 60 * 1000;
if (Box->Changed && (Box->Closed || Box->LastScan == 0 || (CurTick - Box->LastScan) > MinScanInterval)) { if ((Box->Changed && (!Box->IsWatched || Box->LastScan == 0 || (CurTick - Box->LastScan) > MinScanInterval)) || Box->ForceUpdate) {
qDebug() << "Rescanning:" << Key << "(" + QDateTime::currentDateTime().toString() + ")"; qDebug() << "Rescanning:" << Key << "(" + QDateTime::currentDateTime().toString() + ")";
quint64 ScanStart = GetCurTick(); quint64 ScanStart = GetCurTick();
Box->ScanDuration = -1;
Box->TotalSize = CounDirSize(Key, Box); Box->TotalSize = CounDirSize(Key, Box);
Box->ScanDuration = GetCurTick() - ScanStart; Box->ScanDuration = GetCurTick() - ScanStart;
@ -79,6 +80,7 @@ void CBoxMonitor::run()
); );
Box->Changed = false; Box->Changed = false;
Box->ForceUpdate = false;
} }
m_Mutex.lock(); m_Mutex.lock();
@ -86,14 +88,12 @@ void CBoxMonitor::run()
m_Boxes.remove(Key); m_Boxes.remove(Key);
m_Mutex.unlock(); m_Mutex.unlock();
} }
Sleep(1000);
} }
} }
void CBoxMonitor::UpdateBox(const QString& Path) void CBoxMonitor::UpdateBox(const QString& Path)
{ {
// Note: this functin runs in the main thread // Note: this private functin runs in the main thread
m_Mutex.lock(); m_Mutex.lock();
SBox Box = m_Boxes.value(Path); SBox Box = m_Boxes.value(Path);
@ -103,27 +103,86 @@ void CBoxMonitor::UpdateBox(const QString& Path)
Box.pBox->SetSize(Box.TotalSize); Box.pBox->SetSize(Box.TotalSize);
} }
void CBoxMonitor::AddBox(CSandBoxPlus* pBox, bool AndWatch) void CBoxMonitor::WatchBox(CSandBoxPlus* pBox)
{ {
QMutexLocker Lock(&m_Mutex); QMutexLocker Lock(&m_Mutex);
if (!isRunning()) start();
m_Boxes[pBox->GetFileRoot()].pBox = pBox; SBox& Box = m_Boxes[pBox->GetFileRoot()];
Box.pBox = pBox;
if (AndWatch) { Box.IsWatched = true;
m_Boxes[pBox->GetFileRoot()].Closed = false; AddDirectory(pBox->GetFileRoot().toStdWString().c_str(), true, FILE_NOTIFY_CHANGE_SIZE);
AddDirectory(pBox->GetFileRoot().toStdWString().c_str(), true, FILE_NOTIFY_CHANGE_SIZE); }
void CBoxMonitor::ScanBox(CSandBoxPlus* pBox)
{
QMutexLocker Lock(&m_Mutex);
if (!isRunning()) start();
SBox& Box = m_Boxes[pBox->GetFileRoot()];
Box.pBox = pBox;
Box.ForceUpdate = true;
}
void CBoxMonitor::CloseBox(CSandBoxPlus* pBox)
{
QMutexLocker Lock(&m_Mutex);
if (!isRunning()) return;
SBox& Box = m_Boxes[pBox->GetFileRoot()];
if(Box.IsWatched)
DetachDirectory(pBox->GetFileRoot().toStdWString().c_str());
Box.IsWatched = false;
//Box.Changed = true;
}
void CBoxMonitor::RemoveBox(CSandBoxPlus* pBox)
{
QMutexLocker Lock(&m_Mutex);
if (!isRunning()) return;
auto I = m_Boxes.find(pBox->GetFileRoot());
if (I == m_Boxes.end())
return;
if(I->IsWatched)
DetachDirectory(pBox->GetFileRoot().toStdWString().c_str());
I->pBox.clear();
}
bool CBoxMonitor::IsScanPending(const CSandBoxPlus* pBox)
{
QMutexLocker Lock(&m_Mutex);
if (!isRunning()) false;
auto I = m_Boxes.find(pBox->GetFileRoot());
if (I == m_Boxes.end())
return false;
return (I->Changed && !I->IsWatched) || I->ForceUpdate || I->ScanDuration == -1;
}
void CBoxMonitor::Stop()
{
QMutexLocker Lock(&m_Mutex);
if (!isRunning()) return;
m_bTerminate = true;
if (!wait(10 * 1000)) {
terminate();
qDebug() << "Failed to stop monitor thread, terminating!!!";
} }
else
m_Boxes[pBox->GetFileRoot()].Changed = true; while (!m_Boxes.isEmpty()) {
} SBox Box = m_Boxes.take(m_Boxes.firstKey());
if(Box.IsWatched && Box.pBox)
void CBoxMonitor::CloseBox(CSandBoxPlus* pBox, bool AndClear) DetachDirectory(Box.pBox->GetFileRoot().toStdWString().c_str());
{ }
QMutexLocker Lock(&m_Mutex);
m_bTerminate = false;
if(AndClear)
m_Boxes[pBox->GetFileRoot()].pBox.clear();
m_Boxes[pBox->GetFileRoot()].Closed = true;
DetachDirectory(pBox->GetFileRoot().toStdWString().c_str());
} }

View File

@ -14,8 +14,14 @@ public:
virtual void run(); virtual void run();
void AddBox(CSandBoxPlus* pBox, bool AndWatch = false); void WatchBox(CSandBoxPlus* pBox);
void CloseBox(CSandBoxPlus* pBox, bool AndClear = false); void ScanBox(CSandBoxPlus* pBox);
void CloseBox(CSandBoxPlus* pBox);
void RemoveBox(CSandBoxPlus* pBox);
bool IsScanPending(const CSandBoxPlus* pBox);
void Stop();
private slots: private slots:
void UpdateBox(const QString& Path); void UpdateBox(const QString& Path);
@ -25,16 +31,18 @@ protected:
struct SBox struct SBox
{ {
SBox() { SBox() {
ForceUpdate = false;
Changed = false; Changed = false;
Closed = false; IsWatched = false;
LastScan = 0; LastScan = 0;
ScanDuration = 0; ScanDuration = 0;
TotalSize = 0; TotalSize = 0;
} }
QPointer<CSandBoxPlus> pBox; QPointer<CSandBoxPlus> pBox;
bool ForceUpdate;
bool Changed; bool Changed;
bool Closed; bool IsWatched;
quint64 LastScan; quint64 LastScan;
quint64 ScanDuration; quint64 ScanDuration;

View File

@ -233,7 +233,7 @@ QList<QVariant> CSbieModel::Sync(const QMap<QString, CSandBoxPtr>& BoxList, cons
{ {
case eName: Value = pBox->GetName(); break; case eName: Value = pBox->GetName(); break;
case eStatus: Value = pBox.objectCast<CSandBoxPlus>()->GetStatusStr(); break; case eStatus: Value = pBox.objectCast<CSandBoxPlus>()->GetStatusStr(); break;
case eInfo: Value = bWatchSize ? pBox.objectCast<CSandBoxPlus>()->GetSize() : 0; break; case eInfo: Value = pBox.objectCast<CSandBoxPlus>()->IsEmptyCached() ? -2 : (bWatchSize ? pBox.objectCast<CSandBoxPlus>()->GetSize() : 0); break;
case ePath: Value = pBox->GetFileRoot(); break; case ePath: Value = pBox->GetFileRoot(); break;
} }
@ -248,7 +248,7 @@ QList<QVariant> CSbieModel::Sync(const QMap<QString, CSandBoxPtr>& BoxList, cons
switch (section) switch (section)
{ {
case eName: ColValue.Formatted = Value.toString().replace("_", " "); break; case eName: ColValue.Formatted = Value.toString().replace("_", " "); break;
case eInfo: ColValue.Formatted = Value.toULongLong() > 0 ? FormatSize(Value.toULongLong()) : ""; break; case eInfo: ColValue.Formatted = Value.toULongLong() == -2 ? tr("Empty") : (Value.toULongLong() > 0 ? FormatSize(Value.toULongLong()) : ""); break;
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -69,6 +69,7 @@
<file>IconOffCx.png</file> <file>IconOffCx.png</file>
<file>Actions/Monitor.png</file> <file>Actions/Monitor.png</file>
<file>SideLogo.png</file> <file>SideLogo.png</file>
<file>Actions/Refresh.png</file>
</qresource> </qresource>
<qresource prefix="/Boxes"> <qresource prefix="/Boxes">
<file alias="Empty3">Boxes/sandbox-b-empty.png</file> <file alias="Empty3">Boxes/sandbox-b-empty.png</file>

View File

@ -134,7 +134,7 @@ CSandMan::CSandMan(QWidget *parent)
theAPI = new CSbiePlusAPI(this); theAPI = new CSbiePlusAPI(this);
connect(theAPI, SIGNAL(StatusChanged()), this, SLOT(OnStatusChanged())); connect(theAPI, SIGNAL(StatusChanged()), this, SLOT(OnStatusChanged()));
connect(theAPI, SIGNAL(BoxClosed(const QString&)), this, SLOT(OnBoxClosed(const QString&))); connect(theAPI, SIGNAL(BoxClosed(const CSandBoxPtr&)), this, SLOT(OnBoxClosed(const CSandBoxPtr&)));
m_RequestManager = NULL; m_RequestManager = NULL;
@ -286,6 +286,7 @@ void CSandMan::LoadState()
restoreState(theConf->GetBlob("MainWindow/Window_State")); restoreState(theConf->GetBlob("MainWindow/Window_State"));
//m_pBoxTree->restoreState(theConf->GetBlob("MainWindow/BoxTree_Columns")); //m_pBoxTree->restoreState(theConf->GetBlob("MainWindow/BoxTree_Columns"));
m_pMessageLog->GetView()->header()->restoreState(theConf->GetBlob("MainWindow/LogList_Columns")); m_pMessageLog->GetView()->header()->restoreState(theConf->GetBlob("MainWindow/LogList_Columns"));
m_pRecoveryLog->GetView()->header()->restoreState(theConf->GetBlob("MainWindow/RecoveryLog_Columns"));
m_pLogSplitter->restoreState(theConf->GetBlob("MainWindow/Log_Splitter")); m_pLogSplitter->restoreState(theConf->GetBlob("MainWindow/Log_Splitter"));
m_pPanelSplitter->restoreState(theConf->GetBlob("MainWindow/Panel_Splitter")); m_pPanelSplitter->restoreState(theConf->GetBlob("MainWindow/Panel_Splitter"));
m_pLogTabs->setCurrentIndex(theConf->GetInt("MainWindow/LogTab", 0)); m_pLogTabs->setCurrentIndex(theConf->GetInt("MainWindow/LogTab", 0));
@ -297,6 +298,7 @@ void CSandMan::StoreState()
theConf->SetBlob("MainWindow/Window_State", saveState()); theConf->SetBlob("MainWindow/Window_State", saveState());
//theConf->SetBlob("MainWindow/BoxTree_Columns", m_pBoxTree->saveState()); //theConf->SetBlob("MainWindow/BoxTree_Columns", m_pBoxTree->saveState());
theConf->SetBlob("MainWindow/LogList_Columns", m_pMessageLog->GetView()->header()->saveState()); theConf->SetBlob("MainWindow/LogList_Columns", m_pMessageLog->GetView()->header()->saveState());
theConf->SetBlob("MainWindow/RecoveryLog_Columns", m_pRecoveryLog->GetView()->header()->saveState());
theConf->SetBlob("MainWindow/Log_Splitter", m_pLogSplitter->saveState()); theConf->SetBlob("MainWindow/Log_Splitter", m_pLogSplitter->saveState());
theConf->SetBlob("MainWindow/Panel_Splitter", m_pPanelSplitter->saveState()); theConf->SetBlob("MainWindow/Panel_Splitter", m_pPanelSplitter->saveState());
theConf->SetValue("MainWindow/LogTab", m_pLogTabs->currentIndex()); theConf->SetValue("MainWindow/LogTab", m_pLogTabs->currentIndex());
@ -320,6 +322,10 @@ void CSandMan::CreateMenus()
m_pWndFinder = m_pMenuFile->addAction(CSandMan::GetIcon("finder"), tr("Window Finder"), this, SLOT(OnWndFinder())); m_pWndFinder = m_pMenuFile->addAction(CSandMan::GetIcon("finder"), tr("Window Finder"), this, SLOT(OnWndFinder()));
m_pDisableForce = m_pMenuFile->addAction(tr("Pause Forcing Programs"), this, SLOT(OnDisableForce())); m_pDisableForce = m_pMenuFile->addAction(tr("Pause Forcing Programs"), this, SLOT(OnDisableForce()));
m_pDisableForce->setCheckable(true); m_pDisableForce->setCheckable(true);
m_pDisableRecovery = m_pMenuFile->addAction(tr("Disable File Recovery"));
m_pDisableRecovery->setCheckable(true);
m_pDisableMessages = m_pMenuFile->addAction(tr("Disable Message PopUp"));
m_pDisableMessages->setCheckable(true);
m_pMenuFile->addSeparator(); m_pMenuFile->addSeparator();
m_pMaintenance = m_pMenuFile->addMenu(CSandMan::GetIcon("Maintenance"), tr("&Maintenance")); m_pMaintenance = m_pMenuFile->addMenu(CSandMan::GetIcon("Maintenance"), tr("&Maintenance"));
m_pConnect = m_pMaintenance->addAction(CSandMan::GetIcon("Connect"), tr("Connect"), this, SLOT(OnMaintenance())); m_pConnect = m_pMaintenance->addAction(CSandMan::GetIcon("Connect"), tr("Connect"), this, SLOT(OnMaintenance()));
@ -367,7 +373,7 @@ void CSandMan::CreateMenus()
m_pMenuView->addSeparator(); m_pMenuView->addSeparator();
m_pRefreshAll = m_pMenuView->addAction(CSandMan::GetIcon("Recover"), tr("Refresh View"), this, SLOT(OnRefresh())); m_pRefreshAll = m_pMenuView->addAction(CSandMan::GetIcon("Refresh"), tr("Refresh View"), this, SLOT(OnRefresh()));
m_pRefreshAll->setShortcut(QKeySequence("F5")); m_pRefreshAll->setShortcut(QKeySequence("F5"));
m_pRefreshAll->setShortcutContext(Qt::WidgetWithChildrenShortcut); m_pRefreshAll->setShortcutContext(Qt::WidgetWithChildrenShortcut);
this->addAction(m_pRefreshAll); this->addAction(m_pRefreshAll);
@ -377,6 +383,7 @@ void CSandMan::CreateMenus()
m_pCleanUpMenu->addSeparator(); m_pCleanUpMenu->addSeparator();
m_pCleanUpMsgLog = m_pCleanUpMenu->addAction(tr("Cleanup Message Log"), this, SLOT(OnCleanUp())); m_pCleanUpMsgLog = m_pCleanUpMenu->addAction(tr("Cleanup Message Log"), this, SLOT(OnCleanUp()));
m_pCleanUpTrace = m_pCleanUpMenu->addAction(tr("Cleanup Trace Log"), this, SLOT(OnCleanUp())); m_pCleanUpTrace = m_pCleanUpMenu->addAction(tr("Cleanup Trace Log"), this, SLOT(OnCleanUp()));
m_pCleanUpRecovery = m_pCleanUpMenu->addAction(tr("Cleanup Recovery Log"), this, SLOT(OnCleanUp()));
m_pKeepTerminated = m_pMenuView->addAction(CSandMan::GetIcon("Keep"), tr("Keep terminated"), this, SLOT(OnProcView())); m_pKeepTerminated = m_pMenuView->addAction(CSandMan::GetIcon("Keep"), tr("Keep terminated"), this, SLOT(OnProcView()));
m_pKeepTerminated->setCheckable(true); m_pKeepTerminated->setCheckable(true);
@ -527,6 +534,22 @@ void CSandMan::CreateView()
m_pTraceView->AddAction(m_pCleanUpTrace); m_pTraceView->AddAction(m_pCleanUpTrace);
m_pLogTabs->addTab(m_pTraceView, tr("Trace Log")); m_pLogTabs->addTab(m_pTraceView, tr("Trace Log"));
// Recovery Log
m_pRecoveryLog = new CPanelWidgetEx();
//m_pRecoveryLog->GetView()->setItemDelegate(theGUI->GetItemDelegate());
((QTreeWidgetEx*)m_pRecoveryLog->GetView())->setHeaderLabels(tr("Time|Box Name|File Path").split("|"));
m_pRecoveryLog->GetMenu()->insertAction(m_pRecoveryLog->GetMenu()->actions()[0], m_pCleanUpMsgLog);
m_pRecoveryLog->GetMenu()->insertSeparator(m_pRecoveryLog->GetMenu()->actions()[0]);
m_pRecoveryLog->GetView()->setSelectionMode(QAbstractItemView::ExtendedSelection);
m_pRecoveryLog->GetView()->setSortingEnabled(false);
m_pLogTabs->addTab(m_pRecoveryLog, tr("Recovery Log"));
//
} }
void CSandMan::CreateTrayMenu() void CSandMan::CreateTrayMenu()
@ -581,6 +604,8 @@ void CSandMan::CreateTrayMenu()
m_pTrayMenu->addAction(m_pEmptyAll); m_pTrayMenu->addAction(m_pEmptyAll);
m_pDisableForce2 = m_pTrayMenu->addAction(tr("Pause Forcing Programs"), this, SLOT(OnDisableForce2())); m_pDisableForce2 = m_pTrayMenu->addAction(tr("Pause Forcing Programs"), this, SLOT(OnDisableForce2()));
m_pDisableForce2->setCheckable(true); m_pDisableForce2->setCheckable(true);
m_pTrayMenu->addAction(m_pDisableRecovery);
m_pTrayMenu->addAction(m_pDisableMessages);
m_pTrayMenu->addSeparator(); m_pTrayMenu->addSeparator();
/*QWidgetAction* pBoxWidget = new QWidgetAction(m_pTrayMenu); /*QWidgetAction* pBoxWidget = new QWidgetAction(m_pTrayMenu);
@ -1045,12 +1070,8 @@ finish:
return Ret; return Ret;
} }
void CSandMan::OnBoxClosed(const QString& BoxName) void CSandMan::OnBoxClosed(const CSandBoxPtr& pBox)
{ {
CSandBoxPtr pBox = theAPI->GetBoxByName(BoxName);
if (!pBox)
return;
if (!pBox->GetBool("NeverDelete", false) && pBox->GetBool("AutoDelete", false) && !pBox->IsEmpty()) if (!pBox->GetBool("NeverDelete", false) && pBox->GetBool("AutoDelete", false) && !pBox->IsEmpty())
{ {
bool DeleteShapshots = false; bool DeleteShapshots = false;
@ -1059,7 +1080,7 @@ void CSandMan::OnBoxClosed(const QString& BoxName)
return; return;
if(theConf->GetBool("Options/AutoBoxOpsNotify", false)) if(theConf->GetBool("Options/AutoBoxOpsNotify", false))
OnLogMessage(tr("Auto deleting content of %1").arg(BoxName), true); OnLogMessage(tr("Auto deleting content of %1").arg(pBox->GetName()), true);
if (theConf->GetBool("Options/UseAsyncBoxOps", false)) if (theConf->GetBool("Options/UseAsyncBoxOps", false))
{ {
@ -1199,6 +1220,8 @@ void CSandMan::OnStatusChanged()
m_pBoxView->Clear(); m_pBoxView->Clear();
theAPI->WatchIni(false); theAPI->WatchIni(false);
theAPI->StopMonitor();
} }
m_pSupport->setVisible(g_Certificate.isEmpty()); m_pSupport->setVisible(g_Certificate.isEmpty());
@ -1295,9 +1318,10 @@ void CSandMan::OnLogMessage(const QString& Message, bool bNotify)
void CSandMan::OnLogSbieMessage(quint32 MsgCode, const QStringList& MsgData, quint32 ProcessId) void CSandMan::OnLogSbieMessage(quint32 MsgCode, const QStringList& MsgData, quint32 ProcessId)
{ {
if ((MsgCode & 0xFFFF) == 2198) // file migration progress if ((MsgCode & 0xFFFF) == 2198 ) // file migration progress
{ {
m_pPopUpWindow->ShowProgress(MsgCode, MsgData, ProcessId); if (!m_pDisableMessages->isChecked())
m_pPopUpWindow->ShowProgress(MsgCode, MsgData, ProcessId);
return; return;
} }
@ -1307,7 +1331,7 @@ void CSandMan::OnLogSbieMessage(quint32 MsgCode, const QStringList& MsgData, qui
m_MissingTemplates.append(MsgData[2]); m_MissingTemplates.append(MsgData[2]);
} }
if ((MsgCode & 0xFFFF) == 6004) // certificat error if ((MsgCode & 0xFFFF) == 6004) // certificate error
{ {
static quint64 iLastCertWarning = 0; static quint64 iLastCertWarning = 0;
if (iLastCertWarning + 60 < QDateTime::currentDateTime().toTime_t()) { // reset after 60 seconds if (iLastCertWarning + 60 < QDateTime::currentDateTime().toTime_t()) { // reset after 60 seconds
@ -1359,7 +1383,7 @@ void CSandMan::OnLogSbieMessage(quint32 MsgCode, const QStringList& MsgData, qui
if ((MsgCode & 0xFFFF) == 2111) // process open denided if ((MsgCode & 0xFFFF) == 2111) // process open denided
return; // dont pop that one up return; // dont pop that one up
if(MsgCode != 0 && theConf->GetBool("Options/ShowNotifications", true)) if(MsgCode != 0 && theConf->GetBool("Options/ShowNotifications", true) && !m_pDisableMessages->isChecked())
m_pPopUpWindow->AddLogMessage(Message, MsgCode, MsgData, ProcessId); m_pPopUpWindow->AddLogMessage(Message, MsgCode, MsgData, ProcessId);
} }
@ -1389,6 +1413,23 @@ bool CSandMan::CheckCertificate()
return false; return false;
} }
void CSandMan::UpdateCertState()
{
g_CertInfo.State = theAPI->GetCertState();
g_CertInfo.about_to_expire = g_CertInfo.expirers_in_sec && g_CertInfo.expirers_in_sec < (60 * 60 * 24 * 30);
if (g_CertInfo.outdated)
OnLogMessage(tr("The supporter certificate is not valid for this build, please get an updated certificate"));
// outdated always implicates it is no longer valid
else if (g_CertInfo.expired) // may be still valid for the current and older builds
OnLogMessage(tr("The supporter certificate has expired%1, please get an updated certificate")
.arg(g_CertInfo.valid ? tr(", but it remains valid for the current build") : ""));
else if (g_CertInfo.about_to_expire)
OnLogMessage(tr("The supporter certificate will expire in %1 days, please get an updated certificate").arg(g_CertInfo.expirers_in_sec / (60 * 60 * 24)));
emit CertUpdated();
}
void CSandMan::OnQueuedRequest(quint32 ClientPid, quint32 ClientTid, quint32 RequestId, const QVariantMap& Data) void CSandMan::OnQueuedRequest(quint32 ClientPid, quint32 ClientTid, quint32 RequestId, const QVariantMap& Data)
{ {
m_pPopUpWindow->AddUserPrompt(RequestId, Data, ClientPid); m_pPopUpWindow->AddUserPrompt(RequestId, Data, ClientPid);
@ -1397,7 +1438,7 @@ void CSandMan::OnQueuedRequest(quint32 ClientPid, quint32 ClientTid, quint32 Req
void CSandMan::OnFileToRecover(const QString& BoxName, const QString& FilePath, const QString& BoxPath, quint32 ProcessId) void CSandMan::OnFileToRecover(const QString& BoxName, const QString& FilePath, const QString& BoxPath, quint32 ProcessId)
{ {
CSandBoxPtr pBox = theAPI->GetBoxByName(BoxName); CSandBoxPtr pBox = theAPI->GetBoxByName(BoxName);
if (!pBox.isNull() && pBox.objectCast<CSandBoxPlus>()->IsRecoverySuspended()) if ((!pBox.isNull() && pBox.objectCast<CSandBoxPlus>()->IsRecoverySuspended()) || m_pDisableRecovery->isChecked())
return; return;
if (theConf->GetBool("Options/InstantRecovery", true)) if (theConf->GetBool("Options/InstantRecovery", true))
@ -1426,7 +1467,7 @@ bool CSandMan::OpenRecovery(const CSandBoxPtr& pBox, bool& DeleteShapshots, bool
// todo: resuse window? // todo: resuse window?
} }
CRecoveryWindow* pRecoveryWindow = new CRecoveryWindow(pBox, this); CRecoveryWindow* pRecoveryWindow = new CRecoveryWindow(pBox, false, this);
if (pRecoveryWindow->FindFiles() == 0 && bCloseEmpty) { if (pRecoveryWindow->FindFiles() == 0 && bCloseEmpty) {
delete pRecoveryWindow; delete pRecoveryWindow;
} }
@ -1441,29 +1482,29 @@ CRecoveryWindow* CSandMan::ShowRecovery(const CSandBoxPtr& pBox, bool bFind)
auto pBoxEx = pBox.objectCast<CSandBoxPlus>(); auto pBoxEx = pBox.objectCast<CSandBoxPlus>();
if (!pBoxEx) return false; if (!pBoxEx) return false;
if (pBoxEx->m_pRecoveryWnd == NULL) { if (pBoxEx->m_pRecoveryWnd == NULL) {
pBoxEx->m_pRecoveryWnd = new CRecoveryWindow(pBox); pBoxEx->m_pRecoveryWnd = new CRecoveryWindow(pBox, bFind == false);
connect(pBoxEx->m_pRecoveryWnd, &CRecoveryWindow::Closed, [pBoxEx]() { connect(pBoxEx->m_pRecoveryWnd, &CRecoveryWindow::Closed, [pBoxEx]() {
pBoxEx->m_pRecoveryWnd = NULL; pBoxEx->m_pRecoveryWnd = NULL;
}); });
pBoxEx->m_pRecoveryWnd->show(); pBoxEx->m_pRecoveryWnd->show();
} }
else { /*else {
pBoxEx->m_pRecoveryWnd->setWindowState((pBoxEx->m_pRecoveryWnd->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive); pBoxEx->m_pRecoveryWnd->setWindowState((pBoxEx->m_pRecoveryWnd->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
//SetForegroundWindow((HWND)pBoxEx->m_pRecoveryWnd->winId()); //SetForegroundWindow((HWND)pBoxEx->m_pRecoveryWnd->winId());
} }*/
if(bFind) if(bFind)
pBoxEx->m_pRecoveryWnd->FindFiles(); pBoxEx->m_pRecoveryWnd->FindFiles();
return pBoxEx->m_pRecoveryWnd; return pBoxEx->m_pRecoveryWnd;
} }
SB_PROGRESS CSandMan::RecoverFiles(const QList<QPair<QString, QString>>& FileList, int Action) SB_PROGRESS CSandMan::RecoverFiles(const QString& BoxName, const QList<QPair<QString, QString>>& FileList, int Action)
{ {
CSbieProgressPtr pProgress = CSbieProgressPtr(new CSbieProgress()); CSbieProgressPtr pProgress = CSbieProgressPtr(new CSbieProgress());
QtConcurrent::run(CSandMan::RecoverFilesAsync, pProgress, FileList, Action); QtConcurrent::run(CSandMan::RecoverFilesAsync, pProgress, BoxName, FileList, Action);
return SB_PROGRESS(OP_ASYNC, pProgress); return SB_PROGRESS(OP_ASYNC, pProgress);
} }
void CSandMan::RecoverFilesAsync(const CSbieProgressPtr& pProgress, const QList<QPair<QString, QString>>& FileList, int Action) void CSandMan::RecoverFilesAsync(const CSbieProgressPtr& pProgress, const QString& BoxName, const QList<QPair<QString, QString>>& FileList, int Action)
{ {
SB_STATUS Status = SB_OK; SB_STATUS Status = SB_OK;
@ -1506,6 +1547,13 @@ void CSandMan::RecoverFilesAsync(const CSbieProgressPtr& pProgress, const QList<
if (!QFile::rename(BoxPath, RecoveryPath)) if (!QFile::rename(BoxPath, RecoveryPath))
Unrecovered.append(BoxPath); Unrecovered.append(BoxPath);
else {
QMetaObject::invokeMethod(theGUI, "OnFileRecovered", Qt::BlockingQueuedConnection, // show this question using the GUI thread
Q_ARG(QString, BoxName),
Q_ARG(QString, RecoveryPath),
Q_ARG(QString, BoxPath)
);
}
} }
if (!Unrecovered.isEmpty()) if (!Unrecovered.isEmpty())
@ -1528,6 +1576,21 @@ void CSandMan::RecoverFilesAsync(const CSbieProgressPtr& pProgress, const QList<
pProgress->Finish(Status); pProgress->Finish(Status);
} }
void CSandMan::OnFileRecovered(const QString& BoxName, const QString& FilePath, const QString& BoxPath)
{
QTreeWidgetItem* pItem = new QTreeWidgetItem(); // Time|Box|FilePath
pItem->setText(0, QDateTime::currentDateTime().toString("hh:mm:ss.zzz"));
pItem->setText(1, BoxName);
pItem->setText(2, FilePath);
m_pRecoveryLog->GetTree()->addTopLevelItem(pItem);
m_pRecoveryLog->GetView()->verticalScrollBar()->setValue(m_pRecoveryLog->GetView()->verticalScrollBar()->maximum());
CSandBoxPtr pBox = theAPI->GetBoxByName(BoxName);
if (pBox)
pBox.objectCast<CSandBoxPlus>()->UpdateSize();
}
int CSandMan::ShowQuestion(const QString& question, const QString& checkBoxText, bool* checkBoxSetting, int buttons, int defaultButton) int CSandMan::ShowQuestion(const QString& question, const QString& checkBoxText, bool* checkBoxSetting, int buttons, int defaultButton)
{ {
return CCheckableMessageBox::question(this, "Sandboxie-Plus", question, checkBoxText, checkBoxSetting, (QDialogButtonBox::StandardButtons)buttons, (QDialogButtonBox::StandardButton)defaultButton, QMessageBox::Question); return CCheckableMessageBox::question(this, "Sandboxie-Plus", question, checkBoxText, checkBoxSetting, (QDialogButtonBox::StandardButtons)buttons, (QDialogButtonBox::StandardButton)defaultButton, QMessageBox::Question);
@ -1882,6 +1945,9 @@ void CSandMan::OnCleanUp()
if (sender() == m_pCleanUpTrace || sender() == m_pCleanUpButton) if (sender() == m_pCleanUpTrace || sender() == m_pCleanUpButton)
m_pTraceView->Clear(); m_pTraceView->Clear();
if (sender() == m_pCleanUpRecovery || sender() == m_pCleanUpButton)
m_pRecoveryLog->GetTree()->clear();
if (sender() == m_pCleanUpProcesses || sender() == m_pCleanUpButton) if (sender() == m_pCleanUpProcesses || sender() == m_pCleanUpButton)
theAPI->UpdateProcesses(false, m_pShowAllSessions->isChecked()); theAPI->UpdateProcesses(false, m_pShowAllSessions->isChecked());
} }
@ -2399,443 +2465,6 @@ QString CSandMan::GetVersion()
return Version; return Version;
} }
void CSandMan::CheckForUpdates(bool bManual)
{
if (!m_pUpdateProgress.isNull())
return;
m_pUpdateProgress = CSbieProgressPtr(new CSbieProgress());
AddAsyncOp(m_pUpdateProgress);
m_pUpdateProgress->ShowMessage(tr("Checking for updates..."));
if (m_RequestManager == NULL)
m_RequestManager = new CNetworkAccessManager(30 * 1000, this);
QUrlQuery Query;
Query.addQueryItem("software", "sandboxie-plus");
//QString Branche = theConf->GetString("Options/ReleaseBranche");
//if (!Branche.isEmpty())
// Query.addQueryItem("branche", Branche);
//Query.addQueryItem("version", GetVersion());
Query.addQueryItem("version", QString::number(VERSION_MJR) + "." + QString::number(VERSION_MIN) + "." + QString::number(VERSION_REV) + "." + QString::number(VERSION_UPD));
Query.addQueryItem("system", "windows-" + QSysInfo::kernelVersion() + "-" + QSysInfo::currentCpuArchitecture());
Query.addQueryItem("language", QString::number(m_LanguageId));
QString UpdateKey = GetArguments(g_Certificate, L'\n', L':').value("UPDATEKEY");
if (UpdateKey.isEmpty())
UpdateKey = theAPI->GetGlobalSettings()->GetText("UpdateKey"); // theConf->GetString("Options/UpdateKey");
if (!UpdateKey.isEmpty())
Query.addQueryItem("update_key", UpdateKey);
Query.addQueryItem("auto", bManual ? "0" : "1");
QUrl Url("https://sandboxie-plus.com/update.php");
Url.setQuery(Query);
QNetworkRequest Request = QNetworkRequest(Url);
Request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
//Request.setRawHeader("Accept-Encoding", "gzip");
QNetworkReply* pReply = m_RequestManager->get(Request);
pReply->setProperty("manual", bManual);
connect(pReply, SIGNAL(finished()), this, SLOT(OnUpdateCheck()));
}
void CSandMan::OnUpdateCheck()
{
if (m_pUpdateProgress.isNull())
return;
QNetworkReply* pReply = qobject_cast<QNetworkReply*>(sender());
bool bManual = pReply->property("manual").toBool();
QByteArray Reply = pReply->readAll();
pReply->deleteLater();
m_pUpdateProgress->Finish(SB_OK);
m_pUpdateProgress.clear();
QVariantMap Data = QJsonDocument::fromJson(Reply).toVariant().toMap();
if (Data.isEmpty() || Data["error"].toBool())
{
QString Error = Data.isEmpty() ? tr("server not reachable") : Data["errorMsg"].toString();
OnLogMessage(tr("Failed to check for updates, error: %1").arg(Error), !bManual);
if (bManual)
QMessageBox::critical(this, "Sandboxie-Plus", tr("Failed to check for updates, error: %1").arg(Error));
return;
}
bool bNothing = true;
QStringList IgnoredUpdates = theConf->GetStringList("Options/IgnoredUpdates");
QString UserMsg = Data["userMsg"].toString();
if (!UserMsg.isEmpty())
{
QString MsgHash = QCryptographicHash::hash(Data["userMsg"].toByteArray(), QCryptographicHash::Md5).toHex().left(8);
if (!IgnoredUpdates.contains(MsgHash))
{
QString FullMessage = UserMsg;
QString InfoUrl = Data["infoUrl"].toString();
if (!InfoUrl.isEmpty())
FullMessage += tr("<p>Do you want to go to the <a href=\"%1\">info page</a>?</p>").arg(InfoUrl);
CCheckableMessageBox mb(this);
mb.setWindowTitle("Sandboxie-Plus");
QIcon ico(QLatin1String(":/SandMan.png"));
mb.setIconPixmap(ico.pixmap(64, 64));
//mb.setTextFormat(Qt::RichText);
mb.setText(UserMsg);
mb.setCheckBoxText(tr("Don't show this announcement in the future."));
if (!InfoUrl.isEmpty()) {
mb.setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No);
mb.setDefaultButton(QDialogButtonBox::Yes);
}
else
mb.setStandardButtons(QDialogButtonBox::Ok);
mb.exec();
if (mb.isChecked())
theConf->SetValue("Options/IgnoredUpdates", IgnoredUpdates << MsgHash);
if (mb.clickedStandardButton() == QDialogButtonBox::Yes)
{
QDesktopServices::openUrl(InfoUrl);
}
bNothing = false;
}
}
QString VersionStr = Data["version"].toString();
if (!VersionStr.isEmpty()) //&& VersionStr != GetVersion())
{
UCHAR myVersion[4] = { VERSION_UPD, VERSION_REV, VERSION_MIN, VERSION_MJR }; // ntohl
ULONG MyVersion = *(ULONG*)&myVersion;
ULONG Version = 0;
QStringList Nums = VersionStr.split(".");
for (int i = 0, Bits = 24; i < Nums.count() && Bits >= 0; i++, Bits -= 8)
Version |= (Nums[i].toInt() & 0xFF) << Bits;
if (Version > MyVersion)
if (bManual || !IgnoredUpdates.contains(VersionStr)) // when checked manually always show result
{
bNothing = false;
//QDateTime Updated = QDateTime::fromTime_t(Data["updated"].toULongLong());
QString DownloadUrl = Data["downloadUrl"].toString();
// 'sha256'
// 'signature'
if (!DownloadUrl.isEmpty() && theConf->GetInt("Options/DownloadUpdates", 0) == 1)
DownloadUpdates(DownloadUrl, bManual);
else
{
QString UpdateMsg = Data["updateMsg"].toString();
QString UpdateUrl = Data["updateUrl"].toString();
QString FullMessage = UpdateMsg.isEmpty() ? tr("<p>There is a new version of Sandboxie-Plus available.<br /><font color='red'>New version:</font> <b>%1</b></p>").arg(VersionStr) : UpdateMsg;
if (!DownloadUrl.isEmpty())
FullMessage += tr("<p>Do you want to download the latest version?</p>");
else if (!UpdateUrl.isEmpty())
FullMessage += tr("<p>Do you want to go to the <a href=\"%1\">download page</a>?</p>").arg(UpdateUrl);
CCheckableMessageBox mb(this);
mb.setWindowTitle("Sandboxie-Plus");
QIcon ico(QLatin1String(":/SandMan.png"));
mb.setIconPixmap(ico.pixmap(64, 64));
//mb.setTextFormat(Qt::RichText);
mb.setText(FullMessage);
mb.setCheckBoxText(tr("Don't show this message anymore."));
mb.setCheckBoxVisible(!bManual);
if (!UpdateUrl.isEmpty() || !DownloadUrl.isEmpty()) {
mb.setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No);
mb.setDefaultButton(QDialogButtonBox::Yes);
}
else
mb.setStandardButtons(QDialogButtonBox::Ok);
mb.exec();
if (mb.isChecked())
theConf->SetValue("Options/IgnoredUpdates", IgnoredUpdates << VersionStr);
if (mb.clickedStandardButton() == QDialogButtonBox::Yes)
{
if (!DownloadUrl.isEmpty())
DownloadUpdates(DownloadUrl, bManual);
else
QDesktopServices::openUrl(UpdateUrl);
}
}
}
}
if (bNothing)
{
theConf->SetValue("Options/NextCheckForUpdates", QDateTime::currentDateTime().addDays(7).toTime_t());
if (bManual) {
QMessageBox::information(this, "Sandboxie-Plus", tr("No new updates found, your Sandboxie-Plus is up-to-date.\n"
"\nNote: The update check is often behind the latest GitHub release to ensure that only tested updates are offered."));
}
}
}
void CSandMan::DownloadUpdates(const QString& DownloadUrl, bool bManual)
{
QNetworkRequest Request = QNetworkRequest(DownloadUrl);
Request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
//Request.setRawHeader("Accept-Encoding", "gzip");
QNetworkReply* pReply = m_RequestManager->get(Request);
pReply->setProperty("manual", bManual);
connect(pReply, SIGNAL(finished()), this, SLOT(OnUpdateDownload()));
connect(pReply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(OnUpdateProgress(qint64, qint64)));
m_pUpdateProgress = CSbieProgressPtr(new CSbieProgress());
AddAsyncOp(m_pUpdateProgress);
m_pUpdateProgress->ShowMessage(tr("Downloading new version..."));
}
void CSandMan::OnUpdateProgress(qint64 bytes, qint64 bytesTotal)
{
if (bytesTotal != 0 && !m_pUpdateProgress.isNull())
m_pUpdateProgress->Progress(100 * bytes / bytesTotal);
}
void CSandMan::OnUpdateDownload()
{
if (m_pUpdateProgress.isNull())
return;
QString TempDir = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
if (TempDir.right(1) != "/")
TempDir += "/";
m_pUpdateProgress->Progress(-1);
QNetworkReply* pReply = qobject_cast<QNetworkReply*>(sender());
bool bManual = pReply->property("manual").toBool();
quint64 Size = pReply->bytesAvailable();
QString Name = pReply->request().url().fileName();
if (Name.isEmpty() || Name.right(4).compare(".exe", Qt::CaseInsensitive) != 0)
Name = "Sandboxie-Plus-Install.exe";
QString FilePath = TempDir + Name;
QFile File(FilePath);
if (File.open(QFile::WriteOnly)) {
while (pReply->bytesAvailable() > 0)
File.write(pReply->read(4096));
File.close();
}
pReply->deleteLater();
m_pUpdateProgress->Finish(SB_OK);
m_pUpdateProgress.clear();
if (File.size() != Size) {
QMessageBox::critical(this, "Sandboxie-Plus", tr("Failed to download update from: %1").arg(pReply->request().url().toString()));
return;
}
theConf->SetValue("Options/PendingUpdatePackage", FilePath);
UpdateLabel();
if (bManual)
InstallUpdate();
}
void CSandMan::InstallUpdate()
{
QString FilePath = theConf->GetString("Options/PendingUpdatePackage");
if (FilePath.isEmpty())
return;
QString Message = tr("<p>A Sandboxie-Plus update has been downloaded to the following location:</p><p><a href=\"%2\">%1</a></p><p>Do you want to begin the installation? If any programs are running sandboxed, they will be terminated.</p>")
.arg(FilePath).arg("File:///" + Split2(FilePath, "/", true).first);
int Ret = QMessageBox("Sandboxie-Plus", Message, QMessageBox::Information, QMessageBox::Yes | QMessageBox::Default, QMessageBox::No | QMessageBox::Escape, QMessageBox::Cancel, this).exec();
if (Ret == QMessageBox::Cancel) {
theConf->DelValue("Options/PendingUpdatePackage");
UpdateLabel();
}
if (Ret != QMessageBox::Yes)
return;
theAPI->TerminateAll();
wstring wFile = FilePath.toStdWString();
SHELLEXECUTEINFO si = { 0 };
si.cbSize = sizeof(SHELLEXECUTEINFO);
si.fMask = SEE_MASK_NOCLOSEPROCESS;
si.hwnd = NULL;
si.lpVerb = L"runas";
si.lpFile = wFile.c_str();
si.lpParameters = L"/SILENT";
si.lpDirectory = NULL;
si.nShow = SW_SHOW;
si.hInstApp = NULL;
if (ShellExecuteEx(&si)) {
theConf->DelValue("Options/PendingUpdatePackage");
QApplication::quit();
}
}
void CSandMan::OnHelp()
{
if (sender() == m_pSupport)
QDesktopServices::openUrl(QUrl("https://sandboxie-plus.com/go.php?to=donate"));
else if (sender() == m_pForum)
QDesktopServices::openUrl(QUrl("https://sandboxie-plus.com/go.php?to=sbie-forum"));
else if (sender() == m_pManual)
QDesktopServices::openUrl(QUrl("https://sandboxie-plus.com/go.php?to=sbie-docs"));
else
QDesktopServices::openUrl(QUrl("https://sandboxie-plus.com/go.php?to=patreon"));
}
void CSandMan::OnAbout()
{
if (sender() == m_pAbout)
{
QString AboutCaption = tr(
"<h3>About Sandboxie-Plus</h3>"
"<p>Version %1</p>"
"<p>Copyright (c) 2020-2022 by DavidXanatos</p>"
).arg(GetVersion());
QString CertInfo;
if (!g_Certificate.isEmpty()) {
CertInfo = tr("This copy of Sandboxie+ is certified for: %1").arg(GetArguments(g_Certificate, L'\n', L':').value("NAME"));
} else {
CertInfo = tr("Sandboxie+ is free for personal and non-commercial use.");
}
QString AboutText = tr(
"Sandboxie-Plus is an open source continuation of Sandboxie.<br />"
"Visit <a href=\"https://sandboxie-plus.com\">sandboxie-plus.com</a> for more information.<br />"
"<br />"
"%3<br />"
"<br />"
"Driver version: %1<br />"
"Features: %2<br />"
"<br />"
"Icons from <a href=\"https://icons8.com\">icons8.com</a>"
).arg(theAPI->GetVersion()).arg(theAPI->GetFeatureStr()).arg(CertInfo);
QMessageBox *msgBox = new QMessageBox(this);
msgBox->setAttribute(Qt::WA_DeleteOnClose);
msgBox->setWindowTitle(tr("About Sandboxie-Plus"));
msgBox->setText(AboutCaption);
msgBox->setInformativeText(AboutText);
QIcon ico(QLatin1String(":/SandMan.png"));
msgBox->setIconPixmap(ico.pixmap(128, 128));
SafeExec(msgBox);
}
else if (sender() == m_pAboutQt)
QMessageBox::aboutQt(this);
}
void CSandMan::UpdateCertState()
{
g_CertInfo.State = theAPI->GetCertState();
g_CertInfo.about_to_expire = g_CertInfo.expirers_in_sec && g_CertInfo.expirers_in_sec < (60*60*24*30);
if (g_CertInfo.outdated)
OnLogMessage(tr("The supporter certificate is not valid for this build, please get an updated certificate"));
// outdated always implicates it is no longer valid
else if (g_CertInfo.expired) // may be still valid for the current and older builds
OnLogMessage(tr("The supporter certificate has expired%1, please get an updated certificate")
.arg(g_CertInfo.valid ? tr(", but it remains valid for the current build") : ""));
else if(g_CertInfo.about_to_expire)
OnLogMessage(tr("The supporter certificate will expire in %1 days, please get an updated certificate").arg(g_CertInfo.expirers_in_sec / (60*60*24)));
emit CertUpdated();
}
void CSandMan::UpdateCert()
{
QString UpdateKey; // for now only patreons can update the cert automatically
if(GetArguments(g_Certificate, L'\n', L':').value("type").indexOf("PATREON") == 0)
UpdateKey = GetArguments(g_Certificate, L'\n', L':').value("UPDATEKEY");
if (UpdateKey.isEmpty()) {
OpenUrl("https://sandboxie-plus.com/go.php?to=sbie-get-cert");
return;
}
if (!m_pUpdateProgress.isNull())
return;
m_pUpdateProgress = CSbieProgressPtr(new CSbieProgress());
AddAsyncOp(m_pUpdateProgress);
m_pUpdateProgress->ShowMessage(tr("Checking for certificate..."));
if (m_RequestManager == NULL)
m_RequestManager = new CNetworkAccessManager(30 * 1000, this);
QUrlQuery Query;
Query.addQueryItem("UpdateKey", UpdateKey);
QUrl Url("https://sandboxie-plus.com/get_cert.php");
Url.setQuery(Query);
QNetworkRequest Request = QNetworkRequest(Url);
Request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
//Request.setRawHeader("Accept-Encoding", "gzip");
QNetworkReply* pReply = m_RequestManager->get(Request);
connect(pReply, SIGNAL(finished()), this, SLOT(OnCertCheck()));
}
void CSandMan::OnCertCheck()
{
if (m_pUpdateProgress.isNull())
return;
QNetworkReply* pReply = qobject_cast<QNetworkReply*>(sender());
QByteArray Reply = pReply->readAll();
int Code = pReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
pReply->deleteLater();
m_pUpdateProgress->Finish(SB_OK);
m_pUpdateProgress.clear();
if (Code > 299 || Code < 200) {
QMessageBox::critical(this, "Sandboxie-Plus", tr("No certificate found on server!"));
return;
}
if (Reply.replace("\r\n","\n").compare(g_Certificate.replace("\r\n","\n"), Qt::CaseInsensitive) == 0){
QMessageBox::information(this, "Sandboxie-Plus", tr("There is no updated certificate available."));
return;
}
QString CertPath = theAPI->GetSbiePath() + "\\Certificate.dat";
QString TempPath = QDir::tempPath() + "/Sbie+Certificate.dat";
QFile CertFile(TempPath);
if (CertFile.open(QFile::WriteOnly)) {
CertFile.write(Reply);
CertFile.close();
}
WindowsMoveFile(TempPath.replace("/", "\\"), CertPath.replace("/", "\\"));
if (!theAPI->ReloadCert().IsError()) {
CSettingsWindow::LoadCertificate();
UpdateCertState();
}
else { // this should not happen
g_Certificate.clear();
g_CertInfo.State = 0;
}
}
void CSandMan::SetUITheme() void CSandMan::SetUITheme()
{ {
m_ThemeUpdatePending = false; m_ThemeUpdatePending = false;
@ -2953,234 +2582,7 @@ QT_TRANSLATE_NOOP("CSandBox", "Merging folders: %1 &gt;&gt; %2"),
QT_TRANSLATE_NOOP("CSandBox", "Finishing Snapshot Merge..."), QT_TRANSLATE_NOOP("CSandBox", "Finishing Snapshot Merge..."),
}; };
//////////////////////////////////////////////////////////////////////////////////////////
// WinSpy based window finder
//
#include <windows.h> #include "SandManUpdate.cpp"
#include "Helpers/FindTool.h"
#include "SbieFindWnd.cpp"
typedef enum DEVICE_SCALE_FACTOR {
DEVICE_SCALE_FACTOR_INVALID = 0,
SCALE_100_PERCENT = 100,
SCALE_120_PERCENT = 120,
SCALE_125_PERCENT = 125,
SCALE_140_PERCENT = 140,
SCALE_150_PERCENT = 150,
SCALE_160_PERCENT = 160,
SCALE_175_PERCENT = 175,
SCALE_180_PERCENT = 180,
SCALE_200_PERCENT = 200,
SCALE_225_PERCENT = 225,
SCALE_250_PERCENT = 250,
SCALE_300_PERCENT = 300,
SCALE_350_PERCENT = 350,
SCALE_400_PERCENT = 400,
SCALE_450_PERCENT = 450,
SCALE_500_PERCENT = 500
} DEVICE_SCALE_FACTOR;
typedef HRESULT (CALLBACK *P_GetScaleFactorForMonitor)(HMONITOR, DEVICE_SCALE_FACTOR*);
UINT GetMonitorScaling(HWND hwnd)
{
static HINSTANCE shcore = LoadLibrary(L"Shcore.dll");
if (shcore != nullptr)
{
if (auto getScaleFactorForMonitor =
P_GetScaleFactorForMonitor(GetProcAddress(shcore, "GetScaleFactorForMonitor")))
{
HMONITOR monitor =
MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
DEVICE_SCALE_FACTOR Scale;
getScaleFactorForMonitor(monitor, &Scale);
return Scale;
}
}
return 100;
}
#define IDD_FINDER_TOOL 111
#define ID_FINDER_TARGET 112
#define ID_FINDER_EXPLAIN 113
#define ID_FINDER_RESULT 114
struct SFinderWndData {
int Scale;
HFONT hFont;
};
#define DS(x) ((x) * WndData.Scale / 100)
UINT CALLBACK FindProc(HWND hwndTool, UINT uCode, HWND hwnd)
{
ULONG pid;
if (uCode == WFN_END)
GetWindowThreadProcessId(hwnd, &pid);
else
pid = 0;
hwndTool = GetParent(hwndTool);
SFinderWndData &WndData = *(SFinderWndData*)GetWindowLongPtr(hwndTool, 0);
if (pid && pid != GetCurrentProcessId())
{
RECT rc;
GetWindowRect(hwndTool, &rc);
if (rc.bottom - rc.top <= DS(150))
SetWindowPos(hwndTool, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top + DS(70), SWP_SHOWWINDOW | SWP_NOMOVE);
CBoxedProcessPtr pProcess = theAPI->GetProcessById(pid);
if (!pProcess.isNull())
{
wstring result = CSandMan::tr("The selected window is running as part of program %1 in sandbox %2").arg(pProcess->GetProcessName()).arg(pProcess->GetBoxName()).toStdWString();
SetWindowText(GetDlgItem(hwndTool, ID_FINDER_RESULT), result.c_str());
//::ShowWindow(GetDlgItem(hwndTool, ID_FINDER_YES_BOXED), SW_SHOW);
}
else
{
wstring result = CSandMan::tr("The selected window is not running as part of any sandboxed program.").toStdWString();
SetWindowText(GetDlgItem(hwndTool, ID_FINDER_RESULT), result.c_str());
//::ShowWindow(GetDlgItem(hwndTool, ID_FINDER_NOT_BOXED), SW_SHOW);
}
::ShowWindow(GetDlgItem(hwndTool, ID_FINDER_RESULT), SW_SHOW);
}
else
{
RECT rc;
GetWindowRect(hwndTool, &rc);
if (rc.bottom - rc.top > DS(150))
SetWindowPos(hwndTool, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top - DS(70), SWP_SHOWWINDOW | SWP_NOMOVE);
//::ShowWindow(GetDlgItem(hwndTool, ID_FINDER_YES_BOXED), SW_HIDE);
//::ShowWindow(GetDlgItem(hwndTool, ID_FINDER_NOT_BOXED), SW_HIDE);
::ShowWindow(GetDlgItem(hwndTool, ID_FINDER_RESULT), SW_HIDE);
}
return 0;
}
// hwnd: All window processes are passed the handle of the window
// that they belong to in hwnd.
// msg: Current message (e.g., WM_*) from the OS.
// wParam: First message parameter, note that these are more or less
// integers, but they are really just "data chunks" that
// you are expected to memcpy as raw data to float, etc.
// lParam: Second message parameter, same deal as above.
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
{
CREATESTRUCT* createStruct = (CREATESTRUCT*)lParam;
SFinderWndData &WndData = *(SFinderWndData*)createStruct->lpCreateParams;
SetWindowLongPtr(hwnd, 0, (LONG_PTR)&WndData);
wstring info = CSandMan::tr("Drag the Finder Tool over a window to select it, then release the mouse to check if the window is sandboxed.").toStdWString();
CreateWindow(L"Static", L"", SS_BITMAP | SS_NOTIFY | WS_VISIBLE | WS_CHILD, DS(10), DS(10), DS(32), DS(32), hwnd, (HMENU)ID_FINDER_TARGET, NULL, NULL);
CreateWindow(L"Static", info.c_str(), WS_VISIBLE | WS_CHILD, DS(60), DS(10), DS(180), DS(85), hwnd, (HMENU)ID_FINDER_EXPLAIN, NULL, NULL);
CreateWindow(L"Static", L"", WS_CHILD, DS(60), DS(100), DS(180), DS(50), hwnd, (HMENU)ID_FINDER_RESULT, NULL, NULL);
WndData.hFont = CreateFont(DS(13), 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Tahoma"));
if (WndData.hFont) {
SendMessage(GetDlgItem(hwnd, ID_FINDER_EXPLAIN), WM_SETFONT, (WPARAM)WndData.hFont, TRUE);
SendMessage(GetDlgItem(hwnd, ID_FINDER_RESULT), WM_SETFONT, (WPARAM)WndData.hFont, TRUE);
}
MakeFinderTool(GetDlgItem(hwnd, ID_FINDER_TARGET), FindProc);
break;
}
case WM_CLOSE:
SFinderWndData &WndData = *(SFinderWndData*)GetWindowLongPtr(hwnd, 0);
if (WndData.hFont) DeleteObject(WndData.hFont);
//DestroyWindow(hwnd);
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
DWORD WINAPI FinderThreadFunc(LPVOID lpParam)
{
MSG msg;
WNDCLASS mainWindowClass = { 0 };
HINSTANCE hInstance = NULL;
// You can set the main window name to anything, but
// typically you should prefix custom window classes
// with something that makes it unique.
mainWindowClass.lpszClassName = TEXT("SBp.WndFinder");
mainWindowClass.hInstance = hInstance;
mainWindowClass.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
mainWindowClass.lpfnWndProc = WndProc;
mainWindowClass.hCursor = LoadCursor(0, IDC_ARROW);
mainWindowClass.cbWndExtra = sizeof(void*); // SFinderWndData
RegisterClass(&mainWindowClass);
// Notes:
// - The classname identifies the TYPE of the window. Not a C type.
// This is a (TCHAR*) ID that Windows uses internally.
// - The window name is really just the window text, this is
// commonly used for captions, including the title
// bar of the window itself.
// - parentHandle is considered the "owner" of this
// window. MessageBoxes can use HWND_MESSAGE to
// free them of any window.
// - menuHandle: hMenu specifies the child-window identifier,
// an integer value used by a dialog box
// control to notify its parent about events.
// The application determines the child-window
// identifier; it must be unique for all
// child windows with the same parent window.
SFinderWndData WndData;
WndData.Scale = GetMonitorScaling(MainWndHandle);
HWND hwnd = CreateWindow(mainWindowClass.lpszClassName, CSandMan::tr("Sandboxie-Plus - Window Finder").toStdWString().c_str()
, WS_SYSMENU | WS_CAPTION | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, DS(275), DS(135), NULL, 0, hInstance, &WndData);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
void CSandMan::OnWndFinder()
{
m_pWndFinder->setEnabled(false);
HANDLE hThread = CreateThread(NULL, 0, FinderThreadFunc, NULL, 0, NULL);
QWinEventNotifier* finishedNotifier = new QWinEventNotifier(hThread);
finishedNotifier->setEnabled(true);
connect(finishedNotifier, &QWinEventNotifier::activated, this, [finishedNotifier, this, hThread]() {
CloseHandle(hThread);
m_pWndFinder->setEnabled(true);
finishedNotifier->setEnabled(false);
finishedNotifier->deleteLater();
});
}

View File

@ -34,7 +34,7 @@ public:
static QString GetVersion(); static QString GetVersion();
SB_PROGRESS RecoverFiles(const QList<QPair<QString, QString>>& FileList, int Action = 0); SB_PROGRESS RecoverFiles(const QString& BoxName, const QList<QPair<QString, QString>>& FileList, int Action = 0);
enum EDelMode { enum EDelMode {
eDefault, eDefault,
@ -81,7 +81,7 @@ protected:
SB_STATUS DisconnectSbie(); SB_STATUS DisconnectSbie();
SB_RESULT(void*) StopSbie(bool andRemove = false); SB_RESULT(void*) StopSbie(bool andRemove = false);
static void RecoverFilesAsync(const CSbieProgressPtr& pProgress, const QList<QPair<QString, QString>>& FileList, int Action = 0); static void RecoverFilesAsync(const CSbieProgressPtr& pProgress, const QString& BoxName, const QList<QPair<QString, QString>>& FileList, int Action = 0);
QIcon GetTrayIcon(bool isConnected = true); QIcon GetTrayIcon(bool isConnected = true);
QString GetTrayText(bool isConnected = true); QString GetTrayText(bool isConnected = true);
@ -137,6 +137,7 @@ public slots:
void OnQueuedRequest(quint32 ClientPid, quint32 ClientTid, quint32 RequestId, const QVariantMap& Data); void OnQueuedRequest(quint32 ClientPid, quint32 ClientTid, quint32 RequestId, const QVariantMap& Data);
void OnFileToRecover(const QString& BoxName, const QString& FilePath, const QString& BoxPath, quint32 ProcessId); void OnFileToRecover(const QString& BoxName, const QString& FilePath, const QString& BoxPath, quint32 ProcessId);
void OnFileRecovered(const QString& BoxName, const QString& FilePath, const QString& BoxPath);
bool OpenRecovery(const CSandBoxPtr& pBox, bool& DeleteShapshots, bool bCloseEmpty = false); bool OpenRecovery(const CSandBoxPtr& pBox, bool& DeleteShapshots, bool bCloseEmpty = false);
class CRecoveryWindow* ShowRecovery(const CSandBoxPtr& pBox, bool bFind = true); class CRecoveryWindow* ShowRecovery(const CSandBoxPtr& pBox, bool bFind = true);
@ -153,7 +154,7 @@ public slots:
void OnAsyncProgress(int Progress); void OnAsyncProgress(int Progress);
void OnCancelAsync(); void OnCancelAsync();
void OnBoxClosed(const QString& BoxName); void OnBoxClosed(const CSandBoxPtr& pBox);
void CheckForUpdates(bool bManual = true); void CheckForUpdates(bool bManual = true);
void DownloadUpdates(const QString& DownloadUrl, bool bManual); void DownloadUpdates(const QString& DownloadUrl, bool bManual);
@ -236,6 +237,7 @@ private:
CPanelWidgetEx* m_pMessageLog; CPanelWidgetEx* m_pMessageLog;
CTraceView* m_pTraceView; CTraceView* m_pTraceView;
CPanelWidgetEx* m_pRecoveryLog;
QMenu* m_pMenuFile; QMenu* m_pMenuFile;
@ -245,6 +247,8 @@ private:
QAction* m_pWndFinder; QAction* m_pWndFinder;
QAction* m_pDisableForce; QAction* m_pDisableForce;
QAction* m_pDisableForce2; QAction* m_pDisableForce2;
QAction* m_pDisableRecovery;
QAction* m_pDisableMessages;
QMenu* m_pMaintenance; QMenu* m_pMaintenance;
QAction* m_pConnect; QAction* m_pConnect;
QAction* m_pDisconnect; QAction* m_pDisconnect;
@ -272,6 +276,7 @@ private:
QAction* m_pCleanUpProcesses; QAction* m_pCleanUpProcesses;
QAction* m_pCleanUpMsgLog; QAction* m_pCleanUpMsgLog;
QAction* m_pCleanUpTrace; QAction* m_pCleanUpTrace;
QAction* m_pCleanUpRecovery;
QToolButton* m_pCleanUpButton; QToolButton* m_pCleanUpButton;
QAction* m_pKeepTerminated; QAction* m_pKeepTerminated;
QAction* m_pShowAllSessions; QAction* m_pShowAllSessions;

View File

@ -49,16 +49,6 @@ SOURCES += ./main.cpp \
./Helpers/WindowFromPointEx.cpp \ ./Helpers/WindowFromPointEx.cpp \
./Windows/NewBoxWindow.cpp \ ./Windows/NewBoxWindow.cpp \
./Windows/OptionsWindow.cpp \ ./Windows/OptionsWindow.cpp \
./Windows/OptionsAccess.cpp \
./Windows/OptionsAdvanced.cpp \
./Windows/OptionsForce.cpp \
./Windows/OptionsGeneral.cpp \
./Windows/OptionsGrouping.cpp \
./Windows/OptionsNetwork.cpp \
./Windows/OptionsRecovery.cpp \
./Windows/OptionsStart.cpp \
./Windows/OptionsStop.cpp \
./Windows/OptionsTemplates.cpp \
./Windows/PopUpWindow.cpp \ ./Windows/PopUpWindow.cpp \
./Windows/RecoveryWindow.cpp \ ./Windows/RecoveryWindow.cpp \
./Windows/SettingsWindow.cpp \ ./Windows/SettingsWindow.cpp \

View File

@ -208,6 +208,18 @@
<ClCompile Include="Models\TraceModel.cpp" /> <ClCompile Include="Models\TraceModel.cpp" />
<ClCompile Include="Models\SbieModel.cpp" /> <ClCompile Include="Models\SbieModel.cpp" />
<ClCompile Include="SandMan.cpp" /> <ClCompile Include="SandMan.cpp" />
<ClCompile Include="SandManUpdate.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="SbieFindWnd.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="SbiePlusAPI.cpp" /> <ClCompile Include="SbiePlusAPI.cpp" />
<ClCompile Include="SbieProcess.cpp" /> <ClCompile Include="SbieProcess.cpp" />
<ClCompile Include="stdafx.cpp"> <ClCompile Include="stdafx.cpp">
@ -220,16 +232,66 @@
<ClCompile Include="Views\TraceView.cpp" /> <ClCompile Include="Views\TraceView.cpp" />
<ClCompile Include="Windows\FileBrowserWindow.cpp" /> <ClCompile Include="Windows\FileBrowserWindow.cpp" />
<ClCompile Include="Windows\NewBoxWindow.cpp" /> <ClCompile Include="Windows\NewBoxWindow.cpp" />
<ClCompile Include="Windows\OptionsAccess.cpp" /> <ClCompile Include="Windows\OptionsAccess.cpp">
<ClCompile Include="Windows\OptionsAdvanced.cpp" /> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ClCompile Include="Windows\OptionsForce.cpp" /> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ClCompile Include="Windows\OptionsGeneral.cpp" /> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ClCompile Include="Windows\OptionsGrouping.cpp" /> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
<ClCompile Include="Windows\OptionsNetwork.cpp" /> </ClCompile>
<ClCompile Include="Windows\OptionsRecovery.cpp" /> <ClCompile Include="Windows\OptionsAdvanced.cpp">
<ClCompile Include="Windows\OptionsStart.cpp" /> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ClCompile Include="Windows\OptionsStop.cpp" /> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ClCompile Include="Windows\OptionsTemplates.cpp" /> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="Windows\OptionsForce.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="Windows\OptionsGeneral.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="Windows\OptionsGrouping.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="Windows\OptionsNetwork.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="Windows\OptionsRecovery.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="Windows\OptionsStart.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="Windows\OptionsStop.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="Windows\OptionsTemplates.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="Windows\OptionsWindow.cpp" /> <ClCompile Include="Windows\OptionsWindow.cpp" />
<ClCompile Include="Windows\PopUpWindow.cpp" /> <ClCompile Include="Windows\PopUpWindow.cpp" />
<ClCompile Include="Windows\RecoveryWindow.cpp" /> <ClCompile Include="Windows\RecoveryWindow.cpp" />

View File

@ -162,6 +162,12 @@
<ClCompile Include="BoxMonitor.cpp"> <ClCompile Include="BoxMonitor.cpp">
<Filter>SandMan</Filter> <Filter>SandMan</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="SbieFindWnd.cpp">
<Filter>SandMan</Filter>
</ClCompile>
<ClCompile Include="SandManUpdate.cpp">
<Filter>SandMan</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="stdafx.h"> <ClInclude Include="stdafx.h">

View File

@ -0,0 +1,420 @@
void CSandMan::CheckForUpdates(bool bManual)
{
if (!m_pUpdateProgress.isNull())
return;
m_pUpdateProgress = CSbieProgressPtr(new CSbieProgress());
AddAsyncOp(m_pUpdateProgress);
m_pUpdateProgress->ShowMessage(tr("Checking for updates..."));
if (m_RequestManager == NULL)
m_RequestManager = new CNetworkAccessManager(30 * 1000, this);
QUrlQuery Query;
Query.addQueryItem("software", "sandboxie-plus");
//QString Branche = theConf->GetString("Options/ReleaseBranche");
//if (!Branche.isEmpty())
// Query.addQueryItem("branche", Branche);
//Query.addQueryItem("version", GetVersion());
Query.addQueryItem("version", QString::number(VERSION_MJR) + "." + QString::number(VERSION_MIN) + "." + QString::number(VERSION_REV) + "." + QString::number(VERSION_UPD));
Query.addQueryItem("system", "windows-" + QSysInfo::kernelVersion() + "-" + QSysInfo::currentCpuArchitecture());
Query.addQueryItem("language", QString::number(m_LanguageId));
QString UpdateKey = GetArguments(g_Certificate, L'\n', L':').value("UPDATEKEY");
if (UpdateKey.isEmpty())
UpdateKey = theAPI->GetGlobalSettings()->GetText("UpdateKey"); // theConf->GetString("Options/UpdateKey");
if (!UpdateKey.isEmpty())
Query.addQueryItem("update_key", UpdateKey);
Query.addQueryItem("auto", bManual ? "0" : "1");
QUrl Url("https://sandboxie-plus.com/update.php");
Url.setQuery(Query);
QNetworkRequest Request = QNetworkRequest(Url);
Request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
//Request.setRawHeader("Accept-Encoding", "gzip");
QNetworkReply* pReply = m_RequestManager->get(Request);
pReply->setProperty("manual", bManual);
connect(pReply, SIGNAL(finished()), this, SLOT(OnUpdateCheck()));
}
void CSandMan::OnUpdateCheck()
{
if (m_pUpdateProgress.isNull())
return;
QNetworkReply* pReply = qobject_cast<QNetworkReply*>(sender());
bool bManual = pReply->property("manual").toBool();
QByteArray Reply = pReply->readAll();
pReply->deleteLater();
m_pUpdateProgress->Finish(SB_OK);
m_pUpdateProgress.clear();
QVariantMap Data = QJsonDocument::fromJson(Reply).toVariant().toMap();
if (Data.isEmpty() || Data["error"].toBool())
{
QString Error = Data.isEmpty() ? tr("server not reachable") : Data["errorMsg"].toString();
OnLogMessage(tr("Failed to check for updates, error: %1").arg(Error), !bManual);
if (bManual)
QMessageBox::critical(this, "Sandboxie-Plus", tr("Failed to check for updates, error: %1").arg(Error));
return;
}
bool bNothing = true;
QStringList IgnoredUpdates = theConf->GetStringList("Options/IgnoredUpdates");
QString UserMsg = Data["userMsg"].toString();
if (!UserMsg.isEmpty())
{
QString MsgHash = QCryptographicHash::hash(Data["userMsg"].toByteArray(), QCryptographicHash::Md5).toHex().left(8);
if (!IgnoredUpdates.contains(MsgHash))
{
QString FullMessage = UserMsg;
QString InfoUrl = Data["infoUrl"].toString();
if (!InfoUrl.isEmpty())
FullMessage += tr("<p>Do you want to go to the <a href=\"%1\">info page</a>?</p>").arg(InfoUrl);
CCheckableMessageBox mb(this);
mb.setWindowTitle("Sandboxie-Plus");
QIcon ico(QLatin1String(":/SandMan.png"));
mb.setIconPixmap(ico.pixmap(64, 64));
//mb.setTextFormat(Qt::RichText);
mb.setText(UserMsg);
mb.setCheckBoxText(tr("Don't show this announcement in the future."));
if (!InfoUrl.isEmpty()) {
mb.setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No);
mb.setDefaultButton(QDialogButtonBox::Yes);
}
else
mb.setStandardButtons(QDialogButtonBox::Ok);
mb.exec();
if (mb.isChecked())
theConf->SetValue("Options/IgnoredUpdates", IgnoredUpdates << MsgHash);
if (mb.clickedStandardButton() == QDialogButtonBox::Yes)
{
QDesktopServices::openUrl(InfoUrl);
}
bNothing = false;
}
}
QString VersionStr = Data["version"].toString();
if (!VersionStr.isEmpty()) //&& VersionStr != GetVersion())
{
UCHAR myVersion[4] = { VERSION_UPD, VERSION_REV, VERSION_MIN, VERSION_MJR }; // ntohl
ULONG MyVersion = *(ULONG*)&myVersion;
ULONG Version = 0;
QStringList Nums = VersionStr.split(".");
for (int i = 0, Bits = 24; i < Nums.count() && Bits >= 0; i++, Bits -= 8)
Version |= (Nums[i].toInt() & 0xFF) << Bits;
if (Version > MyVersion)
if (bManual || !IgnoredUpdates.contains(VersionStr)) // when checked manually always show result
{
bNothing = false;
//QDateTime Updated = QDateTime::fromTime_t(Data["updated"].toULongLong());
QString DownloadUrl = Data["downloadUrl"].toString();
// 'sha256'
// 'signature'
if (!DownloadUrl.isEmpty() && theConf->GetInt("Options/DownloadUpdates", 0) == 1)
DownloadUpdates(DownloadUrl, bManual);
else
{
QString UpdateMsg = Data["updateMsg"].toString();
QString UpdateUrl = Data["updateUrl"].toString();
QString FullMessage = UpdateMsg.isEmpty() ? tr("<p>There is a new version of Sandboxie-Plus available.<br /><font color='red'>New version:</font> <b>%1</b></p>").arg(VersionStr) : UpdateMsg;
if (!DownloadUrl.isEmpty())
FullMessage += tr("<p>Do you want to download the latest version?</p>");
else if (!UpdateUrl.isEmpty())
FullMessage += tr("<p>Do you want to go to the <a href=\"%1\">download page</a>?</p>").arg(UpdateUrl);
CCheckableMessageBox mb(this);
mb.setWindowTitle("Sandboxie-Plus");
QIcon ico(QLatin1String(":/SandMan.png"));
mb.setIconPixmap(ico.pixmap(64, 64));
//mb.setTextFormat(Qt::RichText);
mb.setText(FullMessage);
mb.setCheckBoxText(tr("Don't show this message anymore."));
mb.setCheckBoxVisible(!bManual);
if (!UpdateUrl.isEmpty() || !DownloadUrl.isEmpty()) {
mb.setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No);
mb.setDefaultButton(QDialogButtonBox::Yes);
}
else
mb.setStandardButtons(QDialogButtonBox::Ok);
mb.exec();
if (mb.isChecked())
theConf->SetValue("Options/IgnoredUpdates", IgnoredUpdates << VersionStr);
if (mb.clickedStandardButton() == QDialogButtonBox::Yes)
{
if (!DownloadUrl.isEmpty())
DownloadUpdates(DownloadUrl, bManual);
else
QDesktopServices::openUrl(UpdateUrl);
}
}
}
}
if (bNothing)
{
theConf->SetValue("Options/NextCheckForUpdates", QDateTime::currentDateTime().addDays(7).toTime_t());
if (bManual) {
QMessageBox::information(this, "Sandboxie-Plus", tr("No new updates found, your Sandboxie-Plus is up-to-date.\n"
"\nNote: The update check is often behind the latest GitHub release to ensure that only tested updates are offered."));
}
}
}
void CSandMan::DownloadUpdates(const QString& DownloadUrl, bool bManual)
{
QNetworkRequest Request = QNetworkRequest(DownloadUrl);
Request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
//Request.setRawHeader("Accept-Encoding", "gzip");
QNetworkReply* pReply = m_RequestManager->get(Request);
pReply->setProperty("manual", bManual);
connect(pReply, SIGNAL(finished()), this, SLOT(OnUpdateDownload()));
connect(pReply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(OnUpdateProgress(qint64, qint64)));
m_pUpdateProgress = CSbieProgressPtr(new CSbieProgress());
AddAsyncOp(m_pUpdateProgress);
m_pUpdateProgress->ShowMessage(tr("Downloading new version..."));
}
void CSandMan::OnUpdateProgress(qint64 bytes, qint64 bytesTotal)
{
if (bytesTotal != 0 && !m_pUpdateProgress.isNull())
m_pUpdateProgress->Progress(100 * bytes / bytesTotal);
}
void CSandMan::OnUpdateDownload()
{
if (m_pUpdateProgress.isNull())
return;
QString TempDir = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
if (TempDir.right(1) != "/")
TempDir += "/";
m_pUpdateProgress->Progress(-1);
QNetworkReply* pReply = qobject_cast<QNetworkReply*>(sender());
bool bManual = pReply->property("manual").toBool();
quint64 Size = pReply->bytesAvailable();
QString Name = pReply->request().url().fileName();
if (Name.isEmpty() || Name.right(4).compare(".exe", Qt::CaseInsensitive) != 0)
Name = "Sandboxie-Plus-Install.exe";
QString FilePath = TempDir + Name;
QFile File(FilePath);
if (File.open(QFile::WriteOnly)) {
while (pReply->bytesAvailable() > 0)
File.write(pReply->read(4096));
File.close();
}
pReply->deleteLater();
m_pUpdateProgress->Finish(SB_OK);
m_pUpdateProgress.clear();
if (File.size() != Size) {
QMessageBox::critical(this, "Sandboxie-Plus", tr("Failed to download update from: %1").arg(pReply->request().url().toString()));
return;
}
theConf->SetValue("Options/PendingUpdatePackage", FilePath);
UpdateLabel();
if (bManual)
InstallUpdate();
}
void CSandMan::InstallUpdate()
{
QString FilePath = theConf->GetString("Options/PendingUpdatePackage");
if (FilePath.isEmpty())
return;
QString Message = tr("<p>A Sandboxie-Plus update has been downloaded to the following location:</p><p><a href=\"%2\">%1</a></p><p>Do you want to begin the installation? If any programs are running sandboxed, they will be terminated.</p>")
.arg(FilePath).arg("File:///" + Split2(FilePath, "/", true).first);
int Ret = QMessageBox("Sandboxie-Plus", Message, QMessageBox::Information, QMessageBox::Yes | QMessageBox::Default, QMessageBox::No | QMessageBox::Escape, QMessageBox::Cancel, this).exec();
if (Ret == QMessageBox::Cancel) {
theConf->DelValue("Options/PendingUpdatePackage");
UpdateLabel();
}
if (Ret != QMessageBox::Yes)
return;
theAPI->TerminateAll();
wstring wFile = FilePath.toStdWString();
SHELLEXECUTEINFO si = { 0 };
si.cbSize = sizeof(SHELLEXECUTEINFO);
si.fMask = SEE_MASK_NOCLOSEPROCESS;
si.hwnd = NULL;
si.lpVerb = L"runas";
si.lpFile = wFile.c_str();
si.lpParameters = L"/SILENT";
si.lpDirectory = NULL;
si.nShow = SW_SHOW;
si.hInstApp = NULL;
if (ShellExecuteEx(&si)) {
theConf->DelValue("Options/PendingUpdatePackage");
QApplication::quit();
}
}
void CSandMan::OnHelp()
{
if (sender() == m_pSupport)
QDesktopServices::openUrl(QUrl("https://sandboxie-plus.com/go.php?to=donate"));
else if (sender() == m_pForum)
QDesktopServices::openUrl(QUrl("https://sandboxie-plus.com/go.php?to=sbie-forum"));
else if (sender() == m_pManual)
QDesktopServices::openUrl(QUrl("https://sandboxie-plus.com/go.php?to=sbie-docs"));
else
QDesktopServices::openUrl(QUrl("https://sandboxie-plus.com/go.php?to=patreon"));
}
void CSandMan::OnAbout()
{
if (sender() == m_pAbout)
{
QString AboutCaption = tr(
"<h3>About Sandboxie-Plus</h3>"
"<p>Version %1</p>"
"<p>Copyright (c) 2020-2022 by DavidXanatos</p>"
).arg(GetVersion());
QString CertInfo;
if (!g_Certificate.isEmpty()) {
CertInfo = tr("This copy of Sandboxie+ is certified for: %1").arg(GetArguments(g_Certificate, L'\n', L':').value("NAME"));
} else {
CertInfo = tr("Sandboxie+ is free for personal and non-commercial use.");
}
QString AboutText = tr(
"Sandboxie-Plus is an open source continuation of Sandboxie.<br />"
"Visit <a href=\"https://sandboxie-plus.com\">sandboxie-plus.com</a> for more information.<br />"
"<br />"
"%3<br />"
"<br />"
"Driver version: %1<br />"
"Features: %2<br />"
"<br />"
"Icons from <a href=\"https://icons8.com\">icons8.com</a>"
).arg(theAPI->GetVersion()).arg(theAPI->GetFeatureStr()).arg(CertInfo);
QMessageBox *msgBox = new QMessageBox(this);
msgBox->setAttribute(Qt::WA_DeleteOnClose);
msgBox->setWindowTitle(tr("About Sandboxie-Plus"));
msgBox->setText(AboutCaption);
msgBox->setInformativeText(AboutText);
QIcon ico(QLatin1String(":/SandMan.png"));
msgBox->setIconPixmap(ico.pixmap(128, 128));
SafeExec(msgBox);
}
else if (sender() == m_pAboutQt)
QMessageBox::aboutQt(this);
}
void CSandMan::UpdateCert()
{
QString UpdateKey; // for now only patreons can update the cert automatically
if(GetArguments(g_Certificate, L'\n', L':').value("type").indexOf("PATREON") == 0)
UpdateKey = GetArguments(g_Certificate, L'\n', L':').value("UPDATEKEY");
if (UpdateKey.isEmpty()) {
OpenUrl("https://sandboxie-plus.com/go.php?to=sbie-get-cert");
return;
}
if (!m_pUpdateProgress.isNull())
return;
m_pUpdateProgress = CSbieProgressPtr(new CSbieProgress());
AddAsyncOp(m_pUpdateProgress);
m_pUpdateProgress->ShowMessage(tr("Checking for certificate..."));
if (m_RequestManager == NULL)
m_RequestManager = new CNetworkAccessManager(30 * 1000, this);
QUrlQuery Query;
Query.addQueryItem("UpdateKey", UpdateKey);
QUrl Url("https://sandboxie-plus.com/get_cert.php");
Url.setQuery(Query);
QNetworkRequest Request = QNetworkRequest(Url);
Request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
//Request.setRawHeader("Accept-Encoding", "gzip");
QNetworkReply* pReply = m_RequestManager->get(Request);
connect(pReply, SIGNAL(finished()), this, SLOT(OnCertCheck()));
}
void CSandMan::OnCertCheck()
{
if (m_pUpdateProgress.isNull())
return;
QNetworkReply* pReply = qobject_cast<QNetworkReply*>(sender());
QByteArray Reply = pReply->readAll();
int Code = pReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
pReply->deleteLater();
m_pUpdateProgress->Finish(SB_OK);
m_pUpdateProgress.clear();
if (Code > 299 || Code < 200) {
QMessageBox::critical(this, "Sandboxie-Plus", tr("No certificate found on server!"));
return;
}
if (Reply.replace("\r\n","\n").compare(g_Certificate.replace("\r\n","\n"), Qt::CaseInsensitive) == 0){
QMessageBox::information(this, "Sandboxie-Plus", tr("There is no updated certificate available."));
return;
}
QString CertPath = theAPI->GetSbiePath() + "\\Certificate.dat";
QString TempPath = QDir::tempPath() + "/Sbie+Certificate.dat";
QFile CertFile(TempPath);
if (CertFile.open(QFile::WriteOnly)) {
CertFile.write(Reply);
CertFile.close();
}
WindowsMoveFile(TempPath.replace("/", "\\"), CertPath.replace("/", "\\"));
if (!theAPI->ReloadCert().IsError()) {
CSettingsWindow::LoadCertificate();
UpdateCertState();
}
else { // this should not happen
g_Certificate.clear();
g_CertInfo.State = 0;
}
}

View File

@ -0,0 +1,232 @@
//////////////////////////////////////////////////////////////////////////////////////////
// WinSpy based window finder
//
#include <windows.h>
#include "Helpers/FindTool.h"
typedef enum DEVICE_SCALE_FACTOR {
DEVICE_SCALE_FACTOR_INVALID = 0,
SCALE_100_PERCENT = 100,
SCALE_120_PERCENT = 120,
SCALE_125_PERCENT = 125,
SCALE_140_PERCENT = 140,
SCALE_150_PERCENT = 150,
SCALE_160_PERCENT = 160,
SCALE_175_PERCENT = 175,
SCALE_180_PERCENT = 180,
SCALE_200_PERCENT = 200,
SCALE_225_PERCENT = 225,
SCALE_250_PERCENT = 250,
SCALE_300_PERCENT = 300,
SCALE_350_PERCENT = 350,
SCALE_400_PERCENT = 400,
SCALE_450_PERCENT = 450,
SCALE_500_PERCENT = 500
} DEVICE_SCALE_FACTOR;
typedef HRESULT (CALLBACK *P_GetScaleFactorForMonitor)(HMONITOR, DEVICE_SCALE_FACTOR*);
UINT GetMonitorScaling(HWND hwnd)
{
static HINSTANCE shcore = LoadLibrary(L"Shcore.dll");
if (shcore != nullptr)
{
if (auto getScaleFactorForMonitor =
P_GetScaleFactorForMonitor(GetProcAddress(shcore, "GetScaleFactorForMonitor")))
{
HMONITOR monitor =
MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
DEVICE_SCALE_FACTOR Scale;
getScaleFactorForMonitor(monitor, &Scale);
return Scale;
}
}
return 100;
}
#define IDD_FINDER_TOOL 111
#define ID_FINDER_TARGET 112
#define ID_FINDER_EXPLAIN 113
#define ID_FINDER_RESULT 114
struct SFinderWndData {
int Scale;
HFONT hFont;
};
#define DS(x) ((x) * WndData.Scale / 100)
UINT CALLBACK FindProc(HWND hwndTool, UINT uCode, HWND hwnd)
{
ULONG pid;
if (uCode == WFN_END)
GetWindowThreadProcessId(hwnd, &pid);
else
pid = 0;
hwndTool = GetParent(hwndTool);
SFinderWndData &WndData = *(SFinderWndData*)GetWindowLongPtr(hwndTool, 0);
if (pid && pid != GetCurrentProcessId())
{
RECT rc;
GetWindowRect(hwndTool, &rc);
if (rc.bottom - rc.top <= DS(150))
SetWindowPos(hwndTool, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top + DS(70), SWP_SHOWWINDOW | SWP_NOMOVE);
CBoxedProcessPtr pProcess = theAPI->GetProcessById(pid);
if (!pProcess.isNull())
{
wstring result = CSandMan::tr("The selected window is running as part of program %1 in sandbox %2").arg(pProcess->GetProcessName()).arg(pProcess->GetBoxName()).toStdWString();
SetWindowText(GetDlgItem(hwndTool, ID_FINDER_RESULT), result.c_str());
//::ShowWindow(GetDlgItem(hwndTool, ID_FINDER_YES_BOXED), SW_SHOW);
}
else
{
wstring result = CSandMan::tr("The selected window is not running as part of any sandboxed program.").toStdWString();
SetWindowText(GetDlgItem(hwndTool, ID_FINDER_RESULT), result.c_str());
//::ShowWindow(GetDlgItem(hwndTool, ID_FINDER_NOT_BOXED), SW_SHOW);
}
::ShowWindow(GetDlgItem(hwndTool, ID_FINDER_RESULT), SW_SHOW);
}
else
{
RECT rc;
GetWindowRect(hwndTool, &rc);
if (rc.bottom - rc.top > DS(150))
SetWindowPos(hwndTool, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top - DS(70), SWP_SHOWWINDOW | SWP_NOMOVE);
//::ShowWindow(GetDlgItem(hwndTool, ID_FINDER_YES_BOXED), SW_HIDE);
//::ShowWindow(GetDlgItem(hwndTool, ID_FINDER_NOT_BOXED), SW_HIDE);
::ShowWindow(GetDlgItem(hwndTool, ID_FINDER_RESULT), SW_HIDE);
}
return 0;
}
// hwnd: All window processes are passed the handle of the window
// that they belong to in hwnd.
// msg: Current message (e.g., WM_*) from the OS.
// wParam: First message parameter, note that these are more or less
// integers, but they are really just "data chunks" that
// you are expected to memcpy as raw data to float, etc.
// lParam: Second message parameter, same deal as above.
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CREATE:
{
CREATESTRUCT* createStruct = (CREATESTRUCT*)lParam;
SFinderWndData &WndData = *(SFinderWndData*)createStruct->lpCreateParams;
SetWindowLongPtr(hwnd, 0, (LONG_PTR)&WndData);
wstring info = CSandMan::tr("Drag the Finder Tool over a window to select it, then release the mouse to check if the window is sandboxed.").toStdWString();
CreateWindow(L"Static", L"", SS_BITMAP | SS_NOTIFY | WS_VISIBLE | WS_CHILD, DS(10), DS(10), DS(32), DS(32), hwnd, (HMENU)ID_FINDER_TARGET, NULL, NULL);
CreateWindow(L"Static", info.c_str(), WS_VISIBLE | WS_CHILD, DS(60), DS(10), DS(180), DS(85), hwnd, (HMENU)ID_FINDER_EXPLAIN, NULL, NULL);
CreateWindow(L"Static", L"", WS_CHILD, DS(60), DS(100), DS(180), DS(50), hwnd, (HMENU)ID_FINDER_RESULT, NULL, NULL);
WndData.hFont = CreateFont(DS(13), 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Tahoma"));
if (WndData.hFont) {
SendMessage(GetDlgItem(hwnd, ID_FINDER_EXPLAIN), WM_SETFONT, (WPARAM)WndData.hFont, TRUE);
SendMessage(GetDlgItem(hwnd, ID_FINDER_RESULT), WM_SETFONT, (WPARAM)WndData.hFont, TRUE);
}
MakeFinderTool(GetDlgItem(hwnd, ID_FINDER_TARGET), FindProc);
break;
}
case WM_CLOSE:
SFinderWndData &WndData = *(SFinderWndData*)GetWindowLongPtr(hwnd, 0);
if (WndData.hFont) DeleteObject(WndData.hFont);
//DestroyWindow(hwnd);
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
DWORD WINAPI FinderThreadFunc(LPVOID lpParam)
{
MSG msg;
WNDCLASS mainWindowClass = { 0 };
HINSTANCE hInstance = NULL;
// You can set the main window name to anything, but
// typically you should prefix custom window classes
// with something that makes it unique.
mainWindowClass.lpszClassName = TEXT("SBp.WndFinder");
mainWindowClass.hInstance = hInstance;
mainWindowClass.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
mainWindowClass.lpfnWndProc = WndProc;
mainWindowClass.hCursor = LoadCursor(0, IDC_ARROW);
mainWindowClass.cbWndExtra = sizeof(void*); // SFinderWndData
RegisterClass(&mainWindowClass);
// Notes:
// - The classname identifies the TYPE of the window. Not a C type.
// This is a (TCHAR*) ID that Windows uses internally.
// - The window name is really just the window text, this is
// commonly used for captions, including the title
// bar of the window itself.
// - parentHandle is considered the "owner" of this
// window. MessageBoxes can use HWND_MESSAGE to
// free them of any window.
// - menuHandle: hMenu specifies the child-window identifier,
// an integer value used by a dialog box
// control to notify its parent about events.
// The application determines the child-window
// identifier; it must be unique for all
// child windows with the same parent window.
SFinderWndData WndData;
WndData.Scale = GetMonitorScaling(MainWndHandle);
HWND hwnd = CreateWindow(mainWindowClass.lpszClassName, CSandMan::tr("Sandboxie-Plus - Window Finder").toStdWString().c_str()
, WS_SYSMENU | WS_CAPTION | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, DS(275), DS(135), NULL, 0, hInstance, &WndData);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
void CSandMan::OnWndFinder()
{
m_pWndFinder->setEnabled(false);
HANDLE hThread = CreateThread(NULL, 0, FinderThreadFunc, NULL, 0, NULL);
QWinEventNotifier* finishedNotifier = new QWinEventNotifier(hThread);
finishedNotifier->setEnabled(true);
connect(finishedNotifier, &QWinEventNotifier::activated, this, [finishedNotifier, this, hThread]() {
CloseHandle(hThread);
m_pWndFinder->setEnabled(true);
finishedNotifier->setEnabled(false);
finishedNotifier->deleteLater();
});
}

View File

@ -81,6 +81,11 @@ bool CSbiePlusAPI::IsRunningAsAdmin()
return true; return true;
} }
void CSbiePlusAPI::StopMonitor()
{
m_BoxMonitor->Stop();
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// CSandBoxPlus // CSandBoxPlus
// //
@ -163,18 +168,29 @@ void CSandBoxPlus::UpdateDetails()
void CSandBoxPlus::SetBoxPaths(const QString& FilePath, const QString& RegPath, const QString& IpcPath) void CSandBoxPlus::SetBoxPaths(const QString& FilePath, const QString& RegPath, const QString& IpcPath)
{ {
bool bPathChanged = (FilePath != m_FilePath);
if (bPathChanged && !m_FilePath.isEmpty())
((CSbiePlusAPI*)theAPI)->m_BoxMonitor->RemoveBox(this);
CSandBox::SetBoxPaths(FilePath, RegPath, IpcPath); CSandBox::SetBoxPaths(FilePath, RegPath, IpcPath);
if (m_FilePath.isEmpty()) {
m_IsEmpty = true;
return;
}
m_IsEmpty = IsEmpty(); m_IsEmpty = IsEmpty();
if (theConf->GetBool("Options/WatchBoxSize", false) && m_TotalSize == -1) if (bPathChanged && theConf->GetBool("Options/WatchBoxSize", false) && m_TotalSize == -1)
((CSbiePlusAPI*)theAPI)->m_BoxMonitor->AddBox(this); ((CSbiePlusAPI*)theAPI)->m_BoxMonitor->ScanBox(this);
} }
void CSandBoxPlus::UpdateSize() void CSandBoxPlus::UpdateSize()
{ {
m_TotalSize = -1; m_TotalSize = -1;
if(theConf->GetBool("Options/WatchBoxSize", false)) if(theConf->GetBool("Options/WatchBoxSize", false))
((CSbiePlusAPI*)theAPI)->m_BoxMonitor->AddBox(this); ((CSbiePlusAPI*)theAPI)->m_BoxMonitor->ScanBox(this);
m_IsEmpty = IsEmpty(); m_IsEmpty = IsEmpty();
} }
@ -185,6 +201,11 @@ void CSandBoxPlus::SetSize(quint64 Size)
theConf->SetValue("SizeCache/" + m_Name, Size); theConf->SetValue("SizeCache/" + m_Name, Size);
} }
bool CSandBoxPlus::IsSizePending() const
{
return ((CSbiePlusAPI*)theAPI)->m_BoxMonitor->IsScanPending(this);
}
void CSandBoxPlus::OpenBox() void CSandBoxPlus::OpenBox()
{ {
CSandBox::OpenBox(); CSandBox::OpenBox();
@ -192,7 +213,7 @@ void CSandBoxPlus::OpenBox()
m_IsEmpty = false; m_IsEmpty = false;
if (theConf->GetBool("Options/WatchBoxSize", false)) if (theConf->GetBool("Options/WatchBoxSize", false))
((CSbiePlusAPI*)theAPI)->m_BoxMonitor->AddBox(this, true); ((CSbiePlusAPI*)theAPI)->m_BoxMonitor->WatchBox(this);
} }
void CSandBoxPlus::CloseBox() void CSandBoxPlus::CloseBox()
@ -206,7 +227,7 @@ void CSandBoxPlus::CloseBox()
SB_PROGRESS CSandBoxPlus::CleanBox() SB_PROGRESS CSandBoxPlus::CleanBox()
{ {
((CSbiePlusAPI*)theAPI)->m_BoxMonitor->CloseBox(this, true); ((CSbiePlusAPI*)theAPI)->m_BoxMonitor->RemoveBox(this);
SB_PROGRESS Status = CSandBox::CleanBox(); SB_PROGRESS Status = CSandBox::CleanBox();
@ -242,8 +263,8 @@ QString CSandBoxPlus::GetStatusStr() const
QStringList Status; QStringList Status;
if (m_IsEmpty) //if (m_IsEmpty)
Status.append(tr("Empty")); // Status.append(tr("Empty"));
if (m_bApplicationCompartment) if (m_bApplicationCompartment)
Status.append(tr("Application Compartment")); Status.append(tr("Application Compartment"));

View File

@ -19,6 +19,8 @@ public:
virtual bool IsBusy() const { return m_JobCount > 0; } virtual bool IsBusy() const { return m_JobCount > 0; }
virtual void StopMonitor();
protected: protected:
friend class CSandBoxPlus; friend class CSandBoxPlus;
@ -80,9 +82,12 @@ public:
virtual void SetLeaderProgram(const QString& ProgName, bool bSet); virtual void SetLeaderProgram(const QString& ProgName, bool bSet);
virtual int IsLeaderProgram(const QString& ProgName); virtual int IsLeaderProgram(const QString& ProgName);
virtual bool IsEmptyCached() const { return m_IsEmpty; }
virtual void UpdateSize(); virtual void UpdateSize();
virtual quint64 GetSize() const { if(m_TotalSize == -1) return 0; return m_TotalSize; } virtual quint64 GetSize() const { if(m_TotalSize == -1) return 0; return m_TotalSize; }
virtual void SetSize(quint64 Size); //{ m_TotalSize = Size; } virtual void SetSize(quint64 Size); //{ m_TotalSize = Size; }
virtual bool IsSizePending() const;
virtual bool IsRecoverySuspended() const { return m_SuspendRecovery; } virtual bool IsRecoverySuspended() const { return m_SuspendRecovery; }
virtual void SetSuspendRecovery(bool bSet = true) { m_SuspendRecovery = bSet; } virtual void SetSuspendRecovery(bool bSet = true) { m_SuspendRecovery = bSet; }
@ -107,7 +112,7 @@ public:
class COptionsWindow* m_pOptionsWnd; class COptionsWindow* m_pOptionsWnd;
class CRecoveryWindow* m_pRecoveryWnd; class CRecoveryWindow* m_pRecoveryWnd;
bool IsBusy() const { return !m_JobQueue.isEmpty(); } bool IsBusy() const { return IsSizePending() || !m_JobQueue.isEmpty(); }
SB_STATUS DeleteContentAsync(bool DeleteShapshots = true, bool bOnAutoDelete = false); SB_STATUS DeleteContentAsync(bool DeleteShapshots = true, bool bOnAutoDelete = false);
public slots: public slots:
@ -118,6 +123,7 @@ public slots:
protected: protected:
friend class CSbiePlusAPI; friend class CSbiePlusAPI;
virtual bool CheckUnsecureConfig() const; virtual bool CheckUnsecureConfig() const;
virtual bool TestProgramGroup(const QString& Group, const QString& ProgName); virtual bool TestProgramGroup(const QString& Group, const QString& ProgName);

View File

@ -111,6 +111,7 @@ CSbieView::CSbieView(QWidget* parent) : CPanelView(parent)
m_pMenuContent->addSeparator(); m_pMenuContent->addSeparator();
m_pMenuExplore = m_pMenuContent->addAction(CSandMan::GetIcon("Explore"), tr("Explore Content"), this, SLOT(OnSandBoxAction())); m_pMenuExplore = m_pMenuContent->addAction(CSandMan::GetIcon("Explore"), tr("Explore Content"), this, SLOT(OnSandBoxAction()));
m_pMenuRegEdit = m_pMenuContent->addAction(CSandMan::GetIcon("RegEdit"), tr("Open Registry"), this, SLOT(OnSandBoxAction())); m_pMenuRegEdit = m_pMenuContent->addAction(CSandMan::GetIcon("RegEdit"), tr("Open Registry"), this, SLOT(OnSandBoxAction()));
m_pMenuRefresh = m_pMenu->addAction(CSandMan::GetIcon("Refresh"), tr("Refresh Info"), this, SLOT(OnSandBoxAction()));
m_pMenuSnapshots = m_pMenu->addAction(CSandMan::GetIcon("Snapshots"), tr("Snapshots Manager"), this, SLOT(OnSandBoxAction())); m_pMenuSnapshots = m_pMenu->addAction(CSandMan::GetIcon("Snapshots"), tr("Snapshots Manager"), this, SLOT(OnSandBoxAction()));
m_pMenuRecover = m_pMenu->addAction(CSandMan::GetIcon("Recover"), tr("Recover Files"), this, SLOT(OnSandBoxAction())); m_pMenuRecover = m_pMenu->addAction(CSandMan::GetIcon("Recover"), tr("Recover Files"), this, SLOT(OnSandBoxAction()));
m_pMenuCleanUp = m_pMenu->addAction(CSandMan::GetIcon("Erase"), tr("Delete Content"), this, SLOT(OnSandBoxAction())); m_pMenuCleanUp = m_pMenu->addAction(CSandMan::GetIcon("Erase"), tr("Delete Content"), this, SLOT(OnSandBoxAction()));
@ -134,6 +135,10 @@ CSbieView::CSbieView(QWidget* parent) : CPanelView(parent)
m_pMenuPresetsShares = m_pMenuPresets->addAction(tr("Allow Network Shares"), this, SLOT(OnSandBoxAction())); m_pMenuPresetsShares = m_pMenuPresets->addAction(tr("Allow Network Shares"), this, SLOT(OnSandBoxAction()));
m_pMenuPresetsShares->setCheckable(true); m_pMenuPresetsShares->setCheckable(true);
m_pMenuPresets->addSeparator();
m_pMenuPresetsRecovery = m_pMenuPresets->addAction(tr("Immediate Recovery"), this, SLOT(OnSandBoxAction()));
m_pMenuPresetsRecovery->setCheckable(true);
m_pMenuDuplicate = m_pMenu->addAction(CSandMan::GetIcon("Duplicate"), tr("Duplicate Sandbox"), this, SLOT(OnSandBoxAction())); m_pMenuDuplicate = m_pMenu->addAction(CSandMan::GetIcon("Duplicate"), tr("Duplicate Sandbox"), this, SLOT(OnSandBoxAction()));
m_pMenuRename = m_pMenu->addAction(CSandMan::GetIcon("Rename"), tr("Rename Sandbox"), this, SLOT(OnSandBoxAction())); m_pMenuRename = m_pMenu->addAction(CSandMan::GetIcon("Rename"), tr("Rename Sandbox"), this, SLOT(OnSandBoxAction()));
m_iMoveTo = m_pMenu->actions().count(); m_iMoveTo = m_pMenu->actions().count();
@ -197,6 +202,7 @@ CSbieView::CSbieView(QWidget* parent) : CPanelView(parent)
m_pMenu2->addAction(m_pMenuCleanUp); m_pMenu2->addAction(m_pMenuCleanUp);
m_pMenu2->addSeparator(); m_pMenu2->addSeparator();
m_pMenu2->addAction(m_pMenuOptions); m_pMenu2->addAction(m_pMenuOptions);
m_pMenu2->addMenu(m_pMenuPresets);
QByteArray Columns = theConf->GetBlob("MainWindow/BoxTree_Columns"); QByteArray Columns = theConf->GetBlob("MainWindow/BoxTree_Columns");
if (Columns.isEmpty()) if (Columns.isEmpty())
@ -314,8 +320,13 @@ void CSbieView::Refresh()
} }
if (!Added.isEmpty()) { if (!Added.isEmpty()) {
foreach(const QVariant &ID, Added) foreach(const QVariant& ID, Added) {
m_Groups[""].append(ID.toString()); if (ID.type() == QVariant::String) {
QString id = ID.toString();
if (id.left(1) == "!") id.remove(0, 1); // remove group group marker "!"
m_Groups[""].append(id);
}
}
QString Grouping = CSbieView__SerializeGroup(m_Groups); QString Grouping = CSbieView__SerializeGroup(m_Groups);
theAPI->GetUserSettings()->SetText("BoxDisplayOrder", Grouping); theAPI->GetUserSettings()->SetText("BoxDisplayOrder", Grouping);
@ -449,6 +460,7 @@ bool CSbieView::UpdateMenu()
m_pMenuPresetsFakeAdmin->setChecked(pBox && pBox->GetBool("DropAdminRights", false) && pBox->GetBool("FakeAdminRights", false)); m_pMenuPresetsFakeAdmin->setChecked(pBox && pBox->GetBool("DropAdminRights", false) && pBox->GetBool("FakeAdminRights", false));
m_pMenuPresetsINet->setChecked(pBox && pBox.objectCast<CSandBoxPlus>()->IsINetBlocked()); m_pMenuPresetsINet->setChecked(pBox && pBox.objectCast<CSandBoxPlus>()->IsINetBlocked());
m_pMenuPresetsShares->setChecked(pBox && pBox.objectCast<CSandBoxPlus>()->HasSharesAccess()); m_pMenuPresetsShares->setChecked(pBox && pBox.objectCast<CSandBoxPlus>()->HasSharesAccess());
m_pMenuPresetsRecovery->setChecked(pBox && pBox->GetBool("AutoRecover", false));
m_pMenuBrowse->setEnabled(iSandBoxeCount == 1); m_pMenuBrowse->setEnabled(iSandBoxeCount == 1);
m_pMenuExplore->setEnabled(iSandBoxeCount == 1); m_pMenuExplore->setEnabled(iSandBoxeCount == 1);
@ -881,6 +893,8 @@ void CSbieView::OnSandBoxAction(QAction* Action)
SandBoxes.first().objectCast<CSandBoxPlus>()->SetINetBlock(m_pMenuPresetsINet->isChecked()); SandBoxes.first().objectCast<CSandBoxPlus>()->SetINetBlock(m_pMenuPresetsINet->isChecked());
else if (Action == m_pMenuPresetsShares) else if (Action == m_pMenuPresetsShares)
SandBoxes.first().objectCast<CSandBoxPlus>()->SetAllowShares(m_pMenuPresetsShares->isChecked()); SandBoxes.first().objectCast<CSandBoxPlus>()->SetAllowShares(m_pMenuPresetsShares->isChecked());
else if (Action == m_pMenuPresetsRecovery)
m_pMenuPresetsRecovery->setChecked(SandBoxes.first()->SetBool("AutoRecover", m_pMenuPresetsRecovery->isChecked()));
else if (Action == m_pMenuOptions) else if (Action == m_pMenuOptions)
{ {
OnDoubleClicked(m_pSbieTree->selectedRows().first()); OnDoubleClicked(m_pSbieTree->selectedRows().first());
@ -909,6 +923,13 @@ void CSbieView::OnSandBoxAction(QAction* Action)
SetForegroundWindow((HWND)pFileBrowserWindow->winId()); SetForegroundWindow((HWND)pFileBrowserWindow->winId());
} }
} }
else if (Action == m_pMenuRefresh)
{
foreach(const CSandBoxPtr& pBox, SandBoxes)
{
pBox.objectCast<CSandBoxPlus>()->UpdateSize();
}
}
else if (Action == m_pMenuExplore) else if (Action == m_pMenuExplore)
{ {
if (SandBoxes.first()->IsEmpty()) { if (SandBoxes.first()->IsEmpty()) {
@ -1281,11 +1302,14 @@ void CSbieView::OnDoubleClicked(const QModelIndex& index)
if (pBox.isNull()) if (pBox.isNull())
return; return;
if (index.column() == CSbieModel::ePath) if ((QGuiApplication::queryKeyboardModifiers() & Qt::ControlModifier) == 0) {
OnSandBoxAction(m_pMenuExplore);
if (index.column() != CSbieModel::eName) if (index.column() == CSbieModel::ePath)
return; OnSandBoxAction(m_pMenuExplore);
}
//if (index.column() != CSbieModel::eName)
// return;
if (!pBox->IsEnabled()) if (!pBox->IsEnabled())
{ {

View File

@ -119,12 +119,14 @@ private:
QAction* m_pMenuPresetsFakeAdmin; QAction* m_pMenuPresetsFakeAdmin;
QAction* m_pMenuPresetsINet; QAction* m_pMenuPresetsINet;
QAction* m_pMenuPresetsShares; QAction* m_pMenuPresetsShares;
QAction* m_pMenuPresetsRecovery;
QAction* m_pMenuOptions; QAction* m_pMenuOptions;
QAction* m_pMenuSnapshots; QAction* m_pMenuSnapshots;
QAction* m_pMenuEmptyBox; QAction* m_pMenuEmptyBox;
QMenu* m_pMenuContent; QMenu* m_pMenuContent;
QAction* m_pMenuExplore; QAction* m_pMenuExplore;
QAction* m_pMenuBrowse; QAction* m_pMenuBrowse;
QAction* m_pMenuRefresh;
QAction* m_pMenuRegEdit; QAction* m_pMenuRegEdit;
QAction* m_pMenuRecover; QAction* m_pMenuRecover;
QAction* m_pMenuCleanUp; QAction* m_pMenuCleanUp;

View File

@ -223,7 +223,7 @@ void CFileBrowserWindow::OnFileMenu(const QPoint&)
} }
} }
SB_PROGRESS Status = theGUI->RecoverFiles(FileList, 0); SB_PROGRESS Status = theGUI->RecoverFiles(m_pBox->GetName(), FileList, 0);
if (Status.GetStatus() == OP_ASYNC) if (Status.GetStatus() == OP_ASYNC)
theGUI->AddAsyncOp(Status.GetValue()); theGUI->AddAsyncOp(Status.GetValue());

View File

@ -799,6 +799,16 @@ void COptionsWindow::SaveIniSection()
LoadIniSection(); LoadIniSection();
} }
#include "OptionsAccess.cpp"
#include "OptionsAdvanced.cpp"
#include "OptionsForce.cpp"
#include "OptionsGeneral.cpp"
#include "OptionsGrouping.cpp"
#include "OptionsNetwork.cpp"
#include "OptionsRecovery.cpp"
#include "OptionsStart.cpp"
#include "OptionsStop.cpp"
#include "OptionsTemplates.cpp"
#include <windows.h> #include <windows.h>

View File

@ -380,7 +380,7 @@ void CPopUpWindow::OnRecoverFile(int Action)
QList<QPair<QString, QString>> FileList; QList<QPair<QString, QString>> FileList;
FileList.append(qMakePair(pEntry->m_BoxPath, RecoveryFolder + "\\" + FileName)); FileList.append(qMakePair(pEntry->m_BoxPath, RecoveryFolder + "\\" + FileName));
SB_PROGRESS Status = theGUI->RecoverFiles(FileList, Action); SB_PROGRESS Status = theGUI->RecoverFiles(pEntry->m_BoxName, FileList, Action);
if (Status.GetStatus() == OP_ASYNC) if (Status.GetStatus() == OP_ASYNC)
theGUI->AddAsyncOp(Status.GetValue()); theGUI->AddAsyncOp(Status.GetValue());

View File

@ -13,9 +13,11 @@
#endif #endif
CRecoveryWindow::CRecoveryWindow(const CSandBoxPtr& pBox, QWidget *parent) CRecoveryWindow::CRecoveryWindow(const CSandBoxPtr& pBox, bool bImmediate, QWidget *parent)
: QDialog(parent) : QDialog(parent)
{ {
m_bImmediate = bImmediate;
Qt::WindowFlags flags = windowFlags(); Qt::WindowFlags flags = windowFlags();
flags |= Qt::CustomizeWindowHint; flags |= Qt::CustomizeWindowHint;
//flags &= ~Qt::WindowContextHelpButtonHint; //flags &= ~Qt::WindowContextHelpButtonHint;
@ -28,7 +30,7 @@ CRecoveryWindow::CRecoveryWindow(const CSandBoxPtr& pBox, QWidget *parent)
//setWindowState(Qt::WindowActive); //setWindowState(Qt::WindowActive);
SetForegroundWindow((HWND)QWidget::winId()); SetForegroundWindow((HWND)QWidget::winId());
bool bAlwaysOnTop = theConf->GetBool("Options/AlwaysOnTop", false); bool bAlwaysOnTop = theConf->GetBool("Options/AlwaysOnTop", false) || (bImmediate && theConf->GetBool("Options/RecoveryOnTop", true));
this->setWindowFlag(Qt::WindowStaysOnTopHint, bAlwaysOnTop); this->setWindowFlag(Qt::WindowStaysOnTopHint, bAlwaysOnTop);
if (!bAlwaysOnTop) { if (!bAlwaysOnTop) {
@ -302,6 +304,9 @@ int CRecoveryWindow::FindFiles()
Count += FindFiles(Folder); Count += FindFiles(Folder);
} }
if (m_bImmediate && m_FileMap.isEmpty())
this->close();
m_pFileModel->Sync(m_FileMap); m_pFileModel->Sync(m_FileMap);
ui.treeFiles->expandAll(); ui.treeFiles->expandAll();
return Count; return Count;
@ -481,7 +486,7 @@ void CRecoveryWindow::RecoverFiles(bool bBrowse, QString RecoveryFolder)
} }
SB_PROGRESS Status = theGUI->RecoverFiles(FileList); SB_PROGRESS Status = theGUI->RecoverFiles(m_pBox->GetName(), FileList);
if (Status.GetStatus() == OP_ASYNC) if (Status.GetStatus() == OP_ASYNC)
{ {
connect(Status.GetValue().data(), SIGNAL(Finished()), this, SLOT(FindFiles())); connect(Status.GetValue().data(), SIGNAL(Finished()), this, SLOT(FindFiles()));
@ -504,6 +509,7 @@ void CRecoveryWindow::OnCloseUntil()
void CRecoveryWindow::OnAutoDisable() void CRecoveryWindow::OnAutoDisable()
{ {
m_pBox.objectCast<CSandBoxPlus>()->SetSuspendRecovery();
m_pBox->SetBool("AutoRecover", false); m_pBox->SetBool("AutoRecover", false);
close(); close();
} }

View File

@ -36,7 +36,7 @@ class CRecoveryWindow : public QDialog
Q_OBJECT Q_OBJECT
public: public:
CRecoveryWindow(const CSandBoxPtr& pBox, QWidget *parent = Q_NULLPTR); CRecoveryWindow(const CSandBoxPtr& pBox, bool bImmediate = false, QWidget *parent = Q_NULLPTR);
~CRecoveryWindow(); ~CRecoveryWindow();
bool IsDeleteShapshots() { return m_DeleteShapshots; } bool IsDeleteShapshots() { return m_DeleteShapshots; }
@ -85,6 +85,7 @@ protected:
bool m_bTargetsChanged; bool m_bTargetsChanged;
bool m_bReloadPending; bool m_bReloadPending;
bool m_DeleteShapshots; bool m_DeleteShapshots;
bool m_bImmediate;
private: private:
Ui::RecoveryWindow ui; Ui::RecoveryWindow ui;

File diff suppressed because it is too large Load Diff