ReactOS 0.4.16-dev-92-g0c2cdca
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
34static 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 */
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. */
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
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
307static 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
357}
358
359START_TEST(brsfolder)
360{
363}
HRESULT WINAPI SHGetDesktopFolder(IShellFolder **psf)
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
#define ok(value,...)
Definition: atltest.h:57
#define skip(...)
Definition: atltest.h:64
#define broken(x)
Definition: atltest.h:178
#define START_TEST(x)
Definition: atltest.h:75
EXTERN_C LPITEMIDLIST WINAPI SHBrowseForFolderA(LPBROWSEINFOA lpbi)
Definition: brfolder.cpp:1320
static void test_click_make_new_folder_button(void)
Definition: brsfolder.c:154
static int CALLBACK selection_callback(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
Definition: brsfolder.c:262
static const char new_folder_name[]
Definition: brsfolder.c:34
static LPITEMIDLIST selected_folder_pidl
Definition: brsfolder.c:35
#define TIMER_WAIT_MS
Definition: brsfolder.c:32
static void CALLBACK make_new_folder_timer_callback(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
Definition: brsfolder.c:79
#define IDD_MAKENEWFOLDER
Definition: brsfolder.c:31
static BOOL does_folder_or_file_exist(LPCSTR folder_path)
Definition: brsfolder.c:69
static int CALLBACK create_new_folder_callback(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
Definition: brsfolder.c:122
static void test_selection(void)
Definition: brsfolder.c:307
static int get_number_of_folders(LPCSTR path)
Definition: brsfolder.c:40
LPARAM lParam
Definition: combotst.c:139
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
static int find_data(const struct Vector *v, const BYTE *pData, int size)
Definition: filtermapper.c:162
#define GetCurrentDirectoryW(x, y)
Definition: compat.h:756
#define lstrcpynA
Definition: compat.h:751
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define MAX_PATH
Definition: compat.h:34
#define CALLBACK
Definition: compat.h:35
#define MultiByteToWideChar
Definition: compat.h:110
BOOL WINAPI CreateDirectoryA(IN LPCSTR lpPathName, IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
Definition: dir.c:37
DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName)
Definition: fileinfo.c:636
HANDLE WINAPI FindFirstFileA(IN LPCSTR lpFileName, OUT LPWIN32_FIND_DATAA lpFindFileData)
Definition: find.c:263
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:502
BOOL WINAPI FindNextFileA(IN HANDLE hFindFile, OUT LPWIN32_FIND_DATAA lpFindFileData)
Definition: find.c:336
DWORD WINAPI GetCurrentDirectoryA(IN DWORD nBufferLength, OUT LPSTR lpBuffer)
Definition: path.c:2146
HRESULT WINAPI CoInitialize(LPVOID lpReserved)
Definition: compobj.c:1964
void WINAPI DECLSPEC_HOTPATCH CoUninitialize(void)
Definition: compobj.c:2067
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
VOID WINAPI CoTaskMemFree(LPVOID ptr)
Definition: ifs.c:442
HRESULT ParseDisplayName([in] HWND hwndOwner, [in] LPBC pbcReserved, [in, string] LPOLESTR lpszDisplayName, [out] ULONG *pchEaten, [out] PIDLIST_RELATIVE *ppidl, [in, out, unique] ULONG *pdwAttributes)
ULONG Release()
#define S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
unsigned int UINT
Definition: ndis.h:50
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
BOOL WINAPI SHGetPathFromIDListA(LPCITEMIDLIST pidl, LPSTR pszPath)
Definition: pidl.c:1286
static char title[]
Definition: ps.c:92
#define CP_UTF8
Definition: nls.h:20
#define FO_DELETE
Definition: shellapi.h:138
#define FOF_NOERRORUI
Definition: shellapi.h:151
#define FOF_NOCONFIRMATION
Definition: shellapi.h:145
#define FOF_SILENT
Definition: shellapi.h:143
int WINAPI SHFileOperationA(LPSHFILEOPSTRUCTA lpFileOp)
Definition: shlfileop.cpp:1060
HRESULT hr
Definition: shlfolder.c:183
#define BFFM_SETSELECTIONW
Definition: shlobj.h:1246
#define BFFM_INITIALIZED
Definition: shlobj.h:1236
#define BIF_NEWDIALOGSTYLE
Definition: shlobj.h:1223
#define BFFM_SETSELECTIONA
Definition: shlobj.h:1245
ITEMIDLIST UNALIGNED * LPITEMIDLIST
Definition: shtypes.idl:41
DWORD dwTime
Definition: solitaire.cpp:27
FILEOP_FLAGS fFlags
Definition: shellapi.h:349
LPCSTR lpszTitle
Definition: shlobj.h:1192
PCIDLIST_ABSOLUTE pidlRoot
Definition: shlobj.h:1190
BFFCALLBACK lpfn
Definition: shlobj.h:1194
HWND hwndOwner
Definition: shlobj.h:1189
LPSTR pszDisplayName
Definition: shlobj.h:1191
UINT ulFlags
Definition: shlobj.h:1193
#define UL
Definition: tui.h:165
#define INVALID_FILE_ATTRIBUTES
Definition: vfdcmd.c:23
int ret
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4023
LONG_PTR LPARAM
Definition: windef.h:208
#define S_FALSE
Definition: winerror.h:2357
HWND WINAPI GetFocus(void)
Definition: window.c:1865
#define WM_COMMAND
Definition: winuser.h:1743
#define EM_REPLACESEL
Definition: winuser.h:2009
LRESULT WINAPI SendMessageA(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define IDOK
Definition: winuser.h:833
UINT_PTR WINAPI SetTimer(_In_opt_ HWND, _In_ UINT_PTR, _In_ UINT, _In_opt_ TIMERPROC)
HWND WINAPI SetFocus(_In_opt_ HWND)
VOID WINAPI keybd_event(_In_ BYTE, _In_ BYTE, _In_ DWORD, _In_ ULONG_PTR)
#define VK_DOWN
Definition: winuser.h:2230
BOOL WINAPI KillTimer(_In_opt_ HWND, _In_ UINT_PTR)
BOOL WINAPI PostMessageA(_In_opt_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define KEYEVENTF_KEYUP
Definition: winuser.h:1105
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
const char * LPCSTR
Definition: xmlstorage.h:183
__wchar_t WCHAR
Definition: xmlstorage.h:180
char CHAR
Definition: xmlstorage.h:175