https://git.reactos.org/?p=reactos.git;a=commitdiff;h=7f766e94d4087b136f8a142863a395cafd235868

commit 7f766e94d4087b136f8a142863a395cafd235868
Author:     Katayama Hirofumi MZ <[email protected]>
AuthorDate: Sat Feb 29 08:13:52 2020 +0900
Commit:     GitHub <[email protected]>
CommitDate: Sat Feb 29 08:13:52 2020 +0900

    [SHELL32_APITEST] Support multi-process of SHChangeNotify testcase (#2399)
    
    The shell32!SHChangeNotify function must be tested on multiple processes. 
CORE-13950
---
 modules/rostests/apitests/shell32/CMakeLists.txt   |   6 +
 .../rostests/apitests/shell32/SHChangeNotify.cpp   | 304 ++++-----------------
 modules/rostests/apitests/shell32/shell-notify.cpp | 256 +++++++++++++++++
 3 files changed, 317 insertions(+), 249 deletions(-)

diff --git a/modules/rostests/apitests/shell32/CMakeLists.txt 
b/modules/rostests/apitests/shell32/CMakeLists.txt
index aab3e8bcfb8..1ef8819746c 100644
--- a/modules/rostests/apitests/shell32/CMakeLists.txt
+++ b/modules/rostests/apitests/shell32/CMakeLists.txt
@@ -46,3 +46,9 @@ set_module_type(shell32_apitest win32cui)
 add_importlibs(shell32_apitest user32 gdi32 shell32 ole32 oleaut32 advapi32 
shlwapi msvcrt kernel32 ntdll)
 add_pch(shell32_apitest shelltest.h SOURCE)
 add_rostests_file(TARGET shell32_apitest)
+
+# shell-notify.exe
+add_executable(shell-notify shell-notify.cpp)
+set_module_type(shell-notify win32gui UNICODE)
+add_importlibs(shell-notify msvcrt kernel32 user32 shell32 shlwapi ole32)
+add_rostests_file(TARGET shell-notify SUBDIR testdata)
diff --git a/modules/rostests/apitests/shell32/SHChangeNotify.cpp 
b/modules/rostests/apitests/shell32/SHChangeNotify.cpp
index c4257b993ec..372696d24ec 100644
--- a/modules/rostests/apitests/shell32/SHChangeNotify.cpp
+++ b/modules/rostests/apitests/shell32/SHChangeNotify.cpp
@@ -10,8 +10,8 @@
 #include <stdio.h>
 
 #define WM_SHELL_NOTIFY (WM_USER + 100)
-
-#define ID_TEST 1000
+#define WM_GET_NOTIFY_FLAGS (WM_USER + 101)
+#define WM_CLEAR_FLAGS (WM_USER + 102)
 
 static WCHAR s_dir1[MAX_PATH];  // "%TEMP%\\WatchDir1"
 static WCHAR s_dir2[MAX_PATH];  // "%TEMP%\\WatchDir1\\Dir2"
@@ -20,12 +20,7 @@ static WCHAR s_file1[MAX_PATH]; // 
"%TEMP%\\WatchDir1\\File1.txt"
 static WCHAR s_file2[MAX_PATH]; // "%TEMP%\\WatchDir1\\File2.txt"
 
 static HWND s_hwnd = NULL;
-static WCHAR s_szName[] = L"SHChangeNotify testcase";
-static LPITEMIDLIST s_pidl = NULL;
-static UINT s_uRegID = 0;
-static SHChangeNotifyEntry s_entry;
-
-static CHAR s_path1[MAX_PATH], s_path2[MAX_PATH];
+static const WCHAR s_szName[] = L"SHChangeNotify testcase";
 
 typedef enum TYPE
 {
@@ -40,21 +35,6 @@ typedef enum TYPE
     TYPE_FREESPACE
 } TYPE;
 
-static BYTE s_counters[TYPE_FREESPACE + 1];
-
-static LPCSTR
-DoGetPattern(void)
-{
-    size_t i;
-    static char buf[TYPE_FREESPACE + 1 + 1];
-    for (i = 0; i < TYPE_FREESPACE + 1; ++i)
-    {
-        buf[i] = (char)('0' + s_counters[i]);
-    }
-    buf[i] = 0;
-    return buf;
-}
-
 typedef void (*ACTION)(void);
 
 typedef struct TEST_ENTRY
@@ -134,13 +114,10 @@ static const TEST_ENTRY s_TestEntries[] = {
     {__LINE__, SHCNE_RMDIR, s_dir2, NULL, "000010000", DoAction2},
     {__LINE__, SHCNE_MKDIR, s_dir2, NULL, "000100000", DoAction1},
     {__LINE__, SHCNE_RENAMEFOLDER, s_dir2, s_dir3, "000000010", NULL},
-    {__LINE__, SHCNE_RENAMEFOLDER, s_dir2, NULL, "000000010", NULL},
     {__LINE__, SHCNE_RENAMEFOLDER, s_dir2, s_dir3, "000000010", DoAction3},
-    {__LINE__, SHCNE_RENAMEFOLDER, s_dir2, NULL, "000000010", NULL},
     {__LINE__, SHCNE_CREATE, s_file1, NULL, "010000000", NULL},
     {__LINE__, SHCNE_CREATE, s_file1, s_file2, "010000000", NULL},
     {__LINE__, SHCNE_CREATE, s_file1, NULL, "010000000", DoAction4},
-    {__LINE__, SHCNE_RENAMEITEM, s_file1, NULL, "100000000", NULL},
     {__LINE__, SHCNE_RENAMEITEM, s_file1, s_file2, "100000000", NULL},
     {__LINE__, SHCNE_RENAMEITEM, s_file1, s_file2, "100000000", DoAction5},
     {__LINE__, SHCNE_RENAMEITEM, s_file1, s_file2, "100000000", NULL},
@@ -175,11 +152,21 @@ static const TEST_ENTRY s_TestEntries[] = {
     {__LINE__, SHCNE_RMDIR, s_dir1, NULL, "000010000", NULL},
     {__LINE__, SHCNE_RMDIR, s_dir1, NULL, "000010000", DoAction8},
 };
-static const size_t s_nTestEntries = _countof(s_TestEntries);
-static size_t s_iTest = 0;
+
+LPCSTR PatternFromFlags(DWORD flags)
+{
+    static char s_buf[TYPE_FREESPACE + 1 + 1];
+    DWORD i;
+    for (i = 0; i <= TYPE_FREESPACE; ++i)
+    {
+        s_buf[i] = (char)('0' + !!(flags & (1 << i)));
+    }
+    s_buf[i] = 0;
+    return s_buf;
+}
 
 static void
-DoTestEntry1(const TEST_ENTRY *entry)
+DoTestEntry(const TEST_ENTRY *entry)
 {
     if (entry->action)
     {
@@ -187,16 +174,13 @@ DoTestEntry1(const TEST_ENTRY *entry)
     }
 
     SHChangeNotify(entry->event, SHCNF_PATHW | SHCNF_FLUSH, entry->item1, 
entry->item2);
-    SendMessageW(s_hwnd, WM_COMMAND, ID_TEST + s_iTest, 0);
 
-    ZeroMemory(&s_counters, sizeof(s_counters));
-}
+    DWORD flags = SendMessageW(s_hwnd, WM_GET_NOTIFY_FLAGS, 0, 0);
+    LPCSTR pattern = PatternFromFlags(flags);
 
-static void
-DoTestEntry2(const TEST_ENTRY *entry)
-{
-    LPCSTR pattern = DoGetPattern();
     ok(lstrcmpA(pattern, entry->pattern) == 0, "Line %d: pattern mismatch 
'%s'\n", entry->line, pattern);
+
+    SendMessageW(s_hwnd, WM_CLEAR_FLAGS, 0, 0);
 }
 
 static BOOL
@@ -223,252 +207,74 @@ DoInit(HWND hwnd)
     lstrcpyW(s_file2, s_dir1);
     PathAppendW(s_file2, L"File2.txt");
 
-    s_pidl = ILCreateFromPathW(s_dir1);
-
-    s_entry.pidl = s_pidl;
-    s_entry.fRecursive = TRUE;
-    LONG fEvents = SHCNE_ALLEVENTS;
-    s_uRegID = SHChangeNotifyRegister(hwnd, SHCNRF_ShellLevel, fEvents, 
WM_SHELL_NOTIFY,
-                                      1, &s_entry);
-    return s_uRegID != 0;
-}
-
-static DWORD WINAPI ThreadFunc(LPVOID)
-{
-    for (size_t i = 0; i < s_nTestEntries; ++i)
-    {
-        s_iTest = i;
-        DoTestEntry1(&s_TestEntries[i]);
-    }
-
-    SendMessageW(s_hwnd, WM_COMMAND, IDOK, 0);
-    return 0;
-}
-
-static BOOL
-OnCreate(HWND hwnd)
-{
-    s_hwnd = hwnd;
-
-    BOOL bOK = DoInit(hwnd);
-    if (!bOK)
-    {
-        skip("SHChangeNotifyRegister failed\n");
-        return FALSE;
-    }
-
-    DWORD tid;
-    HANDLE hThread = CreateThread(NULL, 0, ThreadFunc, NULL, 0, &tid);
-    if (hThread == NULL)
-    {
-        skip("CreateThread failed\n");
-        return FALSE;
-    }
-    CloseHandle(hThread);
-
     return TRUE;
 }
 
 static void
-OnCommand(HWND hwnd, UINT id)
-{
-    switch (id)
-    {
-        case IDOK:
-        case IDCANCEL:
-            DestroyWindow(hwnd);
-            break;
-        default:
-            if (ID_TEST <= id && id < ID_TEST + 1000)
-            {
-                DoTestEntry2(&s_TestEntries[s_iTest]);
-            }
-            break;
-    }
-}
-
-static void
-OnDestroy(HWND hwnd)
+DoEnd(HWND hwnd)
 {
-    SHChangeNotifyDeregister(s_uRegID);
-    CoTaskMemFree(s_pidl);
     DeleteFileW(s_file1);
     DeleteFileW(s_file2);
     RemoveDirectoryW(s_dir3);
     RemoveDirectoryW(s_dir2);
     RemoveDirectoryW(s_dir1);
-    PostQuitMessage(0);
-    s_hwnd = NULL;
+
+    SendMessageW(s_hwnd, WM_COMMAND, IDOK, 0);
 }
 
-static void
-DoShellNotify(HWND hwnd, PIDLIST_ABSOLUTE pidl1, PIDLIST_ABSOLUTE pidl2, LONG 
lEvent)
+START_TEST(SHChangeNotify)
 {
-    if (pidl1)
-        SHGetPathFromIDListA(pidl1, s_path1);
-    else
-        s_path1[0] = 0;
-
-    if (pidl2)
-        SHGetPathFromIDListA(pidl2, s_path2);
-    else
-        s_path2[0] = 0;
+    WCHAR szPath[MAX_PATH];
+    GetModuleFileNameW(NULL, szPath, _countof(szPath));
+    PathRemoveFileSpecW(szPath);
+    PathAppendW(szPath, L"shell-notify.exe");
 
-    switch (lEvent)
+    if (!PathFileExistsW(szPath))
     {
-        case SHCNE_RENAMEITEM:
-            trace("SHCNE_RENAMEITEM('%s', '%s')\n", s_path1, s_path2);
-            s_counters[TYPE_RENAMEITEM] = 1;
-            break;
-        case SHCNE_CREATE:
-            trace("SHCNE_CREATE('%s', '%s')\n", s_path1, s_path2);
-            s_counters[TYPE_CREATE] = 1;
-            break;
-        case SHCNE_DELETE:
-            trace("SHCNE_DELETE('%s', '%s')\n", s_path1, s_path2);
-            s_counters[TYPE_DELETE] = 1;
-            break;
-        case SHCNE_MKDIR:
-            trace("SHCNE_MKDIR('%s', '%s')\n", s_path1, s_path2);
-            s_counters[TYPE_MKDIR] = 1;
-            break;
-        case SHCNE_RMDIR:
-            trace("SHCNE_RMDIR('%s', '%s')\n", s_path1, s_path2);
-            s_counters[TYPE_RMDIR] = 1;
-            break;
-        case SHCNE_MEDIAINSERTED:
-            trace("SHCNE_MEDIAINSERTED('%s', '%s')\n", s_path1, s_path2);
-            break;
-        case SHCNE_MEDIAREMOVED:
-            trace("SHCNE_MEDIAREMOVED('%s', '%s')\n", s_path1, s_path2);
-            break;
-        case SHCNE_DRIVEREMOVED:
-            trace("SHCNE_DRIVEREMOVED('%s', '%s')\n", s_path1, s_path2);
-            break;
-        case SHCNE_DRIVEADD:
-            trace("SHCNE_DRIVEADD('%s', '%s')\n", s_path1, s_path2);
-            break;
-        case SHCNE_NETSHARE:
-            trace("SHCNE_NETSHARE('%s', '%s')\n", s_path1, s_path2);
-            break;
-        case SHCNE_NETUNSHARE:
-            trace("SHCNE_NETUNSHARE('%s', '%s')\n", s_path1, s_path2);
-            break;
-        case SHCNE_ATTRIBUTES:
-            trace("SHCNE_ATTRIBUTES('%s', '%s')\n", s_path1, s_path2);
-            break;
-        case SHCNE_UPDATEDIR:
-            trace("SHCNE_UPDATEDIR('%s', '%s')\n", s_path1, s_path2);
-            s_counters[TYPE_UPDATEDIR] = 1;
-            break;
-        case SHCNE_UPDATEITEM:
-            trace("SHCNE_UPDATEITEM('%s', '%s')\n", s_path1, s_path2);
-            s_counters[TYPE_UPDATEITEM] = 1;
-            break;
-        case SHCNE_SERVERDISCONNECT:
-            trace("SHCNE_SERVERDISCONNECT('%s', '%s')\n", s_path1, s_path2);
-            break;
-        case SHCNE_UPDATEIMAGE:
-            trace("SHCNE_UPDATEIMAGE('%s', '%s')\n", s_path1, s_path2);
-            break;
-        case SHCNE_DRIVEADDGUI:
-            trace("SHCNE_DRIVEADDGUI('%s', '%s')\n", s_path1, s_path2);
-            break;
-        case SHCNE_RENAMEFOLDER:
-            trace("SHCNE_RENAMEFOLDER('%s', '%s')\n", s_path1, s_path2);
-            s_counters[TYPE_RENAMEFOLDER] = 1;
-            break;
-        case SHCNE_FREESPACE:
-            trace("SHCNE_FREESPACE('%s', '%s')\n", s_path1, s_path2);
-            s_counters[TYPE_FREESPACE] = 1;
-            break;
-        case SHCNE_EXTENDED_EVENT:
-            trace("SHCNE_EXTENDED_EVENT('%p', '%p')\n", pidl1, pidl2);
-            break;
-        case SHCNE_ASSOCCHANGED:
-            trace("SHCNE_ASSOCCHANGED('%s', '%s')\n", s_path1, s_path2);
-            break;
-        default:
-            trace("(lEvent:%08lX)('%s', '%s')\n", lEvent, s_path1, s_path2);
-            break;
+        trace("szPath: %S\n", szPath);
+        PathRemoveFileSpecW(szPath);
+        PathAppendW(szPath, L"testdata\\shell-notify.exe");
+
+        if (!PathFileExistsW(szPath))
+        {
+            trace("szPath: %S\n", szPath);
+            skip("shell-notify.exe not found\n");
+            return;
+        }
     }
-}
 
-static INT_PTR
-OnShellNotify(HWND hwnd, WPARAM wParam, LPARAM lParam)
-{
-    LONG lEvent;
-    PIDLIST_ABSOLUTE *pidlAbsolute;
-    HANDLE hLock = SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, 
&pidlAbsolute, &lEvent);
-    if (hLock)
-    {
-        DoShellNotify(hwnd, pidlAbsolute[0], pidlAbsolute[1], lEvent);
-        SHChangeNotification_Unlock(hLock);
-    }
-    else
+    HINSTANCE hinst = ShellExecuteW(NULL, NULL, szPath, NULL, NULL, 
SW_SHOWNORMAL);
+    if ((INT_PTR)hinst <= 32)
     {
-        pidlAbsolute = (PIDLIST_ABSOLUTE *)wParam;
-        DoShellNotify(hwnd, pidlAbsolute[0], pidlAbsolute[1], lParam);
+        skip("Unable to run shell-notify.exe.\n");
+        return;
     }
-    return TRUE;
-}
 
-static LRESULT CALLBACK
-WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
-    switch (uMsg)
+    for (int i = 0; i < 10; ++i)
     {
-        case WM_CREATE:
-            return (OnCreate(hwnd) ? 0 : -1);
-
-        case WM_COMMAND:
-            OnCommand(hwnd, LOWORD(wParam));
-            break;
-
-        case WM_SHELL_NOTIFY:
-            return OnShellNotify(hwnd, wParam, lParam);
-
-        case WM_DESTROY:
-            OnDestroy(hwnd);
+        s_hwnd = FindWindowW(s_szName, s_szName);
+        if (s_hwnd)
             break;
 
-        default:
-            return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+        Sleep(100);
     }
-    return 0;
-}
 
