+fix: reactivate FileChangeInterval (used on dir changed notification too)

+chg: refactoring: use background worker helper
This commit is contained in:
METANEOCORTEX\Kotti 2023-03-16 00:42:00 +01:00
parent dfdd887d8c
commit 2eb023b099
9 changed files with 212 additions and 197 deletions

View File

@ -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));

View File

@ -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;

View File

@ -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;
}

View File

@ -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() ============================================================

View File

@ -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);
}

View File

@ -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);
//=============================================================================
//

View File

@ -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);

View File

@ -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) {

View File

@ -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;