[SHELL32_WINETEST] Sync with Wine Staging 4.0. CORE-15682
[reactos.git] / modules / rostests / winetests / shell32 / progman_dde.c
1 /*
2 * Unit test of the Program Manager DDE Interfaces
3 *
4 * Copyright 2009 Mikey Alexander
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 /* DDE Program Manager Tests
22 * - Covers basic CreateGroup, ShowGroup, DeleteGroup, AddItem, and DeleteItem
23 * functionality
24 * - Todo: Handle CommonGroupFlag
25 * Better AddItem Tests (Lots of parameters to test)
26 * Tests for Invalid Characters in Names / Invalid Parameters
27 */
28
29 #include <stdio.h>
30 #include <wine/test.h>
31 #include <winbase.h>
32 #include "dde.h"
33 #include "ddeml.h"
34 #include "winuser.h"
35 #include "shlobj.h"
36
37 static HRESULT (WINAPI *pSHGetLocalizedName)(LPCWSTR, LPWSTR, UINT, int *);
38
39 static void init_function_pointers(void)
40 {
41 HMODULE hmod;
42
43 hmod = GetModuleHandleA("shell32.dll");
44 pSHGetLocalizedName = (void*)GetProcAddress(hmod, "SHGetLocalizedName");
45 }
46
47 static BOOL use_common(void)
48 {
49 HMODULE hmod;
50 static BOOL (WINAPI *pIsNTAdmin)(DWORD, LPDWORD);
51
52 /* IsNTAdmin() is available on all platforms. */
53 hmod = LoadLibraryA("advpack.dll");
54 pIsNTAdmin = (void*)GetProcAddress(hmod, "IsNTAdmin");
55
56 if (!pIsNTAdmin(0, NULL))
57 {
58 /* We are definitely not an administrator */
59 FreeLibrary(hmod);
60 return FALSE;
61 }
62 FreeLibrary(hmod);
63
64 /* If we end up here we are on NT4+ as Win9x and WinMe don't have the
65 * notion of administrators (as we need it).
66 */
67
68 /* As of Vista we should always use the users directory. Tests with the
69 * real Administrator account on Windows 7 proved this.
70 *
71 * FIXME: We need a better way of identifying Vista+ as currently this check
72 * also covers Wine and we don't know yet which behavior we want to follow.
73 */
74 if (pSHGetLocalizedName)
75 return FALSE;
76
77 return TRUE;
78 }
79
80 static BOOL full_title(void)
81 {
82 CABINETSTATE cs;
83
84 memset(&cs, 0, sizeof(cs));
85 ReadCabinetState(&cs, sizeof(cs));
86
87 return (cs.fFullPathTitle == -1);
88 }
89
90 static char ProgramsDir[MAX_PATH];
91
92 static void init_strings(void)
93 {
94 char commonprograms[MAX_PATH];
95 char programs[MAX_PATH];
96
97 SHGetSpecialFolderPathA(NULL, programs, CSIDL_PROGRAMS, FALSE);
98 SHGetSpecialFolderPathA(NULL, commonprograms, CSIDL_COMMON_PROGRAMS, FALSE);
99
100 /* ProgramsDir on Vista+ is always the users one (CSIDL_PROGRAMS). Before Vista
101 * it depends on whether the user is an administrator (CSIDL_COMMON_PROGRAMS) or
102 * not (CSIDL_PROGRAMS).
103 */
104 if (use_common())
105 lstrcpyA(ProgramsDir, commonprograms);
106 else
107 lstrcpyA(ProgramsDir, programs);
108 }
109
110 static HDDEDATA CALLBACK DdeCallback(UINT type, UINT format, HCONV hConv, HSZ hsz1, HSZ hsz2,
111 HDDEDATA hDDEData, ULONG_PTR data1, ULONG_PTR data2)
112 {
113 trace("Callback: type=%i, format=%i\n", type, format);
114 return NULL;
115 }
116
117 static UINT dde_execute(DWORD instance, HCONV hconv, const char *command_str)
118 {
119 HDDEDATA command, hdata;
120 DWORD result;
121 UINT ret;
122
123 command = DdeCreateDataHandle(instance, (BYTE *)command_str, strlen(command_str)+1, 0, 0, 0, 0);
124 ok(command != NULL, "DdeCreateDataHandle() failed: %u\n", DdeGetLastError(instance));
125
126 hdata = DdeClientTransaction((BYTE *)command, -1, hconv, 0, 0, XTYP_EXECUTE, 2000, &result);
127 ret = DdeGetLastError(instance);
128 /* PROGMAN always returns 1 on success */
129 ok((UINT_PTR)hdata == !ret, "expected %u, got %p\n", !ret, hdata);
130
131 return ret;
132 }
133
134 static char *dde_request(DWORD instance, HCONV hconv, const char *request_str)
135 {
136 static char data[2000];
137 HDDEDATA hdata;
138 HSZ item;
139 DWORD result;
140
141 item = DdeCreateStringHandleA(instance, request_str, CP_WINANSI);
142 ok(item != NULL, "DdeCreateStringHandle() failed: %u\n", DdeGetLastError(instance));
143
144 hdata = DdeClientTransaction(NULL, -1, hconv, item, CF_TEXT, XTYP_REQUEST, 2000, &result);
145 if (hdata == NULL) return NULL;
146
147 DdeGetData(hdata, (BYTE *)data, 2000, 0);
148
149 return data;
150 }
151
152 static BOOL check_window_exists(const char *name)
153 {
154 char title[MAX_PATH];
155 HWND window = NULL;
156 int i;
157
158 if (full_title())
159 {
160 strcpy(title, ProgramsDir);
161 strcat(title, "\\");
162 strcat(title, name);
163 }
164 else
165 strcpy(title, name);
166
167 for (i = 0; i < 20; i++)
168 {
169 Sleep(100 * i);
170 if ((window = FindWindowA("ExplorerWClass", title)) ||
171 (window = FindWindowA("CabinetWClass", title)))
172 {
173 SendMessageA(window, WM_SYSCOMMAND, SC_CLOSE, 0);
174 break;
175 }
176 }
177
178 return (window != NULL);
179 }
180
181 static BOOL check_exists(const char *name)
182 {
183 char path[MAX_PATH];
184
185 strcpy(path, ProgramsDir);
186 strcat(path, "\\");
187 strcat(path, name);
188 return GetFileAttributesA(path) != INVALID_FILE_ATTRIBUTES;
189 }
190
191 static void test_parser(DWORD instance, HCONV hConv)
192 {
193 UINT error;
194
195 /* Invalid Command */
196 error = dde_execute(instance, hConv, "[InvalidCommand()]");
197 ok(error == DMLERR_NOTPROCESSED, "expected DMLERR_NOTPROCESSED, got %u\n", error);
198
199 /* test parsing */
200 error = dde_execute(instance, hConv, "");
201 ok(error == DMLERR_NOTPROCESSED, "expected DMLERR_NOTPROCESSED, got %u\n", error);
202
203 error = dde_execute(instance, hConv, "CreateGroup");
204 ok(error == DMLERR_NOTPROCESSED, "expected DMLERR_NOTPROCESSED, got %u\n", error);
205
206 error = dde_execute(instance, hConv, "[CreateGroup");
207 ok(error == DMLERR_NOTPROCESSED, "expected DMLERR_NOTPROCESSED, got %u\n", error);
208
209 error = dde_execute(instance, hConv, "[CreateGroup]");
210 ok(error == DMLERR_NOTPROCESSED, "expected DMLERR_NOTPROCESSED, got %u\n", error);
211
212 error = dde_execute(instance, hConv, "[CreateGroup()]");
213 ok(error == DMLERR_NOTPROCESSED, "expected DMLERR_NOTPROCESSED, got %u\n", error);
214
215 error = dde_execute(instance, hConv, "[cREATEgROUP(test)]");
216 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
217 ok(check_exists("test"), "directory not created\n");
218 ok(check_window_exists("test"), "window not created\n");
219
220 error = dde_execute(instance, hConv, "[AddItem(notepad,foobar)]");
221 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
222 ok(check_exists("test/foobar.lnk"), "link not created\n");
223
224 error = dde_execute(instance, hConv, "[AddItem(notepad,foo bar)]");
225 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
226 ok(check_exists("test/foo bar.lnk"), "link not created\n");
227
228 error = dde_execute(instance, hConv, "[AddItem(notepad,a[b,c]d)]");
229 ok(error == DMLERR_NOTPROCESSED, "expected DMLERR_NOTPROCESSED, got %u\n", error);
230
231 error = dde_execute(instance, hConv, "[AddItem(notepad,\"a[b,c]d\")]");
232 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
233 ok(check_exists("test/a[b,c]d.lnk"), "link not created\n");
234
235 error = dde_execute(instance, hConv, " [ AddItem ( notepad , test ) ] ");
236 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
237 ok(check_exists("test/test.lnk"), "link not created\n");
238
239 error = dde_execute(instance, hConv, "[AddItem(notepad,one)][AddItem(notepad,two)]");
240 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
241 ok(check_exists("test/one.lnk"), "link not created\n");
242 ok(check_exists("test/two.lnk"), "link not created\n");
243
244 error = dde_execute(instance, hConv, "[FakeCommand(test)][DeleteGroup(test)]");
245 ok(error == DMLERR_NOTPROCESSED, "expected DMLERR_NOTPROCESSED, got %u\n", error);
246 ok(check_exists("test"), "directory should exist\n");
247
248 error = dde_execute(instance, hConv, "[DeleteGroup(test)]");
249 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
250 ok(!check_exists("test"), "directory should not exist\n");
251
252 error = dde_execute(instance, hConv, "[ExitProgman()]");
253 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
254
255 error = dde_execute(instance, hConv, "[ExitProgman]");
256 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
257 }
258
259 /* 1st set of tests */
260 static void test_progman_dde(DWORD instance, HCONV hConv)
261 {
262 UINT error;
263
264 /* test creating and deleting groups and items */
265 error = dde_execute(instance, hConv, "[CreateGroup(Group1)]");
266 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
267 ok(check_exists("Group1"), "directory not created\n");
268 ok(check_window_exists("Group1"), "window not created\n");
269
270 error = dde_execute(instance, hConv, "[AddItem]");
271 ok(error == DMLERR_NOTPROCESSED, "expected DMLERR_NOTPROCESSED, got %u\n", error);
272
273 error = dde_execute(instance, hConv, "[AddItem(test)]");
274 ok(error == DMLERR_NOTPROCESSED, "expected DMLERR_NOTPROCESSED, got %u\n", error);
275
276 error = dde_execute(instance, hConv, "[AddItem(notepad.exe)]");
277 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
278 ok(check_exists("Group1/notepad.lnk"), "link not created\n");
279
280 error = dde_execute(instance, hConv, "[DeleteItem(notepad.exe)]");
281 ok(error == DMLERR_NOTPROCESSED, "expected DMLERR_NOTPROCESSED, got %u\n", error);
282
283 error = dde_execute(instance, hConv, "[DeleteItem(notepad)]");
284 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
285 ok(!check_exists("Group1/notepad.lnk"), "link should not exist\n");
286
287 error = dde_execute(instance, hConv, "[DeleteItem(notepad)]");
288 ok(error == DMLERR_NOTPROCESSED, "expected DMLERR_NOTPROCESSED, got %u\n", error);
289
290 error = dde_execute(instance, hConv, "[AddItem(notepad)]");
291 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
292 ok(check_exists("Group1/notepad.lnk"), "link not created\n");
293
294 error = dde_execute(instance, hConv, "[AddItem(notepad)]");
295 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
296
297 /* XP allows any valid path even if it does not exist; Vista+ requires that
298 * the path both exist and be a file (directories are invalid). */
299
300 error = dde_execute(instance, hConv, "[AddItem(C:\\windows\\system.ini)]");
301 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
302 ok(check_exists("Group1/system.lnk"), "link not created\n");
303
304 error = dde_execute(instance, hConv, "[AddItem(notepad,test1)]");
305 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
306 ok(check_exists("Group1/test1.lnk"), "link not created\n");
307
308 error = dde_execute(instance, hConv, "[DeleteItem(test1)]");
309 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
310 ok(!check_exists("Group1/test1.lnk"), "link should not exist\n");
311
312 error = dde_execute(instance, hConv, "[AddItem(notepad,test1)]");
313 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
314 ok(check_exists("Group1/test1.lnk"), "link not created\n");
315
316 error = dde_execute(instance, hConv, "[ReplaceItem(test1)]");
317 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
318 ok(!check_exists("Group1/test1.lnk"), "link should not exist\n");
319
320 error = dde_execute(instance, hConv, "[AddItem(regedit)]");
321 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
322 ok(check_exists("Group1/regedit.lnk"), "link not created\n");
323
324 /* test ShowGroup() and test which group an item gets added to */
325 error = dde_execute(instance, hConv, "[ShowGroup(Group1)]");
326 ok(error == DMLERR_NOTPROCESSED, "expected DMLERR_NOTPROCESSED, got %u\n", error);
327
328 error = dde_execute(instance, hConv, "[ShowGroup(Group1, 0)]");
329 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
330 ok(check_window_exists("Group1"), "window not created\n");
331
332 error = dde_execute(instance, hConv, "[CreateGroup(Group2)]");
333 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
334 ok(check_exists("Group2"), "directory not created\n");
335 ok(check_window_exists("Group2"), "window not created\n");
336
337 error = dde_execute(instance, hConv, "[AddItem(notepad,test2)]");
338 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
339 ok(check_exists("Group2/test2.lnk"), "link not created\n");
340
341 error = dde_execute(instance, hConv, "[ShowGroup(Group1, 0)]");
342 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
343 ok(check_window_exists("Group1"), "window not created\n");
344
345 error = dde_execute(instance, hConv, "[AddItem(notepad,test3)]");
346 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
347 ok(check_exists("Group1/test3.lnk"), "link not created\n");
348
349 error = dde_execute(instance, hConv, "[DeleteGroup(Group1)]");
350 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
351 ok(!check_exists("Group1"), "directory should not exist\n");
352
353 error = dde_execute(instance, hConv, "[DeleteGroup(Group1)]");
354 ok(error == DMLERR_NOTPROCESSED, "expected DMLERR_NOTPROCESSED, got %u\n", error);
355
356 error = dde_execute(instance, hConv, "[ShowGroup(Group2, 0)]");
357 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
358 ok(check_window_exists("Group2"), "window not created\n");
359
360 error = dde_execute(instance, hConv, "[ExitProgman(1)]");
361 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
362
363 error = dde_execute(instance, hConv, "[AddItem(notepad,test4)]");
364 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
365 ok(check_exists("Group2/test4.lnk"), "link not created\n");
366 }
367
368 /* 2nd set of tests - 2nd connection */
369 static void test_progman_dde2(DWORD instance, HCONV hConv)
370 {
371 UINT error;
372
373 /* last open group is retained across connections */
374 error = dde_execute(instance, hConv, "[AddItem(notepad)]");
375 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
376 ok(check_exists("Group2/notepad.lnk"), "link not created\n");
377
378 error = dde_execute(instance, hConv, "[DeleteGroup(Group2)]");
379 ok(error == DMLERR_NO_ERROR, "expected DMLERR_NO_ERROR, got %u\n", error);
380 ok(!check_exists("Group2"), "directory should not exist\n");
381 }
382
383 static BOOL check_in_programs_list(const char *list, const char *group)
384 {
385 while (1)
386 {
387 if (!strncmp(list, group, strlen(group)) && list[strlen(group)] == '\r')
388 return TRUE;
389 if (!(list = strchr(list, '\r'))) break;
390 list += 2;
391 }
392 return FALSE;
393 }
394
395 static void test_request_groups(DWORD instance, HCONV hconv)
396 {
397 char *list;
398 char programs[MAX_PATH];
399 WIN32_FIND_DATAA finddata;
400 HANDLE hfind;
401
402 list = dde_request(instance, hconv, "Groups");
403 ok(list != NULL, "request failed: %u\n", DdeGetLastError(instance));
404 strcpy(programs, ProgramsDir);
405 strcat(programs, "/*");
406 hfind = FindFirstFileA(programs, &finddata);
407 do
408 {
409 if ((finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && finddata.cFileName[0] != '.')
410 {
411 ok(check_in_programs_list(list, finddata.cFileName),
412 "directory '%s' missing from group list\n", finddata.cFileName);
413 }
414 } while (FindNextFileA(hfind, &finddata));
415 FindClose(hfind);
416 }
417
418 START_TEST(progman_dde)
419 {
420 DWORD instance = 0;
421 UINT err;
422 HSZ hszProgman;
423 HCONV hConv;
424 BOOL ret;
425
426 init_function_pointers();
427 init_strings();
428
429 /* Initialize DDE Instance */
430 err = DdeInitializeA(&instance, DdeCallback, APPCMD_CLIENTONLY, 0);
431 ok(err == DMLERR_NO_ERROR, "DdeInitialize() failed: %u\n", err);
432
433 /* Create Connection */
434 hszProgman = DdeCreateStringHandleA(instance, "PROGMAN", CP_WINANSI);
435 ok(hszProgman != NULL, "DdeCreateStringHandle() failed: %u\n", DdeGetLastError(instance));
436 hConv = DdeConnect(instance, hszProgman, hszProgman, NULL);
437 ret = DdeFreeStringHandle(instance, hszProgman);
438 ok(ret, "DdeFreeStringHandle() failed: %u\n", DdeGetLastError(instance));
439 /* Seeing failures on early versions of Windows Connecting to progman, exit if connection fails */
440 if (hConv == NULL)
441 {
442 ok (DdeUninitialize(instance), "DdeUninitialize failed\n");
443 return;
444 }
445
446 test_parser(instance, hConv);
447 test_progman_dde(instance, hConv);
448 test_request_groups(instance, hConv);
449
450 /* Cleanup & Exit */
451 ret = DdeDisconnect(hConv);
452 ok(ret, "DdeDisonnect() failed: %u\n", DdeGetLastError(instance));
453 ret = DdeUninitialize(instance);
454 ok(ret, "DdeUninitialize() failed: %u\n", DdeGetLastError(instance));
455
456 /* 2nd Instance (Followup Tests) */
457 /* Initialize DDE Instance */
458 instance = 0;
459 err = DdeInitializeA(&instance, DdeCallback, APPCMD_CLIENTONLY, 0);
460 ok (err == DMLERR_NO_ERROR, "DdeInitialize() failed: %u\n", err);
461
462 /* Create Connection */
463 hszProgman = DdeCreateStringHandleA(instance, "PROGMAN", CP_WINANSI);
464 ok(hszProgman != NULL, "DdeCreateStringHandle() failed: %u\n", DdeGetLastError(instance));
465 hConv = DdeConnect(instance, hszProgman, hszProgman, NULL);
466 ok(hConv != NULL, "DdeConnect() failed: %u\n", DdeGetLastError(instance));
467 ret = DdeFreeStringHandle(instance, hszProgman);
468 ok(ret, "DdeFreeStringHandle() failed: %u\n", DdeGetLastError(instance));
469
470 /* Run Tests */
471 test_progman_dde2(instance, hConv);
472
473 /* Cleanup & Exit */
474 ret = DdeDisconnect(hConv);
475 ok(ret, "DdeDisonnect() failed: %u\n", DdeGetLastError(instance));
476 ret = DdeUninitialize(instance);
477 ok(ret, "DdeUninitialize() failed: %u\n", DdeGetLastError(instance));
478 }