-START_TEST(SHChangeNotify)
-{
-    WNDCLASSW wc;
-    ZeroMemory(&wc, sizeof(wc));
-    wc.lpfnWndProc = WindowProc;
-    wc.hInstance = GetModuleHandleW(NULL);
-    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
-    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
-    wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
-    wc.lpszClassName = s_szName;
-    if (!RegisterClassW(&wc))
+    if (!s_hwnd)
     {
-        skip("RegisterClassW failed\n");
+        skip("Unable to find window.\n");
         return;
     }
 
-    HWND hwnd = CreateWindowW(s_szName, s_szName, WS_OVERLAPPEDWINDOW,
-                              CW_USEDEFAULT, CW_USEDEFAULT, 100, 100,
-                              NULL, NULL, GetModuleHandleW(NULL), NULL);
-    if (!hwnd)
+    if (!DoInit(s_hwnd))
     {
-        skip("CreateWindowW failed\n");
+        skip("Unable to initialize.\n");
         return;
     }
-    ShowWindow(hwnd, SW_SHOWNORMAL);
-    UpdateWindow(hwnd);
 
-    MSG msg;
-    while (GetMessageW(&msg, NULL, 0, 0))
+    for (size_t i = 0; i < _countof(s_TestEntries); ++i)
     {
-        TranslateMessage(&msg);
-        DispatchMessageW(&msg);
+        DoTestEntry(&s_TestEntries[i]);
     }
+
+    DoEnd(s_hwnd);
 }
