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