mirror of
https://github.com/rizonesoft/Notepad3.git
synced 2026-06-14 21:09:05 +08:00
+fix: reactivate FileChangeInterval (used on dir changed notification too)
+chg: refactoring: use background worker helper
This commit is contained in:
parent
dfdd887d8c
commit
2eb023b099
@ -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));
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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() ============================================================
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
|
||||
@ -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);
|
||||
|
||||
210
src/Notepad3.c
210
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) {
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user