Add Win10+ OS Restart-app feature

It will allow for the Notepad++ to be a "restartable app", like some other SW can do today (eg Google Chrome, Mozilla Firefox or all the Microsoft UWP apps).

This is to create a seamless experience wherein, if you have to reboot your PC, you can now pick back up from where you left off and resume being productive.

The OS app-restart feature needs at least Windows 10 (20H1) and the user has to switch on the "Restart apps" in the system Settings (subsection Accounts > Sign-in options).

Implemented as per previous discussion: https://github.com/notepad-plus-plus/notepad-plus-plus/issues/12541#issuecomment-1332662024

To disable this feature, add "noRestartAutomatically.xml" into "%APPDATA%\Notepad++\" or Notepad++ installation directory.

Fix #9722, fix #11721, fix #11934, close #14074
pull/14171/head
xomx 1 year ago committed by Don Ho
parent 39001d7a02
commit 87efdf5084

@ -18,6 +18,7 @@
#include <algorithm> #include <algorithm>
#include <shlwapi.h> #include <shlwapi.h>
#include <uxtheme.h> // for EnableThemeDialogTexture #include <uxtheme.h> // for EnableThemeDialogTexture
#include <format>
#include "Notepad_plus_Window.h" #include "Notepad_plus_Window.h"
#include "TaskListDlg.h" #include "TaskListDlg.h"
#include "ImageListSet.h" #include "ImageListSet.h"
@ -57,6 +58,114 @@ struct SortTaskListPred final
} }
}; };
// app-restart feature needs Win10 20H1+ (builds 18963+), but it was quietly introduced earlier in the Fall Creators Update (b1709+)
bool SetOSAppRestart()
{
NppParameters& nppParam = NppParameters::getInstance();
if (nppParam.getWinVersion() < WV_WIN10)
return false; // unsupported
bool bRet = false;
bool bUnregister = nppParam.isRegForOSAppRestartDisabled();
generic_string nppIssueLog;
if (nppParam.doNppLogNulContentCorruptionIssue())
{
generic_string issueFn = nppLogNulContentCorruptionIssue;
issueFn += TEXT(".log");
nppIssueLog = nppParam.getUserPath();
pathAppend(nppIssueLog, issueFn);
}
WCHAR wszCmdLine[RESTART_MAX_CMD_LINE] = { 0 };
DWORD cchCmdLine = _countof(wszCmdLine);
DWORD dwPreviousFlags = 0;
HRESULT hr = ::GetApplicationRestartSettings(::GetCurrentProcess(), wszCmdLine, &cchCmdLine, &dwPreviousFlags);
if (bUnregister)
{
// unregistering (disabling) request
if (hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND))
{
// has not been registered before, nothing to do here
bRet = true;
}
else
{
if (hr == S_OK)
{
// has been already registered before, try to unregister
if (::UnregisterApplicationRestart() == S_OK)
{
bRet = true;
}
else
{
if (nppParam.doNppLogNulContentCorruptionIssue())
{
std::string msg = "ERROR: UnregisterApplicationRestart WINAPI failed! (HRESULT: ";
msg += std::format("{:#010x}", hr);
msg += ")";
writeLog(nppIssueLog.c_str(), msg.c_str());
}
}
}
else
{
if (nppParam.doNppLogNulContentCorruptionIssue())
{
std::string msg = "ERROR: GetApplicationRestartSettings WINAPI failed! (HRESULT: ";
msg += std::format("{:#010x}", hr);
msg += ")";
writeLog(nppIssueLog.c_str(), msg.c_str());
}
}
}
}
else
{
// registering request
if (hr == S_OK)
::UnregisterApplicationRestart(); // remove a previous registration 1st
if (nppParam.getCmdLineString().length() >= RESTART_MAX_CMD_LINE)
{
if (nppParam.doNppLogNulContentCorruptionIssue())
{
std::string msg = "WARNING: Skipping the RegisterApplicationRestart WINAPI call because of the cmdline length exceeds the RESTART_MAX_CMD_LINE! \n(current cmdline length: ";
msg += std::to_string(nppParam.getCmdLineString().length());
msg += " chars)";
writeLog(nppIssueLog.c_str(), msg.c_str());
}
}
else
{
// do not restart the process:
// RESTART_NO_CRASH (1) ... for termination due to application crashes
// RESTART_NO_HANG (2) ... for termination due to application hangs
// RESTART_NO_PATCH (4) ... for termination due to patch installations
// RESTART_NO_REBOOT (8) ... when the system is rebooted
hr = ::RegisterApplicationRestart(nppParam.getCmdLineString().c_str(), RESTART_NO_CRASH | RESTART_NO_HANG | RESTART_NO_PATCH);
if (hr == S_OK)
{
bRet = true;
}
else
{
if (nppParam.doNppLogNulContentCorruptionIssue())
{
std::string msg = "ERROR: RegisterApplicationRestart WINAPI failed! (HRESULT: ";
msg += std::format("{:#010x}", hr);
msg += ")";
writeLog(nppIssueLog.c_str(), msg.c_str());
}
}
}
}
return bRet;
}
LRESULT CALLBACK Notepad_plus_Window::Notepad_plus_Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) LRESULT CALLBACK Notepad_plus_Window::Notepad_plus_Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{ {
@ -115,6 +224,8 @@ LRESULT Notepad_plus_Window::runProc(HWND hwnd, UINT message, WPARAM wParam, LPA
SWP_FRAMECHANGED); SWP_FRAMECHANGED);
} }
SetOSAppRestart();
return lRet; return lRet;
} }
catch (std::exception& ex) catch (std::exception& ex)
@ -2303,10 +2414,8 @@ LRESULT Notepad_plus::process(HWND hwnd, UINT message, WPARAM wParam, LPARAM lPa
} }
} }
// TODO: here is the last opportunity to call the following WINAPI in a possible future version of the Notepad++ // NOTE: This should be the last possible place to eventually register Notepad++ for the app-restart OS feature,
// // but unfortunately it doesn't work here.
// flags RESTART_NO_PATCH and RESTART_NO_REBOOT are not set, so we should be restarted if terminated by an update or restart
//::RegisterApplicationRestart(restartCommandLine.c_str(), RESTART_NO_CRASH | RESTART_NO_HANG);
return TRUE; // nowadays, with the monstrous Win10+ Windows Update behind, is futile to try to interrupt the shutdown by returning FALSE here return TRUE; // nowadays, with the monstrous Win10+ Windows Update behind, is futile to try to interrupt the shutdown by returning FALSE here
// (if one really needs so, there is the ShutdownBlockReasonCreate WINAPI for the rescue ...) // (if one really needs so, there is the ShutdownBlockReasonCreate WINAPI for the rescue ...)