diff --git a/modules/rostests/apitests/shell32/shell-notify.cpp 
b/modules/rostests/apitests/shell32/shell-notify.cpp
new file mode 100644
index 00000000000..f6ac62e8a5d
--- /dev/null
+++ b/modules/rostests/apitests/shell32/shell-notify.cpp
@@ -0,0 +1,256 @@
+/*
+ * PROJECT:     ReactOS api tests
+ * LICENSE:     LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
+ * PURPOSE:     Test for SHChangeNotify
+ * COPYRIGHT:   Copyright 2020 Katayama Hirofumi MZ 
([email protected])
+ */
+
+#include "shelltest.h"
+#include <shlwapi.h>
+#include <stdio.h>
+
+#define WM_SHELL_NOTIFY (WM_USER + 100)
+#define WM_GET_NOTIFY_FLAGS (WM_USER + 101)
+#define WM_CLEAR_FLAGS (WM_USER + 102)
+
+static HWND s_hwnd = NULL;
+static const WCHAR s_szName[] = L"SHChangeNotify testcase";
+
+typedef enum TYPE
+{
+    TYPE_RENAMEITEM,
+    TYPE_CREATE,
+    TYPE_DELETE,
+    TYPE_MKDIR,
+    TYPE_RMDIR,
+    TYPE_UPDATEDIR,
+    TYPE_UPDATEITEM,
+    TYPE_RENAMEFOLDER,
+    TYPE_FREESPACE
+} TYPE;
+
+static BYTE s_counters[TYPE_FREESPACE + 1];
+static UINT s_uRegID = 0;
+static WCHAR s_dir1[MAX_PATH];  // "%TEMP%\\WatchDir1"
+static LPITEMIDLIST s_pidl = NULL;
+static SHChangeNotifyEntry s_entry;
+
+static BOOL
+OnCreate(HWND hwnd)
+{
+    s_hwnd = hwnd;
+
+    WCHAR szTemp[MAX_PATH], szPath[MAX_PATH];
+
+    GetTempPathW(_countof(szTemp), szTemp);
+    GetLongPathNameW(szTemp, szPath, _countof(szPath));
+
+    lstrcpyW(s_dir1, szPath);
+    PathAppendW(s_dir1, L"WatchDir1");
+
+    s_pidl = ILCreateFromPathW(s_dir1);
+
+    s_entry.pidl = s_pidl;
+    s_entry.fRecursive = TRUE;
+    LONG fEvents = SHCNE_ALLEVENTS;
+    s_uRegID = SHChangeNotifyRegister(hwnd, SHCNRF_ShellLevel, fEvents, 
WM_SHELL_NOTIFY,
+                                      1, &s_entry);
+    return s_uRegID != 0;
+}
+
+static void
+OnCommand(HWND hwnd, UINT id)
+{
+    switch (id)
+    {
+        case IDOK:
+        case IDCANCEL:
+            DestroyWindow(hwnd);
+            break;
+    }
+}
+
+static void
+OnDestroy(HWND hwnd)
+{
+    SHChangeNotifyDeregister(s_uRegID);
+    s_uRegID = 0;
+
+    CoTaskMemFree(s_pidl);
+    s_pidl = NULL;
+
+    PostQuitMessage(0);
+    s_hwnd = NULL;
+}
+
+static void
+DoShellNotify(HWND hwnd, PIDLIST_ABSOLUTE pidl1, PIDLIST_ABSOLUTE pidl2, LONG 
lEvent)
+{
+    CHAR path1[MAX_PATH], path2[MAX_PATH];
+
+    if (pidl1)
+        SHGetPathFromIDListA(pidl1, path1);
+    else
+        path1[0] = 0;
+
+    if (pidl2)
+        SHGetPathFromIDListA(pidl2, path2);
+    else
+        path2[0] = 0;
+
+    switch (lEvent)
+    {
+        case SHCNE_RENAMEITEM:
+            s_counters[TYPE_RENAMEITEM] = 1;
+            break;
+        case SHCNE_CREATE:
+            s_counters[TYPE_CREATE] = 1;
+            break;
+        case SHCNE_DELETE:
+            s_counters[TYPE_DELETE] = 1;
+            break;
+        case SHCNE_MKDIR:
+            s_counters[TYPE_MKDIR] = 1;
+            break;
+        case SHCNE_RMDIR:
+            s_counters[TYPE_RMDIR] = 1;
+            break;
+        case SHCNE_MEDIAINSERTED:
+            break;
+        case SHCNE_MEDIAREMOVED:
+            break;
+        case SHCNE_DRIVEREMOVED:
+            break;
+        case SHCNE_DRIVEADD:
+            break;
+        case SHCNE_NETSHARE:
+            break;
+        case SHCNE_NETUNSHARE:
+            break;
+        case SHCNE_ATTRIBUTES:
+            break;
+        case SHCNE_UPDATEDIR:
+            s_counters[TYPE_UPDATEDIR] = 1;
+            break;
+        case SHCNE_UPDATEITEM:
+            s_counters[TYPE_UPDATEITEM] = 1;
+            break;
+        case SHCNE_SERVERDISCONNECT:
+            break;
+        case SHCNE_UPDATEIMAGE:
+            break;
+        case SHCNE_DRIVEADDGUI:
+            break;
+        case SHCNE_RENAMEFOLDER:
+            s_counters[TYPE_RENAMEFOLDER] = 1;
+            break;
+        case SHCNE_FREESPACE:
+            s_counters[TYPE_FREESPACE] = 1;
+            break;
+        case SHCNE_EXTENDED_EVENT:
+            break;
+        case SHCNE_ASSOCCHANGED:
+            break;
+        default:
+            break;
+    }
+}
+
+static INT_PTR
+OnShellNotify(HWND hwnd, WPARAM wParam, LPARAM lParam)
+{
+    LONG lEvent;
+    PIDLIST_ABSOLUTE *pidlAbsolute;
+    HANDLE hLock = SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, 
&pidlAbsolute, &lEvent);
+    if (hLock)
+    {
+        DoShellNotify(hwnd, pidlAbsolute[0], pidlAbsolute[1], lEvent);
+        SHChangeNotification_Unlock(hLock);
+    }
+    else
+    {
+        pidlAbsolute = (PIDLIST_ABSOLUTE *)wParam;
+        DoShellNotify(hwnd, pidlAbsolute[0], pidlAbsolute[1], lParam);
+    }
+    return TRUE;
+}
+
+static LRESULT
+OnGetNotifyFlags(HWND hwnd)
+{
+    DWORD dwFlags = 0;
+    for (size_t i = 0; i < _countof(s_counters); ++i)
+    {
+        if (s_counters[i])
+            dwFlags |= (1 << i);
+    }
+    return dwFlags;
+}
+
+static LRESULT CALLBACK
+WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+    switch (uMsg)
+    {
+        case WM_CREATE:
+            return (OnCreate(hwnd) ? 0 : -1);
+
+        case WM_COMMAND:
+            OnCommand(hwnd, LOWORD(wParam));
+            break;
+
+        case WM_SHELL_NOTIFY:
+            return OnShellNotify(hwnd, wParam, lParam);
+
+        case WM_DESTROY:
+            OnDestroy(hwnd);
+            break;
+
+        case WM_GET_NOTIFY_FLAGS:
+            return OnGetNotifyFlags(hwnd);
+
+        case WM_CLEAR_FLAGS:
+            ZeroMemory(&s_counters, sizeof(s_counters));
+            break;
+
+        default:
+            return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+    }
+    return 0;
+}
+
+INT APIENTRY
+wWinMain(HINSTANCE hInstance,
+         HINSTANCE hPrevInstance,
+         LPWSTR    lpCmdLine,
+         INT       nCmdShow)
+{
+    WNDCLASSW wc;
+    ZeroMemory(&wc, sizeof(wc));
+    wc.lpfnWndProc = WindowProc;
+    wc.hInstance = GetModuleHandleW(NULL);
+    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+    wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
+    wc.lpszClassName = s_szName;
+    if (!RegisterClassW(&wc))
+        return -1;
+
+    HWND hwnd = CreateWindowW(s_szName, s_szName, WS_OVERLAPPEDWINDOW,
+                              CW_USEDEFAULT, CW_USEDEFAULT, 100, 100,
+                              NULL, NULL, GetModuleHandleW(NULL), NULL);
+    if (!hwnd)
+        return -1;
+
+    ShowWindow(hwnd, SW_SHOWNORMAL);
+    UpdateWindow(hwnd);
+
+    MSG msg;
+    while (GetMessageW(&msg, NULL, 0, 0))
+    {
+        TranslateMessage(&msg);
+        DispatchMessageW(&msg);
+    }
+
+    return 0;
+}

Reply via email to