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

commit 7e9cf359675f0ab4c71dd459fea955d509cf4449
Author:     Katayama Hirofumi MZ <[email protected]>
AuthorDate: Mon Dec 27 09:45:44 2021 +0900
Commit:     GitHub <[email protected]>
CommitDate: Mon Dec 27 09:45:44 2021 +0900

    [SHELL32_APITEST] Strengthen SHChangeNotify testcase more and more (#4174)
    
    CORE-13950
---
 .../rostests/apitests/shell32/SHChangeNotify.cpp   | 1035 +++++++++++++++-----
 modules/rostests/apitests/shell32/SHChangeNotify.h |   79 +-
 .../apitests/shell32/shell32_apitest_sub.cpp       |  162 +--
 3 files changed, 916 insertions(+), 360 deletions(-)

diff --git a/modules/rostests/apitests/shell32/SHChangeNotify.cpp 
b/modules/rostests/apitests/shell32/SHChangeNotify.cpp
index 377b9ce1cec..50481848357 100644
--- a/modules/rostests/apitests/shell32/SHChangeNotify.cpp
+++ b/modules/rostests/apitests/shell32/SHChangeNotify.cpp
@@ -2,213 +2,502 @@
  * 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])
+ * COPYRIGHT:   Copyright 2020-2021 Katayama Hirofumi MZ 
([email protected])
  */
 
-// NOTE: This test program closes the Explorer cabinets before tests.
+// NOTE: This test program closes the Explorer windows before tests.
 
 #include "shelltest.h"
-#include <shlwapi.h>
-#include <stdio.h>
 #include "SHChangeNotify.h"
-
-#define DONT_SEND 0x24242424
+#include <time.h>
+#include <process.h>
+#include <versionhelpers.h>
+
+// --- The selection of tests ---
+//#define DISABLE_THIS_TESTCASE
+#define NO_TRIVIAL
+//#define NO_INTERRUPT_LEVEL
+//#define NO_SHELL_LEVEL
+#define NEW_DELIVERY_ONLY
+//#define RANDOM_HALF
+#define RANDOM_QUARTER
+
+// --- Show the elapsed time by GetTickCount() ---
+//#define ENTRY_TICK
+#define GROUP_TICK
+#define TOTAL_TICK
 
 static HWND s_hwnd = NULL;
-static const WCHAR s_szName[] = L"SHChangeNotify testcase";
 static WCHAR s_szSubProgram[MAX_PATH];
+static HANDLE s_hThread = NULL;
+static HANDLE s_hEvent = NULL;
+
+static HWND DoWaitForWindow(LPCWSTR clsname, LPCWSTR text, BOOL bClosing, BOOL 
bForce)
+{
+    HWND hwnd = NULL;
+    for (INT i = 0; i < 50; ++i)
+    {
+        hwnd = FindWindowW(clsname, text);
+        if (bClosing)
+        {
+            if (!hwnd)
+                break;
+
+            if (bForce)
+                PostMessage(hwnd, WM_CLOSE, 0, 0);
+        }
+        else
+        {
+            if (hwnd)
+                break;
+        }
+
+        Sleep(1);
+    }
+    return hwnd;
+}
+
+static BOOL DoCreateEmptyFile(LPCWSTR pszFileName)
+{
+    FILE *fp = _wfopen(pszFileName, L"wb");
+    if (fp)
+        fclose(fp);
+    return fp != NULL;
+}
 
-typedef void (*ACTION)(void);
+struct TEST_ENTRY;
+
+typedef BOOL (*ACTION)(const struct TEST_ENTRY *entry);
 
 typedef struct TEST_ENTRY
 {
     INT line;
-    DWORD event;
-    LPCVOID item1;
-    LPCVOID item2;
+    DIRTYPE iWriteDir;
     LPCSTR pattern;
-    ACTION action;
     LPCWSTR path1;
     LPCWSTR path2;
+    ACTION action;
 } TEST_ENTRY;
 
-static BOOL
-DoCreateEmptyFile(LPCWSTR pszFileName)
+#define TEST_FILE      L"_TEST_.txt"
+#define TEST_FILE_KAI  L"_TEST_KAI_.txt"
+#define TEST_DIR       L"_TESTDIR_"
+#define TEST_DIR_KAI   L"_TESTDIR_KAI_"
+#define MOVE_FILE(from, to) MoveFileW((from), (to))
+
+static BOOL DoAction1(const TEST_ENTRY *entry)
 {
-    FILE *fp = _wfopen(pszFileName, L"wb");
-    fclose(fp);
-    return fp != NULL;
+    LPWSTR pszPath = DoGetDir(entry->iWriteDir);
+    PathAppendW(pszPath, TEST_FILE);
+    ok(DoCreateEmptyFile(pszPath), "Line %d: DoCreateEmptyFile failed\n", 
entry->line);
+    return TRUE;
 }
 
-static void
-DoAction1(void)
+static BOOL DoAction2(const TEST_ENTRY *entry)
 {
-    ok_int(CreateDirectoryW(s_dir2, NULL), TRUE);
+    LPWSTR pszPath1 = DoGetDir(entry->iWriteDir), pszPath2 = 
DoGetDir(entry->iWriteDir);
+    PathAppendW(pszPath1, TEST_FILE);
+    PathAppendW(pszPath2, TEST_FILE_KAI);
+    ok(MOVE_FILE(pszPath1, pszPath2), "Line %d: MOVE_FILE(%ls, %ls) failed 
(%ld)\n",
+       entry->line, pszPath1, pszPath2, GetLastError());
+    return TRUE;
 }
 
-static void
-DoAction2(void)
+static BOOL DoAction3(const TEST_ENTRY *entry)
 {
-    ok_int(RemoveDirectoryW(s_dir2), TRUE);
+    LPWSTR pszPath1 = DoGetDir(entry->iWriteDir), pszPath2 = 
DoGetDir(entry->iWriteDir);
+    PathAppendW(pszPath1, TEST_FILE_KAI);
+    PathAppendW(pszPath2, TEST_FILE);
+    ok(MOVE_FILE(pszPath1, pszPath2), "Line %d: MOVE_FILE(%ls, %ls) failed 
(%ld)\n",
+       entry->line, pszPath1, pszPath2, GetLastError());
+    return TRUE;
 }
 
-static void
-DoAction3(void)
+static BOOL DoAction4(const TEST_ENTRY *entry)
 {
-    ok_int(MoveFileExW(s_dir2, s_dir3, MOVEFILE_COPY_ALLOWED | 
MOVEFILE_REPLACE_EXISTING), TRUE);
+    LPWSTR pszPath = DoGetDir(entry->iWriteDir);
+    PathAppendW(pszPath, TEST_FILE);
+    ok(DeleteFileW(pszPath), "Line %d: DeleteFileW(%ls) failed (%ld)\n",
+       entry->line, pszPath, GetLastError());
+    return TRUE;
 }
 
-static void
-DoAction4(void)
+static BOOL DoAction5(const TEST_ENTRY *entry)
 {
-    ok_int(DoCreateEmptyFile(s_file1), TRUE);
+    LPWSTR pszPath = DoGetDir(entry->iWriteDir);
+    PathAppendW(pszPath, TEST_DIR);
+    ok(CreateDirectoryW(pszPath, NULL), "Line %d: CreateDirectoryW(%ls) failed 
(%ld)\n",
+       entry->line, pszPath, GetLastError());
+    return TRUE;
 }
 
-static void
-DoAction5(void)
+static BOOL DoAction6(const TEST_ENTRY *entry)
 {
-    ok_int(MoveFileExW(s_file1, s_file2, MOVEFILE_COPY_ALLOWED | 
MOVEFILE_REPLACE_EXISTING), TRUE);
+    LPWSTR pszPath1 = DoGetDir(entry->iWriteDir), pszPath2 = 
DoGetDir(entry->iWriteDir);
+    PathAppendW(pszPath1, TEST_DIR);
+    PathAppendW(pszPath2, TEST_DIR_KAI);
+    ok(MOVE_FILE(pszPath1, pszPath2), "Line %d: MOVE_FILE(%ls, %ls) failed 
(%ld)\n",
+       entry->line, pszPath1, pszPath2, GetLastError());
+    return TRUE;
 }
 
-static void
-DoAction6(void)
+static BOOL DoAction7(const TEST_ENTRY *entry)
 {
-    ok_int(DeleteFileW(s_file2), TRUE);
+    LPWSTR pszPath1 = DoGetDir(entry->iWriteDir), pszPath2 = 
DoGetDir(entry->iWriteDir);
+    PathAppendW(pszPath1, TEST_DIR_KAI);
+    PathAppendW(pszPath2, TEST_DIR);
+    ok(MOVE_FILE(pszPath1, pszPath2), "Line %d: MOVE_FILE(%ls, %ls) failed 
(%ld)\n",
+       entry->line, pszPath1, pszPath2, GetLastError());
+    return TRUE;
 }
 
-static void
-DoAction7(void)
+static BOOL DoAction8(const TEST_ENTRY *entry)
 {
-    DeleteFileW(s_file1);
-    DeleteFileW(s_file2);
-    ok_int(RemoveDirectoryW(s_dir3), TRUE);
+    LPWSTR pszPath = DoGetDir(entry->iWriteDir);
+    PathAppendW(pszPath, TEST_DIR);
+    ok(RemoveDirectoryW(pszPath), "Line %d: RemoveDirectoryW(%ls) failed 
(%ld)\n",
+       entry->line, pszPath, GetLastError());
+    return TRUE;
 }
 
-static void
-DoAction8(void)
+static BOOL DoAction9(const TEST_ENTRY *entry)
+{
+    LPWSTR pszPath = DoGetDir(entry->iWriteDir);
+    PathAppendW(pszPath, TEST_FILE);
+    SHChangeNotify(SHCNE_CREATE, SHCNF_PATHW | SHCNF_FLUSH, pszPath, NULL);
+    return FALSE;
+}
+
+static BOOL DoAction10(const TEST_ENTRY *entry)
 {
-    BOOL ret = RemoveDirectoryW(s_dir1);
-    ok(ret, "RemoveDirectoryW failed. GetLastError() == %ld\n", 
GetLastError());
+    LPWSTR pszPath = DoGetDir(entry->iWriteDir);
+    PathAppendW(pszPath, TEST_FILE);
+    SHChangeNotify(SHCNE_DELETE, SHCNF_PATHW | SHCNF_FLUSH, pszPath, NULL);
+    return FALSE;
 }
 
