ReactOS  0.4.15-dev-321-g2d9b385
SHChangeNotify.cpp
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS api tests
3  * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
4  * PURPOSE: Test for SHChangeNotify
5  * COPYRIGHT: Copyright 2020 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
6  */
7 
8 #include "shelltest.h"
9 #include <shlwapi.h>
10 #include <stdio.h>
11 #include "SHChangeNotify.h"
12 
13 #define DONT_SEND 0x24242424
14 
15 static HWND s_hwnd = NULL;
16 static const WCHAR s_szName[] = L"SHChangeNotify testcase";
18 
19 typedef void (*ACTION)(void);
20 
21 typedef struct TEST_ENTRY
22 {
23  INT line;
31 } TEST_ENTRY;
32 
33 static BOOL
35 {
36  FILE *fp = _wfopen(pszFileName, L"wb");
37  fclose(fp);
38  return fp != NULL;
39 }
40 
41 static void
42 DoAction1(void)
43 {
45 }
46 
47 static void
48 DoAction2(void)
49 {
51 }
52 
53 static void
54 DoAction3(void)
55 {
57 }
58 
59 static void
60 DoAction4(void)
61 {
63 }
64 
65 static void
66 DoAction5(void)
67 {
69 }
70 
71 static void
72 DoAction6(void)
73 {
75 }
76 
77 static void
78 DoAction7(void)
79 {
83 }
84 
85 static void
86 DoAction8(void)
87 {
89 }
90 
92 {
93  {__LINE__, SHCNE_MKDIR, s_dir1, NULL, "000100000", NULL, s_dir1, L""},
94  {__LINE__, SHCNE_MKDIR, s_dir2, NULL, "000100000", NULL, s_dir2, L""},
95  {__LINE__, SHCNE_RMDIR, s_dir2, NULL, "000010000", NULL, s_dir2, L""},
96  {__LINE__, SHCNE_MKDIR, s_dir2, NULL, "000100000", DoAction1, s_dir2, L""},
97  {__LINE__, SHCNE_RMDIR, s_dir2, NULL, "000010000", NULL, s_dir2, L""},
98  {__LINE__, SHCNE_RMDIR, s_dir2, NULL, "000010000", DoAction2, s_dir2, L""},
99  {__LINE__, SHCNE_MKDIR, s_dir2, NULL, "000100000", DoAction1, s_dir2, L""},
100  {__LINE__, SHCNE_RENAMEFOLDER, s_dir2, s_dir3, "000000010", NULL, s_dir2, s_dir3},
101  {__LINE__, SHCNE_RENAMEFOLDER, s_dir2, s_dir3, "000000010", DoAction3, s_dir2, s_dir3},
102  {__LINE__, SHCNE_CREATE, s_file1, NULL, "010000000", NULL, s_file1, L""},
103  {__LINE__, SHCNE_CREATE, s_file1, s_file2, "010000000", NULL, s_file1, s_file2},
104  {__LINE__, SHCNE_CREATE, s_file1, NULL, "010000000", DoAction4, s_file1, L""},
105  {__LINE__, SHCNE_RENAMEITEM, s_file1, s_file2, "100000000", NULL, s_file1, s_file2},
106  {__LINE__, SHCNE_RENAMEITEM, s_file1, s_file2, "100000000", DoAction5, s_file1, s_file2},
107  {__LINE__, SHCNE_RENAMEITEM, s_file1, s_file2, "100000000", NULL, s_file1, s_file2},
108  {__LINE__, SHCNE_UPDATEITEM, s_file1, NULL, "000000100", NULL, s_file1, L""},
109  {__LINE__, SHCNE_UPDATEITEM, s_file2, NULL, "000000100", NULL, s_file2, L""},
110  {__LINE__, SHCNE_UPDATEITEM, s_file1, s_file2, "000000100", NULL, s_file1, s_file2},
111  {__LINE__, SHCNE_UPDATEITEM, s_file2, s_file1, "000000100", NULL, s_file2, s_file1},
112  {__LINE__, SHCNE_DELETE, s_file1, NULL, "001000000", NULL, s_file1, L""},
113  {__LINE__, SHCNE_DELETE, s_file2, NULL, "001000000", NULL, s_file2, L""},
114  {__LINE__, SHCNE_DELETE, s_file2, s_file1, "001000000", NULL, s_file2, s_file1},
115  {__LINE__, SHCNE_DELETE, s_file1, s_file2, "001000000", NULL, s_file1, s_file2},
116  {__LINE__, SHCNE_DELETE, s_file2, NULL, "001000000", DoAction6, s_file2, L""},
117  {__LINE__, SHCNE_DELETE, s_file2, NULL, "001000000", NULL, s_file2, L""},
118  {__LINE__, SHCNE_DELETE, s_file1, NULL, "001000000", NULL, s_file1, L""},
119  {__LINE__, SHCNE_UPDATEDIR, s_file1, NULL, "000001000", NULL, s_file1, L""},
120  {__LINE__, SHCNE_UPDATEDIR, s_file2, NULL, "000001000", NULL, s_file2, L""},
121  {__LINE__, SHCNE_UPDATEDIR, s_file1, s_file2, "000001000", NULL, s_file1, s_file2},
122  {__LINE__, SHCNE_UPDATEDIR, s_file2, s_file1, "000001000", NULL, s_file2, s_file1},
123  {__LINE__, SHCNE_UPDATEDIR, s_dir1, NULL, "000001000", NULL, s_dir1, L""},
124  {__LINE__, SHCNE_UPDATEDIR, s_dir2, NULL, "000001000", NULL, s_dir2, L""},
125  {__LINE__, SHCNE_UPDATEDIR, s_dir1, s_dir2, "000001000", NULL, s_dir1, s_dir2},
126  {__LINE__, SHCNE_UPDATEDIR, s_dir2, s_dir1, "000001000", NULL, s_dir2, s_dir1},
127  {__LINE__, SHCNE_RMDIR, s_dir1, NULL, "000010000", NULL, s_dir1, L""},
128  {__LINE__, SHCNE_RMDIR, s_dir2, NULL, "000010000", NULL, s_dir2, L""},
129  {__LINE__, SHCNE_RMDIR, s_dir3, NULL, "000010000", NULL, s_dir3, L""},
130  {__LINE__, SHCNE_RMDIR, s_dir1, s_dir2, "000010000", NULL, s_dir1, s_dir2},
131  {__LINE__, SHCNE_RMDIR, s_dir1, s_dir3, "000010000", NULL, s_dir1, s_dir3},
132  {__LINE__, SHCNE_RMDIR, s_dir2, s_dir1, "000010000", NULL, s_dir2, s_dir1},
133  {__LINE__, SHCNE_RMDIR, s_dir2, s_dir3, "000010000", NULL, s_dir2, s_dir3},
134  {__LINE__, SHCNE_RMDIR, s_dir3, NULL, "000010000", NULL, s_dir3, L""},
135  {__LINE__, SHCNE_RMDIR, s_dir3, NULL, "000010000", DoAction7, s_dir3, L""},
136  {__LINE__, SHCNE_RMDIR, s_dir1, NULL, "000010000", NULL, s_dir1, L""},
137  {__LINE__, SHCNE_RMDIR, s_dir1, NULL, "000010000", DoAction8, s_dir1, L""},
138 };
139 
140 #define s_TestEntriesMode1 s_TestEntriesMode0
141 #define s_TestEntriesMode2 s_TestEntriesMode0
142 
144 {
145  static char s_buf[TYPE_FREESPACE + 1 + 1];
146  DWORD i;
147  for (i = 0; i <= TYPE_FREESPACE; ++i)
148  {
149  s_buf[i] = (char)('0' + !!(flags & (1 << i)));
150  }
151  s_buf[i] = 0;
152  return s_buf;
153 }
154 
155 static BOOL
156 DoGetClipText(LPWSTR pszPath1, LPWSTR pszPath2)
157 {
158  pszPath1[0] = pszPath2[0] = 0;
159 
161  return FALSE;
162 
163  if (!OpenClipboard(NULL))
164  return FALSE;
165 
166  WCHAR szText[MAX_PATH * 2];
168  LPWSTR psz = (LPWSTR)GlobalLock(hGlobal);
170  GlobalUnlock(hGlobal);
171  CloseClipboard();
172 
173  LPWSTR pch = wcschr(szText, L'|');
174  if (pch == NULL)
175  return FALSE;
176 
177  *pch = 0;
178  lstrcpynW(pszPath1, szText, MAX_PATH);
179  lstrcpynW(pszPath2, pch + 1, MAX_PATH);
180  return TRUE;
181 }
182 
183 static void
185 {
186  if (entry->action)
187  {
188  (*entry->action)();
189  }
190 
191  if (entry->event != DONT_SEND)
192  {
193  SHChangeNotify(entry->event, SHCNF_PATHW | SHCNF_FLUSH, entry->item1, entry->item2);
194  }
195 
198 
199  ok(lstrcmpA(pattern, entry->pattern) == 0, "Line %d: pattern mismatch '%s'\n", entry->line, pattern);
200 
202 
203  WCHAR szPath1[MAX_PATH], szPath2[MAX_PATH];
204  BOOL bOK = DoGetClipText(szPath1, szPath2);
205  if (entry->path1)
206  ok(bOK && lstrcmpiW(entry->path1, szPath1) == 0,
207  "Line %d: path1 mismatch '%S' (%d)\n", entry->line, szPath1, bOK);
208  if (entry->path2)
209  ok(bOK && lstrcmpiW(entry->path2, szPath2) == 0,
210  "Line %d: path2 mismatch '%S' (%d)\n", entry->line, szPath2, bOK);
211 
213 }
214 
215 static BOOL
216 DoInit(void)
217 {
218  DoInitPaths();
219 
221 
222  return PathIsDirectoryW(s_dir1);
223 }
224 
225 static void
227 {
233 
235 }
236 
237 static BOOL
239 {
242  PathAppendW(s_szSubProgram, L"shell-notify.exe");
243 
245  {
247  PathAppendW(s_szSubProgram, L"testdata\\shell-notify.exe");
248 
250  {
251  return FALSE;
252  }
253  }
254 
255  return TRUE;
256 }
257 
258 static void
259 JustDoIt(INT nMode)
260 {
261  if (!DoInit())
262  {
263  skip("Unable to initialize.\n");
264  return;
265  }
266 
267  WCHAR szParams[8];
268  wsprintfW(szParams, L"%u", nMode);
269 
271  if ((INT_PTR)hinst <= 32)
272  {
273  skip("Unable to run shell-notify.exe.\n");
274  return;
275  }
276 
277  for (int i = 0; i < 15; ++i)
278  {
280  if (s_hwnd)
281  break;
282 
283  Sleep(50);
284  }
285 
286  if (!s_hwnd)
287  {
288  skip("Unable to find window.\n");
289  return;
290  }
291 
292  switch (nMode)
293  {
294  case 0:
295  case 1:
296  case 2:
297  for (size_t i = 0; i < _countof(s_TestEntriesMode0); ++i)
298  {
300  }
301  break;
302  }
303 
304  DoEnd(s_hwnd);
305 
306  for (int i = 0; i < 15; ++i)
307  {
309  if (!s_hwnd)
310  break;
311 
312  Sleep(50);
313  }
314 }
315 
317 {
318  if (!GetSubProgramPath())
319  {
320  skip("shell-notify.exe not found\n");
321  }
322 
323  JustDoIt(0);
324  JustDoIt(1);
325  JustDoIt(2);
326 }
int WINAPIV wsprintfW(_Out_ LPWSTR, _In_ _Printf_format_string_ LPCWSTR,...)
#define SHCNE_MKDIR
Definition: shlobj.h:1732
static WCHAR s_file1[MAX_PATH]
BOOL WINAPI CreateDirectoryW(IN LPCWSTR lpPathName, IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
Definition: dir.c:90
static BOOL DoCreateEmptyFile(LPCWSTR pszFileName)
BOOL WINAPI PathIsDirectoryW(LPCWSTR lpszPath)
Definition: path.c:1702
DWORD WINAPI GetModuleFileNameW(HINSTANCE hModule, LPWSTR lpFilename, DWORD nSize)
Definition: loader.c:600
const DOCKBAR PVOID HWND HWND * hwnd
Definition: tooldock.h:22
BOOL WINAPI PathRemoveFileSpecW(LPWSTR lpszPath)
Definition: path.c:624
LPCSTR pattern
#define TRUE
Definition: types.h:120
#define SHCNE_RMDIR
Definition: shlobj.h:1733
#define IDOK
Definition: winuser.h:824
VOID WINAPI DECLSPEC_HOTPATCH Sleep(IN DWORD dwMilliseconds)
Definition: synch.c:790
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
static WCHAR s_dir3[MAX_PATH]
BOOL WINAPI IsClipboardFormatAvailable(_In_ UINT)
static WCHAR s_szSubProgram[MAX_PATH]
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#define MOVEFILE_REPLACE_EXISTING
Definition: filesup.h:28
_Check_return_ _CRTIMP FILE *__cdecl _wfopen(_In_z_ const wchar_t *_Filename, _In_z_ const wchar_t *_Mode)
void DoInitPaths(void)
#define MOVEFILE_COPY_ALLOWED
Definition: filesup.h:29
#define SHCNE_RENAMEFOLDER
Definition: shlobj.h:1746
static WCHAR s_dir2[MAX_PATH]
static const TEST_ENTRY s_TestEntriesMode0[]
int WINAPI lstrcmpA(LPCSTR lpString1, LPCSTR lpString2)
Definition: lstring.c:18
START_TEST(SHChangeNotify)
static BOOL GetSubProgramPath(void)
int32_t INT_PTR
Definition: typedefs.h:63
static BOOL DoGetClipText(LPWSTR pszPath1, LPWSTR pszPath2)
#define SHCNE_RENAMEITEM
Definition: shlobj.h:1729
static WCHAR s_dir1[MAX_PATH]
int32_t INT
Definition: typedefs.h:57
#define pch(ap)
Definition: match.c:418
#define lstrcpynW
Definition: compat.h:406
BOOL WINAPI PathAppendW(LPWSTR lpszPath, LPCWSTR lpszAppend)
Definition: path.c:121
int WINAPI lstrcmpiW(LPCWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:194
static BOOL DoInit(void)
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
static const WCHAR szText[]
Definition: dialog.c:139
unsigned int BOOL
Definition: ntddk_ex.h:94
long LONG
Definition: pedump.c:60
#define WM_CLEAR_FLAGS
WORD WORD PSZ PSZ pszFileName
Definition: vdmdbg.h:41
BOOL WINAPI DeleteFileW(IN LPCWSTR lpFileName)
Definition: delete.c:39
LPCSTR PatternFromFlags(DWORD flags)
#define CF_UNICODETEXT
Definition: constants.h:408
smooth NULL
Definition: ftsmooth.c:416
struct TEST_ENTRY TEST_ENTRY
unsigned char
Definition: typeof.h:29
#define ok_int(expression, result)
Definition: atltest.h:134
LONG event
BOOL WINAPI PathFileExistsW(LPCWSTR lpszPath)
Definition: path.c:1756
static void DoAction4(void)
#define WM_SET_PATHS
const char * LPCSTR
Definition: xmlstorage.h:183
static void DoEnd(HWND hwnd)
BOOL WINAPI RemoveDirectoryW(IN LPCWSTR lpPathName)
Definition: dir.c:732
static void DoAction2(void)
LPCVOID item1
_CONST_RETURN wchar_t *__cdecl wcschr(_In_z_ const wchar_t *_Str, wchar_t _Ch)
__wchar_t WCHAR
Definition: xmlstorage.h:180
HWND WINAPI FindWindowW(_In_opt_ LPCWSTR, _In_opt_ LPCWSTR)
#define _countof(array)
Definition: sndvol32.h:68
#define MAX_PATH
Definition: compat.h:26
INT line
Definition: cmd.c:14
#define DONT_SEND
unsigned long DWORD
Definition: ntddk_ex.h:95
#define WM_GET_NOTIFY_FLAGS
GLbitfield flags
Definition: glext.h:7161
static const WCHAR s_szName[]
BOOL WINAPI CloseClipboard(void)
Definition: ntwrapper.h:178
LPCWSTR path2
static void DoAction6(void)
EXTERN_C void WINAPI SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2)
Definition: cmd.c:12
static const WCHAR L[]
Definition: oid.c:1250
#define SHCNF_FLUSH
Definition: shlobj.h:1767
LPVOID NTAPI GlobalLock(HGLOBAL hMem)
Definition: heapmem.c:755
static void DoAction1(void)
uint32_t entry
Definition: isohybrid.c:63
static void DoAction7(void)
_Check_return_opt_ _CRTIMP int __cdecl fclose(_Inout_ FILE *_File)
#define WM_COMMAND
Definition: winuser.h:1722
static void DoTestEntry(const TEST_ENTRY *entry)
LPCVOID item2
static void DoAction3(void)
static WCHAR s_file2[MAX_PATH]
#define SHCNF_PATHW
Definition: shlobj.h:1764
#define SW_SHOWNORMAL
Definition: winuser.h:764
#define SHCNE_DELETE
Definition: shlobj.h:1731
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define ok(value,...)
Definition: atltest.h:57
LPCWSTR path1
#define SHCNE_UPDATEDIR
Definition: shlobj.h:1741
static HWND s_hwnd
BOOL NTAPI GlobalUnlock(HGLOBAL hMem)
Definition: heapmem.c:1190
HANDLE WINAPI GetClipboardData(_In_ UINT)
#define skip(...)
Definition: atltest.h:64
CONST void * LPCVOID
Definition: windef.h:191
static void DoAction5(void)
HINSTANCE WINAPI ShellExecuteW(HWND hwnd, LPCWSTR lpVerb, LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd)
Definition: shlexec.cpp:2274
static HINSTANCE hinst
Definition: edit.c:551
BOOL WINAPI MoveFileExW(IN LPCWSTR lpExistingFileName, IN LPCWSTR lpNewFileName OPTIONAL, IN DWORD dwFlags)
Definition: move.c:1060
static void DoAction8(void)
BOOL WINAPI OpenClipboard(_In_opt_ HWND)
#define SHCNE_CREATE
Definition: shlobj.h:1730
#define SHCNE_UPDATEITEM
Definition: shlobj.h:1742
WCHAR * LPWSTR
Definition: xmlstorage.h:184
static void JustDoIt(INT nMode)
ACTION action
GLubyte * pattern
Definition: glext.h:7787