fix: hardening of INI file handling for multi instances workflows

This commit is contained in:
METANEOCORTEX\Kotti 2026-05-04 20:36:06 +02:00
parent 78108398fd
commit 1bf01cd41a
3 changed files with 64 additions and 0 deletions

View File

@ -251,6 +251,48 @@ bool ReleaseFileLock(HANDLE hFile, OVERLAPPED& rOvrLpd)
return bUnLocked;
}
// ============================================================================
//
// Cross-instance INI save serialization
//
static HANDLE s_hMtxIniFileSave = NULL;
static unsigned long _HashIniPath(LPCWSTR path)
{
unsigned long hash = 5381;
for (; *path; ++path) {
WCHAR ch = *path;
if (ch >= L'A' && ch <= L'Z') { ch += 32; }
if (ch == L'/') { ch = L'\\'; }
hash = ((hash << 5) + hash) ^ (unsigned long)ch;
}
return hash;
}
extern "C" void InitIniFileSaveMutex(void)
{
if (Path_IsEmpty(Paths.IniFile)) {
return;
}
if (IS_VALID_HANDLE(s_hMtxIniFileSave)) {
CloseHandle(s_hMtxIniFileSave);
s_hMtxIniFileSave = NULL;
}
WCHAR szMutexName[80];
unsigned long const hash = _HashIniPath(Path_Get(Paths.IniFile));
StringCchPrintfW(szMutexName, COUNTOF(szMutexName),
L"Local\\Notepad3_INI_%08lX", hash);
s_hMtxIniFileSave = CreateMutexW(NULL, FALSE, szMutexName);
}
extern "C" void CloseIniFileSaveMutex(void)
{
if (IS_VALID_HANDLE(s_hMtxIniFileSave)) {
CloseHandle(s_hMtxIniFileSave);
s_hMtxIniFileSave = NULL;
}
}
// ============================================================================
static CSimpleIni s_TMPINI(s_bIsUTF8, s_bUseMultiKey, s_bUseMultiLine);
@ -2437,6 +2479,15 @@ bool SaveAllSettings(bool bForceSaveSettings)
return false;
}
// Cross-instance serialization: acquire mutex so only one instance
// performs the load-modify-save cycle at a time.
DWORD dwMtxWait = WAIT_OBJECT_0;
if (IS_VALID_HANDLE(s_hMtxIniFileSave)) {
dwMtxWait = WaitForSingleObject(s_hMtxIniFileSave, 10000);
}
// Force fresh reload from disk to pick up changes from other instances
ResetIniFileCache();
WCHAR tchMsg[80];
GetLngString(IDS_MUI_SAVINGSETTINGS, tchMsg, COUNTOF(tchMsg));
@ -2489,6 +2540,13 @@ bool SaveAllSettings(bool bForceSaveSettings)
Globals.bIniFileFromScratch = false; // INI has content now
// Release cross-instance save mutex (INI is flushed to disk)
if (IS_VALID_HANDLE(s_hMtxIniFileSave)) {
if (dwMtxWait == WAIT_OBJECT_0 || dwMtxWait == WAIT_ABANDONED) {
ReleaseMutex(s_hMtxIniFileSave);
}
}
// maybe separate INI files for Style-Themes
if (Globals.uCurrentThemeIndex > 0) {
Style_SaveSettings(bForceSaveSettings);

View File

@ -36,6 +36,9 @@ bool SaveWindowPositionSettings(bool bClearSettings);
bool SaveAllSettings(bool bForceSaveSettings);
void CmdSaveSettingsNow();
void InitIniFileSaveMutex(void);
void CloseIniFileSaveMutex(void);
bool OpenSettingsFile(LPCSTR fctname);
bool CloseSettingsFile(LPCSTR fctname, bool bSaveSettings);

View File

@ -1149,6 +1149,8 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
}
LoadSettings();
InitIniFileSaveMutex();
PrivateSetCurrentProcessExplicitAppUserModelID(Settings2.AppUserModelID);
(void)CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_SPEED_OVER_MEMORY);
@ -3385,6 +3387,7 @@ LRESULT MsgEndSession(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam)
// call SaveAllSettings() when Globals.hwndToolbar is still valid
SaveAllSettings(false);
CloseIniFileSaveMutex();
// Remove tray icon in any case
ShowNotifyIcon(hwnd, false);