-static const TEST_ENTRY s_TestEntriesMode0[] =
-{
-    {__LINE__, SHCNE_MKDIR, s_dir2, NULL, NULL, DoAction1, NULL, NULL},
-    {__LINE__, SHCNE_RMDIR, s_dir2, NULL, "00001000", NULL, s_dir2, L""},
-    {__LINE__, SHCNE_RMDIR, s_dir2, NULL, "00001000", DoAction2, s_dir2, L""},
-    {__LINE__, SHCNE_MKDIR, s_dir2, NULL, "00010000", DoAction1, s_dir2, L""},
-    {__LINE__, SHCNE_RENAMEFOLDER, s_dir2, s_dir3, "00000001", NULL, s_dir2, 
s_dir3},
-    {__LINE__, SHCNE_RENAMEFOLDER, s_dir2, s_dir3, "00000001", DoAction3, 
s_dir2, s_dir3},
-    {__LINE__, SHCNE_CREATE, s_file1, NULL, "01000000", NULL, s_file1, L""},
-    {__LINE__, SHCNE_CREATE, s_file1, s_file2, "01000000", NULL, s_file1, 
s_file2},
-    {__LINE__, SHCNE_CREATE, s_file1, NULL, "01000000", DoAction4, s_file1, 
L""},
-    {__LINE__, SHCNE_RENAMEITEM, s_file1, s_file2, "10000000", NULL, s_file1, 
s_file2},
-    {__LINE__, SHCNE_RENAMEITEM, s_file1, s_file2, "10000000", DoAction5, 
s_file1, s_file2},
-    {__LINE__, SHCNE_RENAMEITEM, s_file1, s_file2, "10000000", NULL, s_file1, 
s_file2},
-    {__LINE__, SHCNE_UPDATEITEM, s_file1, NULL, "00000010", NULL, s_file1, 
L""},
-    {__LINE__, SHCNE_UPDATEITEM, s_file2, NULL, "00000010", NULL, s_file2, 
L""},
-    {__LINE__, SHCNE_DELETE, s_file1, NULL, "00100000", NULL, s_file1, L""},
-    {__LINE__, SHCNE_DELETE, s_file2, NULL, "00100000", NULL, s_file2, L""},
-    {__LINE__, SHCNE_DELETE, s_file2, NULL, "00100000", DoAction6, s_file2, 
L""},
-    {__LINE__, SHCNE_DELETE, s_file2, NULL, "00100000", NULL, s_file2, L""},
-    {__LINE__, SHCNE_DELETE, s_file1, NULL, "00100000", NULL, s_file1, L""},
-    {__LINE__, SHCNE_RMDIR, s_dir2, NULL, "00001000", NULL, s_dir2, L""},
-    {__LINE__, SHCNE_RMDIR, s_dir3, NULL, "00001000", DoAction7, s_dir3, L""},
-    {__LINE__, SHCNE_RMDIR, s_dir1, NULL, "00001000", NULL, s_dir1, L""},
-    {__LINE__, SHCNE_RMDIR, s_dir1, NULL, "00001000", DoAction8, s_dir1, L""},
+static BOOL DoAction11(const TEST_ENTRY *entry)
+{
+    LPWSTR pszPath = DoGetDir(entry->iWriteDir);
+    PathAppendW(pszPath, TEST_DIR);
+    SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHW | SHCNF_FLUSH, pszPath, NULL);
+    return FALSE;
+}
+
+static BOOL DoAction12(const TEST_ENTRY *entry)
+{
+    LPWSTR pszPath = DoGetDir(entry->iWriteDir);
+    PathAppendW(pszPath, TEST_DIR);
+    SHChangeNotify(SHCNE_RMDIR, SHCNF_PATHW | SHCNF_FLUSH, pszPath, NULL);
+    return FALSE;
+}
+
+#define WRITEDIR_0 DIRTYPE_DESKTOP
+static WCHAR s_szDesktop[MAX_PATH];
+static WCHAR s_szTestFile0[MAX_PATH];
+static WCHAR s_szTestFile0Kai[MAX_PATH];
+static WCHAR s_szTestDir0[MAX_PATH];
+static WCHAR s_szTestDir0Kai[MAX_PATH];
+
+#define WRITEDIR_1 DIRTYPE_MYDOCUMENTS
+static WCHAR s_szDocuments[MAX_PATH];
+static WCHAR s_szTestFile1[MAX_PATH];
+static WCHAR s_szTestFile1Kai[MAX_PATH];
+static WCHAR s_szTestDir1[MAX_PATH];
+static WCHAR s_szTestDir1Kai[MAX_PATH];
+
+static void DoDeleteFilesAndDirs(void)
+{
+    DeleteFileW(TEMP_FILE);
+    DeleteFileW(s_szTestFile0);
+    DeleteFileW(s_szTestFile0Kai);
+    DeleteFileW(s_szTestFile1);
+    DeleteFileW(s_szTestFile1Kai);
+    RemoveDirectoryW(s_szTestDir0);
+    RemoveDirectoryW(s_szTestDir0Kai);
+    RemoveDirectoryW(s_szTestDir1);
+    RemoveDirectoryW(s_szTestDir1Kai);
+}
+
+static const TEST_ENTRY s_group_00[] =
+{
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction1 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction2 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction3 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction4 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction5 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction6 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction7 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction8 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction9 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction10 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction11 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction12 },
+
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction1 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction2 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction3 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction4 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction5 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction6 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction7 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction8 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction9 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction10 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction11 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction12 },
 };
 
-#define s_TestEntriesMode1 s_TestEntriesMode0
-#define s_TestEntriesMode2 s_TestEntriesMode0
-
-static const TEST_ENTRY s_TestEntriesMode3[] =
-{
-    {__LINE__, DONT_SEND, s_dir2, NULL, NULL, DoAction1, NULL, NULL},
-    {__LINE__, DONT_SEND, s_dir2, NULL, "00001000", DoAction2, s_dir2, L""},
-    {__LINE__, DONT_SEND, s_dir2, NULL, "00010000", DoAction1, s_dir2, L""},
-    {__LINE__, DONT_SEND, s_dir2, s_dir3, "00000001", DoAction3, s_dir2, 
s_dir3},
-    {__LINE__, DONT_SEND, s_file1, NULL, "01000000", DoAction4, s_file1, L""},
-    {__LINE__, DONT_SEND, s_file1, s_file2, "10000000", DoAction5, s_file1, 
s_file2},
-    {__LINE__, DONT_SEND, s_file2, NULL, "00100000", DoAction6, s_file2, L""},
-    {__LINE__, DONT_SEND, s_dir3, NULL, "00001000", DoAction7, s_dir3, L""},
-    {__LINE__, SHCNE_MKDIR, s_dir2, NULL, "00000000", NULL, NULL, NULL},
-    {__LINE__, SHCNE_INTERRUPT | SHCNE_MKDIR, s_dir2, NULL, "00000000", NULL, 
NULL, NULL},
+static const TEST_ENTRY s_group_01[] =
+{
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction1 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction2 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction3 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction4 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction5 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction6 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction7 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction8 },
+    { __LINE__, WRITEDIR_0, "0100000", s_szTestFile0, L"", DoAction9 },
+    { __LINE__, WRITEDIR_0, "0010000", s_szTestFile0, L"", DoAction10 },
+    { __LINE__, WRITEDIR_0, "0001000", s_szTestDir0, L"", DoAction11 },
+    { __LINE__, WRITEDIR_0, "0000100", s_szTestDir0, L"", DoAction12 },
+
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction1 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction2 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction3 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction4 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction5 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction6 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction7 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction8 },
+    { __LINE__, WRITEDIR_1, "0100000", s_szTestFile1, L"", DoAction9 },
+    { __LINE__, WRITEDIR_1, "0010000", s_szTestFile1, L"", DoAction10 },
+    { __LINE__, WRITEDIR_1, "0001000", s_szTestDir1, L"", DoAction11 },
+    { __LINE__, WRITEDIR_1, "0000100", s_szTestDir1, L"", DoAction12 },
 };
 
-static const TEST_ENTRY s_TestEntriesMode4[] =
-{
-    {__LINE__, DONT_SEND, s_dir2, NULL, NULL, DoAction1, NULL, NULL},
-    {__LINE__, DONT_SEND, s_dir2, NULL, "00001000", DoAction2, s_dir2, L""},
-    {__LINE__, DONT_SEND, s_dir2, NULL, "00010000", DoAction1, s_dir2, L""},
-    {__LINE__, DONT_SEND, s_dir2, s_dir3, "00000001", DoAction3, s_dir2, 
s_dir3},
-    {__LINE__, DONT_SEND, s_file1, NULL, "01000000", DoAction4, s_file1, L""},
-    {__LINE__, DONT_SEND, s_file1, s_file2, "10000000", DoAction5, s_file1, 
s_file2},
-    {__LINE__, DONT_SEND, s_file2, NULL, "00100000", DoAction6, s_file2, L""},
-    {__LINE__, DONT_SEND, s_dir3, NULL, "00001000", DoAction7, s_dir3, L""},
-    {__LINE__, SHCNE_MKDIR, s_dir2, NULL, "00000000", NULL, NULL, NULL},
-    {__LINE__, SHCNE_INTERRUPT | SHCNE_MKDIR, s_dir2, NULL, "00000000", NULL, 
NULL, NULL},
+static const TEST_ENTRY s_group_02[] =
+{
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction1 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction2 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction3 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction4 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction5 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction6 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction7 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction8 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction9 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction10 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction11 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction12 },
+
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction1 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction2 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction3 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction4 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction5 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction6 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction7 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction8 },
+    { __LINE__, WRITEDIR_1, "0100000", s_szTestFile1, L"", DoAction9 },
+    { __LINE__, WRITEDIR_1, "0010000", s_szTestFile1, L"", DoAction10 },
+    { __LINE__, WRITEDIR_1, "0001000", s_szTestDir1, L"", DoAction11 },
+    { __LINE__, WRITEDIR_1, "0000100", s_szTestDir1, L"", DoAction12 },
 };
 
