From 2eb023b09996d4965bf5fc3fd44dc9e423169f6b Mon Sep 17 00:00:00 2001 From: "METANEOCORTEX\\Kotti" Date: Thu, 16 Mar 2023 00:42:00 +0100 Subject: [PATCH] +fix: reactivate FileChangeInterval (used on dir changed notification too) +chg: refactoring: use background worker helper --- src/Config/Config.cpp | 7 +- src/Dialogs.c | 10 +- src/Dlapi.c | 9 +- src/Dlapi.h | 2 +- src/DynStrg.c | 57 +++++++----- src/Helpers.c | 69 ++++++++------ src/Helpers.h | 19 ++-- src/Notepad3.c | 210 +++++++++++++++++------------------------- src/TypeDefs.h | 26 ++++++ 9 files changed, 212 insertions(+), 197 deletions(-) diff --git a/src/Config/Config.cpp b/src/Config/Config.cpp index cd464accc..f6eaaed39 100644 --- a/src/Config/Config.cpp +++ b/src/Config/Config.cpp @@ -1245,10 +1245,10 @@ void LoadSettings() // handle deprecated (typo) key 'FileCheckInverval' int const dfci = IniSectionGetInt(IniSecSettings2, L"FileCheckInverval", 0); - Settings2.FileCheckInterval = clampul(IniSectionGetInt(IniSecSettings2, L"FileCheckInterval", dfci), 0, 86400000 << 2); // max: 48h + Settings2.FileCheckInterval = clampul(IniSectionGetInt(IniSecSettings2, L"FileCheckInterval", dfci), 0UL, (24UL*60*60*1000) << 1); // max: 48h // handle deprecated old "AutoReloadTimeout" - int const autoReload = IniSectionGetInt(IniSecSettings2, L"AutoReloadTimeout", -1); // deprecated - unsigned int const fci = max_u(250, (autoReload > 0) ? max_u(autoReload, Settings2.FileCheckInterval) : Settings2.FileCheckInterval); + int const autoReload = IniSectionGetInt(IniSecSettings2, L"AutoReloadTimeout", -1); // deprecated + unsigned int const fci = (autoReload > 0) ? max_u(autoReload, Settings2.FileCheckInterval) : Settings2.FileCheckInterval; if (((Settings2.FileCheckInterval > 0) && (fci != Settings2.FileCheckInterval)) || (dfci != 0)) { Settings2.FileCheckInterval = fci; IniSectionSetInt(IniSecSettings2, L"FileCheckInterval", Settings2.FileCheckInterval); @@ -1257,6 +1257,7 @@ void LoadSettings() } bDirtyFlag = true; } + Settings2.FileCheckInterval = clampul(Settings2.FileCheckInterval, 120UL, (24UL*60*60*1000) << 1); // min: 120msec max: 48h FileWatching.FileCheckInterval = Settings2.FileCheckInterval; IniSectionGetString(IniSecSettings2, L"FileChangedIndicator", L"[@]", Settings2.FileChangedIndicator, COUNTOF(Settings2.FileChangedIndicator)); diff --git a/src/Dialogs.c b/src/Dialogs.c index aef02281f..58a6f008f 100644 --- a/src/Dialogs.c +++ b/src/Dialogs.c @@ -2163,7 +2163,7 @@ bool AddToFavDlg(HWND hwnd, const HPATHL hTargetPth) // FileMRUDlgProc() // // -unsigned int WINAPI FileMRUIconThread(LPVOID lpParam) +unsigned int WINAPIV FileMRUIconThread(LPVOID lpParam) { BackgroundWorker *worker = (BackgroundWorker *)lpParam; @@ -2236,7 +2236,7 @@ unsigned int WINAPI FileMRUIconThread(LPVOID lpParam) } CoUninitialize(); - BackgroundWorker_End(0); + BackgroundWorker_End(worker, 0); return 0; } @@ -2245,7 +2245,7 @@ static INT_PTR CALLBACK FileMRUDlgProc(HWND hwnd, UINT umsg, WPARAM wParam, LPAR { static HWND hwndLV = NULL; static HPATHL hFilePath = NULL; - + switch (umsg) { case WM_INITDIALOG: { SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)lParam); @@ -2331,9 +2331,9 @@ static INT_PTR CALLBACK FileMRUDlgProc(HWND hwnd, UINT umsg, WPARAM wParam, LPAR Settings.SaveFindReplace = IsButtonChecked(hwnd, IDC_REMEMBERSEARCHPATTERN); Settings.AutoLoadMRUFile = IsButtonChecked(hwnd, IDC_AUTOLOAD_MRU_FILE); - Path_Release(hFilePath); - ResizeDlg_Destroy(hwnd, &Settings.FileMRUDlgSizeX, &Settings.FileMRUDlgSizeY); + + Path_Release(hFilePath); } return FALSE; diff --git a/src/Dlapi.c b/src/Dlapi.c index a27439fde..c1b84569b 100644 --- a/src/Dlapi.c +++ b/src/Dlapi.c @@ -55,7 +55,7 @@ static const WCHAR *pDirListProp = L"DirListData"; // // Initializes the DLDATA structure and sets up the listview control // -bool DirList_Init(HWND hwnd,LPCWSTR pszHeader, HPATHL hFilePath) +bool DirList_Init(HWND hwnd,LPCWSTR pszHeader, const HPATHL hFilePath) { UNREFERENCED_PARAMETER(pszHeader); @@ -68,7 +68,7 @@ bool DirList_Init(HWND hwnd,LPCWSTR pszHeader, HPATHL hFilePath) lpdl->cbidl = 0; lpdl->pidl = NULL; lpdl->lpsf = NULL; - lpdl->hDirectoryPath = hFilePath; + lpdl->hDirectoryPath = Path_Copy(hFilePath); Path_Empty(lpdl->hDirectoryPath, false); // Add Imagelists @@ -120,6 +120,7 @@ bool DirList_Destroy(HWND hwnd) } // Free DirListData Property RemoveProp(hwnd,pDirListProp); + Path_Release(lpdl->hDirectoryPath); GlobalFree(lpdl); return false; @@ -333,7 +334,7 @@ int DirList_Fill(HWND hwnd,LPCWSTR lpszDir,DWORD grfFlags,LPCWSTR lpszFileSpec, // // Thread to extract file icons in the background // -unsigned int WINAPI DirList_IconThread(LPVOID lpParam) +unsigned int WINAPIV DirList_IconThread(LPVOID lpParam) { LPDLDATA lpdl = (LPDLDATA)lpParam; BackgroundWorker *worker = &lpdl->worker; @@ -432,7 +433,7 @@ unsigned int WINAPI DirList_IconThread(LPVOID lpParam) } CoUninitialize(); - BackgroundWorker_End(0); + BackgroundWorker_End(worker, 0); return 0; } diff --git a/src/Dlapi.h b/src/Dlapi.h index 9ec5a59e8..1ecd302b2 100644 --- a/src/Dlapi.h +++ b/src/Dlapi.h @@ -36,7 +36,7 @@ typedef struct tagLV_ITEMDATA { // lvid //==== DlInit() =============================================================== -bool DirList_Init(HWND hwnd, LPCWSTR pszHeader, HPATHL hFilePath); +bool DirList_Init(HWND hwnd, LPCWSTR pszHeader, const HPATHL hFilePath); //==== DlDestroy() ============================================================ diff --git a/src/DynStrg.c b/src/DynStrg.c index 543e03fc7..ff5ec354b 100644 --- a/src/DynStrg.c +++ b/src/DynStrg.c @@ -33,6 +33,8 @@ #define STRINGW_MAX_CCH STRSAFE_MAX_CCH +const wchar_t WCHR_NULL = L'\0'; + typedef struct tagSTRINGW { LPWSTR data; @@ -156,8 +158,8 @@ static void ReAllocW(STRINGW* pstr, size_t len, bool bZeroMem) pstr->alloc_length = LengthOfBuffer(pstr->data); assert("inconsistent data" && (alloc_len != (pstr->alloc_length * sizeof(wchar_t)))); pstr->data_length = 0; - pstr->data[len] = L'\0'; // ensure terminating zero - pstr->data[0] = L'\0'; // ensure empty + pstr->data[len] = WCHR_NULL; // ensure terminating zero + pstr->data[0] = WCHR_NULL; // ensure empty } else { pstr->alloc_length = 0; @@ -170,7 +172,7 @@ static void ReAllocW(STRINGW* pstr, size_t len, bool bZeroMem) assert("inconsistent data 1" && (alloc_len != (pstr->alloc_length * sizeof(wchar_t)))); /// original memory block is moved, so data_length is not touched assert("inconsistent data 2" && (alloc_len > pstr->data_length)); - pstr->data[pstr->data_length] = L'\0'; // ensure terminating zero + pstr->data[pstr->data_length] = WCHR_NULL; // ensure terminating zero } else { if (bZeroMem) { @@ -257,6 +259,8 @@ static void ConcatW(STRINGW* pstr, size_t len, LPCWSTR p) } // ---------------------------------------------------------------------------- +#pragma warning(push) +#pragma warning(disable : 6269) static void FormatW(STRINGW* pstr, LPCWSTR fmt, va_list args) { @@ -265,7 +269,7 @@ static void FormatW(STRINGW* pstr, LPCWSTR fmt, va_list args) size_t max_len = 0; LPCWSTR p; - for (p = fmt; *p != L'\0'; p = _wcsinc(p)) { + for (p = fmt; *p != WCHR_NULL; p = _wcsinc(p)) { size_t item_len = 0, width = 0, prec = 0, modif = 0; if (*p != L'%' || *(p = _wcsinc(p)) == L'%') { ++max_len; @@ -273,7 +277,7 @@ static void FormatW(STRINGW* pstr, LPCWSTR fmt, va_list args) } item_len = 0; width = 0; - for (; *p != L'\0'; p = _wcsinc(p)) { + for (; *p != WCHR_NULL; p = _wcsinc(p)) { if (*p == L'#') max_len += 2; /* L'0x'*/ else if (*p == L'*') @@ -286,7 +290,7 @@ static void FormatW(STRINGW* pstr, LPCWSTR fmt, va_list args) } if (width == 0) { width = _wtoi(p); - for (; *p != L'\0' && isdigit(*p); p = _wcsinc(p)) + for (; *p != WCHR_NULL && isdigit(*p); p = _wcsinc(p)) ; } assert("negative width" && (width >= 0)); @@ -300,7 +304,7 @@ static void FormatW(STRINGW* pstr, LPCWSTR fmt, va_list args) p = _wcsinc(p); } else { prec = _ttoi(p); - for (; *p != L'\0' && isdigit(*p); p = _wcsinc(p)) + for (; *p != WCHR_NULL && isdigit(*p); p = _wcsinc(p)) ; } assert("negative prec" && (prec >= 0)); @@ -413,6 +417,7 @@ static void FormatW(STRINGW* pstr, LPCWSTR fmt, va_list args) va_end(orig_list); } +#pragma warning(pop) // ---------------------------------------------------------------------------- @@ -475,7 +480,7 @@ int STRAPI StrgIsEmpty(const HSTRINGW hstr) if (!pstr) return !0; - int const res = (!pstr->data || ((pstr->data)[0] == L'\0')) ? !0 : 0; + int const res = (!pstr->data || ((pstr->data)[0] == WCHR_NULL)) ? !0 : 0; assert("inconsistent data" && (pstr->data_length != (size_t)res)); return res; @@ -532,7 +537,7 @@ void STRAPI StrgEmpty(const HSTRINGW hstr, bool truncate) ReAllocW(pstr, 0, true); return; } - (pstr->data)[0] = L'\0'; + (pstr->data)[0] = WCHR_NULL; pstr->data_length = 0; if (truncate) { FreeUnusedData(pstr, 0); @@ -546,7 +551,7 @@ void STRAPI StrgSetAt(HSTRINGW hstr, const size_t index, const wchar_t ch) STRINGW* pstr = ToWStrg(hstr); if (!pstr) return; - if (!pstr->data) { + if (!(pstr->data)) { ReAllocW(pstr, 0, true); } if (index >= pstr->data_length) @@ -554,7 +559,8 @@ void STRAPI StrgSetAt(HSTRINGW hstr, const size_t index, const wchar_t ch) assert("buffer too small" && 0); return; } - pstr->data[index] = ch; + if (pstr->data) + (pstr->data)[index] = ch; } // ---------------------------------------------------------------------------- @@ -563,16 +569,16 @@ wchar_t STRAPI StrgGetAt(const HSTRINGW hstr, const size_t index) { STRINGW* pstr = ToWStrg(hstr); if (!pstr) - return L'\0'; + return WCHR_NULL; if (!pstr->data) { ReAllocW(pstr, 0, true); } if (index >= pstr->data_length) { assert("buffer too small" && 0); - return L'\0'; + return WCHR_NULL; } - return pstr->data[index]; + return (pstr->data) ? pstr->data[index] : WCHR_NULL; } // ---------------------------------------------------------------------------- @@ -669,7 +675,8 @@ size_t STRAPI StrgInsertCh(HSTRINGW hstr, size_t index, const wchar_t c) } wmemmove_s((pstr->data + index + 1), (pstr->alloc_length - index - 1), (pstr->data + index), (new_len - index)); - pstr->data[index] = c; + if (pstr->data) + pstr->data[index] = c; pstr->data_length = StrlenW(pstr->data); return new_len; } @@ -724,7 +731,7 @@ size_t STRAPI StrgReplace(HSTRINGW hstr, LPCWSTR pOld, LPCWSTR pNew) wmemmove_s(target + repl_len, (pstr->alloc_length - (target - pstr->data) - repl_len), target + src_len, bal); wmemcpy_s(target, (pstr->alloc_length - (target - pstr->data)), pNew, repl_len); start = target + repl_len; - start[bal] = L'\0'; + start[bal] = WCHR_NULL; old_len += (repl_len - src_len); } start += wcslen(start) + 1; @@ -796,7 +803,8 @@ size_t STRAPI StrgRemoveCh(HSTRINGW hstr, const wchar_t chRemove) } source++; } - *dest = L'\0'; + if (dest) + *dest = WCHR_NULL; count = (int)(ptrdiff_t)(source - dest); pstr->data_length -= count; @@ -857,7 +865,8 @@ void STRAPI StrgToUpper(HSTRINGW hstr) if (!pstr->data) { ReAllocW(pstr, 0, true); } - _wcsupr_s(pstr->data, pstr->data_length); + if (pstr->data) + _wcsupr_s(pstr->data, pstr->data_length); } // ---------------------------------------------------------------------------- @@ -870,7 +879,8 @@ void STRAPI StrgToLower(HSTRINGW hstr) if (!pstr->data) { ReAllocW(pstr, 0, true); } - _wcslwr_s(pstr->data, pstr->data_length); + if (pstr->data) + _wcslwr_s(pstr->data, pstr->data_length); } // ---------------------------------------------------------------------------- @@ -900,7 +910,7 @@ void STRAPI StrgTrimRight(HSTRINGW hstr, const wchar_t wch) LPWSTR start = pstr->data; LPWSTR end = NULL; - while (*start != L'\0') + while (start && (*start != WCHR_NULL)) { if (isspace(*start) || (wch ? (*start == wch) : 0)) { @@ -914,7 +924,7 @@ void STRAPI StrgTrimRight(HSTRINGW hstr, const wchar_t wch) if (end != NULL) { - *end = L'\0'; + *end = WCHR_NULL; pstr->data_length = end - pstr->data; } } @@ -932,7 +942,7 @@ void STRAPI StrgTrimLeft(HSTRINGW hstr, const wchar_t wch) LPWSTR start = pstr->data; - while (isspace(*start) || (wch ? (*start == wch) : 0)) + while (start && (isspace(*start) || (wch ? (*start == wch) : 0))) start++; if (start != pstr->data) @@ -1123,7 +1133,8 @@ void STRAPI StrgSanitize(HSTRINGW hstr) pstr->alloc_length = LengthOfBuffer(pstr->data); ptrdiff_t const end = (ptrdiff_t)pstr->alloc_length - 1; if (end >= 0) { - pstr->data[end] = L'\0'; // terminating zero + if (pstr->data) + pstr->data[end] = WCHR_NULL; // terminating zero } pstr->data_length = StrlenW(pstr->data); } diff --git a/src/Helpers.c b/src/Helpers.c index 456009ffa..31178956f 100644 --- a/src/Helpers.c +++ b/src/Helpers.c @@ -552,51 +552,68 @@ bool IsRunAsAdmin() //============================================================================= -void BackgroundWorker_Init(BackgroundWorker* worker, HWND hwnd, HPATHL hFilePath) +void BackgroundWorker_Init(BackgroundWorker* worker, HWND hwnd, const HPATHL hFilePath) { - worker->hwnd = hwnd; - worker->eventCancel = CreateEvent(NULL, TRUE, FALSE, NULL); - worker->workerThread = NULL; - worker->hFilePath = hFilePath; + if (worker) { + worker->hwnd = hwnd; + // manual (not automatic) reset & initial state: not signaled (TRUE, FALSE) + worker->eventCancel = CreateEvent(NULL, TRUE, FALSE, NULL); + worker->workerThread = INVALID_HANDLE_VALUE; + worker->hFilePath = Path_Allocate(Path_Get(hFilePath)); + } } void BackgroundWorker_Start(BackgroundWorker* worker, _beginthreadex_proc_type routine, LPVOID property) { - //~worker->workerThread = CreateThread(NULL, 0, routine, property, 0, NULL); // MD(d) dll - worker->workerThread = (HANDLE)_beginthreadex(NULL, 0, routine, property, 0, NULL); // MT(d) static + if (worker) { + ResetEvent(worker->eventCancel); // init should be 'not signaled' + //~worker->workerThread = CreateThread(NULL, 0, routine, property, 0, NULL); // MD(d) dll + uintptr_t const thread = _beginthreadex(NULL, 0, routine, property, 0, NULL); // MT(d) static + worker->workerThread = (thread != 0LL) ? (HANDLE)thread : INVALID_HANDLE_VALUE; + } } -void BackgroundWorker_End(unsigned int retcode) +// inline void BackgroundWorker_End(BackgroundWorker* worker, unsigned int retcode); + +static void _BckgrdWrkr_Stop(BackgroundWorker* worker) { - _endthreadex(retcode); -} - -static void _BackgroundWorker_Stop(BackgroundWorker* worker) { - SetEvent(worker->eventCancel); - HANDLE const workerThread = worker->workerThread; - if (workerThread) { - worker->workerThread = NULL; - while (WaitForSingleObject(workerThread, 0) != WAIT_OBJECT_0) { - MSG msg; - if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessage(&msg); + if (worker) { + SetEvent(worker->eventCancel); // signal + HANDLE const workerThread = worker->workerThread; + if (IS_VALID_HANDLE(workerThread)) { + // Optimize: MsgDispatch only in case of hwnd ? + // DWORD const wait = SignalObjectAndWait(worker->eventCancel, workerThread, 100 /*INFINITE*/, FALSE); + while (WaitForSingleObject(workerThread, 0) != WAIT_OBJECT_0) { + MSG msg; + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } } + CloseHandle(workerThread); + worker->workerThread = INVALID_HANDLE_VALUE; } - CloseHandle(workerThread); } } void BackgroundWorker_Cancel(BackgroundWorker* worker) { - _BackgroundWorker_Stop(worker); - ResetEvent(worker->eventCancel); + if (worker) { + _BckgrdWrkr_Stop(worker); + ResetEvent(worker->eventCancel); + } } void BackgroundWorker_Destroy(BackgroundWorker* worker) { - _BackgroundWorker_Stop(worker); - CloseHandle(worker->eventCancel); + if (worker) { + _BckgrdWrkr_Stop(worker); + CloseHandle(worker->eventCancel); + worker->eventCancel = INVALID_HANDLE_VALUE; + Path_Release(worker->hFilePath); + worker->hFilePath = NULL; + } } +// inline bool BackgroundWorker_Continue(BackgroundWorker* worker); //============================================================================= // diff --git a/src/Helpers.h b/src/Helpers.h index ca0f77ca7..80ef4a5e2 100644 --- a/src/Helpers.h +++ b/src/Helpers.h @@ -418,19 +418,14 @@ bool IsProcessElevated(); bool IsUserInAdminGroup(); bool IsRunAsAdmin(); -typedef struct BackgroundWorker { - HWND hwnd; - HANDLE eventCancel; - HANDLE workerThread; - HPATHL hFilePath; // PATHLONG_MAX_CCH -} BackgroundWorker; +void BackgroundWorker_Init(BackgroundWorker* worker, HWND hwnd, const HPATHL hFilePath); +void BackgroundWorker_Start(BackgroundWorker* worker, _beginthreadex_proc_type routine, LPVOID property); +void BackgroundWorker_Cancel(BackgroundWorker *worker); +void BackgroundWorker_Destroy(BackgroundWorker *worker); + +inline void BackgroundWorker_End(BackgroundWorker* worker, unsigned int retcode) { if (worker) { _endthreadex(retcode); }} +inline bool BackgroundWorker_Continue(BackgroundWorker* worker) { return (worker) ? (WaitForSingleObject(worker->eventCancel, 0) != WAIT_OBJECT_0) : false; } -void BackgroundWorker_Init(BackgroundWorker* worker, HWND hwnd, HPATHL hFilePath); -void BackgroundWorker_Start(BackgroundWorker* worker, _beginthreadex_proc_type routine, LPVOID property); -void BackgroundWorker_End(unsigned int retcode); -void BackgroundWorker_Cancel(BackgroundWorker *worker); -void BackgroundWorker_Destroy(BackgroundWorker *worker); -__forceinline bool BackgroundWorker_Continue(BackgroundWorker* worker) { return (WaitForSingleObject(worker->eventCancel, 0) != WAIT_OBJECT_0); } bool BitmapMergeAlpha(HBITMAP hbmp,COLORREF crDest); bool BitmapAlphaBlend(HBITMAP hbmp,COLORREF crDest,BYTE alpha); diff --git a/src/Notepad3.c b/src/Notepad3.c index b2bf26c4a..a8ce15471 100644 --- a/src/Notepad3.c +++ b/src/Notepad3.c @@ -608,15 +608,16 @@ static bool IsFileReadOnly() // HasCurrentFileChanged // -static WIN32_FIND_DATA s_fdCurFile = { 0 }; -static HANDLE s_hEventFileChangedExt = INVALID_HANDLE_VALUE; -static HANDLE s_hEventFileDeletedExt = INVALID_HANDLE_VALUE; +static FCOBSRVDATA_T s_FileChgObsvrData = INIT_FCOBSRV_T; + +// ---------------------------------------------------------------------------- static inline bool IsFileChangedFlagSet() { - return (WaitForSingleObject(s_hEventFileChangedExt, 0) != WAIT_TIMEOUT); + return (WaitForSingleObject(s_FileChgObsvrData.hEventFileChanged, 0) != WAIT_TIMEOUT); } + static inline bool IsFileDeletedFlagSet() { - return (WaitForSingleObject(s_hEventFileDeletedExt, 0) != WAIT_TIMEOUT); + return (WaitForSingleObject(s_FileChgObsvrData.hEventFileDeleted, 0) != WAIT_TIMEOUT); } static inline bool HasCurrentFileChanged() { @@ -630,36 +631,39 @@ static inline bool HasCurrentFileChanged() { if (IsFileDeletedFlagSet()) { return false; } - SetEvent(s_hEventFileChangedExt); - SetEvent(s_hEventFileDeletedExt); + SetEvent(s_FileChgObsvrData.hEventFileChanged); + SetEvent(s_FileChgObsvrData.hEventFileDeleted); return true; } if (IsFileDeletedFlagSet()) { // The current file has been restored - ResetEvent(s_hEventFileDeletedExt); + ResetEvent(s_FileChgObsvrData.hEventFileDeleted); } - - bool const changed = (s_fdCurFile.nFileSizeLow != fdUpdated.nFileSizeLow) || (s_fdCurFile.nFileSizeHigh != fdUpdated.nFileSizeHigh) - //~|| (CompareFileTime(&s_fdCurFile.ftLastWriteTime, &fdUpdated.ftLastWriteTime) != 0) - || (s_fdCurFile.ftLastWriteTime.dwLowDateTime != fdUpdated.ftLastWriteTime.dwLowDateTime) - || (s_fdCurFile.ftLastWriteTime.dwHighDateTime != fdUpdated.ftLastWriteTime.dwHighDateTime); + + bool const changed = (s_FileChgObsvrData.fdCurFile.nFileSizeLow != fdUpdated.nFileSizeLow) || (s_FileChgObsvrData.fdCurFile.nFileSizeHigh != fdUpdated.nFileSizeHigh) + //~|| (CompareFileTime(&(s_FileChgObsvrData.fdCurFile.ftLastWriteTime), &fdUpdated.ftLastWriteTime) != 0) + || (s_FileChgObsvrData.fdCurFile.ftLastWriteTime.dwLowDateTime != fdUpdated.ftLastWriteTime.dwLowDateTime) + || (s_FileChgObsvrData.fdCurFile.ftLastWriteTime.dwHighDateTime != fdUpdated.ftLastWriteTime.dwHighDateTime); if (changed) { - SetEvent(s_hEventFileChangedExt); + SetEvent(s_FileChgObsvrData.hEventFileChanged); } return changed; } +// ---------------------------------------------------------------------------- static inline void ResetFileObservationData(const bool bResetEvt) { if (bResetEvt) { - ResetEvent(s_hEventFileChangedExt); - ResetEvent(s_hEventFileDeletedExt); + ResetEvent(s_FileChgObsvrData.hEventFileChanged); + ResetEvent(s_FileChgObsvrData.hEventFileDeleted); } if (Path_IsNotEmpty(Paths.CurrentFile)) { - if (!GetFileAttributesEx(Path_Get(Paths.CurrentFile), GetFileExInfoStandard, &s_fdCurFile)) { - ZeroMemory(&s_fdCurFile, sizeof(WIN32_FIND_DATA)); + if (!GetFileAttributesEx(Path_Get(Paths.CurrentFile), GetFileExInfoStandard, &(s_FileChgObsvrData.fdCurFile))) + { + ZeroMemory(&(s_FileChgObsvrData.fdCurFile), sizeof(WIN32_FIND_DATA)); } } } +// ---------------------------------------------------------------------------- //============================================================================= @@ -867,15 +871,19 @@ static void _CleanUpResources(const HWND hwnd, bool bIsInitialized) UndoRedoSelectionUTArray = NULL; } - if (IS_VALID_HANDLE(s_hEventFileChangedExt)) { - CloseHandle(s_hEventFileChangedExt); - s_hEventFileChangedExt = INVALID_HANDLE_VALUE; + if (IS_VALID_HANDLE(s_FileChgObsvrData.hEventFileChanged)) { + CloseHandle(s_FileChgObsvrData.hEventFileChanged); + s_FileChgObsvrData.hEventFileChanged = INVALID_HANDLE_VALUE; } - if (IS_VALID_HANDLE(s_hEventFileDeletedExt)) { - CloseHandle(s_hEventFileDeletedExt); - s_hEventFileDeletedExt = INVALID_HANDLE_VALUE; + if (IS_VALID_HANDLE(s_FileChgObsvrData.hEventFileDeleted)) { + CloseHandle(s_FileChgObsvrData.hEventFileDeleted); + s_FileChgObsvrData.hEventFileDeleted = INVALID_HANDLE_VALUE; } + BackgroundWorker_Destroy(&(s_FileChgObsvrData.worker)); + + // --------------------------------------------- + if (s_SelectionBuffer) { FreeMem(s_SelectionBuffer); s_SelectionBuffer = NULL; @@ -1799,9 +1807,9 @@ HWND InitInstance(const HINSTANCE hInstance, int nCmdShow) SetDialogIconNP3(hwndMain); InitWindowCommon(hwndMain, true); - // manual (no automatic) reset & initial state: not signaled (TRUE, FALSE) - s_hEventFileChangedExt = CreateEvent(NULL, TRUE, FALSE, NULL); - s_hEventFileDeletedExt = CreateEvent(NULL, TRUE, FALSE, NULL); + // manual (not automatic) reset & initial state: not signaled (TRUE, FALSE) + s_FileChgObsvrData.hEventFileChanged = CreateEvent(NULL, TRUE, FALSE, NULL); + s_FileChgObsvrData.hEventFileDeleted = CreateEvent(NULL, TRUE, FALSE, NULL); if (Settings.TransparentMode) { SetWindowTransparentMode(hwndMain, true, Settings2.OpacityLevel); @@ -12527,7 +12535,6 @@ void CALLBACK PasteBoardTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD // //============================================================================= -static DWORD s_dwFileChangeNotifyTime = 0UL; static inline void NotifyIfFileHasChanged(const bool forcedNotify) { @@ -12535,7 +12542,7 @@ static inline void NotifyIfFileHasChanged(const bool forcedNotify) { PostMessage(Globals.hwndMain, WM_FILECHANGEDNOTIFY, 0, 0); } // reset Timeout interval - s_dwFileChangeNotifyTime = GetTickCount(); + s_FileChgObsvrData.dwFileChangeNotifyTime = GetTickCount(); } // ---------------------------------------------------------------------------- @@ -12548,7 +12555,7 @@ static void CALLBACK WatchTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWOR UNREFERENCED_PARAMETER(uMsg); UNREFERENCED_PARAMETER(hwnd); - DWORD const diff = GetTickCount() - s_dwFileChangeNotifyTime; + DWORD const diff = GetTickCount() - s_FileChgObsvrData.dwFileChangeNotifyTime; // Directory-Observer is not notified for continously updated (log-)files if (diff > Settings2.FileCheckInterval) { @@ -12558,100 +12565,51 @@ static void CALLBACK WatchTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWOR // ---------------------------------------------------------------------------- -DWORD const dwObservingTimeout = 250UL; // then check for done -static HANDLE s_hEventObserverDone = INVALID_HANDLE_VALUE; - -static unsigned __stdcall FileChangeObserver(void * pArg) { - - if (!pArg) { - _endthreadex(0); - return 0; - } - - // get handle for change notify from FindFirstChangeNotification() - HANDLE* const pChangeHandle = (HANDLE*)(LONG_PTR)pArg; - - if (pChangeHandle && IS_VALID_HANDLE(*pChangeHandle)) { - - // not manual (automatic) reset & initial state: not signaled (FALSE, FALSE) - s_hEventObserverDone = CreateEvent(NULL, FALSE, FALSE, NULL); - - if (IS_VALID_HANDLE(s_hEventObserverDone)) { - - while (WaitForSingleObject(s_hEventObserverDone, 0) == WAIT_TIMEOUT) { - - DWORD const chgEvt = WaitForSingleObject(*pChangeHandle, dwObservingTimeout); - switch (chgEvt) { - case WAIT_TIMEOUT: - // okay, wait again until done - break; - - case WAIT_OBJECT_0: - if (HasCurrentFileChanged()) { - PostMessage(Globals.hwndMain, WM_FILECHANGEDNOTIFY, 0, 0); - } - FindNextChangeNotification(*pChangeHandle); - break; - - case WAIT_ABANDONED: - case WAIT_FAILED: - default: - SetEvent(s_hEventObserverDone); - break; - } - } - } - FindCloseChangeNotification(*pChangeHandle); - *pChangeHandle = INVALID_HANDLE_VALUE; - } - - if (IS_VALID_HANDLE(s_hEventObserverDone)) { - CloseHandle(s_hEventObserverDone); - s_hEventObserverDone = INVALID_HANDLE_VALUE; - } - _endthreadex(0); - return 0; -} -// ---------------------------------------------------------------------------- - - -static void StopFileChangeObserver(HANDLE* phObserverThread) +unsigned int WINAPIV FileChangeObserver(LPVOID lpParam) { -#pragma warning(push) -#pragma warning(disable : 6258) + PFCOBSRVDATA_T const pFCOBSVData = (PFCOBSRVDATA_T)(LONG_PTR)lpParam; - if (IS_VALID_HANDLE(*phObserverThread)) { - if (IS_VALID_HANDLE(s_hEventObserverDone)) { - DWORD const wait = SignalObjectAndWait(s_hEventObserverDone, *phObserverThread, - /*INFINITE*/ (dwObservingTimeout << 1), FALSE); - if (wait == WAIT_OBJECT_0) { - CloseHandle(*phObserverThread); // ok - } - else if (wait == WAIT_TIMEOUT) { - TerminateThread(*phObserverThread, 0UL); - assert("Observer Timeout Exceeded Error!" && false); - } - else { - TerminateThread(*phObserverThread, 0UL); - assert("Fatal Observer Error!" && false); + unsigned int retcode = 0; + + if (pFCOBSVData) { + + BackgroundWorker* const worker = &(pFCOBSVData->worker); + + while (BackgroundWorker_Continue(worker)) { + + switch (WaitForSingleObject(pFCOBSVData->hFileChanged, (FileWatching.FileCheckInterval >> 1))) { + + case WAIT_TIMEOUT: + // okay, wait again until done + break; + + case WAIT_OBJECT_0: + //~NotifyIfFileHasChanged(false); // immediate notification + WatchTimerProc(NULL, 0, 0ULL, 0); // rely on FileCheckInterval + FindNextChangeNotification(pFCOBSVData->hFileChanged); + break; + + case WAIT_ABANDONED: + case WAIT_FAILED: + default: + BackgroundWorker_Cancel(worker); + retcode = 1; + break; } } - else { - TerminateThread(*phObserverThread, 0UL); - assert("Fatal: Invalid Observer Done Handle!" && false); - } + + FindCloseChangeNotification(pFCOBSVData->hFileChanged); + pFCOBSVData->hFileChanged = INVALID_HANDLE_VALUE; + + BackgroundWorker_End(worker, retcode); } - *phObserverThread = INVALID_HANDLE_VALUE; - -#pragma warning(pop) + return retcode; } // ---------------------------------------------------------------------------- void InstallFileWatching(const bool bInstall) { - static HANDLE _hChangeHandle = INVALID_HANDLE_VALUE; // observer - static HANDLE _hObserverThread = INVALID_HANDLE_VALUE; static HANDLE _hCurrFileHandle = INVALID_HANDLE_VALUE; // exclusive lock // don't install FileWathing on own Settings IniFile @@ -12672,35 +12630,40 @@ void InstallFileWatching(const bool bInstall) { _hCurrFileHandle = INVALID_HANDLE_VALUE; } + if (!IS_VALID_HANDLE(s_FileChgObsvrData.worker.eventCancel)) { + BackgroundWorker_Init(&(s_FileChgObsvrData.worker), NULL, NULL); + } + bool const bTerminate = !bInstall || !bWatchFile || !bFileDirExists; // Terminate previous watching if (bTerminate) { - ResetFileObservationData(true); KillTimer(Globals.hwndMain, ID_WATCHTIMER); - StopFileChangeObserver(&_hObserverThread); + BackgroundWorker_Cancel(&(s_FileChgObsvrData.worker)); + ResetFileObservationData(true); } if (bInstall) { if (bWatchFile) { - if (!IS_VALID_HANDLE(_hObserverThread)) { + if (!IS_VALID_HANDLE(s_FileChgObsvrData.worker.workerThread)) { // Save data of current file ResetFileObservationData(false); // (!) false - assert(!IS_VALID_HANDLE(_hChangeHandle) && "ChangeHandle not properly closed!"); + assert(!IS_VALID_HANDLE(s_FileChgObsvrData.hFileChanged) && "ChangeHandle not properly closed!"); - _hChangeHandle = FindFirstChangeNotificationW(Path_Get(hdir_pth), false, + s_FileChgObsvrData.hFileChanged = FindFirstChangeNotificationW(Path_Get(hdir_pth), false, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE); - _hObserverThread = (HANDLE)_beginthreadex(NULL, 0, &FileChangeObserver, (void *)&_hChangeHandle, 0, NULL); + BackgroundWorker_Start(&(s_FileChgObsvrData.worker), FileChangeObserver, &s_FileChgObsvrData); } - s_dwFileChangeNotifyTime = (FileWatching.FileWatchingMode == FWM_AUTORELOAD) ? GetTickCount() : 0UL; + s_FileChgObsvrData.dwFileChangeNotifyTime = (FileWatching.FileWatchingMode == FWM_AUTORELOAD) ? GetTickCount() : 0UL; + if (FileWatching.FileCheckInterval > 0) { SetTimer(Globals.hwndMain, ID_WATCHTIMER, FileWatching.FileCheckInterval, WatchTimerProc); } @@ -12757,13 +12720,14 @@ void InstallFileWatching(const bool bInstall) { -static bool s_bAutoSaveTimerSet = false; - //============================================================================= // // AutoSaveStart() // -void AutoSaveStart(bool bReset) + +static bool s_bAutoSaveTimerSet = false; + +void AutoSaveStart(bool bReset) { if ((Settings.AutoSaveOptions & ASB_Periodic) && Settings.AutoSaveInterval >= USER_TIMER_MINIMUM) { if (bReset || !s_bAutoSaveTimerSet) { diff --git a/src/TypeDefs.h b/src/TypeDefs.h index d378c63d6..9eb7ab1b5 100644 --- a/src/TypeDefs.h +++ b/src/TypeDefs.h @@ -834,6 +834,32 @@ extern FOCUSEDVIEW_T FocusedView; //============================================================================= +typedef struct BackgroundWorker { + HWND hwnd; + HANDLE eventCancel; + HANDLE workerThread; + HPATHL hFilePath; // PATHLONG_MAX_CCH +} BackgroundWorker; + +//============================================================================= + +typedef struct FCOBSRVDATA_T { + + DWORD dwFileChangeNotifyTime; + + WIN32_FIND_DATA fdCurFile; + HANDLE hEventFileChanged; + HANDLE hEventFileDeleted; + + HANDLE hFileChanged; // FindFirstChangeNotification() + BackgroundWorker worker; + +} FCOBSRVDATA_T, *PFCOBSRVDATA_T; + +#define INIT_FCOBSRV_T { 0UL, { 0 }, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, { NULL, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, NULL } } + +//============================================================================= + typedef struct FILEWATCHING_T { FILE_WATCHING_MODE flagChangeNotify; // <-> s_flagChangeNotify;