From 7e9cf359675f0ab4c71dd459fea955d509cf4449 Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Mon, 27 Dec 2021 09:45:44 +0900 Subject: [PATCH] [SHELL32_APITEST] Strengthen SHChangeNotify testcase more and more (#4174) CORE-13950 --- .../apitests/shell32/SHChangeNotify.cpp | 1035 +++++++++++++---- .../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 (katayama.hirofumi.mz@gmail.com) + * COPYRIGHT: Copyright 2020-2021 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) */ -// NOTE: This test program closes the Explorer cabinets before tests. +// NOTE: This test program closes the Explorer windows before tests. #include "shelltest.h" -#include -#include #include "SHChangeNotify.h" - -#define DONT_SEND 0x24242424 +#include +#include +#include + +// --- 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 +#include +#include +#include + +#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 -#include #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; } -- 2.17.1