-static const TEST_ENTRY s_TestEntriesMode5[] =
-{
-    {__LINE__, SHCNE_MKDIR, s_dir2, NULL, "00000000", NULL, NULL, NULL},
-    {__LINE__, SHCNE_RMDIR, s_dir2, NULL, "00000000", NULL, NULL, NULL},
-    {__LINE__, SHCNE_MKDIR, s_dir2, NULL, "00000000", DoAction1, NULL, NULL},
-    {__LINE__, SHCNE_RMDIR, s_dir2, NULL, "00000000", NULL, NULL, NULL},
-    {__LINE__, SHCNE_RMDIR, s_dir2, NULL, "00000000", DoAction2, NULL, NULL},
-    {__LINE__, SHCNE_MKDIR, s_dir2, NULL, "00000000", DoAction1, NULL, NULL},
-    {__LINE__, SHCNE_RENAMEFOLDER, s_dir2, s_dir3, "00000000", NULL, NULL, 
NULL},
-    {__LINE__, SHCNE_RENAMEFOLDER, s_dir2, s_dir3, "00000000", DoAction3, 
NULL, NULL},
-    {__LINE__, SHCNE_CREATE, s_file1, NULL, "00000000", NULL, NULL, NULL},
-    {__LINE__, SHCNE_CREATE, s_file1, s_file2, "00000000", NULL, NULL, NULL},
-    {__LINE__, SHCNE_CREATE, s_file1, NULL, "00000000", DoAction4, NULL, NULL},
-    {__LINE__, SHCNE_RENAMEITEM, s_file1, s_file2, "00000000", NULL, NULL, 
NULL},
-    {__LINE__, SHCNE_RENAMEITEM, s_file1, s_file2, "00000000", DoAction5, 
NULL, NULL},
-    {__LINE__, SHCNE_RENAMEITEM, s_file1, s_file2, "00000000", NULL, NULL, 
NULL},
-    {__LINE__, SHCNE_UPDATEITEM, s_file1, NULL, "00000000", NULL, NULL, NULL},
-    {__LINE__, SHCNE_UPDATEITEM, s_file2, NULL, "00000000", NULL, NULL, NULL},
-    {__LINE__, SHCNE_UPDATEITEM, s_file1, s_file2, "00000000", NULL, NULL, 
NULL},
-    {__LINE__, SHCNE_UPDATEITEM, s_file2, s_file1, "00000000", NULL, NULL, 
NULL},
-    {__LINE__, SHCNE_DELETE, s_file1, NULL, "00000000", NULL, NULL, NULL},
-    {__LINE__, SHCNE_DELETE, s_file2, NULL, "00000000", NULL, NULL, NULL},
-    {__LINE__, SHCNE_DELETE, s_file2, s_file1, "00000000", NULL, NULL, NULL},
-    {__LINE__, SHCNE_DELETE, s_file1, s_file2, "00000000", NULL, NULL, NULL},
-    {__LINE__, SHCNE_DELETE, s_file2, NULL, "00000000", DoAction6, NULL, NULL},
-    {__LINE__, SHCNE_DELETE, s_file2, NULL, "00000000", NULL, NULL, NULL},
-    {__LINE__, SHCNE_DELETE, s_file1, NULL, "00000000", NULL, NULL, NULL},
-    {__LINE__, SHCNE_INTERRUPT | SHCNE_RMDIR, s_dir1, NULL, "00000000", NULL, 
NULL, NULL},
-    {__LINE__, SHCNE_INTERRUPT | SHCNE_RMDIR, s_dir2, NULL, "00000000", NULL, 
NULL, NULL},
-    {__LINE__, SHCNE_INTERRUPT | SHCNE_RMDIR, s_dir3, NULL, "00000000", NULL, 
NULL, NULL},
-    {__LINE__, SHCNE_INTERRUPT | SHCNE_RMDIR, s_dir1, s_dir2, "00000000", 
NULL, NULL, NULL},
-    {__LINE__, SHCNE_INTERRUPT | SHCNE_RMDIR, s_dir1, s_dir3, "00000000", 
NULL, NULL, NULL},
-    {__LINE__, SHCNE_INTERRUPT | SHCNE_RMDIR, s_dir2, s_dir1, "00000000", 
NULL, NULL, NULL},
-    {__LINE__, SHCNE_INTERRUPT | SHCNE_RMDIR, s_dir2, s_dir3, "00000000", 
NULL, NULL, NULL},
-    {__LINE__, SHCNE_INTERRUPT | SHCNE_RMDIR, s_dir3, NULL, "00000000", NULL, 
NULL, NULL},
-    {__LINE__, SHCNE_INTERRUPT | SHCNE_RMDIR, s_dir3, NULL, "00000000", 
DoAction7, NULL, NULL},
-    {__LINE__, SHCNE_INTERRUPT | SHCNE_RMDIR, s_dir1, NULL, "00000000", NULL, 
NULL, NULL},
-    {__LINE__, SHCNE_INTERRUPT | SHCNE_RMDIR, s_dir1, NULL, "00000000", 
DoAction8, NULL, NULL},
+static const TEST_ENTRY s_group_03[] =
+{
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction1 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction2 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction3 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction4 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction5 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction6 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction7 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction8 },
+    { __LINE__, WRITEDIR_0, "0100000", s_szTestFile0, L"", DoAction9 },
+    { __LINE__, WRITEDIR_0, "0010000", s_szTestFile0, L"", DoAction10 },
+    { __LINE__, WRITEDIR_0, "0001000", s_szTestDir0, L"", DoAction11 },
+    { __LINE__, WRITEDIR_0, "0000100", s_szTestDir0, L"", DoAction12 },
+
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction1 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction2 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction3 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction4 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction5 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction6 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction7 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction8 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction9 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction10 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction11 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction12 },
 };
 
