@@ -172,19 +172,21 @@ Win32 error
172172 while (true )
173173 {
174174
175- DWORD cbCompletion = 0 ;
175+ DWORD bytesTransferred = 0 ;
176176 OVERLAPPED* pOverlapped = nullptr ;
177177 ULONG_PTR completionKey;
178178
179179 BOOL success = GetQueuedCompletionStatus (
180180 pFileMonitor->m_hCompletionPort ,
181- &cbCompletion ,
181+ &bytesTransferred ,
182182 &completionKey,
183183 &pOverlapped,
184184 INFINITE);
185185
186- DBG_ASSERT (success);
187- (void )success;
186+ if (!success)
187+ {
188+ LOG_INFOF (L" Failure when watching app directory. HR: 0x%x" , HRESULT_FROM_WIN32 (GetLastError ()));
189+ }
188190
189191 if (completionKey == FILE_WATCHER_SHUTDOWN_KEY)
190192 {
@@ -194,7 +196,7 @@ Win32 error
194196 DBG_ASSERT (pOverlapped != nullptr );
195197 if (pOverlapped != nullptr )
196198 {
197- pFileMonitor->HandleChangeCompletion (cbCompletion );
199+ pFileMonitor->HandleChangeCompletion (bytesTransferred );
198200
199201 if (!pFileMonitor->_lStopMonitorCalled )
200202 {
@@ -222,7 +224,7 @@ Win32 error
222224
223225HRESULT
224226FILE_WATCHER::HandleChangeCompletion (
225- _In_ DWORD cbCompletion
227+ _In_ DWORD bytesTransferred
226228)
227229/* ++
228230
@@ -234,7 +236,7 @@ need to be flushed)
234236Arguments:
235237
236238dwCompletionStatus - Completion status
237- cbCompletion - Bytes of completion
239+ bytesTransferred - Bytes of completion
238240
239241Return Value:
240242
@@ -259,13 +261,28 @@ HRESULT
259261 }
260262
261263 //
262- // There could be a FCN overflow
263- // Let assume the file got changed instead of checking files
264- // Otherwise we have to cache the file info
264+ // There could be a FCN overflow, see https://learn.microsoft.com/windows/win32/api/winbase/nf-winbase-readdirectorychangesw#remarks
265+ // specifically about lpBytesReturned being zero on a successful call
265266 //
266- if (cbCompletion == 0 )
267+ // We'll do a manual check for the existence of app_offline.htm since it's possible the file was added
268+ // When ShadowCopy is enabled we also look for .dll changes, in order to detect a dll change in this edge case we'd need to cache all dll information
269+ // and manually iterate over the directory and compare the file attributes. For now we'll assume that if dlls are changing we'll get another
270+ // file change notification in that case
271+ //
272+ if (bytesTransferred == 0 )
267273 {
268- fAppOfflineChanged = TRUE ;
274+ LOG_INFO (L" 0 bytes transferred for file notifications. Falling back to manually looking for app_offline." );
275+ DWORD fileAttr = GetFileAttributesW (_strFullName.QueryStr ());
276+ if (fileAttr != INVALID_FILE_ATTRIBUTES && !(fileAttr & FILE_ATTRIBUTE_DIRECTORY))
277+ {
278+ fAppOfflineChanged = TRUE ;
279+ auto app = _pApplication.get ();
280+ app->m_detectedAppOffline = true ;
281+ }
282+ else
283+ {
284+ return S_OK;
285+ }
269286 }
270287 else
271288 {
@@ -277,7 +294,8 @@ HRESULT
277294 //
278295 // check whether the monitored file got changed
279296 //
280- if (_wcsnicmp (pNotificationInfo->FileName ,
297+ if (_strFileName.QuerySizeCCH () == (pNotificationInfo->FileNameLength / sizeof (WCHAR))
298+ && _wcsnicmp (pNotificationInfo->FileName ,
281299 _strFileName.QueryStr (),
282300 pNotificationInfo->FileNameLength / sizeof (WCHAR)) == 0 )
283301 {
@@ -427,7 +445,7 @@ FILE_WATCHER::Monitor(VOID)
427445 _buffDirectoryChanges.QueryPtr (),
428446 _buffDirectoryChanges.QuerySize (),
429447 FALSE , // Watching sub dirs. Set to False now as only monitoring app_offline
430- FILE_NOTIFY_VALID_MASK & ~FILE_NOTIFY_CHANGE_LAST_ACCESS,
448+ FILE_NOTIFY_VALID_MASK & ~FILE_NOTIFY_CHANGE_LAST_ACCESS & ~FILE_NOTIFY_CHANGE_SECURITY & ~FILE_NOTIFY_CHANGE_ATTRIBUTES ,
431449 &cbRead,
432450 &_overlapped,
433451 nullptr ));
0 commit comments