rsaenh/tests: Fix memory leaks.
[wine] / dlls / shell32 / tests / 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  *         Handle Difference between administrator and non-administrator calls
26  *           as documented
27  *         Better AddItem Tests (Lots of parameters to test)
28  *         Tests for Invalid Characters in Names / Invalid Parameters
29  * - Technically, calling as an administrator creates groups in the CSIDL_COMMON_PROGRAMS
30  *   directory.  Win 9x and non-administrator calls us CSIDL_PROGRAMS directory.
31  *   Original plans were to check that items/groups were created in appropriate
32  *   places.  As of this writing and in order to simplify the test code, it now
33  *   checks for existence in either place.  From web searches, it is not at all
34  *   obvious or trivial to detect if the call is coming from an administrator or
35  *   non-administrator. IsUserAnAdmin
36  */
37
38 #include <stdio.h>
39 #include <wine/test.h>
40 #include <winbase.h>
41 #include "dde.h"
42 #include "ddeml.h"
43 #include "winuser.h"
44 #include "shlobj.h"
45
46 /* Timeout on DdeClientTransaction Call */
47 #define MS_TIMEOUT_VAL 1000
48 /* # of times to poll for window creation */
49 #define PDDE_POLL_NUM 150
50 /* time to sleep between polls */
51 #define PDDE_POLL_TIME 300
52
53 /* Call Info */
54 #define DDE_TEST_MISC            0x00010000
55 #define DDE_TEST_CREATEGROUP     0x00020000
56 #define DDE_TEST_DELETEGROUP     0x00030000
57 #define DDE_TEST_SHOWGROUP       0x00040000
58 #define DDE_TEST_ADDITEM         0x00050000
59 #define DDE_TEST_DELETEITEM      0x00060000
60 #define DDE_TEST_COMPOUND        0x00070000
61 #define DDE_TEST_CALLMASK        0x00ff0000
62
63 /* Type of Test (Common, Individual) */
64 #define DDE_TEST_COMMON            0x01000000
65 #define DDE_TEST_INDIVIDUAL        0x02000000
66
67 #define DDE_TEST_NUMMASK           0x0000ffff
68
69 static BOOL (WINAPI *pSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL);
70 static BOOL (WINAPI *pReadCabinetState)(CABINETSTATE *, int);
71
72 static void init_function_pointers(void)
73 {
74     HMODULE hmod;
75
76     hmod = GetModuleHandleA("shell32.dll");
77     pSHGetSpecialFolderPathA = (void*)GetProcAddress(hmod, "SHGetSpecialFolderPathA");
78     pReadCabinetState = (void*)GetProcAddress(hmod, "ReadCabinetState");
79     if (!pReadCabinetState)
80         pReadCabinetState = (void*)GetProcAddress(hmod, (LPSTR)651);
81 }
82
83 static char CommonPrograms[MAX_PATH];
84 static char Programs[MAX_PATH];
85
86 static char Group1Title[MAX_PATH]  = "Group1";
87 static char Group2Title[MAX_PATH]  = "Group2";
88 static char Group3Title[MAX_PATH]  = "Group3";
89 static char Startup[MAX_PATH]      = "Startup";
90 static char StartupTitle[MAX_PATH] = "Startup";
91
92 static void init_strings(void)
93 {
94     char startup[MAX_PATH];
95     CABINETSTATE cs;
96
97     if (pSHGetSpecialFolderPathA)
98     {
99         pSHGetSpecialFolderPathA(NULL, Programs, CSIDL_PROGRAMS, FALSE);
100         if (!pSHGetSpecialFolderPathA(NULL, CommonPrograms, CSIDL_COMMON_PROGRAMS, FALSE))
101         {
102             /* Win9x */
103             lstrcpyA(CommonPrograms, Programs);
104         }
105         if (GetProcAddress(GetModuleHandleA("shell32.dll"), "SHGetKnownFolderPath"))
106         {
107             /* Vista and higher use CSIDL_PROGRAMS for these tests.
108              * Wine doesn't have SHGetKnownFolderPath yet but should most likely follow
109              * this new ProgMan DDE behavior once implemented.
110              */
111             lstrcpyA(CommonPrograms, Programs);
112         }
113         pSHGetSpecialFolderPathA(NULL, startup, CSIDL_STARTUP, FALSE);
114         lstrcpyA(Startup, (strrchr(startup, '\\') + 1));
115     }
116     else
117     {
118         HKEY key;
119         DWORD size;
120         LONG res;
121
122         /* Older Win9x and NT4 */
123         RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", &key);
124         size = sizeof(Programs);
125         RegQueryValueExA(key, "Programs", NULL, NULL, (LPBYTE)&Programs, &size);
126         size = sizeof(startup);
127         RegQueryValueExA(key, "Startup", NULL, NULL, (LPBYTE)&startup, &size);
128         lstrcpyA(Startup, (strrchr(startup, '\\') + 1));
129         RegCloseKey(key);
130
131         RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", &key);
132         size = sizeof(CommonPrograms);
133         res = RegQueryValueExA(key, "Common Programs", NULL, NULL, (LPBYTE)&CommonPrograms, &size);
134         RegCloseKey(key);
135         if (res != ERROR_SUCCESS)
136         {
137             /* Win9x */
138             lstrcpyA(CommonPrograms, Programs);
139         }
140     }
141
142     memset(&cs, 0, sizeof(cs));
143     pReadCabinetState(&cs, sizeof(cs));
144     if (cs.fFullPathTitle == -1)
145     {
146         lstrcpyA(Group1Title, CommonPrograms);
147         lstrcatA(Group1Title, "\\Group1");
148         lstrcpyA(Group2Title, CommonPrograms);
149         lstrcatA(Group2Title, "\\Group2");
150         lstrcpyA(Group3Title, CommonPrograms);
151         lstrcatA(Group3Title, "\\Group3");
152
153         lstrcpyA(StartupTitle, startup);
154     }
155     else
156     {
157         lstrcpyA(StartupTitle, Startup);
158     }
159 }
160
161 static HDDEDATA CALLBACK DdeCallback(UINT type, UINT format, HCONV hConv, HSZ hsz1, HSZ hsz2,
162                                      HDDEDATA hDDEData, ULONG_PTR data1, ULONG_PTR data2)
163 {
164     trace("Callback: type=%i, format=%i\n", type, format);
165     return NULL;
166 }
167
168 /*
169  * Encoded String for Error Messages so that inner failures can determine
170  * what test is failing.  Format is: [Code:TestNum]
171  */
172 static const char * GetStringFromTestParams(int testParams)
173 {
174     int testNum;
175     static char testParamString[64];
176     const char *callId;
177
178     testNum = testParams & DDE_TEST_NUMMASK;
179     switch (testParams & DDE_TEST_CALLMASK)
180     {
181     default:
182     case DDE_TEST_MISC:
183         callId = "MISC";
184         break;
185     case DDE_TEST_CREATEGROUP:
186         callId = "C_G";
187         break;
188     case DDE_TEST_DELETEGROUP:
189         callId = "D_G";
190         break;
191     case DDE_TEST_SHOWGROUP:
192         callId = "S_G";
193         break;
194     case DDE_TEST_ADDITEM:
195         callId = "A_I";
196         break;
197     case DDE_TEST_DELETEITEM:
198         callId = "D_I";
199         break;
200     case DDE_TEST_COMPOUND:
201         callId = "CPD";
202         break;
203     }
204
205     sprintf(testParamString, "  [%s:%i]", callId, testNum);
206     return testParamString;
207 }
208
209 /* Transfer DMLERR's into text readable strings for Error Messages */
210 #define DMLERR_TO_STR(x) case x: return#x;
211 static const char * GetStringFromError(UINT err)
212 {
213     switch (err)
214     {
215     DMLERR_TO_STR(DMLERR_NO_ERROR);
216     DMLERR_TO_STR(DMLERR_ADVACKTIMEOUT);
217     DMLERR_TO_STR(DMLERR_BUSY);
218     DMLERR_TO_STR(DMLERR_DATAACKTIMEOUT);
219     DMLERR_TO_STR(DMLERR_DLL_NOT_INITIALIZED);
220     DMLERR_TO_STR(DMLERR_DLL_USAGE);
221     DMLERR_TO_STR(DMLERR_EXECACKTIMEOUT);
222     DMLERR_TO_STR(DMLERR_INVALIDPARAMETER);
223     DMLERR_TO_STR(DMLERR_LOW_MEMORY);
224     DMLERR_TO_STR(DMLERR_MEMORY_ERROR);
225     DMLERR_TO_STR(DMLERR_NOTPROCESSED);
226     DMLERR_TO_STR(DMLERR_NO_CONV_ESTABLISHED);
227     DMLERR_TO_STR(DMLERR_POKEACKTIMEOUT);
228     DMLERR_TO_STR(DMLERR_POSTMSG_FAILED);
229     DMLERR_TO_STR(DMLERR_REENTRANCY);
230     DMLERR_TO_STR(DMLERR_SERVER_DIED);
231     DMLERR_TO_STR(DMLERR_SYS_ERROR);
232     DMLERR_TO_STR(DMLERR_UNADVACKTIMEOUT);
233     DMLERR_TO_STR(DMLERR_UNFOUND_QUEUE_ID);
234     default:
235         return "Unknown DML Error";
236     }
237 }
238
239 /* Helper Function to Transfer DdeGetLastError into a String */
240 static const char * GetDdeLastErrorStr(DWORD instance)
241 {
242     UINT err = DdeGetLastError(instance);
243
244     return GetStringFromError(err);
245 }
246
247 /* Execute a Dde Command and return the error & result */
248 /* Note: Progman DDE always returns a pointer to 0x00000001 on a successful result */
249 static void DdeExecuteCommand(DWORD instance, HCONV hConv, const char *strCmd, HDDEDATA *hData, UINT *err, int testParams)
250 {
251     HDDEDATA command;
252
253     command = DdeCreateDataHandle(instance, (LPBYTE) strCmd, strlen(strCmd)+1, 0, 0L, 0, 0);
254     ok (command != NULL, "DdeCreateDataHandle Error %s.%s\n",
255         GetDdeLastErrorStr(instance), GetStringFromTestParams(testParams));
256     *hData = DdeClientTransaction((void *) command,
257                                   -1,
258                                   hConv,
259                                   0,
260                                   0,
261                                   XTYP_EXECUTE,
262                                   MS_TIMEOUT_VAL,
263                                   NULL);
264
265     /* hData is technically a pointer, but for Program Manager,
266      * it is NULL (error) or 1 (success)
267      * TODO: Check other versions of Windows to verify 1 is returned.
268      * While it is unlikely that anyone is actually testing that the result is 1
269      * if all versions of windows return 1, Wine should also.
270      */
271     if (*hData == NULL)
272     {
273         *err = DdeGetLastError(instance);
274     }
275     else
276     {
277         *err = DMLERR_NO_ERROR;
278         todo_wine
279         {
280             ok(*hData == (HDDEDATA) 1, "Expected HDDEDATA Handle == 1, actually %p.%s\n",
281                *hData, GetStringFromTestParams(testParams));
282         }
283     }
284     DdeFreeDataHandle(command);
285 }
286
287 /*
288  * Check if Window is onscreen with the appropriate name.
289  *
290  * Windows are not created synchronously.  So we do not know
291  * when and if the window will be created/shown on screen.
292  * This function implements a polling mechanism to determine
293  * creation.
294  * A more complicated method would be to use SetWindowsHookEx.
295  * Since polling worked fine in my testing, no reason to implement
296  * the other.  Comments about other methods of determining when
297  * window creation happened were not encouraging (not including
298  * SetWindowsHookEx).
299  */
300 static void CheckWindowCreated(const char *winName, int closeWindow, int testParams)
301 {
302     HWND window = NULL;
303     int i;
304
305     /* Poll for Window Creation */
306     for (i = 0; window == NULL && i < PDDE_POLL_NUM; i++)
307     {
308         Sleep(PDDE_POLL_TIME);
309         window = FindWindowA(NULL, winName);
310     }
311     ok (window != NULL, "Window \"%s\" was not created in %i seconds - assumed failure.%s\n",
312         winName, PDDE_POLL_NUM*PDDE_POLL_TIME/1000, GetStringFromTestParams(testParams));
313
314     /* Close Window as desired. */
315     if (window != NULL && closeWindow)
316     {
317         SendMessageA(window, WM_SYSCOMMAND, SC_CLOSE, 0);
318     }
319 }
320
321 /* Check for Existence (or non-existence) of a file or group
322  *   When testing for existence of a group, groupName is not needed
323  */
324 static void CheckFileExistsInProgramGroups(const char *nameToCheck, int shouldExist, int isGroup,
325                                            const char *groupName, int testParams)
326 {
327     char path[MAX_PATH];
328     DWORD attributes;
329     int len;
330
331     if (testParams & DDE_TEST_COMMON)
332         lstrcpyA(path, CommonPrograms);
333     else
334         lstrcpyA(path, Programs);
335
336     len = strlen(path) + strlen(nameToCheck)+1;
337     if (groupName != NULL)
338     {
339         len += strlen(groupName)+1;
340     }
341     ok (len <= MAX_PATH, "Path Too Long.%s\n", GetStringFromTestParams(testParams));
342     if (len <= MAX_PATH)
343     {
344         if (groupName != NULL)
345         {
346             strcat(path, "\\");
347             strcat(path, groupName);
348         }
349         strcat(path, "\\");
350         strcat(path, nameToCheck);
351         attributes = GetFileAttributes(path);
352         if (!shouldExist)
353         {
354             ok (attributes == INVALID_FILE_ATTRIBUTES , "File exists and shouldn't %s.%s\n",
355                 path, GetStringFromTestParams(testParams));
356         } else {
357             if (attributes == INVALID_FILE_ATTRIBUTES)
358             {
359                 ok (FALSE, "Created File %s doesn't exist.%s\n", path, GetStringFromTestParams(testParams));
360             } else if (isGroup) {
361                 ok (attributes & FILE_ATTRIBUTE_DIRECTORY, "%s is not a folder (attr=%x).%s\n",
362                     path, attributes, GetStringFromTestParams(testParams));
363             } else {
364                 ok (attributes & FILE_ATTRIBUTE_ARCHIVE, "Created File %s has wrong attributes (%x).%s\n",
365                     path, attributes, GetStringFromTestParams(testParams));
366             }
367         }
368     }
369 }
370
371 /* Create Group Test.
372  *   command and expected_result.
373  *   if expected_result is DMLERR_NO_ERROR, test
374  *        1. group was created
375  *        2. window is open
376  */
377 static void CreateGroupTest(DWORD instance, HCONV hConv, const char *command, UINT expected_result,
378                             const char *groupName, const char *windowTitle, int testParams)
379 {
380     HDDEDATA hData;
381     UINT error;
382
383     /* Execute Command & Check Result */
384     DdeExecuteCommand(instance, hConv, command, &hData, &error, testParams);
385     todo_wine
386     {
387         ok (expected_result == error, "CreateGroup %s: Expected Error %s, received %s.%s\n",
388             groupName, GetStringFromError(expected_result), GetStringFromError(error),
389             GetStringFromTestParams(testParams));
390     }
391
392     /* No Error */
393     if (error == DMLERR_NO_ERROR)
394     {
395
396         /* Check if Group Now Exists */
397         CheckFileExistsInProgramGroups(groupName, TRUE, TRUE, NULL, testParams);
398         /* Check if Window is Open (polling) */
399         CheckWindowCreated(windowTitle, TRUE, testParams);
400     }
401 }
402
403 /* Show Group Test.
404  *   DDE command, expected_result, and the group name to check for existence
405  *   if expected_result is DMLERR_NO_ERROR, test
406  *        1. window is open
407  */
408 static void ShowGroupTest(DWORD instance, HCONV hConv, const char *command, UINT expected_result,
409                           const char *groupName, const char *windowTitle, int closeAfterShowing, int testParams)
410 {
411     HDDEDATA hData;
412     UINT error;
413
414     DdeExecuteCommand(instance, hConv, command, &hData, &error, testParams);
415 /* todo_wine...  Is expected to fail, wine stubbed functions DO fail */
416 /* TODO REMOVE THIS CODE!!! */
417     if (expected_result == DMLERR_NOTPROCESSED)
418     {
419         ok (expected_result == error, "ShowGroup %s: Expected Error %s, received %s.%s\n",
420             groupName, GetStringFromError(expected_result), GetStringFromError(error),
421             GetStringFromTestParams(testParams));
422     } else {
423         todo_wine
424         {
425             ok (expected_result == error, "ShowGroup %s: Expected Error %s, received %s.%s\n",
426                 groupName, GetStringFromError(expected_result), GetStringFromError(error),
427                 GetStringFromTestParams(testParams));
428         }
429     }
430
431     if (error == DMLERR_NO_ERROR)
432     {
433         /* Check if Window is Open (polling) */
434         CheckWindowCreated(windowTitle, closeAfterShowing, testParams);
435     }
436 }
437
438 /* Delete Group Test.
439  *   DDE command, expected_result, and the group name to check for existence
440  *   if expected_result is DMLERR_NO_ERROR, test
441  *        1. group does not exist
442  */
443 static void DeleteGroupTest(DWORD instance, HCONV hConv, const char *command, UINT expected_result,
444                             const char *groupName, int testParams)
445 {
446     HDDEDATA hData;
447     UINT error;
448
449     DdeExecuteCommand(instance, hConv, command, &hData, &error, testParams);
450     todo_wine
451     {
452         ok (expected_result == error, "DeleteGroup %s: Expected Error %s, received %s.%s\n",
453             groupName, GetStringFromError(expected_result), GetStringFromError(error),
454             GetStringFromTestParams(testParams));
455     }
456
457     if (error == DMLERR_NO_ERROR)
458     {
459         /* Check that Group does not exist */
460         CheckFileExistsInProgramGroups(groupName, FALSE, TRUE, NULL, testParams);
461     }
462 }
463
464 /* Add Item Test
465  *   DDE command, expected result, and group and file name where it should exist.
466  *   checks to make sure error code matches expected error code
467  *   checks to make sure item exists if successful
468  */
469 static void AddItemTest(DWORD instance, HCONV hConv, const char *command, UINT expected_result,
470                         const char *fileName, const char *groupName, int testParams)
471 {
472     HDDEDATA hData;
473     UINT error;
474
475     DdeExecuteCommand(instance, hConv, command, &hData, &error, testParams);
476     todo_wine
477     {
478         ok (expected_result == error, "AddItem %s: Expected Error %s, received %s.%s\n",
479             fileName, GetStringFromError(expected_result), GetStringFromError(error),
480             GetStringFromTestParams(testParams));
481     }
482
483     if (error == DMLERR_NO_ERROR)
484     {
485         /* Check that File exists */
486         CheckFileExistsInProgramGroups(fileName, TRUE, FALSE, groupName, testParams);
487     }
488 }
489
490 /* Delete Item Test.
491  *   DDE command, expected result, and group and file name where it should exist.
492  *   checks to make sure error code matches expected error code
493  *   checks to make sure item does not exist if successful
494  */
495 static void DeleteItemTest(DWORD instance, HCONV hConv, const char *command, UINT expected_result,
496                            const char *fileName, const char *groupName, int testParams)
497 {
498     HDDEDATA hData;
499     UINT error;
500
501     DdeExecuteCommand(instance, hConv, command, &hData, &error, testParams);
502     todo_wine
503     {
504         ok (expected_result == error, "DeleteItem %s: Expected Error %s, received %s.%s\n",
505             fileName, GetStringFromError(expected_result), GetStringFromError(error),
506             GetStringFromTestParams(testParams));
507     }
508
509     if (error == DMLERR_NO_ERROR)
510     {
511         /* Check that File does not exist */
512         CheckFileExistsInProgramGroups(fileName, FALSE, FALSE, groupName, testParams);
513     }
514 }
515
516 /* Compound Command Test.
517  *   not really generic, assumes command of the form:
518  *          [CreateGroup ...][AddItem ...][AddItem ...]
519  *   All samples I've seen using Compound were of this form (CreateGroup,
520  *   AddItems) so this covers minimum expected functionality.
521  */
522 static void CompoundCommandTest(DWORD instance, HCONV hConv, const char *command, UINT expected_result,
523                                 const char *groupName, const char *windowTitle, const char *fileName1,
524                                 const char *fileName2, int testParams)
525 {
526     HDDEDATA hData;
527     UINT error;
528
529     DdeExecuteCommand(instance, hConv, command, &hData, &error, testParams);
530     todo_wine
531     {
532         ok (expected_result == error, "Compound String %s: Expected Error %s, received %s.%s\n",
533             command, GetStringFromError(expected_result), GetStringFromError(error),
534             GetStringFromTestParams(testParams));
535     }
536
537     if (error == DMLERR_NO_ERROR)
538     {
539         /* Check that File exists */
540         CheckFileExistsInProgramGroups(groupName, TRUE, TRUE, NULL, testParams);
541         CheckWindowCreated(windowTitle, FALSE, testParams);
542         CheckFileExistsInProgramGroups(fileName1, TRUE, FALSE, groupName, testParams);
543         CheckFileExistsInProgramGroups(fileName2, TRUE, FALSE, groupName, testParams);
544     }
545 }
546
547 static void CreateAddItemText(char *itemtext, const char *cmdline, const char *name)
548 {
549     lstrcpyA(itemtext, "[AddItem(");
550     lstrcatA(itemtext, cmdline);
551     lstrcatA(itemtext, ",");
552     lstrcatA(itemtext, name);
553     lstrcatA(itemtext, ")]");
554 }
555
556 /* 1st set of tests */
557 static int DdeTestProgman(DWORD instance, HCONV hConv)
558 {
559     HDDEDATA hData;
560     UINT error;
561     int testnum;
562     char temppath[MAX_PATH];
563     char f1g1[MAX_PATH], f2g1[MAX_PATH], f3g1[MAX_PATH], f1g3[MAX_PATH], f2g3[MAX_PATH];
564     char itemtext[MAX_PATH + 20];
565     char comptext[2 * (MAX_PATH + 20) + 21];
566
567     testnum = 1;
568     /* Invalid Command */
569     DdeExecuteCommand(instance, hConv, "[InvalidCommand()]", &hData, &error, DDE_TEST_MISC|testnum++);
570     ok (error == DMLERR_NOTPROCESSED, "InvalidCommand(), expected error %s, received %s.\n",
571         GetStringFromError(DMLERR_NOTPROCESSED), GetStringFromError(error));
572
573     /* On Vista+ the files have to exist when adding a link */
574     GetTempPathA(MAX_PATH, temppath);
575     GetTempFileNameA(temppath, "dde", 0, f1g1);
576     GetTempFileNameA(temppath, "dde", 0, f2g1);
577     GetTempFileNameA(temppath, "dde", 0, f3g1);
578     GetTempFileNameA(temppath, "dde", 0, f1g3);
579     GetTempFileNameA(temppath, "dde", 0, f2g3);
580
581     /* CreateGroup Tests (including AddItem, DeleteItem) */
582     CreateGroupTest(instance, hConv, "[CreateGroup(Group1)]", DMLERR_NO_ERROR, "Group1", Group1Title, DDE_TEST_COMMON|DDE_TEST_CREATEGROUP|testnum++);
583     CreateAddItemText(itemtext, f1g1, "f1g1Name");
584     AddItemTest(instance, hConv, itemtext, DMLERR_NO_ERROR, "f1g1Name.lnk", "Group1", DDE_TEST_COMMON|DDE_TEST_ADDITEM|testnum++);
585     CreateAddItemText(itemtext, f2g1, "f2g1Name");
586     AddItemTest(instance, hConv, itemtext, DMLERR_NO_ERROR, "f2g1Name.lnk", "Group1", DDE_TEST_COMMON|DDE_TEST_ADDITEM|testnum++);
587     DeleteItemTest(instance, hConv, "[DeleteItem(f2g1Name)]", DMLERR_NO_ERROR, "f2g1Name.lnk", "Group1", DDE_TEST_COMMON|DDE_TEST_DELETEITEM|testnum++);
588     CreateAddItemText(itemtext, f3g1, "f3g1Name");
589     AddItemTest(instance, hConv, itemtext, DMLERR_NO_ERROR, "f3g1Name.lnk", "Group1", DDE_TEST_COMMON|DDE_TEST_ADDITEM|testnum++);
590     CreateGroupTest(instance, hConv, "[CreateGroup(Group2)]", DMLERR_NO_ERROR, "Group2", Group2Title, DDE_TEST_COMMON|DDE_TEST_CREATEGROUP|testnum++);
591     /* Create Group that already exists - same instance */
592     CreateGroupTest(instance, hConv, "[CreateGroup(Group1)]", DMLERR_NO_ERROR, "Group1", Group1Title, DDE_TEST_COMMON|DDE_TEST_CREATEGROUP|testnum++);
593
594     /* ShowGroup Tests */
595     ShowGroupTest(instance, hConv, "[ShowGroup(Group1)]", DMLERR_NOTPROCESSED, Startup, StartupTitle, TRUE, DDE_TEST_SHOWGROUP|testnum++);
596     DeleteItemTest(instance, hConv, "[DeleteItem(f3g1Name)]", DMLERR_NO_ERROR, "f3g1Name.lnk", "Group1", DDE_TEST_COMMON|DDE_TEST_DELETEITEM|testnum++);
597     ShowGroupTest(instance, hConv, "[ShowGroup(Startup,0)]", DMLERR_NO_ERROR, Startup, StartupTitle, TRUE, DDE_TEST_SHOWGROUP|testnum++);
598     ShowGroupTest(instance, hConv, "[ShowGroup(Group1,0)]", DMLERR_NO_ERROR, "Group1", Group1Title, FALSE, DDE_TEST_SHOWGROUP|testnum++);
599
600     /* DeleteGroup Test - Note that Window is Open for this test */
601     DeleteGroupTest(instance, hConv, "[DeleteGroup(Group1)]", DMLERR_NO_ERROR, "Group1", DDE_TEST_DELETEGROUP|testnum++);
602
603     /* Compound Execute String Command */
604     lstrcpyA(comptext, "[CreateGroup(Group3)]");
605     CreateAddItemText(itemtext, f1g3, "f1g3Name");
606     lstrcatA(comptext, itemtext);
607     CreateAddItemText(itemtext, f2g3, "f2g3Name");
608     lstrcatA(comptext, itemtext);
609     CompoundCommandTest(instance, hConv, comptext, DMLERR_NO_ERROR, "Group3", Group3Title, "f1g3Name.lnk", "f2g3Name.lnk", DDE_TEST_COMMON|DDE_TEST_COMPOUND|testnum++);
610
611     DeleteGroupTest(instance, hConv, "[DeleteGroup(Group3)]", DMLERR_NO_ERROR, "Group3", DDE_TEST_DELETEGROUP|testnum++);
612
613     /* Full Parameters of Add Item */
614     /* AddItem(CmdLine[,Name[,IconPath[,IconIndex[,xPos,yPos[,DefDir[,HotKey[,fMinimize[fSeparateSpace]]]]]]]) */
615
616     DeleteFileA(f1g1);
617     DeleteFileA(f2g1);
618     DeleteFileA(f3g1);
619     DeleteFileA(f1g3);
620     DeleteFileA(f2g3);
621
622     return testnum;
623 }
624
625 /* 2nd set of tests - 2nd connection */
626 static void DdeTestProgman2(DWORD instance, HCONV hConv, int testnum)
627 {
628     /* Create Group that already exists on a separate connection */
629     CreateGroupTest(instance, hConv, "[CreateGroup(Group2)]", DMLERR_NO_ERROR, "Group2", Group2Title, DDE_TEST_COMMON|DDE_TEST_CREATEGROUP|testnum++);
630     DeleteGroupTest(instance, hConv, "[DeleteGroup(Group2)]", DMLERR_NO_ERROR, "Group2", DDE_TEST_COMMON|DDE_TEST_DELETEGROUP|testnum++);
631 }
632
633 START_TEST(progman_dde)
634 {
635     DWORD instance = 0;
636     UINT err;
637     HSZ hszProgman;
638     HCONV hConv;
639     int testnum;
640
641     init_function_pointers();
642     init_strings();
643
644     /* Initialize DDE Instance */
645     err = DdeInitialize(&instance, DdeCallback, APPCMD_CLIENTONLY, 0);
646     ok (err == DMLERR_NO_ERROR, "DdeInitialize Error %s\n", GetStringFromError(err));
647
648     /* Create Connection */
649     hszProgman = DdeCreateStringHandle(instance, "PROGMAN", CP_WINANSI);
650     ok (hszProgman != NULL, "DdeCreateStringHandle Error %s\n", GetDdeLastErrorStr(instance));
651     hConv = DdeConnect(instance, hszProgman, hszProgman, NULL);
652     ok (DdeFreeStringHandle(instance, hszProgman), "DdeFreeStringHandle failure\n");
653     /* Seeing failures on early versions of Windows Connecting to progman, exit if connection fails */
654     if (hConv == NULL)
655     {
656         ok (DdeUninitialize(instance), "DdeUninitialize failed\n");
657         return;
658     }
659
660     /* Run Tests */
661     testnum = DdeTestProgman(instance, hConv);
662
663     /* Cleanup & Exit */
664     ok (DdeDisconnect(hConv), "DdeDisonnect Error %s\n", GetDdeLastErrorStr(instance));
665     ok (DdeUninitialize(instance), "DdeUninitialize failed\n");
666
667     /* 2nd Instance (Followup Tests) */
668     /* Initialize DDE Instance */
669     instance = 0;
670     err = DdeInitialize(&instance, DdeCallback, APPCMD_CLIENTONLY, 0);
671     ok (err == DMLERR_NO_ERROR, "DdeInitialize Error %s\n", GetStringFromError(err));
672
673     /* Create Connection */
674     hszProgman = DdeCreateStringHandle(instance, "PROGMAN", CP_WINANSI);
675     ok (hszProgman != NULL, "DdeCreateStringHandle Error %s\n", GetDdeLastErrorStr(instance));
676     hConv = DdeConnect(instance, hszProgman, hszProgman, NULL);
677     ok (hConv != NULL, "DdeConnect Error %s\n", GetDdeLastErrorStr(instance));
678     ok (DdeFreeStringHandle(instance, hszProgman), "DdeFreeStringHandle failure\n");
679
680     /* Run Tests */
681     DdeTestProgman2(instance, hConv, testnum);
682
683     /* Cleanup & Exit */
684     ok (DdeDisconnect(hConv), "DdeDisonnect Error %s\n", GetDdeLastErrorStr(instance));
685     ok (DdeUninitialize(instance), "DdeUninitialize failed\n");
686 }