diff --git a/Sandboxie/common/my_version.h b/Sandboxie/common/my_version.h index 8406b174..9ba754d6 100644 --- a/Sandboxie/common/my_version.h +++ b/Sandboxie/common/my_version.h @@ -21,8 +21,8 @@ #ifndef _MY_VERSION_H #define _MY_VERSION_H -#define MY_VERSION_BINARY 5,56,1 -#define MY_VERSION_STRING "5.56.1" +#define MY_VERSION_BINARY 5,56,2 +#define MY_VERSION_STRING "5.56.2" #define MY_VERSION_COMPAT "5.55.0" // this refers to the driver ABI compatibility // These #defines are used by either Resource Compiler or NSIS installer diff --git a/Sandboxie/core/dll/sysinfo.c b/Sandboxie/core/dll/sysinfo.c index a8a15809..5b4babe8 100644 --- a/Sandboxie/core/dll/sysinfo.c +++ b/Sandboxie/core/dll/sysinfo.c @@ -133,7 +133,7 @@ _FX BOOLEAN SysInfo_Init(void) SysInfo_UseSbieJob = !Gui_OpenAllWinClasses && !SbieApi_QueryConfBool(NULL, L"NoAddProcessToJob", FALSE); if (Dll_OsBuild >= 8400) - SysInfo_CanUseJobs = SbieApi_QueryConfBool(NULL, L"AllowBoxedJobs", TRUE); + SysInfo_CanUseJobs = SbieApi_QueryConfBool(NULL, L"AllowBoxedJobs", FALSE); SBIEDLL_HOOK(SysInfo_, NtCreateJobObject); SBIEDLL_HOOK(SysInfo_, NtOpenJobObject); diff --git a/Sandboxie/core/drv/process.c b/Sandboxie/core/drv/process.c index 642a1f72..2e9f7e09 100644 --- a/Sandboxie/core/drv/process.c +++ b/Sandboxie/core/drv/process.c @@ -1348,7 +1348,7 @@ _FX BOOLEAN Process_NotifyProcess_Create( // boxed job to a process will not interfere with the job assigned by SbieSvc // - new_proc->can_use_jobs = Conf_Get_Boolean(new_proc->box->name, L"AllowBoxedJobs", 0, TRUE); + new_proc->can_use_jobs = Conf_Get_Boolean(new_proc->box->name, L"AllowBoxedJobs", 0, FALSE); } // diff --git a/SandboxiePlus/SandMan/SandMan.cpp b/SandboxiePlus/SandMan/SandMan.cpp index 8cffa448..3a71d48f 100644 --- a/SandboxiePlus/SandMan/SandMan.cpp +++ b/SandboxiePlus/SandMan/SandMan.cpp @@ -286,6 +286,7 @@ void CSandMan::LoadState() restoreState(theConf->GetBlob("MainWindow/Window_State")); //m_pBoxTree->restoreState(theConf->GetBlob("MainWindow/BoxTree_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_pPanelSplitter->restoreState(theConf->GetBlob("MainWindow/Panel_Splitter")); m_pLogTabs->setCurrentIndex(theConf->GetInt("MainWindow/LogTab", 0)); @@ -297,6 +298,7 @@ void CSandMan::StoreState() theConf->SetBlob("MainWindow/Window_State", saveState()); //theConf->SetBlob("MainWindow/BoxTree_Columns", m_pBoxTree->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/Panel_Splitter", m_pPanelSplitter->saveState()); theConf->SetValue("MainWindow/LogTab", m_pLogTabs->currentIndex()); @@ -377,6 +379,7 @@ void CSandMan::CreateMenus() m_pCleanUpMenu->addSeparator(); 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_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->setCheckable(true); @@ -527,6 +530,22 @@ void CSandMan::CreateView() m_pTraceView->AddAction(m_pCleanUpTrace); 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() @@ -1389,6 +1408,23 @@ bool CSandMan::CheckCertificate() 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) { m_pPopUpWindow->AddUserPrompt(RequestId, Data, ClientPid); @@ -1456,14 +1492,14 @@ CRecoveryWindow* CSandMan::ShowRecovery(const CSandBoxPtr& pBox, bool bFind) return pBoxEx->m_pRecoveryWnd; } -SB_PROGRESS CSandMan::RecoverFiles(const QList>& FileList, int Action) +SB_PROGRESS CSandMan::RecoverFiles(const QString& BoxName, const QList>& FileList, int Action) { 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); } -void CSandMan::RecoverFilesAsync(const CSbieProgressPtr& pProgress, const QList>& FileList, int Action) +void CSandMan::RecoverFilesAsync(const CSbieProgressPtr& pProgress, const QString& BoxName, const QList>& FileList, int Action) { SB_STATUS Status = SB_OK; @@ -1506,6 +1542,13 @@ void CSandMan::RecoverFilesAsync(const CSbieProgressPtr& pProgress, const QList< if (!QFile::rename(BoxPath, RecoveryPath)) 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()) @@ -1528,6 +1571,17 @@ void CSandMan::RecoverFilesAsync(const CSbieProgressPtr& pProgress, const QList< 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()); +} + 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); @@ -1881,6 +1935,9 @@ void CSandMan::OnCleanUp() if (sender() == m_pCleanUpTrace || sender() == m_pCleanUpButton) m_pTraceView->Clear(); + + if (sender() == m_pCleanUpRecovery || sender() == m_pCleanUpButton) + m_pRecoveryLog->GetTree()->clear(); if (sender() == m_pCleanUpProcesses || sender() == m_pCleanUpButton) theAPI->UpdateProcesses(false, m_pShowAllSessions->isChecked()); @@ -2399,443 +2456,6 @@ QString CSandMan::GetVersion() 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(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("