-LPCSTR PatternFromFlags(DWORD flags)
+static const TEST_ENTRY s_group_04[] =
 {
-    static char s_buf[TYPE_RENAMEFOLDER + 1 + 1];
-    DWORD i;
-    for (i = 0; i <= TYPE_RENAMEFOLDER; ++i)
-    {
+    { __LINE__, WRITEDIR_0, "0100000", s_szTestFile0, L"", DoAction1 },
+    { __LINE__, WRITEDIR_0, "1000000", s_szTestFile0, s_szTestFile0Kai, 
DoAction2 },
+    { __LINE__, WRITEDIR_0, "1000000", s_szTestFile0Kai, s_szTestFile0, 
DoAction3 },
+    { __LINE__, WRITEDIR_0, "0010000", s_szTestFile0, L"", DoAction4 },
+    { __LINE__, WRITEDIR_0, "0001000", s_szTestDir0, L"", DoAction5 },
+    { __LINE__, WRITEDIR_0, "0000010", s_szTestDir0, s_szTestDir0Kai, 
DoAction6 },
+    { __LINE__, WRITEDIR_0, "0000010", s_szTestDir0Kai, s_szTestDir0, 
DoAction7 },
+    { __LINE__, WRITEDIR_0, "0000100", s_szTestDir0, L"", DoAction8 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction9 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction10 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction11 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction12 },
+
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction1 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction2 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction3 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction4 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction5 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction6 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction7 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction8 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction9 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction10 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction11 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction12 },
+};
+
+static const TEST_ENTRY s_group_05[] =
+{
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction1 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction2 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction3 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction4 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction5 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction6 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction7 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction8 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction9 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction10 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction11 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction12 },
+
+    { __LINE__, WRITEDIR_1, "0100000", s_szTestFile1, L"", DoAction1 },
+    { __LINE__, WRITEDIR_1, "1000000", s_szTestFile1, s_szTestFile1Kai, 
DoAction2 },
+    { __LINE__, WRITEDIR_1, "1000000", s_szTestFile1Kai, s_szTestFile1, 
DoAction3 },
+    { __LINE__, WRITEDIR_1, "0010000", s_szTestFile1, L"", DoAction4 },
+    { __LINE__, WRITEDIR_1, "0001000", s_szTestDir1, L"", DoAction5 },
+    { __LINE__, WRITEDIR_1, "0000010", s_szTestDir1, s_szTestDir1Kai, 
DoAction6 },
+    { __LINE__, WRITEDIR_1, "0000010", s_szTestDir1Kai, s_szTestDir1, 
DoAction7 },
+    { __LINE__, WRITEDIR_1, "0000100", s_szTestDir1, L"", DoAction8 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction9 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction10 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction11 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction12 },
+};
+
+static const TEST_ENTRY s_group_06[] =
+{
+    { __LINE__, WRITEDIR_0, "0100000", s_szTestFile0, L"", DoAction1 },
+    { __LINE__, WRITEDIR_0, "1000000", s_szTestFile0, s_szTestFile0Kai, 
DoAction2 },
+    { __LINE__, WRITEDIR_0, "1000000", s_szTestFile0Kai, s_szTestFile0, 
DoAction3 },
+    { __LINE__, WRITEDIR_0, "0010000", s_szTestFile0, L"", DoAction4 },
+    { __LINE__, WRITEDIR_0, "0001000", s_szTestDir0, L"", DoAction5 },
+    { __LINE__, WRITEDIR_0, "0000010", s_szTestDir0, s_szTestDir0Kai, 
DoAction6 },
+    { __LINE__, WRITEDIR_0, "0000010", s_szTestDir0Kai, s_szTestDir0, 
DoAction7 },
+    { __LINE__, WRITEDIR_0, "0000100", s_szTestDir0, L"", DoAction8 },
+    { __LINE__, WRITEDIR_0, "0100000", s_szTestFile0, L"", DoAction9 },
+    { __LINE__, WRITEDIR_0, "0010000", s_szTestFile0, L"", DoAction10 },
+    { __LINE__, WRITEDIR_0, "0001000", s_szTestDir0, L"", DoAction11 },
+    { __LINE__, WRITEDIR_0, "0000100", s_szTestDir0, L"", DoAction12 },
+
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction1 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction2 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction3 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction4 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction5 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction6 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction7 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction8 },
+    { __LINE__, WRITEDIR_1, "0100000", s_szTestFile1, L"", DoAction9 },
+    { __LINE__, WRITEDIR_1, "0010000", s_szTestFile1, L"", DoAction10 },
+    { __LINE__, WRITEDIR_1, "0001000", s_szTestDir1, L"", DoAction11 },
+    { __LINE__, WRITEDIR_1, "0000100", s_szTestDir1, L"", DoAction12 },
+};
+
+static const TEST_ENTRY s_group_07[] =
+{
+    { __LINE__, WRITEDIR_0, "0100000", s_szTestFile0, L"", DoAction1 },
+    { __LINE__, WRITEDIR_0, "1000000", s_szTestFile0, s_szTestFile0Kai, 
DoAction2 },
+    { __LINE__, WRITEDIR_0, "1000000", s_szTestFile0Kai, s_szTestFile0, 
DoAction3 },
+    { __LINE__, WRITEDIR_0, "0010000", s_szTestFile0, L"", DoAction4 },
+    { __LINE__, WRITEDIR_0, "0001000", s_szTestDir0, L"", DoAction5 },
+    { __LINE__, WRITEDIR_0, "0000010", s_szTestDir0, s_szTestDir0Kai, 
DoAction6 },
+    { __LINE__, WRITEDIR_0, "0000010", s_szTestDir0Kai, s_szTestDir0, 
DoAction7 },
+    { __LINE__, WRITEDIR_0, "0000100", s_szTestDir0, L"", DoAction8 },
+    { __LINE__, WRITEDIR_0, "0100000", s_szTestFile0, L"", DoAction9 },
+    { __LINE__, WRITEDIR_0, "0010000", s_szTestFile0, L"", DoAction10 },
+    { __LINE__, WRITEDIR_0, "0001000", s_szTestDir0, L"", DoAction11 },
+    { __LINE__, WRITEDIR_0, "0000100", s_szTestDir0, L"", DoAction12 },
+
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction1 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction2 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction3 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction4 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction5 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction6 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction7 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction8 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction9 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction10 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction11 },
+    { __LINE__, WRITEDIR_1, "0000000", L"", L"", DoAction12 },
+};
+
+static const TEST_ENTRY s_group_08[] =
+{
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction1 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction2 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction3 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction4 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction5 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction6 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction7 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction8 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction9 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction10 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction11 },
+    { __LINE__, WRITEDIR_0, "0000000", L"", L"", DoAction12 },
+
+    { __LINE__, WRITEDIR_1, "0100000", s_szTestFile1, L"", DoAction1 },
+    { __LINE__, WRITEDIR_1, "1000000", s_szTestFile1, s_szTestFile1Kai, 
DoAction2 },
+    { __LINE__, WRITEDIR_1, "1000000", s_szTestFile1Kai, s_szTestFile1, 
DoAction3 },
+    { __LINE__, WRITEDIR_1, "0010000", s_szTestFile1, L"", DoAction4 },
+    { __LINE__, WRITEDIR_1, "0001000", s_szTestDir1, L"", DoAction5 },
+    { __LINE__, WRITEDIR_1, "0000010", s_szTestDir1, s_szTestDir1Kai, 
DoAction6 },
+    { __LINE__, WRITEDIR_1, "0000010", s_szTestDir1Kai, s_szTestDir1, 
DoAction7 },
+    { __LINE__, WRITEDIR_1, "0000100", s_szTestDir1, L"", DoAction8 },
+    { __LINE__, WRITEDIR_1, "0100000", s_szTestFile1, L"", DoAction9 },
+    { __LINE__, WRITEDIR_1, "0010000", s_szTestFile1, L"", DoAction10 },
+    { __LINE__, WRITEDIR_1, "0001000", s_szTestDir1, L"", DoAction11 },
+    { __LINE__, WRITEDIR_1, "0000100", s_szTestDir1, L"", DoAction12 },
+};
+
+static LPCSTR PatternFromFlags(DWORD flags)
+{
+    static CHAR s_buf[(TYPE_MAX + 1) + 1];
+    for (INT i = 0; i < (TYPE_MAX + 1); ++i)
         s_buf[i] = (char)('0' + !!(flags & (1 << i)));
-    }
-    s_buf[i] = 0;
+
+    s_buf[TYPE_MAX + 1] = 0;
     return s_buf;
 }
 
-static BOOL
-DoGetPaths(LPWSTR pszPath1, LPWSTR pszPath2)
+static BOOL DoGetPaths(LPWSTR pszPath1, LPWSTR pszPath2)
 {
     pszPath1[0] = pszPath2[0] = 0;
 
     WCHAR szText[MAX_PATH * 2];
     szText[0] = 0;
-    if (FILE *fp = fopen(TEMP_FILE, "rb"))
+    FILE *fp = _wfopen(TEMP_FILE, L"rb");
+    if (fp)
     {
         fread(szText, 1, sizeof(szText), fp);
         fclose(fp);
@@ -219,56 +508,77 @@ DoGetPaths(LPWSTR pszPath1, LPWSTR pszPath2)
         return FALSE;
 
     *pch = 0;
-    lstrcpynW(pszPath1, szText, MAX_PATH);
-    lstrcpynW(pszPath2, pch + 1, MAX_PATH);
+    StringCchCopyW(pszPath1, MAX_PATH, szText);
+    StringCchCopyW(pszPath2, MAX_PATH, pch + 1);
     return TRUE;
 }
 
-static void
-DoTestEntry(const TEST_ENTRY *entry)
+static void DoTestEntry(INT iEntry, const TEST_ENTRY *entry, INT nSources)
 {
+#ifdef ENTRY_TICK
+    DWORD dwOldTick = GetTickCount();
+#endif
+
+    BOOL bInterrupting = FALSE;
     if (entry->action)
-    {
-        (*entry->action)();
-    }
+        bInterrupting = entry->action(entry);
 
-    if (entry->event != DONT_SEND)
+    DWORD flags;
+    LPCSTR pattern;
+    if ((nSources & SHCNRF_InterruptLevel) && bInterrupting)
     {
-        SHChangeNotify(entry->event, SHCNF_PATHW | SHCNF_FLUSH, entry->item1, 
entry->item2);
+        // The event won't work at here. Manually waiting...
+        UINT cTry = ((iEntry == 0) ? 100 : 60);
+        for (UINT iTry = 0; iTry < cTry; ++iTry)
+        {
+            flags = SendMessageW(s_hwnd, WM_GET_NOTIFY_FLAGS, 0, 0);
+            pattern = PatternFromFlags(flags);
+            if (strcmp(pattern, "0000000") != 0)
+                break;
+
+            Sleep(1);
+        }
     }
     else
     {
-        SHChangeNotify(0, SHCNF_FLUSH, NULL, NULL);
-    }
+        if (WaitForSingleObject(s_hEvent, 100) == WAIT_OBJECT_0)
+            Sleep(1);
 
-    DWORD flags = SendMessageW(s_hwnd, WM_GET_NOTIFY_FLAGS, 0, 0);
-    LPCSTR pattern = PatternFromFlags(flags);
-
-    if (entry->pattern)
-    {
-        ok(lstrcmpA(pattern, entry->pattern) == 0 ||
-           lstrcmpA(pattern, "00000100") == 0, // SHCNE_UPDATEDIR
-           "Line %d: pattern mismatch '%s'\n", entry->line, pattern);
+        flags = SendMessageW(s_hwnd, WM_GET_NOTIFY_FLAGS, 0, 0);
+        pattern = PatternFromFlags(flags);
     }
 
     SendMessageW(s_hwnd, WM_SET_PATHS, 0, 0);
-    Sleep(50);
 
     WCHAR szPath1[MAX_PATH], szPath2[MAX_PATH];
     szPath1[0] = szPath2[0] = 0;
     BOOL bOK = DoGetPaths(szPath1, szPath2);
 
-    if (lstrcmpA(pattern, "00000100") == 0) // SHCNE_UPDATEDIR
+    static UINT s_cCalmDown = 0;
+
+    if (pattern[TYPE_UPDATEDIR] == '1')
     {
+        trace("Line %d: SHCNE_UPDATEDIR: Calm down (%u)...\n", entry->line, 
s_cCalmDown);
+
+        if (++s_cCalmDown < 3)
+            Sleep(3000);
+
+        if (entry->pattern)
+            ok(TRUE, "Line %d:\n", entry->line);
         if (entry->path1)
-            ok(bOK && lstrcmpiW(s_dir1, szPath1) == 0,
-               "Line %d: path1 mismatch '%S' (%d)\n", entry->line, szPath1, 
bOK);
+            ok(TRUE, "Line %d:\n", entry->line);
         if (entry->path2)
-            ok(bOK && lstrcmpiW(L"", szPath2) == 0,
-               "Line %d: path2 mismatch '%S' (%d)\n", entry->line, szPath2, 
bOK);
+            ok(TRUE, "Line %d:\n", entry->line);
     }
     else
     {
+        s_cCalmDown = 0;
+        if (entry->pattern)
+        {
+            ok(strcmp(pattern, entry->pattern) == 0,
+               "Line %d: pattern mismatch '%s', tick=0x%08lX\n",
+               entry->line, pattern, GetTickCount());
+        }
         if (entry->path1)
             ok(bOK && lstrcmpiW(entry->path1, szPath1) == 0,
                "Line %d: path1 mismatch '%S' (%d)\n", entry->line, szPath1, 
bOK);
@@ -278,43 +588,108 @@ DoTestEntry(const TEST_ENTRY *entry)
     }
 
     SendMessageW(s_hwnd, WM_CLEAR_FLAGS, 0, 0);
+    ResetEvent(s_hEvent);
+
+#ifdef ENTRY_TICK
+    DWORD dwNewTick = GetTickCount();
+    DWORD dwTick = dwNewTick - dwOldTick;
+    trace("DoTestEntry: Line %d: tick=%lu.%lu sec\n", entry->line,
+          (dwTick / 1000), (dwTick / 100 % 10));
+#endif
 }
 
-static BOOL
-DoInit(void)
+static void DoQuitTest(BOOL bForce)
 {
-    DoInitPaths();
+    PostMessageW(s_hwnd, WM_COMMAND, IDOK, 0);
 
-    CreateDirectoryW(s_dir1, NULL);
+    DoWaitForWindow(CLASSNAME, CLASSNAME, TRUE, bForce);
+    s_hwnd = NULL;
 
-    // close Explorer before tests
-    INT i, nCount = 50;
-    for (i = 0; i < nCount; ++i)
+    if (s_hEvent)
     {
-        HWND hwnd = FindWindowW(L"CabinetWClass", NULL);
-        if (hwnd == NULL)
-            break;
+        CloseHandle(s_hEvent);
+        s_hEvent = NULL;
+    }
 
-        PostMessage(hwnd, WM_CLOSE, 0, 0);
-        Sleep(100);
+    DoDeleteFilesAndDirs();
+}
+
+static void DoAbortThread(void)
+{
+    skip("Aborting the thread...\n");
+    if (s_hThread)
+    {
+        TerminateThread(s_hThread, -1);
+        s_hThread = NULL;
     }
-    if (i == nCount)
-        skip("Unable to close Explorer cabinet\n");
+}
 
-    return PathIsDirectoryW(s_dir1);
+static BOOL CALLBACK HandlerRoutine(DWORD dwCtrlType)
+{
+    switch (dwCtrlType)
+    {
+        case CTRL_C_EVENT:
+        case CTRL_BREAK_EVENT:
+            DoAbortThread();
+            DoQuitTest(TRUE);
+            return TRUE;
+    }
+    return FALSE;
 }
 
-static void
-DoEnd(HWND hwnd)
+static BOOL DoInitTest(void)
 {
-    DeleteFileW(s_file1);
-    DeleteFileW(s_file2);
-    RemoveDirectoryW(s_dir3);
-    RemoveDirectoryW(s_dir2);
-    RemoveDirectoryW(s_dir1);
-    DeleteFileA(TEMP_FILE);
+    // DIRTYPE_DESKTOP
+    LPWSTR psz = DoGetDir(DIRTYPE_DESKTOP);
+    StringCchCopyW(s_szDesktop, _countof(s_szDesktop), psz);
+
+    PathAppendW(psz, TEST_FILE);
+    StringCchCopyW(s_szTestFile0, _countof(s_szTestFile0), psz);
+
+    PathRemoveFileSpecW(psz);
+    PathAppendW(psz, TEST_FILE_KAI);
+    StringCchCopyW(s_szTestFile0Kai, _countof(s_szTestFile0Kai), psz);
+
+    PathRemoveFileSpecW(psz);
+    PathAppendW(psz, TEST_DIR);
+    StringCchCopyW(s_szTestDir0, _countof(s_szTestDir0), psz);
+
+    PathRemoveFileSpecW(psz);
+    PathAppendW(psz, TEST_DIR_KAI);
+    StringCchCopyW(s_szTestDir0Kai, _countof(s_szTestDir0Kai), psz);
+
+    // DIRTYPE_MYDOCUMENTS
+    psz = DoGetDir(DIRTYPE_MYDOCUMENTS);
+    StringCchCopyW(s_szDocuments, _countof(s_szDocuments), psz);
+
+    PathAppendW(psz, TEST_FILE);
+    StringCchCopyW(s_szTestFile1, _countof(s_szTestFile1), psz);
+
+    PathRemoveFileSpecW(psz);
+    PathAppendW(psz, TEST_FILE_KAI);
+    StringCchCopyW(s_szTestFile1Kai, _countof(s_szTestFile1Kai), psz);
+
+    PathRemoveFileSpecW(psz);
+    PathAppendW(psz, TEST_DIR);
+    StringCchCopyW(s_szTestDir1, _countof(s_szTestDir1), psz);
+
+    PathRemoveFileSpecW(psz);
+    PathAppendW(psz, TEST_DIR_KAI);
+    StringCchCopyW(s_szTestDir1Kai, _countof(s_szTestDir1Kai), psz);
+
+    // prepare for files and dirs
+    DoDeleteFilesAndDirs();
+    DoCreateEmptyFile(TEMP_FILE);
 
-    SendMessageW(s_hwnd, WM_COMMAND, IDOK, 0);
+    // Ctrl+C
+    SetConsoleCtrlHandler(HandlerRoutine, TRUE);
+
+    // close Explorer windows
+    trace("Closing Explorer windows...\n");
+    DoWaitForWindow(L"CabinetWClass", NULL, TRUE, TRUE);
+
+    // close the CLASSNAME windows
+    return DoWaitForWindow(CLASSNAME, CLASSNAME, TRUE, TRUE) == NULL;
 }
 
 static BOOL
@@ -330,28 +705,69 @@ GetSubProgramPath(void)
         PathAppendW(s_szSubProgram, L"testdata\\shell32_apitest_sub.exe");
 
         if (!PathFileExistsW(s_szSubProgram))
-        {
             return FALSE;
-        }
     }
 
     return TRUE;
 }
 