@ -1604,8 +1604,22 @@ bool NppParameters::load()
_doNppLogNulContentCorruptionIssue = (PathFileExists(filePath2.c_str()) == TRUE); _doNppLogNulContentCorruptionIssue = (PathFileExists(filePath2.c_str()) == TRUE);
} }
//-------------------------------------------------------------//
// noRestartAutomatically.xml //
// This empty xml file is optional - user adds this empty file //
// manually in order to prevent Notepad++ registration //
// for the Win10+ OS app-restart feature. //
//-------------------------------------------------------------//
filePath = _nppPath;
std::wstring noRegForOSAppRestartTrigger = L"noRestartAutomatically.xml";
pathAppend(filePath, noRegForOSAppRestartTrigger);
_isRegForOSAppRestartDisabled = (::PathFileExists(filePath.c_str()) == TRUE);
if (!_isRegForOSAppRestartDisabled)
{
filePath = _userPath;
pathAppend(filePath, noRegForOSAppRestartTrigger);
_isRegForOSAppRestartDisabled = (::PathFileExists(filePath.c_str()) == TRUE);
}
return isAllLaoded; return isAllLaoded;
} }

@ -283,6 +283,7 @@ struct CmdLineParamsDTO
bool _isRecursive = false; bool _isRecursive = false;
bool _openFoldersAsWorkspace = false; bool _openFoldersAsWorkspace = false;
bool _monitorFiles = false; bool _monitorFiles = false;
bool _isRestartedByOS = false;
intptr_t _line2go = 0; intptr_t _line2go = 0;
intptr_t _column2go = 0; intptr_t _column2go = 0;
@ -851,6 +852,7 @@ struct NppGUI final
std::wstring _definedSessionExt; std::wstring _definedSessionExt;
std::wstring _definedWorkspaceExt; std::wstring _definedWorkspaceExt;
// items with no Notepad++ GUI to set
std::wstring _commandLineInterpreter = CMD_INTERPRETER; std::wstring _commandLineInterpreter = CMD_INTERPRETER;
struct AutoUpdateOptions struct AutoUpdateOptions
@ -1863,6 +1865,7 @@ public:
bool isAdmin() const { return _isAdminMode; } bool isAdmin() const { return _isAdminMode; }
bool regexBackward4PowerUser() const { return _findHistory._regexBackward4PowerUser; } bool regexBackward4PowerUser() const { return _findHistory._regexBackward4PowerUser; }
bool isSelectFgColorEnabled() const { return _isSelectFgColorEnabled; }; bool isSelectFgColorEnabled() const { return _isSelectFgColorEnabled; };
bool isRegForOSAppRestartDisabled() const { return _isRegForOSAppRestartDisabled; };
private: private:
bool _isAnyShortcutModified = false; bool _isAnyShortcutModified = false;
@ -1929,6 +1932,7 @@ private:
bool _isAdminMode = false; bool _isAdminMode = false;
bool _isSelectFgColorEnabled = false; bool _isSelectFgColorEnabled = false;
bool _isRegForOSAppRestartDisabled = false;
bool _doNppLogNetworkDriveIssue = false; bool _doNppLogNetworkDriveIssue = false;

Loading…
Cancel
Save