diff --git a/dll/win32/shell32/wine/changenotify.c b/dll/win32/shell32/wine/changenotify.c index e577547039..40dc022ca4 100644 --- a/dll/win32/shell32/wine/changenotify.c +++ b/dll/win32/shell32/wine/changenotify.c @@ -40,6 +40,331 @@ WINE_DEFAULT_DEBUG_CHANNEL(shell); +#ifdef __REACTOS__ +#define SHARE_MUTEX_NAME L"Shell32ShareMutex" +#define LINKHUB_GROW 5 + +typedef struct ENTRY +{ + BOOL fRecursive; + WCHAR szPath[MAX_PATH]; +} ENTRY, *LPENTRY; + +typedef struct BLOCK +{ + HWND hwnd; + INT fSources; + LONG fEvents; + UINT uMsg; + INT cEntries; + ENTRY Entries[1]; +} BLOCK, *LPBLOCK; + +typedef struct LINK +{ + DWORD dwUserPID; + DWORD dwOwnerPID; + UINT nRegID; + HANDLE hBlock; +} LINK, *LPLINK; + +typedef struct LINKHUB +{ + INT nCount; + INT nCapacity; + LINK Links[1]; +} LINKHUB, *LPLINKHUB; + +/* shared data section */ + +#ifdef _MSC_VER + #define SHELL32SHARE +#else + #define SHELL32SHARE __attribute__((section(".shared"), shared)) +#endif +#ifdef _MSC_VER + #pragma data_seg(".shared") +#endif +static HANDLE s_hLinkHub SHELL32SHARE = NULL; +static DWORD s_dwLinkOwnerPID SHELL32SHARE = 0; +#ifdef _MSC_VER + #pragma data_seg() + #pragma comment(linker, "/SECTION:.shared,RWS") +#endif + +static DWORD +LinkHub_GetSize(INT nCount) +{ + return sizeof(LINKHUB) + (nCount - 1) * sizeof(LINK); +} + +static LPLINKHUB +LinkHub_Lock(HANDLE hLinkHub, DWORD dwOwnerPID) +{ + if (!hLinkHub || !dwOwnerPID || !IsProcessRunning(dwOwnerPID)) + return NULL; + + return (LPLINKHUB)SHLockShared(hLinkHub, dwOwnerPID); +} + +static void +LinkHub_Unlock(LPLINKHUB pLinkHub) +{ + if (!pLinkHub) + return; + + SHUnlockShared(pLinkHub); +} + +static BOOL +IsProcessRunning(DWORD pid) +{ + HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, TRUE, pid); + if (hProcess) + CloseHandle(hProcess); + return hProcess != NULL; +} + +static DWORD +Block_GetSize(INT nEntries) +{ + return sizeof(BLOCK) + (nEntries - 1) * sizeof(ENTRY); +} + +static BLOCK * +Block_Lock(HANDLE hShare, DWORD pid) +{ + if (!hShare || !pid || !IsProcessRunning(pid)) + return NULL; + + LPVOID pv = SHLockShared(hShare, pid); + return (BLOCK *)pv; +} + +static void +Block_Unlock(LPVOID block) +{ + if (!block) + return; + + SHUnlockShared(block); +} + +static void +Block_Destroy(HANDLE hShare, DWORD pid) +{ + if (!hShare || !pid || !IsProcessRunning(pid)) + return; + + SHFreeShared(hShare, pid); +} + +static void +LinkHub_RemoveByRegID(LPLINKHUB pLinkHub, UINT nRegID) +{ + INT iLink; + LPLINK pLink; + for (iLink = 0; iLink < pLinkHub->nCapacity; ++i) + { + pLink = &pLinkHub->Links[iLink]; + if (!pLink->nRegID) + continue; + + if (pLink->nRegID == nRegID) + { + Block_Destroy(pLink->hBlock, pLink->dwOwnerPID); + ZeroMemory(pLink, sizeof(*pLink)); + pLinkHub->nCount--; + } + } +} + +static void +DoRemoveBlockByRegID(UINT nRegID) +{ + LPLINKHUB pLinkHub = LinkHub_Lock(s_hLinkHub, s_dwLinkOwnerPID); + if (pLinkHub) + { + LinkHub_RemoveByRegID(pLinkHub, nRegID); + LinkHub_Unlock(pLinkHub); + } +} + +static UINT +LinkHub_Add(LPLINKHUB pLinkHub, DWORD pid, LPBLOCK block) +{ + INT iLink; + LPLINK pLink; + for (iLink = 0; iLink < pLinkHub->nCapacity; ++i) + { + pLink = &pLinkHub->Links[iLink]; + if (pLink->nRegID != 0) + continue; + + pLink->hBlock = SHAllocShared(block, Block_GetSize(block->cEntries), pid); + if (pLink->hBlock) + { + pLink->dwUserPID = pLink->dwOwnerPID = pid; + pLink->nRegID = ++s_nNextRegID; + pLinkHub->nCount++; + return pLink->nRegID; + } + } + return 0; +} + +static UINT +LinkHub_GrowAdd(LPLINKHUB pOldLinkHub, INT nNewCapacity, DWORD pid, LPBLOCK block) +{ + UINT nRegID = 0; + DWORD cbOldLinkHub = LinkHub_GetSize(pOldLinkHub->nCapacity); + DWORD cbNewLinkHub = LinkHub_GetSize(nNewCapacity); + HANDLE hNewLinkHub = SHAllocShared(NULL, cbNewLinkHub, pid); + LPLINKHUB pNewLinkHub = LinkHub_Lock(hNewLinkHub, pid); + if (pNewLinkHub) + { + CopyMemory(pNewLinkHub, pOldLinkHub, min(cbNewLinkHub, cbOldLinkHub)); + nRegID = LinkHub_Add(pNewLinkHub, pid, block); + SHUnlockShared(pNewLinkHub); + + s_hLinkHub = hNewLinkHub; + s_dwLinkOwnerPID = pid; + } + return nRegID; +} + +static HANDLE +LinkHub_Create(DWORD pid) +{ + LINKHUB LinkHub = { 0, 1 }; + return SHAllocShared(&LinkHub, sizeof(hLinkHub), pid); +} + +static UINT +DoAddBlock(DWORD pid, LPBLOCK block) +{ + UINT nRegID = 0; + HANDLE hOldLinkHub; + DWORD dwOldOwnerPID; + HANDLE hLinkHub; + LPLINKHUB pLinkHub; + + if (!s_hLinkHub) + { + hLinkHub = LinkHub_Create(pid); + if (!hLinkHub) + return nRegID; + + s_hLinkHub = hLinkHub; + s_dwLinkOwnerPID = pid; + } + + pLinkHub = LinkHub_Lock(s_hLinkHub, s_dwLinkOwnerPID); + if (!pLinkHub) + return nRegID; + + nRegID = LinkHub_Add(pLinkHub, pid, block); + if (nRegID) + return nRegID; + + hOldLinkHub = s_hLinkHub; + dwOldOwnerPID = s_dwLinkOwnerPID; + + nRegID = LinkHub_GrowAdd(pLinkHub, pLinkHub->nCapacity + LINKHUB_GROW, pid, block); + LinkHub_Unlock(pLinkHub); + + SHFreeShared(hOldLinkHub, dwOldOwnerPID); + return nRegID; +} + +static void +LinkHub_MoveOwnership(LPLINKHUB pLinkHub, DWORD dwFromPID, DWORD dwToPID) +{ + INT iLink; + LPLINK pLink; + LPBLOCK block; + DWORD cbBlock; + HANDLE hBlock; + for (iLink = 0; iLink < pLinkHub->nCapacity; ++i) + { + pLink = &pLinkHub->Links[iLink]; + if (pLink->nRegID == 0) + continue; + + if (pLink->dwOwnerPID != dwFromPID) + continue; + + block = Block_Lock(pLink->hBlock, pLink->dwOwnerPID); + if (!block) + continue; + + cbBlock = Block_GetSize(block->cEntries); + hBlock = SHAllocShared(block, cbBlock, dwToPID); + Block_Unlock(block); + + if (hBlock) + { + Block_Destroy(pLink->hBlock, pLink->dwOwnerPID); + + pLink->hBlock = hBlock; + pLink->dwOwnerPID = dwToPID; + } + } +} + +static void +LinkHub_RemoveByProcess(LPLINKHUB pLinkHub, DWORD pid) +{ + INT iLink; + LPLINK pLink; + for (iLink = 0; iLink < pLinkHub->nCapacity; ++i) + { + pLink = &pLinkHub->Links[iLink]; + if (pLink->nRegID == 0) + continue; + + if (pLink->dwUserPID == pid) + { + Block_Destroy(pLink->hBlock, pLink->dwOwnerPID); + ZeroMemory(pLink, sizeof(*pLink)); + pLinkHub->nCount--; + } + } +} + +static DWORD +LinkHub_GetAnotherPID(LPLINKHUB pLinkHub, DWORD pid) +{ + INT iLink; + LPLINK pLink; + for (iLink = 0; iLink < pLinkHub->nCapacity; ++i) + { + pLink = &pLinkHub->Links[iLink]; + if (pLink->nRegID == 0) + continue; + + if (pLink->dwOwnerPID != pid) + { + return pLink->dwOwnerPID; + } + } + return 0; +} + +static void +DoRemoveBlockByProcess(DWORD pid) +{ + LPLINKHUB pLinkHub = LinkHub_Lock(); + if (pLinkHub) + { + DWORD dwToPID = LinkHub_GetAnotherPID(pLinkHub, pid); + LinkHub_RemoveByProcess(pid); + LinkHub_MoveOwnership(pLinkHub, pid, dwToPID); + LinkHub_Unlock(pLinkHub); + } +} + +#else static CRITICAL_SECTION SHELL32_ChangenotifyCS; static CRITICAL_SECTION_DEBUG critsect_debug = { @@ -49,20 +374,7 @@ static CRITICAL_SECTION_DEBUG critsect_debug = }; static CRITICAL_SECTION SHELL32_ChangenotifyCS = { &critsect_debug, -1, 0, 0, 0, 0 }; -#ifdef __REACTOS__ -typedef struct { - PCIDLIST_ABSOLUTE pidl; - BOOL fRecursive; - /* File system notification items */ - HANDLE hDirectory; /* Directory handle */ - WCHAR wstrDirectory[MAX_PATH]; /* Directory name */ - OVERLAPPED overlapped; /* Overlapped structure */ - BYTE *buffer; /* Async buffer to fill */ - BYTE *backBuffer; /* Back buffer to swap buffer into */ -} SHChangeNotifyEntryInternal, *LPNOTIFYREGISTER; -#else typedef SHChangeNotifyEntry *LPNOTIFYREGISTER; -#endif /* internal list of notification clients (internal) */ typedef struct _NOTIFICATIONLIST @@ -77,23 +389,8 @@ typedef struct _NOTIFICATIONLIST ULONG id; } NOTIFICATIONLIST, *LPNOTIFICATIONLIST; -#ifdef __REACTOS__ -VOID _ProcessNotification(LPNOTIFYREGISTER item); -BOOL _OpenDirectory(LPNOTIFYREGISTER item); -static void CALLBACK _RequestTermination(ULONG_PTR arg); -static void CALLBACK _RequestAllTermination(ULONG_PTR arg); -static void CALLBACK _AddDirectoryProc(ULONG_PTR arg); -static VOID _BeginRead(LPNOTIFYREGISTER item); -static unsigned int WINAPI _RunAsyncThreadProc(LPVOID arg); -#endif - static struct list notifications = LIST_INIT( notifications ); static LONG next_id; - -#ifdef __REACTOS__ -HANDLE m_hThread; -UINT m_dwThreadId; -BOOL m_bTerminate; #endif #define SHCNE_NOITEMEVENTS ( \ @@ -142,6 +439,7 @@ static const char * DumpEvent( LONG event ) #undef DUMPEV } +#ifndef __REACTOS__ static const char * NodeName(const NOTIFICATIONLIST *item) { const char *str; @@ -165,30 +463,24 @@ static void DeleteNode(LPNOTIFICATIONLIST item) /* free the item */ for (i=0; icidl; i++) -#ifdef __REACTOS__ - { - QueueUserAPC(_RequestTermination, m_hThread, (ULONG_PTR) &item->apidl[i] ); - WaitForSingleObjectEx(m_hThread, 100, FALSE); -#endif SHFree((LPITEMIDLIST)item->apidl[i].pidl); -#ifdef __REACTOS__ - SHFree(item->apidl[i].buffer); - SHFree(item->apidl[i].backBuffer); - } -#endif SHFree(item->apidl); SHFree(item); } +#endif // ndef __REACTOS__ void InitChangeNotifications(void) { -#ifdef __REACTOS__ - m_hThread = NULL; -#endif } void FreeChangeNotifications(void) { +#ifdef __REACTOS__ + HANDLE hMutex = CreateMutexW(NULL, TRUE, SHARE_MUTEX_NAME); + DoRemoveBlockByProcess(GetCurrentProcessId()); + ReleaseMutex(hMutex); + CloseHandle(hMutex); +#else LPNOTIFICATIONLIST ptr, next; TRACE("\n"); @@ -200,11 +492,8 @@ void FreeChangeNotifications(void) LeaveCriticalSection(&SHELL32_ChangenotifyCS); -#ifdef __REACTOS__ - QueueUserAPC(_RequestAllTermination, m_hThread, (ULONG_PTR) NULL ); -#endif - DeleteCriticalSection(&SHELL32_ChangenotifyCS); +#endif } /************************************************************************* @@ -220,6 +509,54 @@ SHChangeNotifyRegister( int cItems, SHChangeNotifyEntry *lpItems) { +#ifdef __REACTOS__ + HANDLE hMutex; + DWORD pid; + UINT nRegID = 0; + DWORD cbBlock; + LPBLOCK lpBlock; + INT iEntries; + LPENTRY lpEntry; + + if (cItems <= 0 || !lpItems || !IsWindow(hwnd)) + return nRegID; + + GetWindowThreadProcessId(hwnd, &pid); + if (pid != GetCurrentProcessId()) + return nRegID; + + hMutex = CreateMutexW(NULL, TRUE, SHARE_MUTEX_NAME); + if (cItems == 1) + { + ENTRY entry = { lpItems->fRecursive }; + BLOCK block = { hwnd, fSources, fEvents, uMsg, 1 }; + + SHGetPathFromIDListW(lpItems->pidl, entry->szPath); + block->Entries[0] = entry; + + nRegID = DoAddBlock(GetCurrentProcessId(), &block); + } + eles + { + cbBlock = Block_GetSize(cItems); + lpBlock = (LPBLOCK)CoTaskMemAlloc(cbBlock); + if (lpBlock) + { + for (iEntries = 0; iEntries < cItems; ++iEntries) + { + lpEntry = &lpBlock->Entries[iEntries]; + lpEntry->fRecursive = lpItems[iEntries].fRecursive; + SHGetPathFromIDListW(lpItems[iEntries].pidl, lpEntry->szPath); + } + nRegID = DoAddBlock(GetCurrentProcessId(), lpBlock); + CoTaskMemFree(lpBlock); + } + } + ReleaseMutex(hMutex); + CloseHandle(hMutex); + + return nRegID; +#else LPNOTIFICATIONLIST item; int i; @@ -228,37 +565,12 @@ SHChangeNotifyRegister( TRACE("(%p,0x%08x,0x%08x,0x%08x,%d,%p) item=%p\n", hwnd, fSources, wEventMask, uMsg, cItems, lpItems, item); -#ifdef __REACTOS__ - if (!m_hThread) - m_hThread = (HANDLE) _beginthreadex(NULL, 0, _RunAsyncThreadProc, NULL, 0, &m_dwThreadId); -#endif - item->cidl = cItems; -#ifdef __REACTOS__ - item->apidl = SHAlloc(sizeof(SHChangeNotifyEntryInternal) * cItems); -#else item->apidl = SHAlloc(sizeof(SHChangeNotifyEntry) * cItems); -#endif for(i=0;iapidl[i], sizeof(SHChangeNotifyEntryInternal)); -#endif item->apidl[i].pidl = ILClone(lpItems[i].pidl); item->apidl[i].fRecursive = lpItems[i].fRecursive; -#ifdef __REACTOS__ - item->apidl[i].buffer = SHAlloc(BUFFER_SIZE); - item->apidl[i].backBuffer = SHAlloc(BUFFER_SIZE); - item->apidl[i].overlapped.hEvent = &item->apidl[i]; - - if (fSources & SHCNRF_InterruptLevel) - { - if (_OpenDirectory( &item->apidl[i] )) - { - QueueUserAPC( _AddDirectoryProc, m_hThread, (ULONG_PTR) &item->apidl[i] ); - } - } -#endif } item->hwnd = hwnd; item->uMsg = uMsg; @@ -275,6 +587,7 @@ SHChangeNotifyRegister( LeaveCriticalSection(&SHELL32_ChangenotifyCS); return item->id; +#endif } /************************************************************************* @@ -282,6 +595,12 @@ SHChangeNotifyRegister( */ BOOL WINAPI SHChangeNotifyDeregister(ULONG hNotify) { +#ifdef __REACTOS__ + HANDLE hMutex = CreateMutexW(NULL, TRUE, SHARE_MUTEX_NAME); + DoRemoveBlockByRegID(hNotify); + ReleaseMutex(hMutex); + CloseHandle(hMutex); +#else LPNOTIFICATIONLIST node; TRACE("(0x%08x)\n", hNotify); @@ -299,6 +618,7 @@ BOOL WINAPI SHChangeNotifyDeregister(ULONG hNotify) } LeaveCriticalSection(&SHELL32_ChangenotifyCS); return FALSE; +#endif } /************************************************************************* @@ -390,49 +710,12 @@ void WINAPI SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID switch (uFlags & SHCNF_TYPE) { case SHCNF_PATHA: - if (dwItem1) Pidls[0] = SHSimpleIDListFromPathA(dwItem1); //FIXME - if (dwItem2) Pidls[1] = SHSimpleIDListFromPathA(dwItem2); //FIXME + if (dwItem1) Pidls[0] = SHSimpleIDListFromPathA(dwItem1); + if (dwItem2) Pidls[1] = SHSimpleIDListFromPathA(dwItem2); break; case SHCNF_PATHW: if (dwItem1) Pidls[0] = SHSimpleIDListFromPathW(dwItem1); if (dwItem2) Pidls[1] = SHSimpleIDListFromPathW(dwItem2); -#ifdef __REACTOS__ - if (wEventId & (SHCNE_MKDIR | SHCNE_RMDIR | SHCNE_UPDATEDIR | SHCNE_RENAMEFOLDER)) - { - /* - * The last items in the ID are currently files. So we chop off the last - * entry, and create a new one using a find data struct. - */ - if (dwItem1 && Pidls[0]){ - WIN32_FIND_DATAW wfd; - LPITEMIDLIST oldpidl, newpidl; - LPWSTR p = PathFindFileNameW((LPCWSTR)dwItem1); - ILRemoveLastID(Pidls[0]); - lstrcpynW(&wfd.cFileName[0], p, MAX_PATH); - wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY; - newpidl = _ILCreateFromFindDataW(&wfd); - oldpidl = ILClone(Pidls[0]); - ILFree(Pidls[0]); - Pidls[0] = ILCombine(oldpidl, newpidl); - ILFree(newpidl); - ILFree(oldpidl); - } - if (dwItem2 && Pidls[1]){ - WIN32_FIND_DATAW wfd; - LPITEMIDLIST oldpidl, newpidl; - LPWSTR p = PathFindFileNameW((LPCWSTR)dwItem2); - ILRemoveLastID(Pidls[1]); - lstrcpynW(&wfd.cFileName[0], p, MAX_PATH); - wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY; - newpidl = _ILCreateFromFindDataW(&wfd); - oldpidl = ILClone(Pidls[0]); - ILFree(Pidls[1]); - Pidls[1] = ILCombine(oldpidl, newpidl); - ILFree(newpidl); - ILFree(oldpidl); - } - } -#endif break; case SHCNF_IDLIST: Pidls[0] = ILClone(dwItem1); @@ -545,22 +828,21 @@ void WINAPI SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID } /************************************************************************* - * NTSHChangeNotifyRegister [SHELL32.640] + * NTSHChangeNotifyRegister [SHELL32.640] * NOTES - * Idlist is an array of structures and Count specifies how many items in the array. - * count should always be one when calling SHChangeNotifyRegister, or - * SHChangeNotifyDeregister will not work properly. + * Idlist is an array of structures and Count specifies how many items in the array + * (usually just one I think). */ -EXTERN_C ULONG WINAPI NTSHChangeNotifyRegister( +ULONG WINAPI NTSHChangeNotifyRegister( HWND hwnd, int fSources, - LONG fEvents, - UINT msg, - int count, - SHChangeNotifyEntry *idlist) + LONG wEventMask, + UINT uMsg, + int cItems, + SHChangeNotifyEntry *lpItems) { return SHChangeNotifyRegister(hwnd, fSources | SHCNRF_NewDelivery, - fEvents, msg, count, idlist); + wEventMask, uMsg, cItems, lpItems); } /************************************************************************* @@ -614,255 +896,3 @@ DWORD WINAPI NTSHChangeNotifyDeregister(ULONG x1) return SHChangeNotifyDeregister( x1 ); } - -#ifdef __REACTOS__ - -static -void -CALLBACK -_AddDirectoryProc(ULONG_PTR arg) -{ - LPNOTIFYREGISTER item = (LPNOTIFYREGISTER)arg; - _BeginRead(item); -} - -BOOL _OpenDirectory(LPNOTIFYREGISTER item) -{ - STRRET strFile; - IShellFolder *psf; - HRESULT hr; - LPCITEMIDLIST child; - ULONG ulAttrs; - - // Makes function idempotent - if (item->hDirectory && !(item->hDirectory == INVALID_HANDLE_VALUE)) - return TRUE; - - hr = SHBindToParent(item->pidl, &IID_IShellFolder, (LPVOID*)&psf, &child); - if (FAILED_UNEXPECTEDLY(hr)) - return hr; - - ulAttrs = SFGAO_FILESYSTEM | SFGAO_FOLDER; - hr = IShellFolder_GetAttributesOf(psf, 1, (LPCITEMIDLIST*)&child, &ulAttrs); - if (SUCCEEDED(hr)) - hr = IShellFolder_GetDisplayNameOf(psf, child, SHGDN_FORPARSING, &strFile); - - IShellFolder_Release(psf); - if (FAILED_UNEXPECTEDLY(hr)) - return FALSE; - - hr = StrRetToBufW(&strFile, NULL, item->wstrDirectory, _countof(item->wstrDirectory)); - if (FAILED_UNEXPECTEDLY(hr)) - return FALSE; - - if ((ulAttrs & (SFGAO_FILESYSTEM | SFGAO_FOLDER)) != (SFGAO_FILESYSTEM | SFGAO_FOLDER)) - { - TRACE("_OpenDirectory ignoring %s\n", debugstr_w(item->wstrDirectory)); - item->hDirectory = INVALID_HANDLE_VALUE; - return FALSE; - } - - TRACE("_OpenDirectory %s\n", debugstr_w(item->wstrDirectory)); - - item->hDirectory = CreateFileW(item->wstrDirectory, // pointer to the file name - GENERIC_READ | FILE_LIST_DIRECTORY, // access (read/write) mode - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, // share mode - NULL, // security descriptor - OPEN_EXISTING, // how to create - FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, // file attributes - NULL); // file with attributes to copy - - if (item->hDirectory == INVALID_HANDLE_VALUE) - { - ERR("_OpenDirectory failed for %s\n", debugstr_w(item->wstrDirectory)); - return FALSE; - } - return TRUE; -} - -static void CALLBACK _RequestTermination(ULONG_PTR arg) -{ - LPNOTIFYREGISTER item = (LPNOTIFYREGISTER) arg; - TRACE("_RequestTermination %p %p \n", item, item->hDirectory); - if (!item->hDirectory || item->hDirectory == INVALID_HANDLE_VALUE) return; - - CancelIo(item->hDirectory); - CloseHandle(item->hDirectory); - item->hDirectory = NULL; -} - -static -void -CALLBACK -_NotificationCompletion(DWORD dwErrorCode, // completion code - DWORD dwNumberOfBytesTransfered, // number of bytes transferred - LPOVERLAPPED lpOverlapped) // I/O information buffer -{ - /* MSDN: The hEvent member of the OVERLAPPED structure is not used by the - system, so you can use it yourself. We do just this, storing a pointer - to the working struct in the overlapped structure. */ - LPNOTIFYREGISTER item = (LPNOTIFYREGISTER) lpOverlapped->hEvent; - TRACE("_NotificationCompletion\n"); - -#if 0 - if (dwErrorCode == ERROR_OPERATION_ABORTED) - { - /* Command was induced by CancelIo in the shutdown procedure. */ - TRACE("_NotificationCompletion ended.\n"); - return; - } -#endif - -#ifdef __REACTOS__ - /* If the FSD doesn't support directory change notifications, there's no - * no need to retry and requeue notification - */ - if (dwErrorCode == ERROR_INVALID_FUNCTION) - { - WARN("Directory watching not supported\n"); - return; - } - - /* Also, if the notify operation was canceled (like, user moved to another - * directory), then, don't requeue notification - */ - if (dwErrorCode == ERROR_OPERATION_ABORTED) - { - TRACE("Notification aborted\n"); - return; - } - - if (!item) - { - ERR("item == NULL\n"); - return; - } - -#endif - - /* This likely means overflow, so force whole directory refresh. */ - if (!dwNumberOfBytesTransfered) - { - ERR("_NotificationCompletion overflow\n"); - - ZeroMemory(item->buffer, BUFFER_SIZE); - _BeginRead(item); - - SHChangeNotify(SHCNE_UPDATEITEM | SHCNE_INTERRUPT, - SHCNF_IDLIST, - item->pidl, - NULL); - - return; - } - - /* - * Get the new read issued as fast as possible (before we do the - * processing and message posting). All of the file notification - * occur on one thread so the buffers should not collide with one another. - * The extra zero mems are because the FNI size isn't written correctly. - */ - - ZeroMemory(item->backBuffer, BUFFER_SIZE); - memcpy(item->backBuffer, item->buffer, dwNumberOfBytesTransfered); - ZeroMemory(item->buffer, BUFFER_SIZE); - - _BeginRead(item); - - _ProcessNotification(item); -} - -static VOID _BeginRead(LPNOTIFYREGISTER item ) -{ - TRACE("_BeginRead %p \n", item->hDirectory); - - /* This call needs to be reissued after every APC. */ - if (!ReadDirectoryChangesW(item->hDirectory, // handle to directory - item->buffer, // read results buffer - BUFFER_SIZE, // length of buffer - FALSE, // monitoring option (recursion) - FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_FILE_NAME, // filter conditions - NULL, // bytes returned - &item->overlapped, // overlapped buffer - _NotificationCompletion)) // completion routine - ERR("ReadDirectoryChangesW failed. (%p, %p, %p, %p, %p) Code: %u \n", - item, - item->hDirectory, - item->buffer, - &item->overlapped, - _NotificationCompletion, - GetLastError()); -} - -DWORD _MapAction(DWORD dwAction, BOOL isDir) -{ - switch (dwAction) - { - case FILE_ACTION_ADDED : return isDir ? SHCNE_MKDIR : SHCNE_CREATE; - case FILE_ACTION_REMOVED : return isDir ? SHCNE_RMDIR : SHCNE_DELETE; - case FILE_ACTION_MODIFIED : return isDir ? SHCNE_UPDATEDIR : SHCNE_UPDATEITEM; - case FILE_ACTION_RENAMED_OLD_NAME : return isDir ? SHCNE_UPDATEDIR : SHCNE_UPDATEITEM; - case FILE_ACTION_RENAMED_NEW_NAME : return isDir ? SHCNE_UPDATEDIR : SHCNE_UPDATEITEM; - default: return SHCNE_UPDATEITEM; - } -} - -VOID _ProcessNotification(LPNOTIFYREGISTER item) -{ - BYTE* pBase = item->backBuffer; - TRACE("_ProcessNotification\n"); - - for (;;) - { - FILE_NOTIFY_INFORMATION* fni = (FILE_NOTIFY_INFORMATION*)pBase; - LPWSTR wszFilename; - INT len = 0; - WCHAR wstrFilename[MAX_PATH]; - WCHAR tmp[MAX_PATH]; - StringCchCopy(tmp, fni->FileNameLength, fni->FileName); - - PathCombine(wstrFilename, item->wstrDirectory, tmp); - - /* If it could be a short filename, expand it. */ - wszFilename = PathFindFileNameW(wstrFilename); - - len = lstrlenW(wszFilename); - /* The maximum length of an 8.3 filename is twelve, including the dot. */ - if (len <= 12 && wcschr(wszFilename, L'~')) - { - /* Convert to the long filename form. Unfortunately, this - does not work for deletions, so it's an imperfect fix. */ - wchar_t wbuf[MAX_PATH]; - if (GetLongPathName(wstrFilename, wbuf, _countof (wbuf)) > 0) - StringCchCopyW(wstrFilename, MAX_PATH, wbuf); - } - - /* On deletion of a folder PathIsDirectory will return false even if - it *was* a directory, so, again, imperfect. */ - SHChangeNotify(_MapAction(fni->Action, PathIsDirectory(wstrFilename)) | SHCNE_INTERRUPT, - SHCNF_PATHW, - wstrFilename, - NULL); - - if (!fni->NextEntryOffset) - break; - pBase += fni->NextEntryOffset; - } -} - -static void CALLBACK _RequestAllTermination(ULONG_PTR arg) -{ - m_bTerminate = TRUE; -} - -static unsigned int WINAPI _RunAsyncThreadProc(LPVOID arg) -{ - m_bTerminate = FALSE; - while (!m_bTerminate) - { - SleepEx(INFINITE, TRUE); - } - return 0; -} - -#endif /* __REACTOS__ */