+#define SRC_00 0
+#define SRC_01 SHCNRF_ShellLevel
+#define SRC_02 (SHCNRF_NewDelivery)
+#define SRC_03 (SHCNRF_NewDelivery | SHCNRF_ShellLevel)
+#define SRC_04 SHCNRF_InterruptLevel
+#define SRC_05 (SHCNRF_InterruptLevel | SHCNRF_ShellLevel)
+#define SRC_06 (SHCNRF_InterruptLevel | SHCNRF_NewDelivery)
+#define SRC_07 (SHCNRF_InterruptLevel | SHCNRF_NewDelivery | SHCNRF_ShellLevel)
+#define SRC_08 (SHCNRF_RecursiveInterrupt | SHCNRF_InterruptLevel)
+#define SRC_09 (SHCNRF_RecursiveInterrupt | SHCNRF_InterruptLevel | 
SHCNRF_ShellLevel)
+#define SRC_10 (SHCNRF_RecursiveInterrupt | SHCNRF_InterruptLevel | 
SHCNRF_NewDelivery)
+#define SRC_11 (SHCNRF_RecursiveInterrupt | SHCNRF_InterruptLevel | 
SHCNRF_NewDelivery | SHCNRF_ShellLevel)
+
+#define WATCHDIR_0 DIRTYPE_NULL
+#define WATCHDIR_1 DIRTYPE_DESKTOP
+#define WATCHDIR_2 DIRTYPE_MYCOMPUTER
+#define WATCHDIR_3 DIRTYPE_MYDOCUMENTS
+
 static void
-JustDoIt(INT nMode)
+DoTestGroup(INT line, UINT cEntries, const TEST_ENTRY *pEntries, BOOL 
fRecursive,
+            INT nSources, DIRTYPE iWatchDir)
 {
-    trace("nMode: %d\n", nMode);
-    SHChangeNotify(0, SHCNF_FLUSH, NULL, NULL);
+#ifdef NO_INTERRUPT_LEVEL
+    if (nSources & SHCNRF_InterruptLevel)
+        return;
+#endif
+#ifdef NO_SHELL_LEVEL
+    if (nSources & SHCNRF_ShellLevel)
+        return;
+#endif
+#ifdef NEW_DELIVERY_ONLY
+    if (!(nSources & SHCNRF_NewDelivery))
+        return;
+#endif
+#ifdef GROUP_TICK
+    DWORD dwOldTick = GetTickCount();
+#endif
+#ifdef RANDOM_QUARTER
+    if ((rand() & 3) == 0)
+        return;
+#elif defined(RANDOM_HALF)
+    if (rand() & 1)
+        return;
+#endif
 
-    if (!DoInit())
+    trace("DoTestGroup: Line %d: fRecursive:%u, iWatchDir:%u, nSources:0x%X\n",
+          line, fRecursive, iWatchDir, nSources);
+
+    if (s_hEvent)
     {
-        skip("Unable to initialize.\n");
-        return;
+        CloseHandle(s_hEvent);
+        s_hEvent = NULL;
     }
+    s_hEvent = CreateEventW(NULL, TRUE, FALSE, EVENT_NAME);
 
-    WCHAR szParams[8];
-    wsprintfW(szParams, L"%u", nMode);
+    WCHAR szParams[64];
+    StringCchPrintfW(szParams, _countof(szParams), L"%u,%u,%u", fRecursive, 
iWatchDir, nSources);
 
     HINSTANCE hinst = ShellExecuteW(NULL, NULL, s_szSubProgram, szParams, 
NULL, SW_SHOWNORMAL);
     if ((INT_PTR)hinst <= 32)
@@ -360,74 +776,189 @@ JustDoIt(INT nMode)
         return;
     }
 
-    for (int i = 0; i < 15; ++i)
-    {
-        s_hwnd = FindWindowW(s_szName, s_szName);
-        if (s_hwnd)
-            break;
-
-        Sleep(50);
-    }
-
+    s_hwnd = DoWaitForWindow(CLASSNAME, CLASSNAME, FALSE, FALSE);
     if (!s_hwnd)
     {
         skip("Unable to find window.\n");
         return;
     }
 
-    switch (nMode)
+    for (UINT i = 0; i < cEntries; ++i)
     {
-        case 0:
-        case 1:
-        case 2:
-            for (size_t i = 0; i < _countof(s_TestEntriesMode0); ++i)
-            {
-                DoTestEntry(&s_TestEntriesMode0[i]);
-            }
-            break;
-        case 3:
-            for (size_t i = 0; i < _countof(s_TestEntriesMode3); ++i)
-            {
-                DoTestEntry(&s_TestEntriesMode3[i]);
-            }
-            break;
-        case 4:
-            for (size_t i = 0; i < _countof(s_TestEntriesMode4); ++i)
-            {
-                DoTestEntry(&s_TestEntriesMode4[i]);
-            }
-            break;
-        case 5:
-            for (size_t i = 0; i < _countof(s_TestEntriesMode5); ++i)
-            {
-                DoTestEntry(&s_TestEntriesMode5[i]);
-            }
+        if (!IsWindow(s_hwnd))
+        {
+            DoAbortThread();
+            DoQuitTest(TRUE);
             break;
+        }
+
+        DoTestEntry(i, &pEntries[i], nSources);
     }
 