Do you want to go to the info page?

").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("

There is a new version of Sandboxie-Plus available.
New version: %1

").arg(VersionStr) : UpdateMsg; - if (!DownloadUrl.isEmpty()) - FullMessage += tr("

Do you want to download the latest version?

"); - else if (!UpdateUrl.isEmpty()) - FullMessage += tr("

Do you want to go to the download page?

").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(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("

A Sandboxie-Plus update has been downloaded to the following location:

%1

Do you want to begin the installation? If any programs are running sandboxed, they will be terminated.

") - .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( - "

About Sandboxie-Plus

" - "

Version %1

" - "

Copyright (c) 2020-2022 by DavidXanatos

" - ).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.
" - "Visit sandboxie-plus.com for more information.
" - "
" - "%3
" - "
" - "Driver version: %1
" - "Features: %2
" - "
" - "Icons from icons8.com" - ).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(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() { m_ThemeUpdatePending = false; @@ -2953,234 +2573,7 @@ QT_TRANSLATE_NOOP("CSandBox", "Merging folders: %1 >> %2"), QT_TRANSLATE_NOOP("CSandBox", "Finishing Snapshot Merge..."), }; -////////////////////////////////////////////////////////////////////////////////////////// -// WinSpy based window finder -// -#include -#include "Helpers/FindTool.h" +#include "SandManUpdate.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(); - }); -} +#include "SbieFindWnd.cpp" diff --git a/SandboxiePlus/SandMan/SandMan.h b/SandboxiePlus/SandMan/SandMan.h index cbd00e99..3930a4e3 100644 --- a/SandboxiePlus/SandMan/SandMan.h +++ b/SandboxiePlus/SandMan/SandMan.h @@ -34,7 +34,7 @@ public: static QString GetVersion(); - SB_PROGRESS RecoverFiles(const QList>& FileList, int Action = 0); + SB_PROGRESS RecoverFiles(const QString& BoxName, const QList>& FileList, int Action = 0); enum EDelMode { eDefault, @@ -81,7 +81,7 @@ protected: SB_STATUS DisconnectSbie(); SB_RESULT(void*) StopSbie(bool andRemove = false); - static void RecoverFilesAsync(const CSbieProgressPtr& pProgress, const QList>& FileList, int Action = 0); + static void RecoverFilesAsync(const CSbieProgressPtr& pProgress, const QString& BoxName, const QList>& FileList, int Action = 0); QIcon GetTrayIcon(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 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); class CRecoveryWindow* ShowRecovery(const CSandBoxPtr& pBox, bool bFind = true); @@ -236,6 +237,7 @@ private: CPanelWidgetEx* m_pMessageLog; CTraceView* m_pTraceView; + CPanelWidgetEx* m_pRecoveryLog; QMenu* m_pMenuFile; @@ -272,6 +274,7 @@ private: QAction* m_pCleanUpProcesses; QAction* m_pCleanUpMsgLog; QAction* m_pCleanUpTrace; + QAction* m_pCleanUpRecovery; QToolButton* m_pCleanUpButton; QAction* m_pKeepTerminated; QAction* m_pShowAllSessions; diff --git a/SandboxiePlus/SandMan/SandMan.pri b/SandboxiePlus/SandMan/SandMan.pri index e4717035..7be3e23f 100644 --- a/SandboxiePlus/SandMan/SandMan.pri +++ b/SandboxiePlus/SandMan/SandMan.pri @@ -49,16 +49,6 @@ SOURCES += ./main.cpp \ ./Helpers/WindowFromPointEx.cpp \ ./Windows/NewBoxWindow.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/RecoveryWindow.cpp \ ./Windows/SettingsWindow.cpp \ diff --git a/SandboxiePlus/SandMan/SandMan.vcxproj b/SandboxiePlus/SandMan/SandMan.vcxproj index a0edcccf..7d748a3c 100644 --- a/SandboxiePlus/SandMan/SandMan.vcxproj +++ b/SandboxiePlus/SandMan/SandMan.vcxproj @@ -208,6 +208,18 @@ + + true + true + true + true + + + true + true + true + true + @@ -220,16 +232,66 @@ - - - - - - - - - - + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + diff --git a/SandboxiePlus/SandMan/SandMan.vcxproj.filters b/SandboxiePlus/SandMan/SandMan.vcxproj.filters index 6dba1fc7..285595b6 100644 --- a/SandboxiePlus/SandMan/SandMan.vcxproj.filters +++ b/SandboxiePlus/SandMan/SandMan.vcxproj.filters @@ -162,6 +162,12 @@ SandMan + + SandMan + + + SandMan + diff --git a/SandboxiePlus/SandMan/SandManUpdate.cpp b/SandboxiePlus/SandMan/SandManUpdate.cpp new file mode 100644 index 00000000..ef6a6f9a --- /dev/null +++ b/SandboxiePlus/SandMan/SandManUpdate.cpp @@ -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(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("

