66#include " debugutil.h"
77#include " AppOfflineTrackingApplication.h"
88#include " exceptions.h"
9+ #include < EventLog.h>
910
1011FILE_WATCHER::FILE_WATCHER () :
1112 m_hCompletionPort(NULL ),
1213 m_hChangeNotificationThread(NULL ),
1314 m_fThreadExit(FALSE ),
14- _fTrackDllChanges(FALSE )
15+ _fTrackDllChanges(FALSE ),
16+ m_copied(false )
1517{
18+ m_pShutdownEvent = CreateEvent (
19+ nullptr , // default security attributes
20+ TRUE , // manual reset event
21+ FALSE , // not set
22+ nullptr ); // name
1623}
1724
1825FILE_WATCHER::~FILE_WATCHER ()
1926{
2027 StopMonitor ();
21- WaitForMonitor (20 );
28+ WaitForMonitor (20000 );
2229}
2330
2431void FILE_WATCHER::WaitForMonitor (DWORD dwRetryCounter)
@@ -60,7 +67,7 @@ FILE_WATCHER::Create(
6067 _In_ PCWSTR pszFileNameToMonitor,
6168 _In_ bool fTrackDllChanges ,
6269 _In_ std::wstring shadowCopyPath,
63- _In_ AppOfflineTrackingApplication * pApplication
70+ _In_ AppOfflineTrackingApplication* pApplication
6471)
6572{
6673 _shadowCopyPath = shadowCopyPath;
@@ -138,10 +145,10 @@ Win32 error
138145
139146--*/
140147{
141- FILE_WATCHER * pFileMonitor;
148+ FILE_WATCHER* pFileMonitor;
142149 BOOL fSuccess = FALSE ;
143150 DWORD cbCompletion = 0 ;
144- OVERLAPPED * pOverlapped = NULL ;
151+ OVERLAPPED* pOverlapped = NULL ;
145152 DWORD dwErrorStatus;
146153 ULONG_PTR completionKey;
147154
@@ -185,7 +192,15 @@ Win32 error
185192
186193 pFileMonitor->m_fThreadExit = TRUE ;
187194
195+ // TODO check instead for if a dll was changed here
196+ if (pFileMonitor->_fTrackDllChanges )
197+ {
198+ pFileMonitor->m_Timer .CancelTimer ();
199+ FILE_WATCHER::CopyAndShutdown (pFileMonitor);
200+ }
201+
188202 LOG_INFO (L" Stopping file watcher thread" );
203+
189204 ExitThread (0 );
190205}
191206
@@ -265,6 +280,7 @@ HRESULT
265280 if (_fTrackDllChanges && notificationPath.extension ().compare (L" .dll" ) == 0 )
266281 {
267282 fFileChanged = TRUE ;
283+ _fDllHadChanged = true ;
268284 fDllChanged = TRUE ;
269285 }
270286
@@ -288,21 +304,72 @@ HRESULT
288304 {
289305 // Reference application before
290306 _pApplication->ReferenceApplication ();
291- if (fDllChanged )
307+ if (fDllChanged || _fTrackDllChanges )
292308 {
293- // wait for all file changes to complete
294- PostQueuedCompletionStatus (m_hCompletionPort, 0 , FILE_WATCHER_SHUTDOWN_KEY, NULL );
295- WaitForMonitor (100 ); // 5 seconds here.
296-
297- // Copy contents before shutdown
298- RETURN_IF_FAILED (Environment::CopyToDirectory (_shadowCopyPath, _strDirectoryName.QueryStr (), false ));
309+ // Call shutdown later.
310+ m_Timer.CancelTimer ();
311+ m_Timer.InitializeTimer (FILE_WATCHER::TimerCallback, this , 5000 , 3000 );
312+ }
313+ else
314+ {
315+ RETURN_LAST_ERROR_IF (!QueueUserWorkItem (RunNotificationCallback, _pApplication.get (), WT_EXECUTEDEFAULT));
299316 }
300- RETURN_LAST_ERROR_IF (!QueueUserWorkItem (RunNotificationCallback, _pApplication.get (), WT_EXECUTEDEFAULT));
301317 }
302318
303319 return S_OK;
304320}
305321
322+
323+ VOID
324+ CALLBACK
325+ FILE_WATCHER::TimerCallback (
326+ _In_ PTP_CALLBACK_INSTANCE Instance,
327+ _In_ PVOID Context,
328+ _In_ PTP_TIMER Timer
329+ )
330+ {
331+ // Need to lock here.
332+ Instance;
333+ Timer;
334+ CopyAndShutdown ((FILE_WATCHER*)Context);
335+ }
336+
337+ DWORD WINAPI FILE_WATCHER::CopyAndShutdown (LPVOID arg)
338+ {
339+ EventLog::Error (
340+ 1 ,
341+ L" Callback" );
342+ auto directoryName = 0 ;
343+ // wrong path.
344+ auto watcher = (FILE_WATCHER*)arg;
345+ SRWExclusiveLock lock (watcher->m_copyLock );
346+
347+ if (watcher->m_copied )
348+ {
349+ return 0 ;
350+ }
351+
352+ watcher->m_copied = true ;
353+
354+ auto dir = std::filesystem::path (watcher->_shadowCopyPath );
355+ auto parent = dir.parent_path ();
356+ directoryName = std::stoi (dir.filename ().string ());
357+
358+ directoryName++;
359+ auto dirNameStr = std::to_wstring (directoryName);
360+ auto destination = parent / dirNameStr.c_str ();
361+
362+ // Copy contents before shutdown
363+ Environment::CopyToDirectory (destination, watcher->_strDirectoryName .QueryStr (), false );
364+
365+ watcher->_pApplication ->ReferenceApplication ();
366+ SetEvent (watcher->m_pShutdownEvent );
367+
368+ QueueUserWorkItem (RunNotificationCallback, watcher->_pApplication .get (), WT_EXECUTEDEFAULT);
369+ return 0 ;
370+ }
371+
372+
306373DWORD
307374WINAPI
308375FILE_WATCHER::RunNotificationCallback (
@@ -311,7 +378,6 @@ FILE_WATCHER::RunNotificationCallback(
311378{
312379 // Recapture application instance into unique_ptr
313380 auto pApplication = std::unique_ptr<AppOfflineTrackingApplication, IAPPLICATION_DELETER>(static_cast <AppOfflineTrackingApplication*>(pvArg));
314- DBG_ASSERT (pFileMonitor != NULL );
315381 pApplication->OnAppOffline ();
316382
317383 return 0 ;
@@ -359,6 +425,10 @@ FILE_WATCHER::StopMonitor()
359425 InterlockedExchange (&_lStopMonitorCalled, 1 );
360426 // signal the file watch thread to exit
361427 PostQueuedCompletionStatus (m_hCompletionPort, 0 , FILE_WATCHER_SHUTDOWN_KEY, NULL );
428+ WaitForMonitor (20000 );
429+ // See if this waits.
430+ WaitForSingleObject (m_pShutdownEvent, 120000 );
431+
362432 // Release application reference
363433 _pApplication.reset (nullptr );
364434}
0 commit comments