-    DoEnd(s_hwnd);
+    DoQuitTest(FALSE);
 
-    for (int i = 0; i < 15; ++i)
-    {
-        s_hwnd = FindWindowW(s_szName, s_szName);
-        if (!s_hwnd)
-            break;
+#ifdef GROUP_TICK
+    DWORD dwNewTick = GetTickCount();
+    DWORD dwTick = dwNewTick - dwOldTick;
+    trace("DoTestGroup: Line %d: %lu.%lu sec\n", line, (dwTick / 1000), 
(dwTick / 100 % 10));
+#endif
+}
 
-        Sleep(50);
-    }
+static unsigned __stdcall TestThreadProc(void *)
+{
+    srand(time(NULL));
+#ifdef RANDOM_QUARTER
+    skip("RANDOM_QUARTER\n");
+#elif defined(RANDOM_HALF)
+    skip("RANDOM_HALF\n");
+#endif
+
+    // fRecursive == FALSE.
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, FALSE, SRC_00, 
WATCHDIR_0);
+    DoTestGroup(__LINE__, _countof(s_group_01), s_group_01, FALSE, SRC_01, 
WATCHDIR_0);
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, FALSE, SRC_02, 
WATCHDIR_0);
+    DoTestGroup(__LINE__, _countof(s_group_01), s_group_01, FALSE, SRC_03, 
WATCHDIR_0);
+    DoTestGroup(__LINE__, _countof(s_group_04), s_group_04, FALSE, SRC_04, 
WATCHDIR_0);
+    DoTestGroup(__LINE__, _countof(s_group_06), s_group_06, FALSE, SRC_05, 
WATCHDIR_0);
+    DoTestGroup(__LINE__, _countof(s_group_04), s_group_04, FALSE, SRC_06, 
WATCHDIR_0);
+    DoTestGroup(__LINE__, _countof(s_group_06), s_group_06, FALSE, SRC_07, 
WATCHDIR_0);
+    DoTestGroup(__LINE__, _countof(s_group_04), s_group_04, FALSE, SRC_08, 
WATCHDIR_0);
+    DoTestGroup(__LINE__, _countof(s_group_06), s_group_06, FALSE, SRC_09, 
WATCHDIR_0);
+    DoTestGroup(__LINE__, _countof(s_group_04), s_group_04, FALSE, SRC_10, 
WATCHDIR_0);
+    DoTestGroup(__LINE__, _countof(s_group_06), s_group_06, FALSE, SRC_11, 
WATCHDIR_0);
+
+    BOOL bTarget = IsWindowsXPOrGreater() && !IsWindowsVistaOrGreater();
+
+#define SWITCH(x, y) (bTarget ? (x) : (y))
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, FALSE, SRC_00, 
WATCHDIR_1);
+    DoTestGroup(__LINE__, _countof(s_group_03), s_group_03, FALSE, SRC_01, 
WATCHDIR_1);
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, FALSE, SRC_02, 
WATCHDIR_1);
+    DoTestGroup(__LINE__, _countof(s_group_03), s_group_03, FALSE, SRC_03, 
WATCHDIR_1);
+    DoTestGroup(__LINE__, SWITCH(_countof(s_group_00), _countof(s_group_04)), 
SWITCH(s_group_00, s_group_04), FALSE, SRC_04, WATCHDIR_1);
+    DoTestGroup(__LINE__, _countof(s_group_07), s_group_07, FALSE, SRC_05, 
WATCHDIR_1);
+    DoTestGroup(__LINE__, SWITCH(_countof(s_group_00), _countof(s_group_04)), 
SWITCH(s_group_00, s_group_04), FALSE, SRC_06, WATCHDIR_1);
+    DoTestGroup(__LINE__, _countof(s_group_07), s_group_07, FALSE, SRC_07, 
WATCHDIR_1);
+    DoTestGroup(__LINE__, _countof(s_group_04), s_group_04, FALSE, SRC_08, 
WATCHDIR_1);
+    DoTestGroup(__LINE__, _countof(s_group_07), s_group_07, FALSE, SRC_09, 
WATCHDIR_1);
+    DoTestGroup(__LINE__, SWITCH(_countof(s_group_00), _countof(s_group_04)), 
SWITCH(s_group_00, s_group_04), FALSE, SRC_06, WATCHDIR_1);
+    DoTestGroup(__LINE__, _countof(s_group_07), s_group_07, FALSE, SRC_11, 
WATCHDIR_1);
+#undef SWITCH
+
+#ifndef NO_TRIVIAL
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, FALSE, SRC_00, 
WATCHDIR_2);
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, FALSE, SRC_01, 
WATCHDIR_2);
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, FALSE, SRC_02, 
WATCHDIR_2);
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, FALSE, SRC_03, 
WATCHDIR_2);
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, FALSE, SRC_04, 
WATCHDIR_2);
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, FALSE, SRC_05, 
WATCHDIR_2);
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, FALSE, SRC_06, 
WATCHDIR_2);
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, FALSE, SRC_07, 
WATCHDIR_2);
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, FALSE, SRC_08, 
WATCHDIR_2);
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, FALSE, SRC_09, 
WATCHDIR_2);
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, FALSE, SRC_10, 
WATCHDIR_2);
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, FALSE, SRC_11, 
WATCHDIR_2);
+#endif
+
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, FALSE, SRC_00, 
WATCHDIR_3);
+    DoTestGroup(__LINE__, _countof(s_group_02), s_group_02, FALSE, SRC_01, 
WATCHDIR_3);
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, FALSE, SRC_02, 
WATCHDIR_3);
+    DoTestGroup(__LINE__, _countof(s_group_02), s_group_02, FALSE, SRC_03, 
WATCHDIR_3);
+    DoTestGroup(__LINE__, _countof(s_group_05), s_group_05, FALSE, SRC_04, 
WATCHDIR_3);
+    DoTestGroup(__LINE__, _countof(s_group_08), s_group_08, FALSE, SRC_05, 
WATCHDIR_3);
+    DoTestGroup(__LINE__, _countof(s_group_05), s_group_05, FALSE, SRC_06, 
WATCHDIR_3);
+    DoTestGroup(__LINE__, _countof(s_group_08), s_group_08, FALSE, SRC_07, 
WATCHDIR_3);
+    DoTestGroup(__LINE__, _countof(s_group_05), s_group_05, FALSE, SRC_08, 
WATCHDIR_3);
+    DoTestGroup(__LINE__, _countof(s_group_08), s_group_08, FALSE, SRC_09, 
WATCHDIR_3);
+    DoTestGroup(__LINE__, _countof(s_group_05), s_group_05, FALSE, SRC_10, 
WATCHDIR_3);
+    DoTestGroup(__LINE__, _countof(s_group_08), s_group_08, FALSE, SRC_11, 
WATCHDIR_3);
+
+    // fRecursive == TRUE.
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, TRUE, SRC_00, 
WATCHDIR_0);
+    DoTestGroup(__LINE__, _countof(s_group_01), s_group_01, TRUE, SRC_01, 
WATCHDIR_0);
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, TRUE, SRC_02, 
WATCHDIR_0);
+    DoTestGroup(__LINE__, _countof(s_group_01), s_group_01, TRUE, SRC_03, 
WATCHDIR_0);
+    DoTestGroup(__LINE__, _countof(s_group_04), s_group_04, TRUE, SRC_04, 
WATCHDIR_0);
+    DoTestGroup(__LINE__, _countof(s_group_06), s_group_06, TRUE, SRC_05, 
WATCHDIR_0);
+    DoTestGroup(__LINE__, _countof(s_group_04), s_group_04, TRUE, SRC_06, 
WATCHDIR_0);
+    DoTestGroup(__LINE__, _countof(s_group_06), s_group_06, TRUE, SRC_07, 
WATCHDIR_0);
+    DoTestGroup(__LINE__, _countof(s_group_04), s_group_04, TRUE, SRC_08, 
WATCHDIR_0);
+    DoTestGroup(__LINE__, _countof(s_group_06), s_group_06, TRUE, SRC_09, 
WATCHDIR_0);
+    DoTestGroup(__LINE__, _countof(s_group_04), s_group_04, TRUE, SRC_10, 
WATCHDIR_0);
+    DoTestGroup(__LINE__, _countof(s_group_06), s_group_06, TRUE, SRC_11, 
WATCHDIR_0);
+
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, TRUE, SRC_00, 
WATCHDIR_1);
+    DoTestGroup(__LINE__, _countof(s_group_01), s_group_01, TRUE, SRC_01, 
WATCHDIR_1);
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, TRUE, SRC_02, 
WATCHDIR_1);
+    DoTestGroup(__LINE__, _countof(s_group_01), s_group_01, TRUE, SRC_03, 
WATCHDIR_1);
+    DoTestGroup(__LINE__, _countof(s_group_04), s_group_04, TRUE, SRC_04, 
WATCHDIR_1);
+    DoTestGroup(__LINE__, _countof(s_group_06), s_group_06, TRUE, SRC_05, 
WATCHDIR_1);
+    DoTestGroup(__LINE__, _countof(s_group_04), s_group_04, TRUE, SRC_06, 
WATCHDIR_1);
+    DoTestGroup(__LINE__, _countof(s_group_06), s_group_06, TRUE, SRC_07, 
WATCHDIR_1);
+    DoTestGroup(__LINE__, _countof(s_group_04), s_group_04, TRUE, SRC_08, 
WATCHDIR_1);
+    DoTestGroup(__LINE__, _countof(s_group_06), s_group_06, TRUE, SRC_09, 
WATCHDIR_1);
+    DoTestGroup(__LINE__, _countof(s_group_04), s_group_04, TRUE, SRC_10, 
WATCHDIR_1);
+    DoTestGroup(__LINE__, _countof(s_group_06), s_group_06, TRUE, SRC_11, 
WATCHDIR_1);
+
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, TRUE, SRC_00, 
WATCHDIR_2);
+    DoTestGroup(__LINE__, _countof(s_group_01), s_group_01, TRUE, SRC_01, 
WATCHDIR_2);
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, TRUE, SRC_02, 
WATCHDIR_2);
+    DoTestGroup(__LINE__, _countof(s_group_01), s_group_01, TRUE, SRC_03, 
WATCHDIR_2);
+    DoTestGroup(__LINE__, _countof(s_group_04), s_group_04, TRUE, SRC_04, 
WATCHDIR_2);
+    DoTestGroup(__LINE__, _countof(s_group_06), s_group_06, TRUE, SRC_05, 
WATCHDIR_2);
+    DoTestGroup(__LINE__, _countof(s_group_04), s_group_04, TRUE, SRC_06, 
WATCHDIR_2);
+    DoTestGroup(__LINE__, _countof(s_group_06), s_group_06, TRUE, SRC_07, 
WATCHDIR_2);
+    DoTestGroup(__LINE__, _countof(s_group_04), s_group_04, TRUE, SRC_08, 
WATCHDIR_2);
+    DoTestGroup(__LINE__, _countof(s_group_06), s_group_06, TRUE, SRC_09, 
WATCHDIR_2);
+    DoTestGroup(__LINE__, _countof(s_group_04), s_group_04, TRUE, SRC_10, 
WATCHDIR_2);
+    DoTestGroup(__LINE__, _countof(s_group_06), s_group_06, TRUE, SRC_11, 
WATCHDIR_2);
+
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, TRUE, SRC_00, 
WATCHDIR_3);
+    DoTestGroup(__LINE__, _countof(s_group_02), s_group_02, TRUE, SRC_01, 
WATCHDIR_3);
+    DoTestGroup(__LINE__, _countof(s_group_00), s_group_00, TRUE, SRC_02, 
WATCHDIR_3);
+    DoTestGroup(__LINE__, _countof(s_group_02), s_group_02, TRUE, SRC_03, 
WATCHDIR_3);
+    DoTestGroup(__LINE__, _countof(s_group_05), s_group_05, TRUE, SRC_04, 
WATCHDIR_3);
+    DoTestGroup(__LINE__, _countof(s_group_08), s_group_08, TRUE, SRC_05, 
WATCHDIR_3);
+    DoTestGroup(__LINE__, _countof(s_group_05), s_group_05, TRUE, SRC_06, 
WATCHDIR_3);
+    DoTestGroup(__LINE__, _countof(s_group_08), s_group_08, TRUE, SRC_07, 
WATCHDIR_3);
+    DoTestGroup(__LINE__, _countof(s_group_05), s_group_05, TRUE, SRC_08, 
WATCHDIR_3);
+    DoTestGroup(__LINE__, _countof(s_group_08), s_group_08, TRUE, SRC_09, 
WATCHDIR_3);
+    DoTestGroup(__LINE__, _countof(s_group_05), s_group_05, TRUE, SRC_10, 
WATCHDIR_3);
+    DoTestGroup(__LINE__, _countof(s_group_08), s_group_08, TRUE, SRC_11, 
WATCHDIR_3);
+
+    return 0;
 }
 
 START_TEST(SHChangeNotify)
 {
+#ifdef DISABLE_THIS_TESTCASE
+    skip("This testcase is disabled by DISABLE_THIS_TESTCASE macro.\n");
+#endif
+#ifdef TOTAL_TICK
+    DWORD dwOldTick = GetTickCount();
+#endif
+
+    trace("Please don't operate your PC while testing...\n");
+
     if (!GetSubProgramPath())
     {
         skip("shell32_apitest_sub.exe not found\n");
+        return;
     }
 
-    JustDoIt(0);
-    JustDoIt(1);
-    JustDoIt(2);
-    JustDoIt(3);
-    JustDoIt(4);
-    JustDoIt(5);
+    if (!DoInitTest())
+    {
+        skip("Unable to initialize.\n");
+        DoQuitTest(TRUE);
+        return;
+    }
+
+    s_hThread = (HANDLE)_beginthreadex(NULL, 0, TestThreadProc, NULL, 0, NULL);
+    WaitForSingleObject(s_hThread, INFINITE);
+    CloseHandle(s_hThread);
+
+#ifdef TOTAL_TICK
+    DWORD dwNewTick = GetTickCount();
+    DWORD dwTick = dwNewTick - dwOldTick;
+    trace("SHChangeNotify: Total %lu.%lu sec\n", (dwTick / 1000), (dwTick / 
100 % 10));
+#endif
 }