Do you want to go to the info page?

").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("

There is a new version of Sandboxie-Plus available.
New version: %1

").arg(VersionStr) : UpdateMsg; + if (!DownloadUrl.isEmpty()) + FullMessage += tr("

Do you want to download the latest version?

"); + else if (!UpdateUrl.isEmpty()) + FullMessage += tr("

Do you want to go to the download page?

").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(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("

A Sandboxie-Plus update has been downloaded to the following location:

%1

Do you want to begin the installation? If any programs are running sandboxed, they will be terminated.

") + .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( + "

About Sandboxie-Plus

" + "

Version %1

" + "

Copyright (c) 2020-2022 by DavidXanatos

" + ).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.
" + "Visit sandboxie-plus.com for more information.
" + "
" + "%3
" + "
" + "Driver version: %1
" + "Features: %2
" + "
" + "Icons from icons8.com" + ).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(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; + } +} \ No newline at end of file diff --git a/SandboxiePlus/SandMan/SbieFindWnd.cpp b/SandboxiePlus/SandMan/SbieFindWnd.cpp new file mode 100644 index 00000000..a8ff7f37 --- /dev/null +++ b/SandboxiePlus/SandMan/SbieFindWnd.cpp @@ -0,0 +1,232 @@ + +////////////////////////////////////////////////////////////////////////////////////////// +// WinSpy based window finder +// + +#include +#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(); + }); +} diff --git a/SandboxiePlus/SandMan/Views/SbieView.cpp b/SandboxiePlus/SandMan/Views/SbieView.cpp index 07bf3789..d033ec11 100644 --- a/SandboxiePlus/SandMan/Views/SbieView.cpp +++ b/SandboxiePlus/SandMan/Views/SbieView.cpp @@ -314,8 +314,10 @@ void CSbieView::Refresh() } if (!Added.isEmpty()) { - foreach(const QVariant &ID, Added) - m_Groups[""].append(ID.toString()); + foreach(const QVariant& ID, Added) { + if(ID.type() == QVariant::String) + m_Groups[""].append(ID.toString()); + } QString Grouping = CSbieView__SerializeGroup(m_Groups); theAPI->GetUserSettings()->SetText("BoxDisplayOrder", Grouping); diff --git a/SandboxiePlus/SandMan/Windows/FileBrowserWindow.cpp b/SandboxiePlus/SandMan/Windows/FileBrowserWindow.cpp index b2dcdbd8..cda11636 100644 --- a/SandboxiePlus/SandMan/Windows/FileBrowserWindow.cpp +++ b/SandboxiePlus/SandMan/Windows/FileBrowserWindow.cpp @@ -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) theGUI->AddAsyncOp(Status.GetValue()); diff --git a/SandboxiePlus/SandMan/Windows/OptionsAdvanced.cpp b/SandboxiePlus/SandMan/Windows/OptionsAdvanced.cpp index e82d6ce9..c3632020 100644 --- a/SandboxiePlus/SandMan/Windows/OptionsAdvanced.cpp +++ b/SandboxiePlus/SandMan/Windows/OptionsAdvanced.cpp @@ -69,7 +69,7 @@ void COptionsWindow::CreateAdvanced() void COptionsWindow::LoadAdvanced() { ui.chkPreferExternalManifest->setChecked(m_pBox->GetBool("PreferExternalManifest", false)); - ui.chkNestedJobs->setChecked(m_pBox->GetBool("AllowBoxedJobs", true)); + ui.chkNestedJobs->setChecked(m_pBox->GetBool("AllowBoxedJobs", false)); ui.chkUseSbieWndStation->setChecked(m_pBox->GetBool("UseSbieWndStation", true)); ui.chkAddToJob->setChecked(!m_pBox->GetBool("NoAddProcessToJob", false)); @@ -179,7 +179,7 @@ void COptionsWindow::SaveAdvanced() WriteAdvancedCheck(ui.chkAddToJob, "NoAddProcessToJob", "", "y"); WriteAdvancedCheck(ui.chkProtectSCM, "UnrestrictedSCM", "", "y"); - WriteAdvancedCheck(ui.chkNestedJobs, "AllowBoxedJobs", "", "n"); + WriteAdvancedCheck(ui.chkNestedJobs, "AllowBoxedJobs", "y", ""); WriteAdvancedCheck(ui.chkRestrictServices, "RunServicesAsSystem", "", "y"); WriteAdvancedCheck(ui.chkElevateRpcss, "RunRpcssAsSystem", "y", ""); WriteAdvancedCheck(ui.chkProtectSystem, "ExposeBoxedSystem", "", "y"); diff --git a/SandboxiePlus/SandMan/Windows/OptionsWindow.cpp b/SandboxiePlus/SandMan/Windows/OptionsWindow.cpp index 1cfe5324..8029131c 100644 --- a/SandboxiePlus/SandMan/Windows/OptionsWindow.cpp +++ b/SandboxiePlus/SandMan/Windows/OptionsWindow.cpp @@ -799,6 +799,16 @@ void COptionsWindow::SaveIniSection() 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 diff --git a/SandboxiePlus/SandMan/Windows/PopUpWindow.cpp b/SandboxiePlus/SandMan/Windows/PopUpWindow.cpp index cfe6f92d..d49ccc73 100644 --- a/SandboxiePlus/SandMan/Windows/PopUpWindow.cpp +++ b/SandboxiePlus/SandMan/Windows/PopUpWindow.cpp @@ -380,7 +380,7 @@ void CPopUpWindow::OnRecoverFile(int Action) QList> FileList; 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) theGUI->AddAsyncOp(Status.GetValue()); diff --git a/SandboxiePlus/SandMan/Windows/RecoveryWindow.cpp b/SandboxiePlus/SandMan/Windows/RecoveryWindow.cpp index 0542f4f6..4c730cbf 100644 --- a/SandboxiePlus/SandMan/Windows/RecoveryWindow.cpp +++ b/SandboxiePlus/SandMan/Windows/RecoveryWindow.cpp @@ -481,7 +481,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) { connect(Status.GetValue().data(), SIGNAL(Finished()), this, SLOT(FindFiles())); diff --git a/SandboxiePlus/version.h b/SandboxiePlus/version.h index 643e9735..f8ccff3e 100644 --- a/SandboxiePlus/version.h +++ b/SandboxiePlus/version.h @@ -2,7 +2,7 @@ #define VERSION_MJR 1 #define VERSION_MIN 1 -#define VERSION_REV 1 +#define VERSION_REV 2 #define VERSION_UPD 0 #ifndef STR