diff --git a/dll/win32/shell32/CChangeNotify.cpp b/dll/win32/shell32/CChangeNotify.cpp new file mode 100644 index 0000000000..34732fcc49 --- /dev/null +++ b/dll/win32/shell32/CChangeNotify.cpp @@ -0,0 +1,491 @@ +/* + * PROJECT: shell32 + * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) + * PURPOSE: Shell change notification + * COPYRIGHT: Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) + */ + +#include "CChangeNotify.h" + +static CChangeNotify s_hwndNotif; + +EXTERN_C void +DoNotifyFreeSpace(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2) +{ + WCHAR path1[MAX_PATH], path2[MAX_PATH]; + + if (!SHGetPathFromIDListW(pidl1, path1)) + return; + + path2[0] = 0; + if (pidl2) + SHGetPathFromIDListW(pidl2, path2); + + if (path2[0]) + SHChangeNotify(SHCNE_FREESPACE, SHCNF_PATHW, path1, path2); + else + SHChangeNotify(SHCNE_FREESPACE, SHCNF_PATHW, path1, NULL); +} + +EXTERN_C UINT +DoGetNextRegID(void) +{ + return s_hwndNotif.GetNextRegID(); +} + +EXTERN_C void +DoRemoveChangeNotifyClientsByProcess(DWORD dwUserID) +{ + DWORD dwOwnerPID; + GetWindowThreadProcessId(s_hwndNotif, &dwOwnerPID); + s_hwndNotif.RemoveItemsByProcess(dwOwnerPID, dwUserID); +} + +static DWORD WINAPI +DoCreateNotifWindowThreadFunc(LPVOID pData) +{ + if (IsWindow(s_hwndNotif)) + return 0; + + HWND hwndShell = (HWND)pData; + DWORD exstyle = WS_EX_TOOLWINDOW; + DWORD style = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; + s_hwndNotif.CreateWorker(hwndShell, exstyle, style); + return 0; +} + +static DWORD WINAPI +ChangeNotifThreadFunc(LPVOID args) +{ + MSG msg; + while (GetMessage(&msg, NULL, 0, 0)) + { + if (!IsWindow(s_hwndNotif)) + break; + + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return 0; +} + +EXTERN_C HWND +DoCreateNotifWindow(HWND hwndShell) +{ + if (!IsWindow(s_hwndNotif)) + { + SHCreateThread(ChangeNotifThreadFunc, hwndShell, CTF_PROCESS_REF, + DoCreateNotifWindowThreadFunc); + } + return s_hwndNotif; +} + +EXTERN_C HWND +DoGetNotifWindow(BOOL bCreate) +{ + if (s_hwndNotif && IsWindow(s_hwndNotif)) + return s_hwndNotif; + + HWND hwnd, hwndShell = GetShellWindow(); + if (bCreate) + { + hwnd = DoCreateNotifWindow(hwndShell); + } + else + { + hwnd = (HWND)SendMessageW(hwndShell, WM_SHELL_GETNOTIFWND, 0, 0); + } + s_hwndNotif.SetHWND(hwnd); + + return hwnd; +} + +static LRESULT CALLBACK +OldDeliveryWorkerWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + HANDLE hLock; + LRESULT ret = 0; + PIDLIST_ABSOLUTE *ppidl = NULL; + LONG lEvent; + OLDDELIVERYWORKER *pNotif = (OLDDELIVERYWORKER *)GetWindowLongW(hwnd,0); + + switch (uMsg) + { + case WM_NOTIF_BANG: + if (pNotif) + { + hLock = SHChangeNotification_Lock((HANDLE)wParam, lParam, &ppidl, &lEvent); + if (hLock) + { + ret = SendMessageW(pNotif->hwnd, pNotif->uMsg, (WPARAM)*ppidl, lEvent); + SHChangeNotification_Unlock(hLock); + return TRUE; + } + } + return FALSE; + + case WM_NCDESTROY: + SetWindowLongW(hwnd, 0, 0); + LocalFree(pNotif); + break; + + default: + return DefWindowProcW(hwnd, uMsg, wParam, lParam); + } + return ret; +} + +EXTERN_C HWND +DoHireOldDeliveryWorker(HWND hwnd, UINT wMsg) +{ + LPOLDDELIVERYWORKER pWorker; + HWND hwndWorker; + + pWorker = (LPOLDDELIVERYWORKER)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(OLDDELIVERYWORKER)); + if (!pWorker) + return NULL; + + pWorker->hwnd = hwnd; + pWorker->uMsg = wMsg; + hwndWorker = SHCreateWorkerWindowW(OldDeliveryWorkerWindowProc, 0, 0, 0, 0, + (LONG_PTR)pWorker); + if (hwndWorker == NULL) + { + LocalFree(pWorker); + } + + return hwndWorker; +} + +EXTERN_C HANDLE +DoCreateNotifShare( + ULONG nRegID, + HWND hwnd, + UINT wMsg, + ULONG fSources, + LONG fEvents, + LONG fRecursive, + LPCITEMIDLIST pidl, + DWORD dwOwnerPID) +{ + DWORD cbPidl = ILGetSize(pidl); + DWORD cbSize = sizeof(NOTIFSHARE) + cbPidl; + HANDLE hShared = SHAllocShared(NULL, cbSize, dwOwnerPID); + if (!hShared) + return NULL; + + LPNOTIFSHARE pShared = (LPNOTIFSHARE)SHLockShared(hShared, dwOwnerPID); + if (pShared == NULL) + { + SHFreeShared(hShared, dwOwnerPID); + return NULL; + } + + pShared->dwMagic = NOTIFSHARE_MAGIC; + pShared->cbSize = cbSize; + pShared->nRegID = nRegID; + pShared->hwnd = hwnd; + pShared->uMsg = wMsg; + pShared->fSources = fSources; + pShared->fEvents = fEvents; + pShared->fRecursive = fRecursive; + pShared->ibPidl = 0; + if (pidl) + { + pShared->ibPidl = DWORD_ALIGNMENT(sizeof(NOTIFSHARE)); + memcpy((LPBYTE)pShared + pShared->ibPidl, pidl, cbPidl); + } + SHUnlockShared(pShared); + + return hShared; +} + +EXTERN_C HANDLE +DoCreateDelivery( + LONG wEventId, + UINT uFlags, + LPCITEMIDLIST pidl1, + LPCITEMIDLIST pidl2, + DWORD dwOwnerPID, + DWORD dwTick) +{ + LPDELITICKET pTicket; + HANDLE hShared = NULL; + DWORD cbPidl1, cbPidl2, ibOffset1, ibOffset2, cbSize; + + ibOffset1 = 0; + if (pidl1) + { + cbPidl1 = ILGetSize(pidl1); + ibOffset1 = DWORD_ALIGNMENT(sizeof(DELITICKET)); + } + + ibOffset2 = 0; + if (pidl2) + { + cbPidl2 = ILGetSize(pidl2); + ibOffset2 = DWORD_ALIGNMENT(ibOffset1 + cbPidl1); + } + + cbSize = ibOffset2 + cbPidl2; + + hShared = SHAllocShared(NULL, cbSize, dwOwnerPID); + if (hShared == NULL) + return NULL; + + pTicket = (LPDELITICKET)SHLockShared(hShared, dwOwnerPID); + if (pTicket == NULL) + { + SHFreeShared(hShared,dwOwnerPID); + return NULL; + } + pTicket->dwMagic = DELIVERY_MAGIC; + pTicket->wEventId = wEventId; + pTicket->uFlags = uFlags; + pTicket->ibOffset1 = ibOffset1; + pTicket->ibOffset2 = ibOffset2; + + if (pidl1) + memcpy((LPBYTE)pTicket + ibOffset1, pidl1, cbPidl1); + + if (pidl2) + memcpy((LPBYTE)pTicket + ibOffset2, pidl1, cbPidl2); + + SHUnlockShared(pTicket); + + return hShared; +} + +EXTERN_C LPCHANGE +DoGetChangeFromTicket(HANDLE hDelivery, DWORD dwOwnerPID) +{ + LPDELITICKET pTicket; + LPCHANGE pChange; + + pTicket = (LPDELITICKET)SHLockShared(hDelivery, dwOwnerPID); + if (!pTicket || pTicket->dwMagic != DELIVERY_MAGIC) + return NULL; + + pChange = (LPCHANGE)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(CHANGE)); + if (pChange == NULL) + { + SHUnlockShared(pTicket); + return NULL; + } + pChange->dwMagic = CHANGE_MAGIC; + + pChange->pidl1 = pChange->pidl2 = NULL; + if (pTicket->ibOffset1) + pChange->pidl1 = (LPITEMIDLIST)((LPBYTE)pTicket + pTicket->ibOffset1); + if (pTicket->ibOffset2) + pChange->pidl2 = (LPITEMIDLIST)((LPBYTE)pTicket + pTicket->ibOffset2); + + pChange->pTicket = pTicket; + return pChange; +} + +EXTERN_C void +DoChangeDelivery(LONG wEventId, UINT uFlags, LPITEMIDLIST pidl1, LPITEMIDLIST pidl2, + DWORD dwTick) +{ + HWND hwndNotif = DoGetNotifWindow(FALSE); + if (!hwndNotif) + return; + + DWORD pid; + GetWindowThreadProcessId(hwndNotif, &pid); + + HANDLE hDelivery = DoCreateDelivery(wEventId, uFlags, pidl1, pidl2, pid, dwTick); + if (hDelivery) + { + if ((uFlags & (SHCNF_FLUSH | SHCNF_FLUSHNOWAIT)) == SHCNF_FLUSH) + { + SendMessageW(hwndNotif, WM_NOTIF_DELIVERY, (WPARAM)hDelivery, pid); + } + else + { + SendNotifyMessageW(hwndNotif, WM_NOTIF_DELIVERY, (WPARAM)hDelivery, pid); + } + } +} + +BOOL CChangeNotify::AddItem(UINT nRegID, DWORD dwUserPID, HANDLE hShare) +{ + for (INT i = 0; i < m_items.GetSize(); ++i) + { + if (m_items[i].nRegID == INVALID_REG_ID) + { + m_items[i].nRegID = nRegID; + m_items[i].dwUserPID = dwUserPID; + m_items[i].hShare = hShare; + return TRUE; + } + } + + ITEM item = { nRegID, dwUserPID, hShare }; + m_items.Add(item); + return TRUE; +} + +BOOL CChangeNotify::RemoveItem(UINT nRegID, DWORD dwOwnerPID) +{ + BOOL bFound = FALSE; + + for (INT i = 0; i < m_items.GetSize(); ++i) + { + if (m_items[i].nRegID == nRegID) + { + bFound = TRUE; + SHFreeShared(m_items[i].hShare, dwOwnerPID); + m_items[i].nRegID = INVALID_REG_ID; + m_items[i].dwUserPID = 0; + m_items[i].hShare = NULL; + } + } + + return bFound; +} + +void CChangeNotify::RemoveItemsByProcess(DWORD dwOwnerPID, DWORD dwUserPID) +{ + for (INT i = 0; i < m_items.GetSize(); ++i) + { + if (m_items[i].dwUserPID == dwUserPID) + { + SHFreeShared(m_items[i].hShare, dwOwnerPID); + m_items[i].nRegID = INVALID_REG_ID; + m_items[i].dwUserPID = 0; + m_items[i].hShare = NULL; + } + } +} + +LRESULT CChangeNotify::OnBang(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) +{ + HANDLE hShared = (HANDLE)wParam; + DWORD dwOwnerPID = (DWORD)lParam; + + LPNOTIFSHARE pShared = (LPNOTIFSHARE)SHLockShared(hShared, dwOwnerPID); + if (!pShared || pShared->dwMagic != NOTIFSHARE_MAGIC) + return FALSE; + + DWORD dwUserPID; + GetWindowThreadProcessId(pShared->hwnd, &dwUserPID); + + HANDLE hNewShared = SHAllocShared(pShared, pShared->cbSize, dwOwnerPID); + return AddItem(m_nNextRegID, dwUserPID, hNewShared); +} + +LRESULT CChangeNotify::OnUnReg(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) +{ + UINT nRegID = (UINT)wParam; + if (nRegID == INVALID_REG_ID) + return FALSE; + + DWORD dwOwnerPID; + GetWindowThreadProcessId(m_hWnd, &dwOwnerPID); + + return RemoveItem(nRegID, dwOwnerPID); +} + +LRESULT CChangeNotify::OnDelivery(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) +{ + HANDLE hDelivery = (HANDLE)wParam; + DWORD dwOwnerPID = (DWORD)lParam; + BOOL ret = FALSE; + + LPCHANGE pChange = DoGetChangeFromTicket(hDelivery, dwOwnerPID); + if (pChange && pChange->dwMagic == CHANGE_MAGIC) + { + LPDELITICKET pTicket = pChange->pTicket; + if (pTicket && pTicket->dwMagic == DELIVERY_MAGIC) + { + ret = DoDelivery(hDelivery, pChange); + } + } + + SHChangeNotification_Unlock(pChange); + SHFreeShared(hDelivery, dwOwnerPID); + return ret; +} + +LRESULT CChangeNotify::OnSuspendResume(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) +{ + // FIXME + return FALSE; +} + +UINT CChangeNotify::GetNextRegID() +{ + m_nNextRegID++; + if (m_nNextRegID == INVALID_REG_ID) + m_nNextRegID++; + return m_nNextRegID; +} + +BOOL CChangeNotify::DoDelivery(HANDLE hDelivery, LPCHANGE pChange) +{ + DWORD dwOwnerPID; + GetWindowThreadProcessId(m_hWnd, &dwOwnerPID); + + for (INT i = 0; i < m_items.GetSize(); ++i) + { + HANDLE hShare = m_items[i].hShare; + if (!m_items[i].nRegID || !hShare) + continue; + + LPNOTIFSHARE pShared = (LPNOTIFSHARE)SHLockShared(hShare, dwOwnerPID); + if (!pShared || pShared->dwMagic != NOTIFSHARE_MAGIC) + continue; + + LPDELITICKET pTicket = (LPDELITICKET)SHLockShared(hDelivery, dwOwnerPID); + if (!pTicket || pTicket->dwMagic != DELIVERY_MAGIC) + { + SHUnlockShared(pShared); + continue; + } + + BOOL bNotify = ShouldNotify(pChange, pTicket, pShared); + SHUnlockShared(pTicket); + + if (bNotify) + { + SendNotifyMessageW(pShared->hwnd, pShared->uMsg, (WPARAM)hDelivery, dwOwnerPID); + } + SHUnlockShared(pShared); + } + + return TRUE; +} + +BOOL CChangeNotify::ShouldNotify(LPCHANGE pChange, LPDELITICKET pTicket, LPNOTIFSHARE pShared) +{ + LPITEMIDLIST pidl = NULL; + if (pShared->ibPidl) + pidl = (LPITEMIDLIST)((LPBYTE)pShared + pShared->ibPidl); + + if (!pidl) + return FALSE; + + LPITEMIDLIST pidl1 = NULL, pidl2 = NULL; + if (pTicket->ibOffset1) + pidl1 = (LPITEMIDLIST)((LPBYTE)pTicket + pTicket->ibOffset1); + if (pTicket->ibOffset2) + pidl2 = (LPITEMIDLIST)((LPBYTE)pTicket + pTicket->ibOffset2); + + if (pidl1 && ILIsEqual(pidl, pidl1)) + return TRUE; + if (pidl2 && ILIsEqual(pidl, pidl2)) + return TRUE; + + if (pShared->fRecursive) + { + if (pidl1 && ILIsParent(pidl, pidl1, FALSE)) + return TRUE; + if (pidl2 && ILIsParent(pidl, pidl2, FALSE)) + return TRUE; + } + + return FALSE; +} diff --git a/dll/win32/shell32/CChangeNotify.h b/dll/win32/shell32/CChangeNotify.h new file mode 100644 index 0000000000..de91caacff --- /dev/null +++ b/dll/win32/shell32/CChangeNotify.h @@ -0,0 +1,181 @@ +/* + * PROJECT: shell32 + * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) + * PURPOSE: Shell change notification + * COPYRIGHT: Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) + */ + +#pragma once + +#define INVALID_REG_ID 0 + +#define WM_SHELL_GETNOTIFWND (WM_USER+25) // 0x419 + +#define WM_NOTIF_BANG (WM_USER + 1) // 0x401 +#define WM_NOTIF_UNREG (WM_USER + 2) // 0x402 +#define WM_NOTIF_DELIVERY (WM_USER + 3) // 0x403 +#define WM_NOTIF_SUSPEND (WM_USER + 6) // 0x406 + +#define DWORD_ALIGNMENT(offset) \ + ((((offset) + sizeof(DWORD) - 1) / sizeof(DWORD)) * sizeof(DWORD)) + +typedef struct OLDDELIVERYWORKER +{ + HWND hwnd; + UINT uMsg; +} OLDDELIVERYWORKER, *LPOLDDELIVERYWORKER; + +typedef struct DELITICKET +{ + DWORD dwMagic; + LONG wEventId; + UINT uFlags; + DWORD dwTick; + DWORD ibOffset1; // offset to pidl1 + DWORD ibOffset2; // offset to pidl2 +} DELITICKET, *LPDELITICKET; + +typedef struct NOTIFSHARE +{ + DWORD dwMagic; + DWORD cbSize; + UINT nRegID; + HWND hwnd; + UINT uMsg; + LONG fSources; + LONG fEvents; + BOOL fRecursive; + UINT ibPidl; +} NOTIFSHARE, *LPNOTIFSHARE; + +typedef struct CHANGE +{ + DWORD dwMagic; + LPITEMIDLIST pidl1; + LPITEMIDLIST pidl2; + LPDELITICKET pTicket; +} CHANGE, *LPCHANGE; + +#define DELIVERY_MAGIC 0xDEADFACE +#define NOTIFSHARE_MAGIC 0xB0B32D1E +#define CHANGE_MAGIC 0xFACEB00C + +EXTERN_C HWND +DoGetNotifWindow(BOOL bCreate); + +EXTERN_C HWND +DoCreateNotifWindow(HWND hwndShell); + +EXTERN_C UINT +DoGetNextRegID(void); + +EXTERN_C void +DoRemoveChangeNotifyClientsByProcess(DWORD dwPID); + +EXTERN_C void +DoNotifyFreeSpace(LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2); + +EXTERN_C HWND +DoHireOldDeliveryWorker(HWND hwnd, UINT wMsg); + +EXTERN_C LPCHANGE +DoGetChangeFromTicket(HANDLE hDelivery, DWORD dwOwnerPID); + +EXTERN_C HANDLE +DoCreateNotifShare(ULONG nRegID, HWND hwnd, UINT wMsg, ULONG fSources, + LONG fEvents, LONG fRecursive, LPCITEMIDLIST pidl, DWORD dwOwnerPID); + +EXTERN_C HANDLE +DoCreateDelivery(LONG wEventId, UINT uFlags, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, + DWORD dwOwnerPID, DWORD dwTick); + +EXTERN_C void +DoChangeDelivery(LONG wEventId, UINT uFlags, LPITEMIDLIST pidl1, LPITEMIDLIST pidl2, + DWORD dwTick); + +#ifdef __cplusplus // C++ + +class CWorker : public CMessageMap +{ +public: + static LRESULT CALLBACK + WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) + { + CWorker *pThis = (CWorker *)GetWindowLongPtr(hwnd, 0); + if (pThis) + { + LRESULT lResult = 0; + BOOL bHandled = pThis->ProcessWindowMessage(hwnd, uMsg, wParam, lParam, lResult, 0); + if (bHandled) + return lResult; + } + return 0; + } + + BOOL CreateWorker(HWND hwndParent, DWORD dwExStyle, DWORD dwStyle) + { + m_hWnd = SHCreateWorkerWindowW(WindowProc, hwndParent, dwExStyle, dwStyle, + NULL, (LONG_PTR)this); + return m_hWnd != NULL; + } + +protected: + HWND m_hWnd; +}; + +class CChangeNotify : public CWorker +{ +public: + struct ITEM + { + UINT nRegID; + DWORD dwUserPID; + HANDLE hShare; + }; + + CChangeNotify() : m_nNextRegID(INVALID_REG_ID) + { + } + + ~CChangeNotify() + { + } + + operator HWND() + { + return m_hWnd; + } + + void SetHWND(HWND hwnd) + { + m_hWnd = hwnd; + } + + BOOL AddItem(UINT nRegID, DWORD dwUserPID, HANDLE hShare); + BOOL RemoveItem(UINT nRegID, DWORD dwOwnerPID); + void RemoveItemsByProcess(DWORD dwOwnerPID, DWORD dwUserPID); + + UINT GetNextRegID(); + BOOL DoDelivery(HANDLE hDelivery, LPCHANGE pChange); + + BOOL ShouldNotify(LPCHANGE pChange, LPDELITICKET pTicket, LPNOTIFSHARE pShared); + BOOL DoNotify(LPCHANGE pChange, LPDELITICKET pTicket, LPNOTIFSHARE pShared); + + LRESULT OnBang(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + LRESULT OnUnReg(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + LRESULT OnDelivery(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + LRESULT OnSuspendResume(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); + + BEGIN_MSG_MAP(CChangeNotify) + MESSAGE_HANDLER(WM_NOTIF_BANG, OnBang) + MESSAGE_HANDLER(WM_NOTIF_UNREG, OnUnReg) + MESSAGE_HANDLER(WM_NOTIF_DELIVERY, OnDelivery) + MESSAGE_HANDLER(WM_NOTIF_SUSPEND, OnSuspendResume) + END_MSG_MAP() + +protected: + UINT m_nNextRegID; + CSimpleArray m_items; +}; + +#endif // C++ diff --git a/dll/win32/shell32/CMakeLists.txt b/dll/win32/shell32/CMakeLists.txt index fb850fceaf..744277bdd7 100644 --- a/dll/win32/shell32/CMakeLists.txt +++ b/dll/win32/shell32/CMakeLists.txt @@ -45,6 +45,7 @@ list(APPEND SOURCE dialogs/general.cpp dialogs/recycler_prop.cpp dialogs/view.cpp + CChangeNotify.cpp CDropTargetHelper.cpp CEnumIDListBase.cpp CExtractIcon.cpp diff --git a/dll/win32/shell32/shelldesktop/CDesktopBrowser.cpp b/dll/win32/shell32/shelldesktop/CDesktopBrowser.cpp index 4ef2ab112e..efabda53ac 100644 --- a/dll/win32/shell32/shelldesktop/CDesktopBrowser.cpp +++ b/dll/win32/shell32/shelldesktop/CDesktopBrowser.cpp @@ -2,6 +2,7 @@ * Shell Desktop * * Copyright 2008 Thomas Bluemel + * Copyright 2020 Katayama Hirofumi MZ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -25,7 +26,7 @@ #include #endif - +#define WM_SHELL_GETNOTIFWND (WM_USER+25) /* 0x419 */ WINE_DEFAULT_DEBUG_CHANNEL(desktop); @@ -82,6 +83,7 @@ public: LRESULT OnOpenNewWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); + LRESULT OnGetNotifWnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); DECLARE_WND_CLASS_EX(szProgmanClassName, CS_DBLCLKS, COLOR_DESKTOP) @@ -94,6 +96,7 @@ BEGIN_MSG_MAP(CBaseBar) MESSAGE_HANDLER(WM_EXPLORER_OPEN_NEW_WINDOW, OnOpenNewWindow) MESSAGE_HANDLER(WM_COMMAND, OnCommand) MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) + MESSAGE_HANDLER(WM_SHELL_GETNOTIFWND, OnGetNotifWnd) END_MSG_MAP() BEGIN_COM_MAP(CDesktopBrowser) @@ -429,6 +432,11 @@ LRESULT CDesktopBrowser::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOO return 0; } +LRESULT CDesktopBrowser::OnGetNotifWnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) +{ + return (LRESULT)::FindWindowExW(m_hWnd, NULL, L"WorkerW", NULL); +} + HRESULT CDesktopBrowser_CreateInstance(IShellDesktopTray *Tray, REFIID riid, void **ppv) { return ShellObjectCreatorInit(Tray, riid, ppv); diff --git a/dll/win32/shell32/wine/changenotify.c b/dll/win32/shell32/wine/changenotify.c index e577547039..689c3ca6dd 100644 --- a/dll/win32/shell32/wine/changenotify.c +++ b/dll/win32/shell32/wine/changenotify.c @@ -39,6 +39,10 @@ #include "pidl.h" WINE_DEFAULT_DEBUG_CHANNEL(shell); +#ifdef __REACTOS__ + #include "../CChangeNotify.h" + DWORD WINAPI SHAnsiToUnicode(LPCSTR lpSrcStr, LPWSTR lpDstStr, int iLen); +#endif static CRITICAL_SECTION SHELL32_ChangenotifyCS; static CRITICAL_SECTION_DEBUG critsect_debug = @@ -49,20 +53,8 @@ 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 +#ifndef __REACTOS__ typedef SHChangeNotifyEntry *LPNOTIFYREGISTER; -#endif /* internal list of notification clients (internal) */ typedef struct _NOTIFICATIONLIST @@ -77,25 +69,9 @@ 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 ( \ SHCNE_ASSOCCHANGED ) @@ -108,6 +84,7 @@ BOOL m_bTerminate; #define SHCNE_TWOITEMEVENTS ( \ SHCNE_RENAMEFOLDER | SHCNE_RENAMEITEM | SHCNE_UPDATEITEM ) +#endif /* ndef __REACTOS__ */ /* for dumping events */ static const char * DumpEvent( LONG event ) @@ -142,6 +119,7 @@ static const char * DumpEvent( LONG event ) #undef DUMPEV } +#ifndef __REACTOS__ static const char * NodeName(const NOTIFICATIONLIST *item) { const char *str; @@ -165,30 +143,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__ + EnterCriticalSection(&SHELL32_ChangenotifyCS); + DoRemoveChangeNotifyClientsByProcess(GetCurrentProcessId()); + LeaveCriticalSection(&SHELL32_ChangenotifyCS); + DeleteCriticalSection(&SHELL32_ChangenotifyCS); +#else LPNOTIFICATIONLIST ptr, next; TRACE("\n"); @@ -200,11 +172,8 @@ void FreeChangeNotifications(void) LeaveCriticalSection(&SHELL32_ChangenotifyCS); -#ifdef __REACTOS__ - QueueUserAPC(_RequestAllTermination, m_hThread, (ULONG_PTR) NULL ); -#endif - DeleteCriticalSection(&SHELL32_ChangenotifyCS); +#endif } /************************************************************************* @@ -220,6 +189,62 @@ SHChangeNotifyRegister( int cItems, SHChangeNotifyEntry *lpItems) { +#ifdef __REACTOS__ + HWND hwndNotif; + HANDLE hShared; + int iItem; + ULONG nRegID = 0; + DWORD pid; + BOOL bAdded; + + TRACE("(%p,0x%08x,0x%08x,0x%08x,%d,%p)\n", + hwnd, fSources, wEventMask, uMsg, cItems, lpItems); + + hwndNotif = DoGetNotifWindow(TRUE); + if (hwndNotif == NULL) + return INVALID_REG_ID; + + if ((fSources & SHCNRF_NewDelivery) == 0) + { + hwnd = (HWND)DoHireOldDeliveryWorker(hwnd, uMsg); + uMsg = WM_NOTIF_BANG; + } + + if ((fSources & SHCNRF_RecursiveInterrupt) != 0 && + (fSources & SHCNRF_InterruptLevel) == 0) + { + fSources &= ~SHCNRF_NewDelivery; + } + + GetWindowThreadProcessId(hwndNotif, &pid); + + EnterCriticalSection(&SHELL32_ChangenotifyCS); + + nRegID = DoGetNextRegID(); + + for (iItem = 0; iItem < cItems; ++iItem) + { + bAdded = FALSE; + hShared = DoCreateNotifShare(nRegID, hwnd, uMsg, fSources, wEventMask, + lpItems[iItem].fRecursive, lpItems[iItem].pidl, + pid); + if (hShared) + { + bAdded = (BOOL)SendMessageW(hwndNotif, WM_NOTIF_BANG, (WPARAM)hShared, pid); + SHFreeShared(hShared, pid); + } + + if (!bAdded && (fSources & SHCNRF_NewDelivery) == 0) + { + DestroyWindow(hwnd); + return INVALID_REG_ID; + } + } + + LeaveCriticalSection(&SHELL32_ChangenotifyCS); + + return nRegID; +#else LPNOTIFICATIONLIST item; int i; @@ -228,37 +253,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 +275,7 @@ SHChangeNotifyRegister( LeaveCriticalSection(&SHELL32_ChangenotifyCS); return item->id; +#endif } /************************************************************************* @@ -282,6 +283,21 @@ SHChangeNotifyRegister( */ BOOL WINAPI SHChangeNotifyDeregister(ULONG hNotify) { +#ifdef __REACTOS__ + HWND hwndNotif; + LRESULT ret = 0; + + TRACE("(0x%08x)\n", hNotify); + + EnterCriticalSection(&SHELL32_ChangenotifyCS); + hwndNotif = DoGetNotifWindow(FALSE); + if (hwndNotif) + { + ret = SendMessageW(hwndNotif, WM_NOTIF_UNREG, hNotify, 0); + } + LeaveCriticalSection(&SHELL32_ChangenotifyCS); + return ret; +#else LPNOTIFICATIONLIST node; TRACE("(0x%08x)\n", hNotify); @@ -299,6 +315,7 @@ BOOL WINAPI SHChangeNotifyDeregister(ULONG hNotify) } LeaveCriticalSection(&SHELL32_ChangenotifyCS); return FALSE; +#endif } /************************************************************************* @@ -313,6 +330,7 @@ BOOL WINAPI SHChangeNotifyUpdateEntryList(DWORD unknown1, DWORD unknown2, return TRUE; } +#ifndef __REACTOS__ struct new_delivery_notification { LONG event; @@ -333,12 +351,81 @@ static BOOL should_notify( LPCITEMIDLIST changed, LPCITEMIDLIST watched, BOOL su return TRUE; return FALSE; } +#endif /* ndef __REACTOS__ */ /************************************************************************* * SHChangeNotify [SHELL32.@] */ void WINAPI SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2) { +#ifdef __REACTOS__ + LPITEMIDLIST pidl1 = NULL, pidl2 = NULL; + LPITEMIDLIST pidlTemp1 = NULL, pidlTemp2 = NULL; + DWORD dwTick = GetTickCount(); + WCHAR szPath1[MAX_PATH], szPath2[MAX_PATH]; + LPWSTR psz1, psz2; + + switch (uFlags & SHCNF_TYPE) + { + case SHCNF_IDLIST: + if (wEventId == SHCNE_FREESPACE) + { + DoNotifyFreeSpace(dwItem1, dwItem2); + goto Quit; + } + pidl1 = (LPITEMIDLIST)dwItem1; + pidl2 = (LPITEMIDLIST)dwItem2; + break; + + case SHCNF_PATHA: + psz1 = psz2 = NULL; + if (dwItem1) + { + SHAnsiToUnicode((LPCSTR)dwItem1, szPath1, ARRAYSIZE(szPath1)); + psz1 = szPath1; + } + if (dwItem2) + { + SHAnsiToUnicode((LPCSTR)dwItem2, szPath2, ARRAYSIZE(szPath2)); + psz2 = szPath2; + } + uFlags &= ~SHCNF_TYPE; + uFlags |= SHCNF_PATHW; + return SHChangeNotify(wEventId, uFlags, psz1, psz2); + + case SHCNF_PATHW: + if (wEventId == SHCNE_FREESPACE) + { + // FIXME + goto Quit; + } + if (dwItem1) + { + pidl1 = pidlTemp1 = SHSimpleIDListFromPathW((LPCWSTR)dwItem1); + if (dwItem2) + { + pidl2 = pidlTemp2 = SHSimpleIDListFromPathW((LPCWSTR)dwItem2); + } + } + break; + + default: + FIXME("unknown type %08x\n", uFlags & SHCNF_TYPE); + return; + } + + if (wEventId == 0 || (wEventId & SHCNE_ASSOCCHANGED) || pidl1 != NULL) + { + TRACE("notifying event %s(%x)\n", DumpEvent(wEventId), wEventId); + DoChangeDelivery(wEventId, uFlags, pidl1, pidl2, dwTick); + } + +Quit: + if (pidlTemp1) + ILFree(pidlTemp1); + if (pidlTemp2) + ILFree(pidlTemp2); +#else struct notification_recipients { struct list entry; HWND hwnd; @@ -370,9 +457,7 @@ void WINAPI SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID { TRACE("dwItem2 is not zero, but should be\n"); dwItem2 = 0; -#ifndef __REACTOS__ return; -#endif } if( ( ( wEventId & SHCNE_NOITEMEVENTS ) && @@ -390,49 +475,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); @@ -534,7 +582,6 @@ void WINAPI SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID SHFree(Pidls[0]); SHFree(Pidls[1]); -#ifndef __REACTOS__ if (wEventId & SHCNE_ASSOCCHANGED) { static const WCHAR args[] = {' ','-','a',0 }; @@ -545,22 +592,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); } /************************************************************************* @@ -572,6 +618,26 @@ HANDLE WINAPI SHChangeNotification_Lock( LPITEMIDLIST **lppidls, LPLONG lpwEventId) { +#ifdef __REACTOS__ + LPDELITICKET pTicket; + LPCHANGE pChange; + + TRACE("%p %08x %p %p\n", hChange, dwProcessId, lppidls, lpwEventId); + + pChange = (LPCHANGE)DoGetChangeFromTicket(hChange, dwProcessId); + if (!pChange || pChange->dwMagic != CHANGE_MAGIC) + return NULL; + + pTicket = pChange->pTicket; + + if (lppidls) + *lppidls = &pChange->pidl1; + + if (lpwEventId) + *lpwEventId = pTicket->wEventId; + + return pChange; +#else struct new_delivery_notification *ndn; UINT offset; @@ -594,6 +660,7 @@ HANDLE WINAPI SHChangeNotification_Lock( *lpwEventId = ndn->event; return ndn; +#endif } /************************************************************************* @@ -601,8 +668,23 @@ HANDLE WINAPI SHChangeNotification_Lock( */ BOOL WINAPI SHChangeNotification_Unlock ( HANDLE hLock) { +#ifdef __REACTOS__ + LPCHANGE pChange = (LPCHANGE)hLock; + BOOL ret; + + TRACE("%p\n", hLock); + + if (!pChange || pChange->dwMagic != CHANGE_MAGIC) + return FALSE; + + ret = SHUnlockShared(pChange->pTicket); + LocalFree(hLock); + + return ret; +#else TRACE("%p\n", hLock); return SHUnlockShared(hLock); +#endif } /************************************************************************* @@ -614,255 +696,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__ */