diff --git a/modules/rostests/apitests/shell32/SHChangeNotify.h 
b/modules/rostests/apitests/shell32/SHChangeNotify.h
index 71389513eb2..e20b6b7a74c 100644
--- a/modules/rostests/apitests/shell32/SHChangeNotify.h
+++ b/modules/rostests/apitests/shell32/SHChangeNotify.h
@@ -1,6 +1,18 @@
 #pragma once
 
-#define TEMP_FILE "shell-notify-temporary.txt"
+#include <shlwapi.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <strsafe.h>
+
+#define TEMP_FILE   L"shell-notify-temporary.txt"
+#define CLASSNAME   L"SHChangeNotify testcase window"
+#define EVENT_NAME  L"SHChangeNotify testcase event"
+
+#define WM_SHELL_NOTIFY     (WM_USER + 100)
+#define WM_GET_NOTIFY_FLAGS (WM_USER + 101)
+#define WM_CLEAR_FLAGS      (WM_USER + 102)
+#define WM_SET_PATHS        (WM_USER + 103)
 
 typedef enum TYPE
 {
@@ -9,40 +21,53 @@ typedef enum TYPE
     TYPE_DELETE,
     TYPE_MKDIR,
     TYPE_RMDIR,
+    TYPE_RENAMEFOLDER,
     TYPE_UPDATEDIR,
-    TYPE_UPDATEITEM,
-    TYPE_RENAMEFOLDER
+    TYPE_MAX = TYPE_UPDATEDIR
 } TYPE;
 
-#define WM_SHELL_NOTIFY (WM_USER + 100)
-#define WM_GET_NOTIFY_FLAGS (WM_USER + 101)
-#define WM_CLEAR_FLAGS (WM_USER + 102)
-#define WM_SET_PATHS (WM_USER + 103)
-
-static WCHAR s_dir1[MAX_PATH];  // "%TEMP%\\WatchDir1"
-static WCHAR s_dir2[MAX_PATH];  // "%TEMP%\\WatchDir1\\Dir2"
-static WCHAR s_dir3[MAX_PATH];  // "%TEMP%\\WatchDir1\\Dir3"
-static WCHAR s_file1[MAX_PATH]; // "%TEMP%\\WatchDir1\\File1.txt"
-static WCHAR s_file2[MAX_PATH]; // "%TEMP%\\WatchDir1\\File2.txt"
+typedef enum DIRTYPE
+{
+    DIRTYPE_NULL = 0,
+    DIRTYPE_DESKTOP,
+    DIRTYPE_MYCOMPUTER,
+    DIRTYPE_MYDOCUMENTS
+} DIRTYPE;
 
-inline void DoInitPaths(void)
+inline LPITEMIDLIST DoGetPidl(DIRTYPE iDir)
 {
-    WCHAR szTemp[MAX_PATH], szPath[MAX_PATH];
-    GetTempPathW(_countof(szTemp), szTemp);
-    GetLongPathNameW(szTemp, szPath, _countof(szPath));
+    LPITEMIDLIST ret = NULL;
+
+    switch (iDir)
+    {
+        case DIRTYPE_NULL:
+            break;
 
-    lstrcpyW(s_dir1, szPath);
-    PathAppendW(s_dir1, L"WatchDir1");
+        case DIRTYPE_DESKTOP:
+            SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &ret);
+            break;
 
-    lstrcpyW(s_dir2, s_dir1);
-    PathAppendW(s_dir2, L"Dir2");
+        case DIRTYPE_MYCOMPUTER:
+            SHGetSpecialFolderLocation(NULL, CSIDL_DRIVES, &ret);
+            break;
 
-    lstrcpyW(s_dir3, s_dir1);
-    PathAppendW(s_dir3, L"Dir3");
+        case DIRTYPE_MYDOCUMENTS:
+            SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &ret);
+            break;
+    }
 
-    lstrcpyW(s_file1, s_dir1);
-    PathAppendW(s_file1, L"File1.txt");
+    return ret;
+}
 
-    lstrcpyW(s_file2, s_dir1);
-    PathAppendW(s_file2, L"File2.txt");
+inline LPWSTR DoGetDir(DIRTYPE iDir)
+{
+    static size_t s_index = 0;
+    static WCHAR s_pathes[3][MAX_PATH];
+    LPWSTR psz = s_pathes[s_index];
+    LPITEMIDLIST pidl = DoGetPidl(iDir);
+    psz[0] = 0;
+    SHGetPathFromIDListW(pidl, psz);
+    CoTaskMemFree(pidl);
+    s_index = (s_index + 1) % _countof(s_pathes);
+    return psz;
 }
diff --git a/modules/rostests/apitests/shell32/shell32_apitest_sub.cpp 
b/modules/rostests/apitests/shell32/shell32_apitest_sub.cpp
index 127ecaf687f..1b90c7ae39a 100644
--- a/modules/rostests/apitests/shell32/shell32_apitest_sub.cpp
+++ b/modules/rostests/apitests/shell32/shell32_apitest_sub.cpp
@@ -6,72 +6,28 @@
  */
 
 #include "shelltest.h"
-#include <shlwapi.h>
-#include <stdio.h>
 #include "SHChangeNotify.h"
 
 static HWND s_hwnd = NULL;
-static const WCHAR s_szName[] = L"SHChangeNotify testcase";
-static INT s_nMode;
-
-static BYTE s_counters[TYPE_RENAMEFOLDER + 1];
 static UINT s_uRegID = 0;
-
-static WCHAR s_path1[MAX_PATH], s_path2[MAX_PATH];
-
+static BOOL s_fRecursive = FALSE;
+static DIRTYPE s_iWatchDir = DIRTYPE_NULL;
+static INT s_nSources = 0;
 static LPITEMIDLIST s_pidl = NULL;
