ReactOS  0.4.14-dev-368-gfa26425
brsfolder.c
Go to the documentation of this file.
1 /*
2  * Unit test of the SHBrowseForFolder function.
3  *
4  * Copyright 2009-2010 Michael Mc Donnell
5  * Copyright 2011 AndrĂ© Hentschel
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #define COBJMACROS
23 
24 #include <windows.h>
25 #include <shlobj.h>
26 #include <shobjidl.h>
27 #include <string.h>
28 #include "shellapi.h"
29 
30 #include "wine/test.h"
31 #define IDD_MAKENEWFOLDER 0x3746 /* From "../shresdef.h" */
32 #define TIMER_WAIT_MS 50 /* Should be long enough for slow systems */
33 
34 static const char new_folder_name[] = "foo";
36 
37 /*
38  * Returns the number of folders in a folder.
39  */
41 {
42  int number_of_folders = 0;
43  char path_search_string[MAX_PATH];
46 
47  lstrcpynA(path_search_string, path, MAX_PATH - 1);
48  strcat(path_search_string, "*");
49 
50  find_handle = FindFirstFileA(path_search_string, &find_data);
52  return -1;
53 
54  do
55  {
56  if ((find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
57  strcmp(find_data.cFileName, ".") != 0 &&
58  strcmp(find_data.cFileName, "..") != 0)
59  {
60  number_of_folders++;
61  }
62  }
63  while (FindNextFileA(find_handle, &find_data) != 0);
64 
66  return number_of_folders;
67 }
68 
70 {
71  DWORD file_attributes = GetFileAttributesA(folder_path);
72  return !(file_attributes == INVALID_FILE_ATTRIBUTES);
73 }
74 
75 /*
76  * Timer callback used by test_click_make_new_folder_button. It simulates a user
77  * making a new folder and calling it "foo".
78  */
80  UINT_PTR idEvent, DWORD dwTime)
81 {
82  static int step = 0;
83 
84  switch (step++)
85  {
86  case 0:
87  /* Click "Make New Folder" button */
89  break;
90  case 1:
91  /* Set the new folder name to foo by replacing text in edit control */
93  SetFocus(hwnd);
94  break;
95  case 2:
96  /*
97  * The test does not trigger the correct state on Windows. This results
98  * in the new folder pidl not being returned. The result is as
99  * expected if the same steps are done manually.
100  * Sending the down key selects the new folder again which sets the
101  * correct state. This ensures that the correct pidl is returned.
102  */
103  keybd_event(VK_DOWN, 0, 0, 0);
104  break;
105  case 3:
107  break;
108  case 4:
109  KillTimer(hwnd, idEvent);
110  /* Close dialog box */
112  break;
113  default:
114  break;
115  }
116 }
117 
118 /*
119  * Callback used by test_click_make_new_folder_button. It sets up a timer to
120  * simulate user input.
121  */
123  LPARAM lParam, LPARAM lpData)
124 {
125  switch (uMsg)
126  {
127  case BFFM_INITIALIZED:
128  /* User input is simulated in timer callback */
130  return TRUE;
131  default:
132  return FALSE;
133  }
134 }
135 
136 /*
137  * Tests if clicking the "Make New Folder" button in a SHBrowseForFolder
138  * dialog box creates a new folder. (Bug 17986).
139  *
140  * Here follows a description of what happens on W2K,Vista, W2K8, W7:
141  * When the "Make New Folder" button is clicked a new folder is created and
142  * inserted into the tree. The folder is given a default name that depends on
143  * the locale (e.g. "New Folder"). The folder name is selected and the dialog
144  * waits for the user to type in a new name. The folder is renamed when the user
145  * types in a name and presses enter.
146  *
147  * Note that XP and W2K3 do not select the folder name or wait for the user
148  * to type in a new folder name. This behavior is considered broken as most
149  * users would like to give the folder a name after creating it. The fact that
150  * it originally waited for the user to type in a new folder name(W2K), and then
151  * again was changed back wait for the new folder name(Vista, W2K8, W7),
152  * indicates that MS also believes that it was broken in XP and W2K3.
153  */
155 {
156  HRESULT resCoInit, hr;
157  BROWSEINFOA bi;
158  LPITEMIDLIST pidl = NULL;
159  LPITEMIDLIST test_folder_pidl;
160  IShellFolder *test_folder_object;
161  char test_folder_path[MAX_PATH];
162  WCHAR test_folder_pathW[MAX_PATH];
163  CHAR new_folder_path[MAX_PATH];
164  CHAR new_folder_pidl_path[MAX_PATH];
165  char selected_folder[MAX_PATH];
166  const CHAR title[] = "test_click_make_new_folder_button";
167  int number_of_folders = -1;
168  SHFILEOPSTRUCTA shfileop;
169 
171  {
172  skip("The test folder already exists.\n");
173  return;
174  }
175 
176  /* Must initialize COM if using the NEWDIAlOGSTYLE according to MSDN. */
177  resCoInit = CoInitialize(NULL);
178  if(!(resCoInit == S_OK || resCoInit == S_FALSE))
179  {
180  skip("COM could not be initialized %u\n", GetLastError());
181  return;
182  }
183 
184  /* Leave room for concatenating title, two backslashes, and an extra NULL. */
185  if (!GetCurrentDirectoryA(MAX_PATH-strlen(title)-3, test_folder_path))
186  {
187  skip("GetCurrentDirectoryA failed %u\n", GetLastError());
188  }
189  strcat(test_folder_path, "\\");
190  strcat(test_folder_path, title);
191  strcat(test_folder_path, "\\");
192 
193  /* Avoid conflicts by creating a test folder. */
194  if (!CreateDirectoryA(title, NULL))
195  {
196  skip("CreateDirectoryA failed %u\n", GetLastError());
197  return;
198  }
199 
200  /* Initialize browse info struct for SHBrowseForFolder */
201  bi.hwndOwner = NULL;
202  bi.pszDisplayName = selected_folder;
203  bi.lpszTitle = title;
206  /* Use test folder as the root folder for dialog box */
207  MultiByteToWideChar(CP_UTF8, 0, test_folder_path, -1,
208  test_folder_pathW, MAX_PATH);
209  hr = SHGetDesktopFolder(&test_folder_object);
210  ok (SUCCEEDED(hr), "SHGetDesktopFolder failed with hr 0x%08x\n", hr);
211  if (FAILED(hr)) {
212  skip("SHGetDesktopFolder failed - skipping\n");
213  return;
214  }
215  test_folder_object->lpVtbl->ParseDisplayName(test_folder_object, NULL, NULL,
216  test_folder_pathW, 0UL, &test_folder_pidl, 0UL);
217  bi.pidlRoot = test_folder_pidl;
218 
219  /* Display dialog box and let callback click the buttons */
220  pidl = SHBrowseForFolderA(&bi);
221 
222  number_of_folders = get_number_of_folders(test_folder_path);
223  ok(number_of_folders == 1 || broken(number_of_folders == 0) /* W95, W98 */,
224  "Clicking \"Make New Folder\" button did not result in a new folder.\n");
225 
226  /* There should be a new folder foo inside the test folder */
227  strcpy(new_folder_path, test_folder_path);
228  strcat(new_folder_path, new_folder_name);
229  ok(does_folder_or_file_exist(new_folder_path)
230  || broken(!does_folder_or_file_exist(new_folder_path)) /* W95, W98, XP, W2K3 */,
231  "The new folder did not get the name %s\n", new_folder_name);
232 
233  /* Dialog should return a pidl pointing to the new folder */
234  ok(SHGetPathFromIDListA(pidl, new_folder_pidl_path),
235  "SHGetPathFromIDList failed for new folder.\n");
236  ok(strcmp(new_folder_path, new_folder_pidl_path) == 0
237  || broken(strcmp(new_folder_path, new_folder_pidl_path) != 0) /* earlier than Vista */,
238  "SHBrowseForFolder did not return the pidl for the new folder. "
239  "Expected '%s' got '%s'\n", new_folder_path, new_folder_pidl_path);
240 
241  /* Remove test folder and any subfolders created in this test */
242  shfileop.hwnd = NULL;
243  shfileop.wFunc = FO_DELETE;
244  /* Path must be double NULL terminated */
245  test_folder_path[strlen(test_folder_path)+1] = '\0';
246  shfileop.pFrom = test_folder_path;
247  shfileop.pTo = NULL;
249  SHFileOperationA(&shfileop);
250 
251  CoTaskMemFree(pidl);
252  CoTaskMemFree(test_folder_pidl);
253  test_folder_object->lpVtbl->Release(test_folder_object);
254 
255  CoUninitialize();
256 }
257 
258 
259 /*
260  * Callback used by test_selection.
261  */
263 {
264  DWORD ret;
265 
266  switch (uMsg)
267  {
268  case BFFM_INITIALIZED:
269  /* test with zero values */
271  ok(!ret, "SendMessage returned: %u\n", ret);
273  ok(!ret, "SendMessage returned: %u\n", ret);
274 
276  ok(!ret, "SendMessage returned: %u\n", ret);
277 
278  if(0)
279  {
280  /* Crashes on NT4 */
282  ok(!ret, "SendMessage returned: %u\n", ret);
283  }
284 
286  ok(!ret, "SendMessage returned: %u\n", ret);
288  ok(!ret, "SendMessage returned: %u\n", ret);
289 
291  ok(!ret, "SendMessage returned: %u\n", ret);
293  ok(!ret, "SendMessage returned: %u\n", ret);
294 
296  ok(!ret, "SendMessage returned: %u\n", ret);
298  ok(!ret, "SendMessage returned: %u\n", ret);
299 
301  return 1;
302  default:
303  return 0;
304  }
305 }
306 
307 static void test_selection(void)
308 {
309  HRESULT resCoInit, hr;
310  BROWSEINFOA bi;
311  LPITEMIDLIST pidl = NULL;
312  IShellFolder *desktop_object;
313  WCHAR selected_folderW[MAX_PATH];
314  const CHAR title[] = "test_selection";
315 
316  resCoInit = CoInitialize(NULL);
317  if(!(resCoInit == S_OK || resCoInit == S_FALSE))
318  {
319  skip("COM could not be initialized %u\n", GetLastError());
320  return;
321  }
322 
323  if (!GetCurrentDirectoryW(MAX_PATH, selected_folderW))
324  {
325  skip("GetCurrentDirectoryW failed %u\n", GetLastError());
326  }
327 
328  /* Initialize browse info struct for SHBrowseForFolder */
329  bi.hwndOwner = NULL;
330  bi.pszDisplayName = NULL;
331  bi.lpszTitle = title;
333 
334  hr = SHGetDesktopFolder(&desktop_object);
335  ok (SUCCEEDED(hr), "SHGetDesktopFolder failed with hr 0x%08x\n", hr);
336  if (FAILED(hr)) {
337  skip("SHGetDesktopFolder failed - skipping\n");
338  return;
339  }
340  desktop_object->lpVtbl->ParseDisplayName(desktop_object, NULL, NULL,
341  selected_folderW, 0UL, &selected_folder_pidl, 0UL);
343 
344  /* test without flags */
345  bi.ulFlags = 0;
346  pidl = SHBrowseForFolderA(&bi);
347  CoTaskMemFree(pidl);
348 
349  /* test with flag */
351  pidl = SHBrowseForFolderA(&bi);
352  CoTaskMemFree(pidl);
353 
354  IShellFolder_Release(desktop_object);
355 
356  CoUninitialize();
357 }
358 
359 START_TEST(brsfolder)
360 {
362  test_selection();
363 }
#define IDD_MAKENEWFOLDER
Definition: brsfolder.c:31
const DOCKBAR PVOID HWND HWND * hwnd
Definition: tooldock.h:22
#define TRUE
Definition: types.h:120
#define IDOK
Definition: winuser.h:824
BOOL WINAPI SHGetPathFromIDListA(LPCITEMIDLIST pidl, LPSTR pszPath)
Definition: pidl.c:1264
VOID WINAPI CoTaskMemFree(LPVOID ptr)
Definition: ifs.c:420
HRESULT hr
Definition: shlfolder.c:183
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
HRESULT ParseDisplayName([in] HWND hwndOwner, [in] LPBC pbcReserved, [in, string] LPOLESTR lpszDisplayName, [out] ULONG *pchEaten, [out] PIDLIST_RELATIVE *ppidl, [in, out, unique] ULONG *pdwAttributes)
#define KEYEVENTF_KEYUP
Definition: winuser.h:1092
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
BOOL WINAPI PostMessageA(_In_opt_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
START_TEST(brsfolder)
Definition: brsfolder.c:359
LRESULT WINAPI SendMessageA(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
FILEOP_FLAGS fFlags
Definition: shellapi.h:347
#define FOF_SILENT
Definition: shellapi.h:140
LPCITEMIDLIST pidlRoot
Definition: shlobj.h:1108
char CHAR
Definition: xmlstorage.h:175
#define GetCurrentDirectoryW(x, y)
Definition: compat.h:421
#define CALLBACK
Definition: compat.h:27
#define BFFM_INITIALIZED
Definition: shlobj.h:1154
#define INVALID_HANDLE_VALUE
Definition: compat.h:399
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
#define BFFM_SETSELECTIONA
Definition: shlobj.h:1163
HWND WINAPI SetFocus(_In_opt_ HWND)
#define VK_DOWN
Definition: winuser.h:2202
BOOL WINAPI FindNextFileA(IN HANDLE hFindFile, OUT LPWIN32_FIND_DATAA lpFindFileData)
Definition: find.c:336
BFFCALLBACK lpfn
Definition: shlobj.h:1112
static int find_data(const struct Vector *v, const BYTE *pData, int size)
Definition: filtermapper.c:162
static int CALLBACK selection_callback(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
Definition: brsfolder.c:262
LPSTR pszDisplayName
Definition: shlobj.h:1109
#define CP_UTF8
Definition: nls.h:20
unsigned int BOOL
Definition: ntddk_ex.h:94
DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName)
Definition: fileinfo.c:786
ULONG Release()
#define S_FALSE
Definition: winerror.h:2357
#define FOF_NOERRORUI
Definition: shellapi.h:148
#define FOF_NOCONFIRMATION
Definition: shellapi.h:142
BOOL WINAPI CreateDirectoryA(IN LPCSTR lpPathName, IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
Definition: dir.c:37
static void CALLBACK make_new_folder_timer_callback(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
Definition: brsfolder.c:79
smooth NULL
Definition: ftsmooth.c:416
#define BFFM_SETSELECTIONW
Definition: shlobj.h:1164
LONG_PTR LPARAM
Definition: windef.h:208
#define TIMER_WAIT_MS
Definition: brsfolder.c:32
const char * LPCSTR
Definition: xmlstorage.h:183
UINT_PTR WINAPI SetTimer(_In_opt_ HWND, _In_ UINT_PTR, _In_ UINT, _In_opt_ TIMERPROC)
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
DWORD dwTime
Definition: solitaire.cpp:25
static int CALLBACK create_new_folder_callback(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
Definition: brsfolder.c:122
HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf)
#define BIF_NEWDIALOGSTYLE
Definition: shlobj.h:1141
__wchar_t WCHAR
Definition: xmlstorage.h:180
LONG HRESULT
Definition: typedefs.h:77
VOID WINAPI keybd_event(_In_ BYTE, _In_ BYTE, _In_ DWORD, _In_ ULONG_PTR)
LPITEMIDLIST WINAPI SHBrowseForFolderA(LPBROWSEINFOA lpbi)
Definition: brsfolder.c:1107
#define MAX_PATH
Definition: compat.h:26
static LPITEMIDLIST selected_folder_pidl
Definition: brsfolder.c:35
unsigned long DWORD
Definition: ntddk_ex.h:95
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
#define INVALID_FILE_ATTRIBUTES
Definition: vfdcmd.c:23
LPCSTR lpszTitle
Definition: shlobj.h:1110
BOOL WINAPI KillTimer(_In_opt_ HWND, _In_ UINT_PTR)
int ret
#define WM_COMMAND
Definition: winuser.h:1722
#define broken(x)
Definition: _sntprintf.h:21
UINT ulFlags
Definition: shlobj.h:1111
static void test_selection(void)
Definition: brsfolder.c:307
#define S_OK
Definition: intsafe.h:59
void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
Definition: compobj.c:2067
static int get_number_of_folders(LPCSTR path)
Definition: brsfolder.c:40
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define ok(value,...)
Definition: atltest.h:57
DWORD WINAPI GetCurrentDirectoryA(IN DWORD nBufferLength, OUT LPSTR lpBuffer)
Definition: path.c:2145
Definition: services.c:325
static BOOL does_folder_or_file_exist(LPCSTR folder_path)
Definition: brsfolder.c:69
unsigned int UINT
Definition: ndis.h:50
#define lstrcpynA
Definition: compat.h:416
static const char new_folder_name[]
Definition: brsfolder.c:34
#define MultiByteToWideChar
Definition: compat.h:100
#define skip(...)
Definition: atltest.h:64
int WINAPI SHFileOperationA(LPSHFILEOPSTRUCTA lpFileOp)
Definition: shlfileop.cpp:1000
static void test_click_make_new_folder_button(void)
Definition: brsfolder.c:154
HRESULT WINAPI CoInitialize(LPVOID lpReserved)
Definition: compobj.c:1964
HWND WINAPI GetFocus(void)
Definition: window.c:1905
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
HWND hwndOwner
Definition: shlobj.h:1107
ITEMIDLIST UNALIGNED * LPITEMIDLIST
Definition: shtypes.idl:41
#define FO_DELETE
Definition: shellapi.h:135
#define UL
Definition: tui.h:83
LPARAM lParam
Definition: combotst.c:139
static char title[]
Definition: ps.c:92
HANDLE WINAPI FindFirstFileA(IN LPCSTR lpFileName, OUT LPWIN32_FIND_DATAA lpFindFileData)
Definition: find.c:263
#define EM_REPLACESEL
Definition: winuser.h:1988
#define SUCCEEDED(hr)
Definition: intsafe.h:57
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:502