-static SHChangeNotifyEntry s_entry;
+static WCHAR s_path1[MAX_PATH], s_path2[MAX_PATH];
+static BYTE s_counters[TYPE_MAX + 1];
+static HANDLE s_hEvent = NULL;
 
 static BOOL
 OnCreate(HWND hwnd)
 {
     s_hwnd = hwnd;
+    s_pidl = DoGetPidl(s_iWatchDir);
 
-    DoInitPaths();
-
-    s_pidl = ILCreateFromPathW(s_dir1);
-    s_entry.pidl = s_pidl;
-
-    INT nSources;
-    switch (s_nMode)
-    {
-        case 0:
-            s_entry.fRecursive = TRUE;
-            nSources = SHCNRF_ShellLevel;
-            break;
-
-        case 1:
-            s_entry.fRecursive = TRUE;
-            nSources = SHCNRF_ShellLevel | SHCNRF_InterruptLevel;
-            break;
-
-        case 2:
-            s_entry.fRecursive = FALSE;
-            nSources = SHCNRF_ShellLevel | SHCNRF_NewDelivery;
-            break;
-
-        case 3:
-            s_entry.fRecursive = TRUE;
-            nSources = SHCNRF_InterruptLevel | SHCNRF_RecursiveInterrupt | 
SHCNRF_NewDelivery;
-            break;
-
-        case 4:
-            s_entry.fRecursive = FALSE;
-            nSources = SHCNRF_InterruptLevel | SHCNRF_NewDelivery;
-            break;
-
-        case 5:
-            s_entry.fRecursive = TRUE;
-            nSources = SHCNRF_InterruptLevel | SHCNRF_RecursiveInterrupt | 
SHCNRF_NewDelivery;
-            s_entry.pidl = NULL;
-            break;
-
-        default:
-            return FALSE;
-    }
-    LONG fEvents = SHCNE_ALLEVENTS;
-    s_uRegID = SHChangeNotifyRegister(hwnd, nSources, fEvents, WM_SHELL_NOTIFY,
-                                      1, &s_entry);
+    SHChangeNotifyEntry entry;
+    entry.pidl = s_pidl;
+    entry.fRecursive = s_fRecursive;
+    s_uRegID = SHChangeNotifyRegister(hwnd, s_nSources, SHCNE_ALLEVENTS, 
WM_SHELL_NOTIFY, 1, &entry);
     return s_uRegID != 0;
 }
 
@@ -100,35 +56,54 @@ OnDestroy(HWND hwnd)
     s_hwnd = NULL;
 }
 
-static void
-DoShellNotify(HWND hwnd, PIDLIST_ABSOLUTE pidl1, PIDLIST_ABSOLUTE pidl2, LONG 
lEvent)
+static BOOL DoPathes(PIDLIST_ABSOLUTE pidl1, PIDLIST_ABSOLUTE pidl2)
 {
-    if (pidl1)
-        SHGetPathFromIDListW(pidl1, s_path1);
-    else
-        s_path1[0] = 0;
+    WCHAR path[MAX_PATH];
+    if (!SHGetPathFromIDListW(pidl1, path))
+    {
+        s_path1[0] = s_path2[0] = 0;
+        return FALSE;
+    }
 
-    if (pidl2)
-        SHGetPathFromIDListW(pidl2, s_path2);
-    else
+    if (wcsstr(path, L"Recent") != NULL)
+        return FALSE;
+
+    StringCchCopyW(s_path1, _countof(s_path1), path);
+
+    if (!SHGetPathFromIDListW(pidl2, s_path2))
         s_path2[0] = 0;
 
+    return TRUE;
+}
+
+static VOID DoPathesAndFlags(UINT type, PIDLIST_ABSOLUTE pidl1, 
PIDLIST_ABSOLUTE pidl2)
+{
+    if (DoPathes(pidl1, pidl2))
+    {
+        s_counters[type] = 1;
+        SetEvent(s_hEvent);
+    }
+}
+
+static void
+DoShellNotify(HWND hwnd, PIDLIST_ABSOLUTE pidl1, PIDLIST_ABSOLUTE pidl2, LONG 
lEvent)
+{
     switch (lEvent)
     {
         case SHCNE_RENAMEITEM:
-            s_counters[TYPE_RENAMEITEM] = 1;
+            DoPathesAndFlags(TYPE_RENAMEITEM, pidl1, pidl2);
             break;
         case SHCNE_CREATE:
-            s_counters[TYPE_CREATE] = 1;
+            DoPathesAndFlags(TYPE_CREATE, pidl1, pidl2);
             break;
         case SHCNE_DELETE:
-            s_counters[TYPE_DELETE] = 1;
+            DoPathesAndFlags(TYPE_DELETE, pidl1, pidl2);
             break;
         case SHCNE_MKDIR:
-            s_counters[TYPE_MKDIR] = 1;
+            DoPathesAndFlags(TYPE_MKDIR, pidl1, pidl2);
             break;
         case SHCNE_RMDIR:
-            s_counters[TYPE_RMDIR] = 1;
+            DoPathesAndFlags(TYPE_RMDIR, pidl1, pidl2);
             break;
         case SHCNE_MEDIAINSERTED:
             break;
@@ -145,10 +120,9 @@ DoShellNotify(HWND hwnd, PIDLIST_ABSOLUTE pidl1, 
PIDLIST_ABSOLUTE pidl2, LONG lE
         case SHCNE_ATTRIBUTES:
             break;
         case SHCNE_UPDATEDIR:
-            s_counters[TYPE_UPDATEDIR] = 1;
+            DoPathesAndFlags(TYPE_UPDATEDIR, pidl1, pidl2);
             break;
         case SHCNE_UPDATEITEM:
-            s_counters[TYPE_UPDATEITEM] = 1;
             break;
         case SHCNE_SERVERDISCONNECT:
             break;
@@ -157,7 +131,7 @@ DoShellNotify(HWND hwnd, PIDLIST_ABSOLUTE pidl1, 
PIDLIST_ABSOLUTE pidl2, LONG lE
         case SHCNE_DRIVEADDGUI:
             break;
         case SHCNE_RENAMEFOLDER:
-            s_counters[TYPE_RENAMEFOLDER] = 1;
+            DoPathesAndFlags(TYPE_RENAMEFOLDER, pidl1, pidl2);
             break;
         case SHCNE_FREESPACE:
             break;
@@ -208,13 +182,14 @@ static void
 DoSetPaths(HWND hwnd)
 {
     WCHAR szText[MAX_PATH * 2];
-    lstrcpyW(szText, s_path1);
-    lstrcatW(szText, L"|");
-    lstrcatW(szText, s_path2);
+    StringCchCopyW(szText, _countof(szText), s_path1);
+    StringCchCatW(szText, _countof(szText), L"|");
+    StringCchCatW(szText, _countof(szText), s_path2);
 
-    if (FILE *fp = fopen(TEMP_FILE, "wb"))
+    FILE *fp = _wfopen(TEMP_FILE, L"wb");
+    if (fp)
     {
-        fwrite(szText, (lstrlenW(szText) + 1) * sizeof(WCHAR), 1, fp);
+        fwrite(szText, (wcslen(szText) + 1) * sizeof(WCHAR), 1, fp);
         fflush(fp);
         fclose(fp);
     }
@@ -244,6 +219,7 @@ WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM 
lParam)
 
         case WM_CLEAR_FLAGS:
             ZeroMemory(&s_counters, sizeof(s_counters));
+            s_path1[0] = s_path2[0] = 0;
             break;
 
         case WM_SET_PATHS:
@@ -256,6 +232,25 @@ WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM 
lParam)
     return 0;
 }
 
+static BOOL ParseCommandLine(LPWSTR lpCmdLine)
+{
+    LPWSTR pch = lpCmdLine; // fRecursive,iWatchDir,nSources
+    s_fRecursive = !!wcstoul(pch, NULL, 0);
+    pch = wcschr(pch, L',');
+    if (!pch)
+        return FALSE;
+    ++pch;
+
+    s_iWatchDir = (DIRTYPE)wcstoul(pch, NULL, 0);
+    pch = wcschr(pch, L',');
+    if (!pch)
+        return FALSE;
+    ++pch;
+
+    s_nSources = wcstoul(pch, NULL, 0);
+    return TRUE;
+}
+
 INT APIENTRY
 wWinMain(HINSTANCE hInstance,
          HINSTANCE hPrevInstance,
@@ -265,7 +260,10 @@ wWinMain(HINSTANCE hInstance,
     if (lstrcmpiW(lpCmdLine, L"") == 0 || lstrcmpiW(lpCmdLine, L"TEST") == 0)
         return 0;
 
-    s_nMode = _wtoi(lpCmdLine);
+    if (!ParseCommandLine(lpCmdLine))
+        return -1;
+
+    s_hEvent = OpenEventW(EVENT_ALL_ACCESS, TRUE, EVENT_NAME);
 
     WNDCLASSW wc;
     ZeroMemory(&wc, sizeof(wc));
@@ -274,12 +272,12 @@ wWinMain(HINSTANCE hInstance,
     wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
     wc.hCursor = LoadCursor(NULL, IDC_ARROW);
     wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
-    wc.lpszClassName = s_szName;
+    wc.lpszClassName = CLASSNAME;
     if (!RegisterClassW(&wc))
         return -1;
 
-    HWND hwnd = CreateWindowW(s_szName, s_szName, WS_OVERLAPPEDWINDOW,
-                              CW_USEDEFAULT, CW_USEDEFAULT, 100, 100,
+    HWND hwnd = CreateWindowW(CLASSNAME, CLASSNAME, WS_OVERLAPPEDWINDOW,
+                              CW_USEDEFAULT, CW_USEDEFAULT, 400, 100,
                               NULL, NULL, GetModuleHandleW(NULL), NULL);
     if (!hwnd)
         return -1;
@@ -294,5 +292,7 @@ wWinMain(HINSTANCE hInstance,
         DispatchMessageW(&msg);
     }
 
+    CloseHandle(s_hEvent);
+
     return 0;
 }

Reply via email to