1 /* 2 * Copyright (C) 2007 Mike McCormack for CodeWeavers 3 * Copyright (C) 2007 Misha Koshelev 4 * 5 * A test program for Microsoft Installer OLE automation functionality. 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 <stdio.h> 25 26 #include <initguid.h> 27 #include <windows.h> 28 #include <msiquery.h> 29 #include <msidefs.h> 30 #include <msi.h> 31 #include <fci.h> 32 #include <oaidl.h> 33 34 #include "wine/test.h" 35 36 #ifdef __REACTOS__ 37 #include "ole2.h" 38 #endif 39 40 static BOOL is_wow64; 41 42 static BOOL (WINAPI *pCheckTokenMembership)(HANDLE,PSID,PBOOL); 43 static BOOL (WINAPI *pOpenProcessToken)(HANDLE, DWORD, PHANDLE); 44 static LONG (WINAPI *pRegDeleteKeyExA)(HKEY, LPCSTR, REGSAM, DWORD); 45 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL); 46 47 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); 48 49 static const char *msifile = "winetest-automation.msi"; 50 static const WCHAR szMsifile[] = {'w','i','n','e','t','e','s','t','-','a','u','t','o','m','a','t','i','o','n','.','m','s','i',0}; 51 static const WCHAR szMSITEST[] = { 'M','S','I','T','E','S','T',0 }; 52 static const WCHAR szProductCode[] = { '{','8','3','7','4','5','0','f','a','-','a','3','9','b','-','4','b','c','8','-','b','3','2','1','-','0','8','b','3','9','3','f','7','8','4','b','3','}',0 }; 53 static const WCHAR szUpgradeCode[] = { '{','C','E','0','6','7','E','8','D','-','2','E','1','A','-','4','3','6','7','-','B','7','3','4','-','4','E','B','2','B','D','A','D','6','5','6','5','}',0 }; 54 static const WCHAR szProductInfoException[] = { 'P','r','o','d','u','c','t','I','n','f','o',',','P','r','o','d','u','c','t',',','A','t','t','r','i','b','u','t','e',0 }; 55 static const WCHAR WINE_INSTALLPROPERTY_PACKAGENAMEW[] = {'P','a','c','k','a','g','e','N','a','m','e',0}; 56 static const WCHAR WINE_INSTALLPROPERTY_PRODUCTNAMEW[] = {'P','r','o','d','u','c','t','N','a','m','e',0}; 57 static const WCHAR WINE_INSTALLPROPERTY_LOCALPACKAGEW[] = {'L','o','c','a','l','P','a','c','k','a','g','e',0}; 58 static FILETIME systemtime; 59 static CHAR CURR_DIR[MAX_PATH]; 60 static EXCEPINFO excepinfo; 61 62 /* 63 * OLE automation data 64 **/ 65 static const WCHAR szProgId[] = { 'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r','.','I','n','s','t','a','l','l','e','r',0 }; 66 static IDispatch *pInstaller; 67 68 /* msi database data */ 69 70 static const CHAR component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n" 71 "s72\tS38\ts72\ti2\tS255\tS72\n" 72 "Component\tComponent\n" 73 "Five\t{8CC92E9D-14B2-4CA4-B2AA-B11D02078087}\tNEWDIR\t2\t\tfive.txt\n" 74 "Four\t{FD37B4EA-7209-45C0-8917-535F35A2F080}\tCABOUTDIR\t2\t\tfour.txt\n" 75 "One\t{783B242E-E185-4A56-AF86-C09815EC053C}\tMSITESTDIR\t2\t\tone.txt\n" 76 "Three\t{010B6ADD-B27D-4EDD-9B3D-34C4F7D61684}\tCHANGEDDIR\t2\t\tthree.txt\n" 77 "Two\t{BF03D1A6-20DA-4A65-82F3-6CAC995915CE}\tFIRSTDIR\t2\t\ttwo.txt\n" 78 "dangler\t{6091DF25-EF96-45F1-B8E9-A9B1420C7A3C}\tTARGETDIR\t4\t\tregdata\n" 79 "component\t\tMSITESTDIR\t0\t1\tfile\n"; 80 81 static const CHAR directory_dat[] = "Directory\tDirectory_Parent\tDefaultDir\n" 82 "s72\tS72\tl255\n" 83 "Directory\tDirectory\n" 84 "CABOUTDIR\tMSITESTDIR\tcabout\n" 85 "CHANGEDDIR\tMSITESTDIR\tchanged:second\n" 86 "FIRSTDIR\tMSITESTDIR\tfirst\n" 87 "MSITESTDIR\tProgramFilesFolder\tmsitest\n" 88 "NEWDIR\tCABOUTDIR\tnew\n" 89 "ProgramFilesFolder\tTARGETDIR\t.\n" 90 "TARGETDIR\t\tSourceDir\n"; 91 92 static const CHAR feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n" 93 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n" 94 "Feature\tFeature\n" 95 "Five\t\tFive\tThe Five Feature\t5\t3\tNEWDIR\t0\n" 96 "Four\t\tFour\tThe Four Feature\t4\t3\tCABOUTDIR\t0\n" 97 "One\t\tOne\tThe One Feature\t1\t3\tMSITESTDIR\t0\n" 98 "Three\tOne\tThree\tThe Three Feature\t3\t3\tCHANGEDDIR\t0\n" 99 "Two\tOne\tTwo\tThe Two Feature\t2\t3\tFIRSTDIR\t0\n" 100 "feature\t\t\t\t2\t1\tTARGETDIR\t0\n"; 101 102 static const CHAR feature_comp_dat[] = "Feature_\tComponent_\n" 103 "s38\ts72\n" 104 "FeatureComponents\tFeature_\tComponent_\n" 105 "Five\tFive\n" 106 "Four\tFour\n" 107 "One\tOne\n" 108 "Three\tThree\n" 109 "Two\tTwo\n" 110 "feature\tcomponent\n"; 111 112 static const CHAR file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n" 113 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n" 114 "File\tFile\n" 115 "five.txt\tFive\tfive.txt\t1000\t\t\t0\t5\n" 116 "four.txt\tFour\tfour.txt\t1000\t\t\t0\t4\n" 117 "one.txt\tOne\tone.txt\t1000\t\t\t0\t1\n" 118 "three.txt\tThree\tthree.txt\t1000\t\t\t0\t3\n" 119 "two.txt\tTwo\ttwo.txt\t1000\t\t\t0\t2\n" 120 "file\tcomponent\tfilename\t100\t\t\t8192\t1\n"; 121 122 static const CHAR install_exec_seq_dat[] = "Action\tCondition\tSequence\n" 123 "s72\tS255\tI2\n" 124 "InstallExecuteSequence\tAction\n" 125 "AllocateRegistrySpace\tNOT Installed\t1550\n" 126 "CostFinalize\t\t1000\n" 127 "CostInitialize\t\t800\n" 128 "FileCost\t\t900\n" 129 "InstallFiles\t\t4000\n" 130 "RegisterProduct\t\t6100\n" 131 "PublishProduct\t\t6400\n" 132 "InstallFinalize\t\t6600\n" 133 "InstallInitialize\t\t1500\n" 134 "InstallValidate\t\t1400\n" 135 "LaunchConditions\t\t100\n" 136 "WriteRegistryValues\tSourceDir And SOURCEDIR\t5000\n"; 137 138 static const CHAR media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n" 139 "i2\ti4\tL64\tS255\tS32\tS72\n" 140 "Media\tDiskId\n" 141 "1\t5\t\t\tDISK1\t\n"; 142 143 static const CHAR property_dat[] = "Property\tValue\n" 144 "s72\tl0\n" 145 "Property\tProperty\n" 146 "DefaultUIFont\tDlgFont8\n" 147 "HASUIRUN\t0\n" 148 "INSTALLLEVEL\t3\n" 149 "InstallMode\tTypical\n" 150 "Manufacturer\tWine\n" 151 "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n" 152 "ProductCode\t{837450fa-a39b-4bc8-b321-08b393f784b3}\n" 153 "ProductID\tnone\n" 154 "ProductLanguage\t1033\n" 155 "ProductName\tMSITEST\n" 156 "ProductVersion\t1.1.1\n" 157 "PROMPTROLLBACKCOST\tP\n" 158 "Setup\tSetup\n" 159 "UpgradeCode\t{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}\n" 160 "MSIFASTINSTALL\t1\n"; 161 162 static const CHAR registry_dat[] = "Registry\tRoot\tKey\tName\tValue\tComponent_\n" 163 "s72\ti2\tl255\tL255\tL0\ts72\n" 164 "Registry\tRegistry\n" 165 "Apples\t1\tSOFTWARE\\Wine\\msitest\tName\timaname\tOne\n" 166 "Oranges\t1\tSOFTWARE\\Wine\\msitest\tnumber\t#314\tTwo\n" 167 "regdata\t1\tSOFTWARE\\Wine\\msitest\tblah\tbad\tdangler\n" 168 "OrderTest\t1\tSOFTWARE\\Wine\\msitest\tOrderTestName\tOrderTestValue\tcomponent\n"; 169 170 typedef struct _msi_table 171 { 172 const CHAR *filename; 173 const CHAR *data; 174 int size; 175 } msi_table; 176 177 #define ADD_TABLE(x) {#x".idt", x##_dat, sizeof(x##_dat)} 178 179 static const msi_table tables[] = 180 { 181 ADD_TABLE(component), 182 ADD_TABLE(directory), 183 ADD_TABLE(feature), 184 ADD_TABLE(feature_comp), 185 ADD_TABLE(file), 186 ADD_TABLE(install_exec_seq), 187 ADD_TABLE(media), 188 ADD_TABLE(property), 189 ADD_TABLE(registry) 190 }; 191 192 typedef struct _msi_summary_info 193 { 194 UINT property; 195 UINT datatype; 196 INT iValue; 197 FILETIME *pftValue; 198 const CHAR *szValue; 199 } msi_summary_info; 200 201 #define ADD_INFO_I2(property, iValue) {property, VT_I2, iValue, NULL, NULL} 202 #define ADD_INFO_I4(property, iValue) {property, VT_I4, iValue, NULL, NULL} 203 #define ADD_INFO_LPSTR(property, szValue) {property, VT_LPSTR, 0, NULL, szValue} 204 #define ADD_INFO_FILETIME(property, pftValue) {property, VT_FILETIME, 0, pftValue, NULL} 205 206 static const msi_summary_info summary_info[] = 207 { 208 ADD_INFO_LPSTR(PID_TEMPLATE, ";1033"), 209 ADD_INFO_LPSTR(PID_REVNUMBER, "{004757CA-5092-49C2-AD20-28E1CE0DF5F2}"), 210 ADD_INFO_I4(PID_PAGECOUNT, 100), 211 ADD_INFO_I4(PID_WORDCOUNT, 0), 212 ADD_INFO_FILETIME(PID_CREATE_DTM, &systemtime), 213 ADD_INFO_FILETIME(PID_LASTPRINTED, &systemtime) 214 }; 215 216 static void init_functionpointers(void) 217 { 218 HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll"); 219 HMODULE hkernel32 = GetModuleHandleA("kernel32.dll"); 220 221 #define GET_PROC(dll, func) \ 222 p ## func = (void *)GetProcAddress(dll, #func); \ 223 if(!p ## func) \ 224 trace("GetProcAddress(%s) failed\n", #func); 225 226 GET_PROC(hadvapi32, CheckTokenMembership); 227 GET_PROC(hadvapi32, OpenProcessToken); 228 GET_PROC(hadvapi32, RegDeleteKeyExA) 229 GET_PROC(hkernel32, IsWow64Process) 230 231 #undef GET_PROC 232 } 233 234 static BOOL is_process_limited(void) 235 { 236 SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; 237 PSID Group = NULL; 238 BOOL IsInGroup; 239 HANDLE token; 240 241 if (!pCheckTokenMembership || !pOpenProcessToken) return FALSE; 242 243 if (!AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, 244 DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &Group) || 245 !pCheckTokenMembership(NULL, Group, &IsInGroup)) 246 { 247 trace("Could not check if the current user is an administrator\n"); 248 FreeSid(Group); 249 return FALSE; 250 } 251 FreeSid(Group); 252 253 if (!IsInGroup) 254 { 255 /* Only administrators have enough privileges for these tests */ 256 return TRUE; 257 } 258 259 if (pOpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) 260 { 261 BOOL ret; 262 TOKEN_ELEVATION_TYPE type = TokenElevationTypeDefault; 263 DWORD size; 264 265 ret = GetTokenInformation(token, TokenElevationType, &type, sizeof(type), &size); 266 CloseHandle(token); 267 return (ret && type == TokenElevationTypeLimited); 268 } 269 return FALSE; 270 } 271 272 static LONG delete_key_portable( HKEY key, LPCSTR subkey, REGSAM access ) 273 { 274 if (pRegDeleteKeyExA) 275 return pRegDeleteKeyExA( key, subkey, access, 0 ); 276 return RegDeleteKeyA( key, subkey ); 277 } 278 279 /* 280 * Database Helpers 281 */ 282 283 static void write_file(const CHAR *filename, const char *data, int data_size) 284 { 285 DWORD size; 286 287 HANDLE hf = CreateFileA(filename, GENERIC_WRITE, 0, NULL, 288 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 289 WriteFile(hf, data, data_size, &size, NULL); 290 CloseHandle(hf); 291 } 292 293 static void write_msi_summary_info(MSIHANDLE db, const msi_summary_info *info, int num_info) 294 { 295 MSIHANDLE summary; 296 UINT r; 297 int j; 298 299 r = MsiGetSummaryInformationA(db, NULL, num_info, &summary); 300 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); 301 302 /* import summary information into the stream */ 303 for (j = 0; j < num_info; j++) 304 { 305 const msi_summary_info *entry = &info[j]; 306 307 r = MsiSummaryInfoSetPropertyA(summary, entry->property, entry->datatype, 308 entry->iValue, entry->pftValue, entry->szValue); 309 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); 310 } 311 312 /* write the summary changes back to the stream */ 313 r = MsiSummaryInfoPersist(summary); 314 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); 315 316 MsiCloseHandle(summary); 317 } 318 319 static void create_database(const CHAR *name, const msi_table *tables, int num_tables, 320 const msi_summary_info *info, int num_info) 321 { 322 MSIHANDLE db; 323 UINT r; 324 WCHAR *nameW; 325 int j, len; 326 327 len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 ); 328 if (!(nameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return; 329 MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, len ); 330 331 r = MsiOpenDatabaseW(nameW, MSIDBOPEN_CREATE, &db); 332 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); 333 334 /* import the tables into the database */ 335 for (j = 0; j < num_tables; j++) 336 { 337 const msi_table *table = &tables[j]; 338 339 write_file(table->filename, table->data, (table->size - 1) * sizeof(char)); 340 341 r = MsiDatabaseImportA(db, CURR_DIR, table->filename); 342 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); 343 344 DeleteFileA(table->filename); 345 } 346 347 write_msi_summary_info(db, info, num_info); 348 349 r = MsiDatabaseCommit(db); 350 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r); 351 352 MsiCloseHandle(db); 353 HeapFree( GetProcessHeap(), 0, nameW ); 354 } 355 356 static BOOL create_package(LPWSTR path) 357 { 358 static const WCHAR slashW[] = {'\\',0}; 359 DWORD len; 360 361 /* Prepare package */ 362 create_database(msifile, tables, 363 sizeof(tables) / sizeof(msi_table), summary_info, 364 sizeof(summary_info) / sizeof(msi_summary_info)); 365 366 len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, 367 CURR_DIR, -1, path, MAX_PATH); 368 ok(len, "MultiByteToWideChar returned error %d\n", GetLastError()); 369 if (!len) 370 return FALSE; 371 372 lstrcatW(path, slashW); 373 lstrcatW(path, szMsifile); 374 return TRUE; 375 } 376 377 /* 378 * Installation helpers 379 */ 380 381 static char PROG_FILES_DIR[MAX_PATH]; 382 383 static BOOL get_program_files_dir(LPSTR buf) 384 { 385 HKEY hkey; 386 DWORD type = REG_EXPAND_SZ, size; 387 388 if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &hkey)) 389 return FALSE; 390 391 size = MAX_PATH; 392 if (RegQueryValueExA(hkey, "ProgramFilesDir (x86)", 0, &type, (LPBYTE)buf, &size) && 393 RegQueryValueExA(hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size)) 394 return FALSE; 395 396 RegCloseKey(hkey); 397 return TRUE; 398 } 399 400 static void create_file(const CHAR *name, DWORD size) 401 { 402 HANDLE file; 403 DWORD written, left; 404 405 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); 406 ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name); 407 WriteFile(file, name, strlen(name), &written, NULL); 408 WriteFile(file, "\n", strlen("\n"), &written, NULL); 409 410 left = size - lstrlenA(name) - 1; 411 412 SetFilePointer(file, left, NULL, FILE_CURRENT); 413 SetEndOfFile(file); 414 415 CloseHandle(file); 416 } 417 418 static void create_test_files(void) 419 { 420 CreateDirectoryA("msitest", NULL); 421 create_file("msitest\\one.txt", 100); 422 CreateDirectoryA("msitest\\first", NULL); 423 create_file("msitest\\first\\two.txt", 100); 424 CreateDirectoryA("msitest\\second", NULL); 425 create_file("msitest\\second\\three.txt", 100); 426 CreateDirectoryA("msitest\\cabout",NULL); 427 create_file("msitest\\cabout\\four.txt", 100); 428 CreateDirectoryA("msitest\\cabout\\new",NULL); 429 create_file("msitest\\cabout\\new\\five.txt", 100); 430 create_file("msitest\\filename", 100); 431 } 432 433 static BOOL delete_pf(const CHAR *rel_path, BOOL is_file) 434 { 435 CHAR path[MAX_PATH]; 436 437 lstrcpyA(path, PROG_FILES_DIR); 438 lstrcatA(path, "\\"); 439 lstrcatA(path, rel_path); 440 441 if (is_file) 442 return DeleteFileA(path); 443 else 444 return RemoveDirectoryA(path); 445 } 446 447 static void delete_test_files(void) 448 { 449 DeleteFileA(msifile); 450 DeleteFileA("msitest\\cabout\\new\\five.txt"); 451 DeleteFileA("msitest\\cabout\\four.txt"); 452 DeleteFileA("msitest\\second\\three.txt"); 453 DeleteFileA("msitest\\first\\two.txt"); 454 DeleteFileA("msitest\\one.txt"); 455 DeleteFileA("msitest\\filename"); 456 RemoveDirectoryA("msitest\\cabout\\new"); 457 RemoveDirectoryA("msitest\\cabout"); 458 RemoveDirectoryA("msitest\\second"); 459 RemoveDirectoryA("msitest\\first"); 460 RemoveDirectoryA("msitest"); 461 } 462 463 /* 464 * Automation helpers and tests 465 */ 466 467 /* ok-like statement which takes two unicode strings or one unicode and one ANSI string as arguments */ 468 static CHAR string1[MAX_PATH], string2[MAX_PATH]; 469 470 #define ok_w2(format, szString1, szString2) \ 471 \ 472 do { \ 473 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \ 474 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \ 475 if (lstrcmpA(string1, string2) != 0) \ 476 ok(0, format, string1, string2); \ 477 } while(0); 478 479 #define ok_w2n(format, szString1, szString2, len) \ 480 \ 481 if (memcmp(szString1, szString2, len * sizeof(WCHAR)) != 0) \ 482 { \ 483 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \ 484 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \ 485 ok(0, format, string1, string2); \ 486 } 487 488 #define ok_aw(format, aString, wString) \ 489 \ 490 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \ 491 if (lstrcmpA(string1, aString) != 0) \ 492 ok(0, format, string1, aString); \ 493 494 #define ok_awplus(format, extra, aString, wString) \ 495 \ 496 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \ 497 if (lstrcmpA(string1, aString) != 0) \ 498 ok(0, format, extra, string1, aString); \ 499 500 /* exception checker */ 501 static const WCHAR szSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0}; 502 503 #define ok_exception(hr, szDescription) \ 504 if (hr == DISP_E_EXCEPTION) \ 505 { \ 506 /* Compare wtype, source, and destination */ \ 507 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \ 508 \ 509 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \ 510 if (excepinfo.bstrSource) \ 511 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, szSource); \ 512 \ 513 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \ 514 if (excepinfo.bstrDescription) \ 515 ok_w2("Exception description was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrDescription, szDescription); \ 516 \ 517 SysFreeString(excepinfo.bstrSource); \ 518 SysFreeString(excepinfo.bstrDescription); \ 519 SysFreeString(excepinfo.bstrHelpFile); \ 520 } 521 522 static DISPID get_dispid( IDispatch *disp, const char *name ) 523 { 524 LPOLESTR str; 525 UINT len; 526 DISPID id = -1; 527 HRESULT r; 528 529 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 ); 530 str = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) ); 531 if (str) 532 { 533 MultiByteToWideChar(CP_ACP, 0, name, -1, str, len ); 534 r = IDispatch_GetIDsOfNames( disp, &IID_NULL, &str, 1, 0, &id ); 535 HeapFree(GetProcessHeap(), 0, str); 536 if (r != S_OK) 537 return -1; 538 } 539 540 return id; 541 } 542 543 typedef struct { 544 DISPID did; 545 const char *name; 546 BOOL todo; 547 } get_did_t; 548 549 static const get_did_t get_did_data[] = { 550 { 1, "CreateRecord" }, 551 { 2, "OpenPackage" }, 552 { 3, "OpenProduct" }, 553 { 4, "OpenDatabase" }, 554 { 5, "SummaryInformation" }, 555 { 6, "UILevel" }, 556 { 7, "EnableLog" }, 557 { 8, "InstallProduct" }, 558 { 9, "Version" }, 559 { 10, "LastErrorRecord" }, 560 { 11, "RegistryValue" }, 561 { 12, "Environment" }, 562 { 13, "FileAttributes" }, 563 { 15, "FileSize" }, 564 { 16, "FileVersion" }, 565 { 17, "ProductState" }, 566 { 18, "ProductInfo" }, 567 { 19, "ConfigureProduct", TRUE }, 568 { 20, "ReinstallProduct", TRUE }, 569 { 21, "CollectUserInfo", TRUE }, 570 { 22, "ApplyPatch", TRUE }, 571 { 23, "FeatureParent", TRUE }, 572 { 24, "FeatureState", TRUE }, 573 { 25, "UseFeature", TRUE }, 574 { 26, "FeatureUsageCount", TRUE }, 575 { 27, "FeatureUsageDate", TRUE }, 576 { 28, "ConfigureFeature", TRUE }, 577 { 29, "ReinstallFeature", TRUE }, 578 { 30, "ProvideComponent", TRUE }, 579 { 31, "ComponentPath", TRUE }, 580 { 32, "ProvideQualifiedComponent", TRUE }, 581 { 33, "QualifierDescription", TRUE }, 582 { 34, "ComponentQualifiers", TRUE }, 583 { 35, "Products" }, 584 { 36, "Features", TRUE }, 585 { 37, "Components", TRUE }, 586 { 38, "ComponentClients", TRUE }, 587 { 39, "Patches", TRUE }, 588 { 40, "RelatedProducts" }, 589 { 41, "PatchInfo", TRUE }, 590 { 42, "PatchTransforms", TRUE }, 591 { 43, "AddSource", TRUE }, 592 { 44, "ClearSourceList", TRUE }, 593 { 45, "ForceSourceListResolution", TRUE }, 594 { 46, "ShortcutTarget", TRUE }, 595 { 47, "FileHash", TRUE }, 596 { 48, "FileSignatureInfo", TRUE }, 597 { 0 } 598 }; 599 600 static void test_dispid(void) 601 { 602 const get_did_t *ptr = get_did_data; 603 DISPID dispid; 604 605 while (ptr->name) 606 { 607 dispid = get_dispid(pInstaller, ptr->name); 608 todo_wine_if (ptr->todo) 609 ok(dispid == ptr->did, "%s: expected %d, got %d\n", ptr->name, ptr->did, dispid); 610 ptr++; 611 } 612 613 dispid = get_dispid(pInstaller, "RemovePatches"); 614 ok(dispid == 49 || dispid == -1, "Expected 49 or -1, got %d\n", dispid); 615 dispid = get_dispid(pInstaller, "ApplyMultiplePatches"); 616 ok(dispid == 51 || dispid == -1, "Expected 51 or -1, got %d\n", dispid); 617 dispid = get_dispid(pInstaller, "ProductsEx"); 618 ok(dispid == 52 || dispid == -1, "Expected 52 or -1, got %d\n", dispid); 619 dispid = get_dispid(pInstaller, "PatchesEx"); 620 ok(dispid == 55 || dispid == -1, "Expected 55 or -1, got %d\n", dispid); 621 dispid = get_dispid(pInstaller, "ExtractPatchXMLData"); 622 ok(dispid == 57 || dispid == -1, "Expected 57 or -1, got %d\n", dispid); 623 dispid = get_dispid( pInstaller, "ProductElevated" ); 624 ok(dispid == 59 || dispid == -1, "Expected 59 or -1, got %d\n", dispid); 625 dispid = get_dispid( pInstaller, "ProvideAssembly" ); 626 ok(dispid == 60 || dispid == -1, "Expected 60 or -1, got %d\n", dispid); 627 dispid = get_dispid( pInstaller, "ProductInfoFromScript" ); 628 ok(dispid == 61 || dispid == -1, "Expected 61 or -1, got %d\n", dispid); 629 dispid = get_dispid( pInstaller, "AdvertiseProduct" ); 630 ok(dispid == 62 || dispid == -1, "Expected 62 or -1, got %d\n", dispid); 631 dispid = get_dispid( pInstaller, "CreateAdvertiseScript" ); 632 ok(dispid == 63 || dispid == -1, "Expected 63 or -1, got %d\n", dispid); 633 dispid = get_dispid( pInstaller, "PatchFiles" ); 634 ok(dispid == 65 || dispid == -1, "Expected 65 or -1, got %d\n", dispid); 635 } 636 637 /* Test basic IDispatch functions */ 638 static void test_dispatch(void) 639 { 640 static WCHAR szOpenPackage[] = { 'O','p','e','n','P','a','c','k','a','g','e',0 }; 641 static const WCHAR szOpenPackageException[] = {'O','p','e','n','P','a','c','k','a','g','e',',','P','a','c','k','a','g','e','P','a','t','h',',','O','p','t','i','o','n','s',0}; 642 static WCHAR szProductState[] = { 'P','r','o','d','u','c','t','S','t','a','t','e',0 }; 643 HRESULT hr; 644 DISPID dispid; 645 OLECHAR *name; 646 VARIANT varresult; 647 VARIANTARG vararg[3]; 648 WCHAR path[MAX_PATH]; 649 DISPPARAMS dispparams = {NULL, NULL, 0, 0}; 650 651 /* Test getting ID of a function name that does not exist */ 652 name = (WCHAR *)szMsifile; 653 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid); 654 ok(hr == DISP_E_UNKNOWNNAME, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr); 655 656 /* Test invoking this function */ 657 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL); 658 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr); 659 660 /* Test getting ID of a function name that does exist */ 661 name = szOpenPackage; 662 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid); 663 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr); 664 665 /* Test invoking this function (without parameters passed) */ 666 if (0) /* All of these crash MSI on Windows XP */ 667 { 668 IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL); 669 IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL); 670 VariantInit(&varresult); 671 IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, &varresult, &excepinfo, NULL); 672 } 673 674 /* Try with NULL params */ 675 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL); 676 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr); 677 678 /* Try one empty parameter */ 679 dispparams.rgvarg = vararg; 680 dispparams.cArgs = 1; 681 VariantInit(&vararg[0]); 682 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL); 683 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr); 684 685 /* Try two empty parameters */ 686 dispparams.cArgs = 2; 687 VariantInit(&vararg[0]); 688 VariantInit(&vararg[1]); 689 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL); 690 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr); 691 692 /* Try one parameter, the required BSTR. Second parameter is optional. 693 * NOTE: The specified package does not exist, which is why the call fails. 694 */ 695 dispparams.cArgs = 1; 696 VariantInit(&vararg[0]); 697 V_VT(&vararg[0]) = VT_BSTR; 698 V_BSTR(&vararg[0]) = SysAllocString(szMsifile); 699 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL); 700 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr); 701 ok_exception(hr, szOpenPackageException); 702 VariantClear(&vararg[0]); 703 704 /* Provide the required BSTR and an empty second parameter. 705 * NOTE: The specified package does not exist, which is why the call fails. 706 */ 707 dispparams.cArgs = 2; 708 VariantInit(&vararg[1]); 709 V_VT(&vararg[1]) = VT_BSTR; 710 V_BSTR(&vararg[1]) = SysAllocString(szMsifile); 711 VariantInit(&vararg[0]); 712 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL); 713 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr); 714 ok_exception(hr, szOpenPackageException); 715 VariantClear(&vararg[1]); 716 717 /* Provide the required BSTR and two empty parameters. 718 * NOTE: The specified package does not exist, which is why the call fails. 719 */ 720 dispparams.cArgs = 3; 721 VariantInit(&vararg[2]); 722 V_VT(&vararg[2]) = VT_BSTR; 723 V_BSTR(&vararg[2]) = SysAllocString(szMsifile); 724 VariantInit(&vararg[1]); 725 VariantInit(&vararg[0]); 726 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL); 727 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr); 728 ok_exception(hr, szOpenPackageException); 729 VariantClear(&vararg[2]); 730 731 /* Provide the required BSTR and a second parameter with the wrong type. */ 732 dispparams.cArgs = 2; 733 VariantInit(&vararg[1]); 734 V_VT(&vararg[1]) = VT_BSTR; 735 V_BSTR(&vararg[1]) = SysAllocString(szMsifile); 736 VariantInit(&vararg[0]); 737 V_VT(&vararg[0]) = VT_BSTR; 738 V_BSTR(&vararg[0]) = SysAllocString(szMsifile); 739 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL); 740 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr); 741 VariantClear(&vararg[0]); 742 VariantClear(&vararg[1]); 743 744 /* Create a proper installer package. */ 745 create_package(path); 746 747 /* Try one parameter, the required BSTR. Second parameter is optional. 748 * Proper installer package exists. Path to the package is relative. 749 */ 750 dispparams.cArgs = 1; 751 VariantInit(&vararg[0]); 752 V_VT(&vararg[0]) = VT_BSTR; 753 V_BSTR(&vararg[0]) = SysAllocString(szMsifile); 754 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL); 755 todo_wine ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr); 756 ok_exception(hr, szOpenPackageException); 757 VariantClear(&vararg[0]); 758 if (hr != DISP_E_EXCEPTION) 759 VariantClear(&varresult); 760 761 /* Try one parameter, the required BSTR. Second parameter is optional. 762 * Proper installer package exists. Path to the package is absolute. 763 */ 764 dispparams.cArgs = 1; 765 VariantInit(&vararg[0]); 766 V_VT(&vararg[0]) = VT_BSTR; 767 V_BSTR(&vararg[0]) = SysAllocString(path); 768 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL); 769 if (hr == DISP_E_EXCEPTION) 770 { 771 skip("OpenPackage failed, insufficient rights?\n"); 772 DeleteFileW(path); 773 return; 774 } 775 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr); 776 VariantClear(&vararg[0]); 777 VariantClear(&varresult); 778 779 /* Provide the required BSTR and an empty second parameter. Proper 780 * installation package exists. 781 */ 782 dispparams.cArgs = 2; 783 VariantInit(&vararg[1]); 784 V_VT(&vararg[1]) = VT_BSTR; 785 V_BSTR(&vararg[1]) = SysAllocString(path); 786 VariantInit(&vararg[0]); 787 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL); 788 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr); 789 VariantClear(&vararg[1]); 790 VariantClear(&varresult); 791 792 /* Provide the required BSTR and two empty parameters. Proper 793 * installation package exists. 794 */ 795 dispparams.cArgs = 3; 796 VariantInit(&vararg[2]); 797 V_VT(&vararg[2]) = VT_BSTR; 798 V_BSTR(&vararg[2]) = SysAllocString(path); 799 VariantInit(&vararg[1]); 800 VariantInit(&vararg[0]); 801 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL); 802 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr); 803 VariantClear(&vararg[2]); 804 VariantClear(&varresult); 805 806 /* Provide the required BSTR and a second parameter with the wrong type. */ 807 dispparams.cArgs = 2; 808 VariantInit(&vararg[1]); 809 V_VT(&vararg[1]) = VT_BSTR; 810 V_BSTR(&vararg[1]) = SysAllocString(path); 811 VariantInit(&vararg[0]); 812 V_VT(&vararg[0]) = VT_BSTR; 813 V_BSTR(&vararg[0]) = SysAllocString(path); 814 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL); 815 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr); 816 VariantClear(&vararg[0]); 817 VariantClear(&vararg[1]); 818 819 /* Provide the required BSTR and a second parameter that can be coerced to 820 * VT_I4. 821 */ 822 dispparams.cArgs = 2; 823 VariantInit(&vararg[1]); 824 V_VT(&vararg[1]) = VT_BSTR; 825 V_BSTR(&vararg[1]) = SysAllocString(path); 826 VariantInit(&vararg[0]); 827 V_VT(&vararg[0]) = VT_I2; 828 V_BSTR(&vararg[0]) = 0; 829 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL); 830 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr); 831 VariantClear(&vararg[1]); 832 VariantClear(&varresult); 833 834 DeleteFileW(path); 835 836 /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */ 837 VariantInit(&vararg[0]); 838 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL); 839 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr); 840 841 VariantInit(&vararg[0]); 842 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL); 843 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr); 844 845 /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */ 846 name = szProductState; 847 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid); 848 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr); 849 850 dispparams.rgvarg = NULL; 851 dispparams.cArgs = 0; 852 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL); 853 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr); 854 855 dispparams.rgvarg = NULL; 856 dispparams.cArgs = 0; 857 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL); 858 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr); 859 } 860 861 /* invocation helper function */ 862 static int _invoke_todo_vtResult = 0; 863 864 static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult) 865 { 866 OLECHAR *name = NULL; 867 DISPID dispid; 868 HRESULT hr; 869 UINT i; 870 UINT len; 871 872 memset(pVarResult, 0, sizeof(VARIANT)); 873 VariantInit(pVarResult); 874 875 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 ); 876 name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) ); 877 if (!name) return E_FAIL; 878 MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len ); 879 hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid); 880 HeapFree(GetProcessHeap(), 0, name); 881 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr); 882 if (hr != S_OK) return hr; 883 884 memset(&excepinfo, 0, sizeof(excepinfo)); 885 hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL); 886 887 if (hr == S_OK) 888 { 889 todo_wine_if (_invoke_todo_vtResult) 890 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult); 891 if (vtResult != VT_EMPTY) 892 { 893 hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult); 894 ok(hr == S_OK, "VariantChangeTypeEx returned 0x%08x\n", hr); 895 } 896 } 897 898 for (i=0; i<pDispParams->cArgs; i++) 899 VariantClear(&pDispParams->rgvarg[i]); 900 901 return hr; 902 } 903 904 /* Object_Property helper functions */ 905 906 static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord) 907 { 908 VARIANT varresult; 909 VARIANTARG vararg[1]; 910 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 911 HRESULT hr; 912 913 VariantInit(&vararg[0]); 914 V_VT(&vararg[0]) = VT_I4; 915 V_I4(&vararg[0]) = count; 916 917 hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH); 918 *pRecord = V_DISPATCH(&varresult); 919 return hr; 920 } 921 922 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect) 923 { 924 VARIANTARG vararg[3]; 925 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 926 927 VariantInit(&vararg[2]); 928 V_VT(&vararg[2]) = VT_I4; 929 V_I4(&vararg[2]) = (INT_PTR)hkey; 930 VariantInit(&vararg[1]); 931 V_VT(&vararg[1]) = VT_BSTR; 932 V_BSTR(&vararg[1]) = SysAllocString(szKey); 933 VariantInit(&vararg[0]); 934 VariantCopy(&vararg[0], &vValue); 935 VariantClear(&vValue); 936 937 return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect); 938 } 939 940 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool) 941 { 942 VARIANT varresult; 943 VARIANTARG vararg; 944 HRESULT hr; 945 946 VariantInit(&vararg); 947 V_VT(&vararg) = VT_EMPTY; 948 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL); 949 *pBool = V_BOOL(&varresult); 950 VariantClear(&varresult); 951 return hr; 952 } 953 954 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString) 955 { 956 VARIANT varresult; 957 VARIANTARG vararg; 958 HRESULT hr; 959 960 VariantInit(&vararg); 961 V_VT(&vararg) = VT_BSTR; 962 V_BSTR(&vararg) = SysAllocString(szValue); 963 964 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR); 965 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult)); 966 VariantClear(&varresult); 967 return hr; 968 } 969 970 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult) 971 { 972 VARIANT varresult; 973 VARIANTARG vararg; 974 HRESULT hr; 975 976 VariantInit(&vararg); 977 V_VT(&vararg) = VT_I4; 978 V_I4(&vararg) = iValue; 979 980 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult); 981 if (SUCCEEDED(hr) && vtResult == VT_BSTR) lstrcpyW(szString, V_BSTR(&varresult)); 982 VariantClear(&varresult); 983 return hr; 984 } 985 986 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession) 987 { 988 VARIANT varresult; 989 VARIANTARG vararg[2]; 990 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 991 HRESULT hr; 992 993 VariantInit(&vararg[1]); 994 V_VT(&vararg[1]) = VT_BSTR; 995 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath); 996 VariantInit(&vararg[0]); 997 V_VT(&vararg[0]) = VT_I4; 998 V_I4(&vararg[0]) = options; 999 1000 hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH); 1001 *pSession = V_DISPATCH(&varresult); 1002 return hr; 1003 } 1004 1005 static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase) 1006 { 1007 VARIANT varresult; 1008 VARIANTARG vararg[2]; 1009 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 1010 HRESULT hr; 1011 1012 VariantInit(&vararg[1]); 1013 V_VT(&vararg[1]) = VT_BSTR; 1014 V_BSTR(&vararg[1]) = SysAllocString(szDatabasePath); 1015 VariantInit(&vararg[0]); 1016 V_VT(&vararg[0]) = VT_I4; 1017 V_I4(&vararg[0]) = openmode; 1018 1019 hr = invoke(pInstaller, "OpenDatabase", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH); 1020 *pDatabase = V_DISPATCH(&varresult); 1021 return hr; 1022 } 1023 1024 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues) 1025 { 1026 VARIANT varresult; 1027 VARIANTARG vararg[2]; 1028 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 1029 1030 VariantInit(&vararg[1]); 1031 V_VT(&vararg[1]) = VT_BSTR; 1032 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath); 1033 VariantInit(&vararg[0]); 1034 V_VT(&vararg[0]) = VT_BSTR; 1035 V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues); 1036 1037 return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY); 1038 } 1039 1040 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState) 1041 { 1042 VARIANT varresult; 1043 VARIANTARG vararg[1]; 1044 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 1045 HRESULT hr; 1046 1047 VariantInit(&vararg[0]); 1048 V_VT(&vararg[0]) = VT_BSTR; 1049 V_BSTR(&vararg[0]) = SysAllocString(szProduct); 1050 1051 hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4); 1052 *pInstallState = V_I4(&varresult); 1053 VariantClear(&varresult); 1054 return hr; 1055 } 1056 1057 static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szString) 1058 { 1059 VARIANT varresult; 1060 VARIANTARG vararg[2]; 1061 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 1062 HRESULT hr; 1063 1064 VariantInit(&vararg[1]); 1065 V_VT(&vararg[1]) = VT_BSTR; 1066 V_BSTR(&vararg[1]) = SysAllocString(szProduct); 1067 VariantInit(&vararg[0]); 1068 V_VT(&vararg[0]) = VT_BSTR; 1069 V_BSTR(&vararg[0]) = SysAllocString(szAttribute); 1070 1071 hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR); 1072 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult)); 1073 VariantClear(&varresult); 1074 return hr; 1075 } 1076 1077 static HRESULT Installer_Products(IDispatch **pStringList) 1078 { 1079 VARIANT varresult; 1080 DISPPARAMS dispparams = {NULL, NULL, 0, 0}; 1081 HRESULT hr; 1082 1083 hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH); 1084 *pStringList = V_DISPATCH(&varresult); 1085 return hr; 1086 } 1087 1088 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList) 1089 { 1090 VARIANT varresult; 1091 VARIANTARG vararg[1]; 1092 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 1093 HRESULT hr; 1094 1095 VariantInit(&vararg[0]); 1096 V_VT(&vararg[0]) = VT_BSTR; 1097 V_BSTR(&vararg[0]) = SysAllocString(szProduct); 1098 1099 hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH); 1100 *pStringList = V_DISPATCH(&varresult); 1101 return hr; 1102 } 1103 1104 static HRESULT Installer_VersionGet(LPWSTR szVersion) 1105 { 1106 VARIANT varresult; 1107 DISPPARAMS dispparams = {NULL, NULL, 0, 0}; 1108 HRESULT hr; 1109 1110 hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR); 1111 if (V_BSTR(&varresult)) lstrcpyW(szVersion, V_BSTR(&varresult)); 1112 VariantClear(&varresult); 1113 return hr; 1114 } 1115 1116 static HRESULT Installer_UILevelPut(int level) 1117 { 1118 VARIANT varresult; 1119 VARIANTARG vararg; 1120 DISPID dispid = DISPID_PROPERTYPUT; 1121 DISPPARAMS dispparams = {&vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1}; 1122 1123 VariantInit(&vararg); 1124 V_VT(&vararg) = VT_I4; 1125 V_I4(&vararg) = level; 1126 1127 return invoke(pInstaller, "UILevel", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY); 1128 } 1129 1130 static HRESULT Installer_SummaryInformation(BSTR PackagePath, int UpdateCount, IDispatch **pSumInfo) 1131 { 1132 VARIANT varresult; 1133 VARIANTARG vararg[2]; 1134 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 1135 HRESULT hr; 1136 1137 VariantInit(&vararg[1]); 1138 V_VT(&vararg[1]) = VT_BSTR; 1139 V_BSTR(&vararg[1]) = SysAllocString(PackagePath); 1140 VariantInit(&vararg[0]); 1141 V_VT(&vararg[0]) = VT_I4; 1142 V_I4(&vararg[0]) = UpdateCount; 1143 1144 hr = invoke(pInstaller, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH); 1145 *pSumInfo = V_DISPATCH(&varresult); 1146 return hr; 1147 } 1148 1149 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst) 1150 { 1151 VARIANT varresult; 1152 DISPPARAMS dispparams = {NULL, NULL, 0, 0}; 1153 HRESULT hr; 1154 1155 hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH); 1156 *pInst = V_DISPATCH(&varresult); 1157 return hr; 1158 } 1159 1160 static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn) 1161 { 1162 VARIANT varresult; 1163 VARIANTARG vararg[1]; 1164 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 1165 HRESULT hr; 1166 1167 VariantInit(&vararg[0]); 1168 V_VT(&vararg[0]) = VT_BSTR; 1169 V_BSTR(&vararg[0]) = SysAllocString(szName); 1170 1171 hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR); 1172 if (V_BSTR(&varresult)) lstrcpyW(szReturn, V_BSTR(&varresult)); 1173 VariantClear(&varresult); 1174 return hr; 1175 } 1176 1177 static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue) 1178 { 1179 VARIANT varresult; 1180 VARIANTARG vararg[2]; 1181 DISPID dispid = DISPID_PROPERTYPUT; 1182 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1}; 1183 1184 VariantInit(&vararg[1]); 1185 V_VT(&vararg[1]) = VT_BSTR; 1186 V_BSTR(&vararg[1]) = SysAllocString(szName); 1187 VariantInit(&vararg[0]); 1188 V_VT(&vararg[0]) = VT_BSTR; 1189 V_BSTR(&vararg[0]) = SysAllocString(szValue); 1190 1191 return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY); 1192 } 1193 1194 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId) 1195 { 1196 VARIANT varresult; 1197 DISPPARAMS dispparams = {NULL, NULL, 0, 0}; 1198 HRESULT hr; 1199 1200 hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4); 1201 *pLangId = V_I4(&varresult); 1202 VariantClear(&varresult); 1203 return hr; 1204 } 1205 1206 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, VARIANT_BOOL *mode) 1207 { 1208 VARIANT varresult; 1209 VARIANTARG vararg[1]; 1210 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 1211 HRESULT hr; 1212 1213 VariantInit(&vararg[0]); 1214 V_VT(&vararg[0]) = VT_I4; 1215 V_I4(&vararg[0]) = iFlag; 1216 1217 hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL); 1218 *mode = V_BOOL(&varresult); 1219 VariantClear(&varresult); 1220 return hr; 1221 } 1222 1223 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, VARIANT_BOOL mode) 1224 { 1225 VARIANT varresult; 1226 VARIANTARG vararg[2]; 1227 DISPID dispid = DISPID_PROPERTYPUT; 1228 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1}; 1229 1230 VariantInit(&vararg[1]); 1231 V_VT(&vararg[1]) = VT_I4; 1232 V_I4(&vararg[1]) = iFlag; 1233 VariantInit(&vararg[0]); 1234 V_VT(&vararg[0]) = VT_BOOL; 1235 V_BOOL(&vararg[0]) = mode; 1236 1237 return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY); 1238 } 1239 1240 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase) 1241 { 1242 VARIANT varresult; 1243 DISPPARAMS dispparams = {NULL, NULL, 0, 0}; 1244 HRESULT hr; 1245 1246 hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH); 1247 *pDatabase = V_DISPATCH(&varresult); 1248 return hr; 1249 } 1250 1251 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn) 1252 { 1253 VARIANT varresult; 1254 VARIANTARG vararg[1]; 1255 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 1256 HRESULT hr; 1257 1258 VariantInit(&vararg[0]); 1259 V_VT(&vararg[0]) = VT_BSTR; 1260 V_BSTR(&vararg[0]) = SysAllocString(szAction); 1261 1262 hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4); 1263 *iReturn = V_I4(&varresult); 1264 VariantClear(&varresult); 1265 return hr; 1266 } 1267 1268 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn) 1269 { 1270 VARIANT varresult; 1271 VARIANTARG vararg[1]; 1272 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 1273 HRESULT hr; 1274 1275 VariantInit(&vararg[0]); 1276 V_VT(&vararg[0]) = VT_BSTR; 1277 V_BSTR(&vararg[0]) = SysAllocString(szCondition); 1278 1279 hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4); 1280 *iReturn = V_I4(&varresult); 1281 VariantClear(&varresult); 1282 return hr; 1283 } 1284 1285 static HRESULT Session_Message(IDispatch *pSession, LONG kind, IDispatch *record, int *ret) 1286 { 1287 VARIANT varresult; 1288 VARIANTARG vararg[2]; 1289 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 1290 HRESULT hr; 1291 1292 VariantInit(&varresult); 1293 V_VT(vararg) = VT_DISPATCH; 1294 V_DISPATCH(vararg) = record; 1295 V_VT(vararg+1) = VT_I4; 1296 V_I4(vararg+1) = kind; 1297 1298 hr = invoke(pSession, "Message", DISPATCH_METHOD, &dispparams, &varresult, VT_I4); 1299 1300 ok(V_VT(&varresult) == VT_I4, "V_VT(varresult) = %d\n", V_VT(&varresult)); 1301 *ret = V_I4(&varresult); 1302 1303 return hr; 1304 } 1305 1306 static HRESULT Session_SetInstallLevel(IDispatch *pSession, LONG iInstallLevel) 1307 { 1308 VARIANT varresult; 1309 VARIANTARG vararg[1]; 1310 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 1311 1312 VariantInit(&vararg[0]); 1313 V_VT(&vararg[0]) = VT_I4; 1314 V_I4(&vararg[0]) = iInstallLevel; 1315 1316 return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY); 1317 } 1318 1319 static HRESULT Session_FeatureCurrentState(IDispatch *pSession, LPCWSTR szName, int *pState) 1320 { 1321 VARIANT varresult; 1322 VARIANTARG vararg[1]; 1323 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 1324 HRESULT hr; 1325 1326 VariantInit(&vararg[0]); 1327 V_VT(&vararg[0]) = VT_BSTR; 1328 V_BSTR(&vararg[0]) = SysAllocString(szName); 1329 1330 hr = invoke(pSession, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4); 1331 *pState = V_I4(&varresult); 1332 VariantClear(&varresult); 1333 return hr; 1334 } 1335 1336 static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState) 1337 { 1338 VARIANT varresult; 1339 VARIANTARG vararg[1]; 1340 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 1341 HRESULT hr; 1342 1343 VariantInit(&vararg[0]); 1344 V_VT(&vararg[0]) = VT_BSTR; 1345 V_BSTR(&vararg[0]) = SysAllocString(szName); 1346 1347 hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4); 1348 *pState = V_I4(&varresult); 1349 VariantClear(&varresult); 1350 return hr; 1351 } 1352 1353 static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState) 1354 { 1355 VARIANT varresult; 1356 VARIANTARG vararg[2]; 1357 DISPID dispid = DISPID_PROPERTYPUT; 1358 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1}; 1359 1360 VariantInit(&vararg[1]); 1361 V_VT(&vararg[1]) = VT_BSTR; 1362 V_BSTR(&vararg[1]) = SysAllocString(szName); 1363 VariantInit(&vararg[0]); 1364 V_VT(&vararg[0]) = VT_I4; 1365 V_I4(&vararg[0]) = iState; 1366 1367 return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY); 1368 } 1369 1370 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView) 1371 { 1372 VARIANT varresult; 1373 VARIANTARG vararg[1]; 1374 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 1375 HRESULT hr; 1376 1377 VariantInit(&vararg[0]); 1378 V_VT(&vararg[0]) = VT_BSTR; 1379 V_BSTR(&vararg[0]) = SysAllocString(szSql); 1380 1381 hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH); 1382 *pView = V_DISPATCH(&varresult); 1383 return hr; 1384 } 1385 1386 static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo) 1387 { 1388 VARIANT varresult; 1389 VARIANTARG vararg[1]; 1390 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 1391 HRESULT hr; 1392 1393 VariantInit(&vararg[0]); 1394 V_VT(&vararg[0]) = VT_I4; 1395 V_I4(&vararg[0]) = iUpdateCount; 1396 1397 hr = invoke(pDatabase, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH); 1398 *pSummaryInfo = V_DISPATCH(&varresult); 1399 return hr; 1400 } 1401 1402 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord) 1403 { 1404 VARIANT varresult; 1405 VARIANTARG vararg[1]; 1406 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 1407 1408 VariantInit(&vararg[0]); 1409 V_VT(&vararg[0]) = VT_DISPATCH; 1410 V_DISPATCH(&vararg[0]) = pRecord; 1411 1412 return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY); 1413 } 1414 1415 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord) 1416 { 1417 VARIANT varresult; 1418 DISPPARAMS dispparams = {NULL, NULL, 0, 0}; 1419 HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH); 1420 *ppRecord = V_DISPATCH(&varresult); 1421 return hr; 1422 } 1423 1424 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord) 1425 { 1426 VARIANT varresult; 1427 VARIANTARG vararg[2]; 1428 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 1429 1430 VariantInit(&vararg[1]); 1431 V_VT(&vararg[1]) = VT_I4; 1432 V_I4(&vararg[1]) = iMode; 1433 VariantInit(&vararg[0]); 1434 V_VT(&vararg[0]) = VT_DISPATCH; 1435 V_DISPATCH(&vararg[0]) = pRecord; 1436 if (pRecord) 1437 IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */ 1438 1439 return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY); 1440 } 1441 1442 static HRESULT View_Close(IDispatch *pView) 1443 { 1444 VARIANT varresult; 1445 DISPPARAMS dispparams = {NULL, NULL, 0, 0}; 1446 return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY); 1447 } 1448 1449 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount) 1450 { 1451 VARIANT varresult; 1452 DISPPARAMS dispparams = {NULL, NULL, 0, 0}; 1453 HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4); 1454 *pFieldCount = V_I4(&varresult); 1455 VariantClear(&varresult); 1456 return hr; 1457 } 1458 1459 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString) 1460 { 1461 VARIANT varresult; 1462 VARIANTARG vararg[1]; 1463 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 1464 HRESULT hr; 1465 1466 VariantInit(&vararg[0]); 1467 V_VT(&vararg[0]) = VT_I4; 1468 V_I4(&vararg[0]) = iField; 1469 1470 hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR); 1471 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult)); 1472 VariantClear(&varresult); 1473 return hr; 1474 } 1475 1476 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString) 1477 { 1478 VARIANT varresult; 1479 VARIANTARG vararg[2]; 1480 DISPID dispid = DISPID_PROPERTYPUT; 1481 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1}; 1482 1483 VariantInit(&vararg[1]); 1484 V_VT(&vararg[1]) = VT_I4; 1485 V_I4(&vararg[1]) = iField; 1486 VariantInit(&vararg[0]); 1487 V_VT(&vararg[0]) = VT_BSTR; 1488 V_BSTR(&vararg[0]) = SysAllocString(szString); 1489 1490 return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY); 1491 } 1492 1493 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue) 1494 { 1495 VARIANT varresult; 1496 VARIANTARG vararg[1]; 1497 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 1498 HRESULT hr; 1499 1500 VariantInit(&vararg[0]); 1501 V_VT(&vararg[0]) = VT_I4; 1502 V_I4(&vararg[0]) = iField; 1503 1504 hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4); 1505 *pValue = V_I4(&varresult); 1506 VariantClear(&varresult); 1507 return hr; 1508 } 1509 1510 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue) 1511 { 1512 VARIANT varresult; 1513 VARIANTARG vararg[2]; 1514 DISPID dispid = DISPID_PROPERTYPUT; 1515 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1}; 1516 1517 VariantInit(&vararg[1]); 1518 V_VT(&vararg[1]) = VT_I4; 1519 V_I4(&vararg[1]) = iField; 1520 VariantInit(&vararg[0]); 1521 V_VT(&vararg[0]) = VT_I4; 1522 V_I4(&vararg[0]) = iValue; 1523 1524 return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY); 1525 } 1526 1527 static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT) 1528 { 1529 VARIANT varresult; 1530 DISPPARAMS dispparams = {NULL, NULL, 0, 0}; 1531 HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN); 1532 *ppEnumVARIANT = V_UNKNOWN(&varresult); 1533 return hr; 1534 } 1535 1536 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString) 1537 { 1538 VARIANT varresult; 1539 VARIANTARG vararg[1]; 1540 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 1541 HRESULT hr; 1542 1543 VariantInit(&vararg[0]); 1544 V_VT(&vararg[0]) = VT_I4; 1545 V_I4(&vararg[0]) = iIndex; 1546 1547 hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR); 1548 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult)); 1549 VariantClear(&varresult); 1550 return hr; 1551 } 1552 1553 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount) 1554 { 1555 VARIANT varresult; 1556 DISPPARAMS dispparams = {NULL, NULL, 0, 0}; 1557 HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4); 1558 *pCount = V_I4(&varresult); 1559 VariantClear(&varresult); 1560 return hr; 1561 } 1562 1563 static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect) 1564 { 1565 VARIANTARG vararg[1]; 1566 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0}; 1567 1568 VariantInit(&vararg[0]); 1569 V_VT(&vararg[0]) = VT_I4; 1570 V_I4(&vararg[0]) = pid; 1571 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYGET, &dispparams, pVarResult, vtExpect); 1572 } 1573 1574 static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant) 1575 { 1576 VARIANT varresult; 1577 VARIANTARG vararg[2]; 1578 DISPID dispid = DISPID_PROPERTYPUT; 1579 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1}; 1580 1581 VariantInit(&vararg[1]); 1582 V_VT(&vararg[1]) = VT_I4; 1583 V_I4(&vararg[1]) = pid; 1584 VariantInit(&vararg[0]); 1585 VariantCopyInd(vararg, pVariant); 1586 1587 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY); 1588 } 1589 1590 static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount) 1591 { 1592 VARIANT varresult; 1593 DISPPARAMS dispparams = {NULL, NULL, 0, 0}; 1594 HRESULT hr; 1595 1596 hr = invoke(pSummaryInfo, "PropertyCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4); 1597 *pCount = V_I4(&varresult); 1598 VariantClear(&varresult); 1599 return hr; 1600 } 1601 1602 /* Test the various objects */ 1603 1604 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4 1605 1606 static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly) 1607 { 1608 static const WCHAR szPropertyException[] = { 'P','r','o','p','e','r','t','y',',','P','i','d',0 }; 1609 static const WCHAR szTitle[] = { 'T','i','t','l','e',0 }; 1610 VARIANT varresult, var; 1611 SYSTEMTIME st; 1612 HRESULT hr; 1613 int j; 1614 1615 /* SummaryInfo::PropertyCount */ 1616 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j); 1617 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr); 1618 ok(j == num_info, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info); 1619 1620 /* SummaryInfo::Property, get for properties we have set */ 1621 for (j = 0; j < num_info; j++) 1622 { 1623 const msi_summary_info *entry = &info[j]; 1624 1625 int vt = entry->datatype; 1626 if (vt == VT_LPSTR) vt = VT_BSTR; 1627 else if (vt == VT_FILETIME) vt = VT_DATE; 1628 else if (vt == VT_I2) vt = VT_I4; 1629 1630 hr = SummaryInfo_PropertyGet(pSummaryInfo, entry->property, &varresult, vt); 1631 ok(hr == S_OK, "SummaryInfo_Property (pid %d) failed, hresult 0x%08x\n", entry->property, hr); 1632 if (V_VT(&varresult) != vt) 1633 skip("Skipping property tests due to type mismatch\n"); 1634 else if (vt == VT_I4) 1635 ok(V_I4(&varresult) == entry->iValue, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %d\n", 1636 entry->property, entry->iValue, V_I4(&varresult)); 1637 else if (vt == VT_DATE) 1638 { 1639 FILETIME ft; 1640 DATE d; 1641 1642 FileTimeToLocalFileTime(entry->pftValue, &ft); 1643 FileTimeToSystemTime(&ft, &st); 1644 SystemTimeToVariantTime(&st, &d); 1645 ok(d == V_DATE(&varresult), "SummaryInfo_Property (pid %d) DATE result expected to be %lf, but was %lf\n", entry->property, d, V_DATE(&varresult)); 1646 } 1647 else if (vt == VT_BSTR) 1648 { 1649 ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry->property, entry->szValue, V_BSTR(&varresult)); 1650 } 1651 else 1652 skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry->property, vt); 1653 1654 VariantClear(&varresult); 1655 } 1656 1657 /* SummaryInfo::Property, get; invalid arguments */ 1658 1659 /* Invalid pids */ 1660 hr = SummaryInfo_PropertyGet(pSummaryInfo, -1, &varresult, VT_EMPTY); 1661 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr); 1662 ok_exception(hr, szPropertyException); 1663 1664 hr = SummaryInfo_PropertyGet(pSummaryInfo, 1000, &varresult, VT_EMPTY); 1665 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr); 1666 ok_exception(hr, szPropertyException); 1667 1668 /* Unsupported pids */ 1669 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_DICTIONARY, &varresult, VT_EMPTY); 1670 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr); 1671 1672 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY); 1673 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr); 1674 1675 /* Pids we have not set, one for each type */ 1676 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_EMPTY); 1677 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr); 1678 1679 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY); 1680 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr); 1681 1682 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY); 1683 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr); 1684 1685 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY); 1686 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr); 1687 1688 if (!readonly) 1689 { 1690 /* SummaryInfo::Property, put; one for each type */ 1691 1692 /* VT_I2 */ 1693 VariantInit(&var); 1694 V_VT(&var) = VT_I2; 1695 V_I2(&var) = 1; 1696 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CODEPAGE, &var); 1697 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr); 1698 1699 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */); 1700 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr); 1701 ok(V_I2(&var) == V_I2(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var), V_I2(&varresult)); 1702 VariantClear(&varresult); 1703 VariantClear(&var); 1704 1705 /* VT_BSTR */ 1706 V_VT(&var) = VT_BSTR; 1707 V_BSTR(&var) = SysAllocString(szTitle); 1708 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_TITLE, &var); 1709 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr); 1710 1711 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var)); 1712 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr); 1713 ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var), V_BSTR(&varresult)); 1714 VariantClear(&varresult); 1715 VariantClear(&var); 1716 1717 /* VT_DATE */ 1718 V_VT(&var) = VT_DATE; 1719 FileTimeToSystemTime(&systemtime, &st); 1720 SystemTimeToVariantTime(&st, &V_DATE(&var)); 1721 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_LASTSAVE_DTM, &var); 1722 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr); 1723 1724 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var)); 1725 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr); 1726 ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult)); 1727 VariantClear(&varresult); 1728 VariantClear(&var); 1729 1730 /* VT_I4 */ 1731 V_VT(&var) = VT_I4; 1732 V_I4(&var) = 1000; 1733 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var); 1734 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr); 1735 1736 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var)); 1737 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr); 1738 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult)); 1739 VariantClear(&varresult); 1740 VariantClear(&var); 1741 1742 /* SummaryInfo::PropertyCount */ 1743 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j); 1744 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr); 1745 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info); 1746 } 1747 } 1748 1749 static void test_Database(IDispatch *pDatabase, BOOL readonly) 1750 { 1751 static const WCHAR szSql[] = { 'S','E','L','E','C','T',' ','`','F','e','a','t','u','r','e','`',' ','F','R','O','M',' ','`','F','e','a','t','u','r','e','`',' ','W','H','E','R','E',' ','`','F','e','a','t','u','r','e','_','P','a','r','e','n','t','`','=','\'','O','n','e','\'',0 }; 1752 static const WCHAR szThree[] = { 'T','h','r','e','e',0 }; 1753 static const WCHAR szTwo[] = { 'T','w','o',0 }; 1754 static const WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 }; 1755 static const WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 }; 1756 IDispatch *pView = NULL, *pSummaryInfo = NULL; 1757 HRESULT hr; 1758 1759 hr = Database_OpenView(pDatabase, szSql, &pView); 1760 ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr); 1761 if (hr == S_OK) 1762 { 1763 IDispatch *pRecord = NULL; 1764 WCHAR szString[MAX_PATH]; 1765 1766 /* View::Execute */ 1767 hr = View_Execute(pView, NULL); 1768 ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr); 1769 1770 /* View::Fetch */ 1771 hr = View_Fetch(pView, &pRecord); 1772 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr); 1773 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n"); 1774 if (pRecord) 1775 { 1776 /* Record::StringDataGet */ 1777 memset(szString, 0, sizeof(szString)); 1778 hr = Record_StringDataGet(pRecord, 1, szString); 1779 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr); 1780 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree); 1781 1782 /* Record::StringDataPut with correct index */ 1783 hr = Record_StringDataPut(pRecord, 1, szTwo); 1784 ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr); 1785 1786 /* Record::StringDataGet */ 1787 memset(szString, 0, sizeof(szString)); 1788 hr = Record_StringDataGet(pRecord, 1, szString); 1789 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr); 1790 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo); 1791 1792 /* Record::StringDataPut with incorrect index */ 1793 hr = Record_StringDataPut(pRecord, -1, szString); 1794 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr); 1795 ok_exception(hr, szStringDataField); 1796 1797 /* View::Modify with incorrect parameters */ 1798 hr = View_Modify(pView, -5, NULL); 1799 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr); 1800 ok_exception(hr, szModifyModeRecord); 1801 1802 hr = View_Modify(pView, -5, pRecord); 1803 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr); 1804 ok_exception(hr, szModifyModeRecord); 1805 1806 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL); 1807 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr); 1808 ok_exception(hr, szModifyModeRecord); 1809 1810 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord); 1811 ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr); 1812 1813 /* Record::StringDataGet, confirm that the record is back to its unmodified value */ 1814 memset(szString, 0, sizeof(szString)); 1815 hr = Record_StringDataGet(pRecord, 1, szString); 1816 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr); 1817 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree); 1818 1819 IDispatch_Release(pRecord); 1820 } 1821 1822 /* View::Fetch */ 1823 hr = View_Fetch(pView, &pRecord); 1824 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr); 1825 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n"); 1826 if (pRecord) 1827 { 1828 /* Record::StringDataGet */ 1829 memset(szString, 0, sizeof(szString)); 1830 hr = Record_StringDataGet(pRecord, 1, szString); 1831 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr); 1832 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo); 1833 1834 IDispatch_Release(pRecord); 1835 } 1836 1837 /* View::Fetch */ 1838 hr = View_Fetch(pView, &pRecord); 1839 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr); 1840 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n"); 1841 if (pRecord) 1842 IDispatch_Release(pRecord); 1843 1844 /* View::Close */ 1845 hr = View_Close(pView); 1846 ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr); 1847 1848 IDispatch_Release(pView); 1849 } 1850 1851 /* Database::SummaryInformation */ 1852 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo); 1853 ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr); 1854 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n"); 1855 if (pSummaryInfo) 1856 { 1857 test_SummaryInfo(pSummaryInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), readonly); 1858 IDispatch_Release(pSummaryInfo); 1859 } 1860 } 1861 1862 static void test_Session(IDispatch *pSession) 1863 { 1864 static const WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 }; 1865 static const WCHAR szOne[] = { 'O','n','e',0 }; 1866 static const WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 }; 1867 static const WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 }; 1868 static const WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 }; 1869 static const WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 }; 1870 static const WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 }; 1871 static const WCHAR szEmpty[] = { 0 }; 1872 static const WCHAR szEquals[] = { '=',0 }; 1873 static const WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 }; 1874 static const WCHAR szModeFlag[] = { 'M','o','d','e',',','F','l','a','g',0 }; 1875 WCHAR stringw[MAX_PATH]; 1876 CHAR string[MAX_PATH]; 1877 UINT len; 1878 VARIANT_BOOL bool; 1879 int myint; 1880 IDispatch *pDatabase = NULL, *pInst = NULL, *record = NULL; 1881 ULONG refs_before, refs_after; 1882 HRESULT hr; 1883 1884 /* Session::Installer */ 1885 hr = Session_Installer(pSession, &pInst); 1886 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr); 1887 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n"); 1888 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n"); 1889 refs_before = IDispatch_AddRef(pInst); 1890 1891 hr = Session_Installer(pSession, &pInst); 1892 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr); 1893 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n"); 1894 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n"); 1895 refs_after = IDispatch_Release(pInst); 1896 ok(refs_before == refs_after, "got %u and %u\n", refs_before, refs_after); 1897 1898 /* Session::Property, get */ 1899 memset(stringw, 0, sizeof(stringw)); 1900 hr = Session_PropertyGet(pSession, szProductName, stringw); 1901 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr); 1902 if (lstrcmpW(stringw, szMSITEST) != 0) 1903 { 1904 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL); 1905 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError()); 1906 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string); 1907 } 1908 1909 /* Session::Property, put */ 1910 hr = Session_PropertyPut(pSession, szProductName, szProductName); 1911 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr); 1912 memset(stringw, 0, sizeof(stringw)); 1913 hr = Session_PropertyGet(pSession, szProductName, stringw); 1914 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr); 1915 if (lstrcmpW(stringw, szProductName) != 0) 1916 { 1917 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL); 1918 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError()); 1919 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string); 1920 } 1921 1922 /* Try putting a property using empty property identifier */ 1923 hr = Session_PropertyPut(pSession, szEmpty, szProductName); 1924 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr); 1925 ok_exception(hr, szPropertyName); 1926 1927 /* Try putting a property using illegal property identifier */ 1928 hr = Session_PropertyPut(pSession, szEquals, szProductName); 1929 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr); 1930 1931 /* Session::Language, get */ 1932 hr = Session_LanguageGet(pSession, &len); 1933 ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr); 1934 /* Not sure how to check the language is correct */ 1935 1936 /* Session::Mode, get */ 1937 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool); 1938 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr); 1939 ok(!bool, "Reboot at end session mode is %d\n", bool); 1940 1941 hr = Session_ModeGet(pSession, MSIRUNMODE_MAINTENANCE, &bool); 1942 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr); 1943 ok(!bool, "Maintenance mode is %d\n", bool); 1944 1945 /* Session::Mode, put */ 1946 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, VARIANT_TRUE); 1947 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr); 1948 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool); 1949 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr); 1950 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool); 1951 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, VARIANT_FALSE); /* set it again so we don't reboot */ 1952 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr); 1953 1954 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, VARIANT_TRUE); 1955 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr); 1956 ok_exception(hr, szModeFlag); 1957 1958 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTNOW, &bool); 1959 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr); 1960 ok(bool, "Reboot now mode is %d, expected 1\n", bool); 1961 1962 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, VARIANT_FALSE); /* set it again so we don't reboot */ 1963 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr); 1964 ok_exception(hr, szModeFlag); 1965 1966 hr = Session_ModePut(pSession, MSIRUNMODE_MAINTENANCE, VARIANT_TRUE); 1967 ok(hr == DISP_E_EXCEPTION, "Session_ModePut failed, hresult 0x%08x\n", hr); 1968 ok_exception(hr, szModeFlag); 1969 1970 /* Session::Database, get */ 1971 hr = Session_Database(pSession, &pDatabase); 1972 ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr); 1973 if (hr == S_OK) 1974 { 1975 test_Database(pDatabase, TRUE); 1976 IDispatch_Release(pDatabase); 1977 } 1978 1979 /* Session::EvaluateCondition */ 1980 hr = Session_EvaluateCondition(pSession, NULL, &myint); 1981 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr); 1982 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN); 1983 1984 hr = Session_EvaluateCondition(pSession, szEmpty, &myint); 1985 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr); 1986 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN); 1987 1988 hr = Session_EvaluateCondition(pSession, szEquals, &myint); 1989 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr); 1990 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN); 1991 1992 /* Session::DoAction(CostInitialize) must occur before the next statements */ 1993 hr = Session_DoAction(pSession, szCostInitialize, &myint); 1994 ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr); 1995 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK); 1996 1997 /* Session::SetInstallLevel */ 1998 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM); 1999 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr); 2000 2001 /* Session::FeatureCurrentState, get */ 2002 hr = Session_FeatureCurrentState(pSession, szOne, &myint); 2003 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr); 2004 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN); 2005 2006 /* Session::Message */ 2007 hr = Installer_CreateRecord(0, &record); 2008 ok(hr == S_OK, "Installer_CreateRecord failed: %08x\n", hr); 2009 hr = Session_Message(pSession, INSTALLMESSAGE_INFO, record, &myint); 2010 ok(hr == S_OK, "Session_Message failed: %08x\n", hr); 2011 ok(myint == 0, "Session_Message returned %x\n", myint); 2012 2013 /* Session::EvaluateCondition */ 2014 hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint); 2015 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr); 2016 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN); 2017 2018 hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint); 2019 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr); 2020 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN); 2021 2022 /* Session::FeatureRequestState, put */ 2023 hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED); 2024 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr); 2025 hr = Session_FeatureRequestStateGet(pSession, szOne, &myint); 2026 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr); 2027 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED); 2028 2029 /* Session::EvaluateCondition */ 2030 hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint); 2031 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr); 2032 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN); 2033 2034 hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint); 2035 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr); 2036 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN); 2037 } 2038 2039 /* delete key and all its subkeys */ 2040 static DWORD delete_key( HKEY hkey ) 2041 { 2042 char name[MAX_PATH]; 2043 DWORD ret; 2044 2045 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name)))) 2046 { 2047 HKEY tmp; 2048 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp ))) 2049 { 2050 ret = delete_key( tmp ); 2051 RegCloseKey( tmp ); 2052 } 2053 if (ret) break; 2054 } 2055 if (ret != ERROR_NO_MORE_ITEMS) return ret; 2056 RegDeleteKeyA( hkey, "" ); 2057 return 0; 2058 } 2059 2060 static void test_Installer_RegistryValue(void) 2061 { 2062 static const DWORD qw[2] = { 0x12345678, 0x87654321 }; 2063 static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 }; 2064 static const WCHAR szOne[] = { 'O','n','e',0 }; 2065 static const WCHAR szTwo[] = { 'T','w','o',0 }; 2066 static const WCHAR szThree[] = { 'T','h','r','e','e',0 }; 2067 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 }; 2068 static const WCHAR szFour[] = { 'F','o','u','r',0 }; 2069 static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 }; 2070 static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 }; 2071 static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 }; 2072 static const WCHAR szSix[] = { 'S','i','x',0 }; 2073 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 }; 2074 static const WCHAR szREG_2[] = { '(','R','E','G','_','?','?',')',0 }; 2075 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 }; 2076 static const WCHAR szEight[] = { 'E','i','g','h','t',0 }; 2077 static const WCHAR szBlank[] = { 0 }; 2078 VARIANT varresult; 2079 VARIANTARG vararg; 2080 WCHAR szString[MAX_PATH]; 2081 HKEY hkey, hkey_sub; 2082 HKEY curr_user = (HKEY)1; 2083 HRESULT hr; 2084 BOOL bRet; 2085 LONG lRet; 2086 2087 /* Delete keys */ 2088 SetLastError(0xdeadbeef); 2089 lRet = RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey ); 2090 if (!lRet && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) 2091 { 2092 win_skip("Needed W-functions are not implemented\n"); 2093 return; 2094 } 2095 if (!lRet) 2096 delete_key( hkey ); 2097 2098 /* Does our key exist? Shouldn't; check with all three possible value parameter types */ 2099 hr = Installer_RegistryValueE(curr_user, szKey, &bRet); 2100 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr); 2101 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n"); 2102 2103 memset(szString, 0, sizeof(szString)); 2104 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString); 2105 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); 2106 2107 memset(szString, 0, sizeof(szString)); 2108 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR); 2109 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr); 2110 2111 /* Create key */ 2112 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n"); 2113 2114 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)), 2115 "RegSetValueExW failed\n"); 2116 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4), 2117 "RegSetValueExW failed\n"); 2118 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4), 2119 "RegSetValueExW failed\n"); 2120 bRet = SetEnvironmentVariableA("MSITEST", "Four"); 2121 ok(bRet, "SetEnvironmentVariableA failed %d\n", GetLastError()); 2122 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)), 2123 "RegSetValueExW failed\n"); 2124 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)), 2125 "RegSetValueExW failed\n"); 2126 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8), 2127 "RegSetValueExW failed\n"); 2128 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, NULL, 0), 2129 "RegSetValueExW failed\n"); 2130 2131 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)), 2132 "RegSetValueExW failed\n"); 2133 2134 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n"); 2135 2136 /* Does our key exist? It should, and make sure we retrieve the correct default value */ 2137 bRet = FALSE; 2138 hr = Installer_RegistryValueE(curr_user, szKey, &bRet); 2139 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr); 2140 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n"); 2141 2142 memset(szString, 0, sizeof(szString)); 2143 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString); 2144 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); 2145 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne); 2146 2147 /* Ask for the value of a nonexistent key */ 2148 memset(szString, 0, sizeof(szString)); 2149 hr = Installer_RegistryValueW(curr_user, szKey, szExpand, szString); 2150 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); 2151 2152 /* Get values of keys */ 2153 memset(szString, 0, sizeof(szString)); 2154 hr = Installer_RegistryValueW(curr_user, szKey, szOne, szString); 2155 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); 2156 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne); 2157 2158 VariantInit(&vararg); 2159 V_VT(&vararg) = VT_BSTR; 2160 V_BSTR(&vararg) = SysAllocString(szTwo); 2161 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_I4); 2162 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr); 2163 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult)); 2164 VariantClear(&varresult); 2165 2166 memset(szString, 0, sizeof(szString)); 2167 hr = Installer_RegistryValueW(curr_user, szKey, szThree, szString); 2168 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); 2169 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY); 2170 2171 memset(szString, 0, sizeof(szString)); 2172 hr = Installer_RegistryValueW(curr_user, szKey, szFour, szString); 2173 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); 2174 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour); 2175 2176 /* Vista does not NULL-terminate this case */ 2177 memset(szString, 0, sizeof(szString)); 2178 hr = Installer_RegistryValueW(curr_user, szKey, szFive, szString); 2179 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); 2180 ok_w2n("Registry value \"%s\" does not match expected \"%s\"\n", 2181 szString, szFiveHi, lstrlenW(szFiveHi)); 2182 2183 memset(szString, 0, sizeof(szString)); 2184 hr = Installer_RegistryValueW(curr_user, szKey, szSix, szString); 2185 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr); 2186 ok(!lstrcmpW(szString, szREG_2) || broken(!lstrcmpW(szString, szREG_)), 2187 "Registry value does not match\n"); 2188 2189 VariantInit(&vararg); 2190 V_VT(&vararg) = VT_BSTR; 2191 V_BSTR(&vararg) = SysAllocString(szSeven); 2192 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_EMPTY); 2193 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr); 2194 2195 /* Get string class name for the key */ 2196 memset(szString, 0, sizeof(szString)); 2197 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR); 2198 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr); 2199 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank); 2200 2201 /* Get name of a value by positive number (RegEnumValue like), valid index */ 2202 memset(szString, 0, sizeof(szString)); 2203 hr = Installer_RegistryValueI(curr_user, szKey, 2, szString, VT_BSTR); 2204 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr); 2205 /* RegEnumValue order seems different on wine */ 2206 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo); 2207 2208 /* Get name of a value by positive number (RegEnumValue like), invalid index */ 2209 memset(szString, 0, sizeof(szString)); 2210 hr = Installer_RegistryValueI(curr_user, szKey, 10, szString, VT_EMPTY); 2211 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr); 2212 2213 /* Get name of a subkey by negative number (RegEnumValue like), valid index */ 2214 memset(szString, 0, sizeof(szString)); 2215 hr = Installer_RegistryValueI(curr_user, szKey, -1, szString, VT_BSTR); 2216 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr); 2217 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight); 2218 2219 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */ 2220 memset(szString, 0, sizeof(szString)); 2221 hr = Installer_RegistryValueI(curr_user, szKey, -10, szString, VT_EMPTY); 2222 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr); 2223 2224 /* clean up */ 2225 delete_key(hkey); 2226 } 2227 2228 static void test_Installer_Products(BOOL bProductInstalled) 2229 { 2230 WCHAR szString[MAX_PATH]; 2231 HRESULT hr; 2232 int idx; 2233 IUnknown *pUnk = NULL; 2234 IEnumVARIANT *pEnum = NULL; 2235 VARIANT var; 2236 ULONG celt; 2237 int iCount, iValue; 2238 IDispatch *pStringList = NULL; 2239 BOOL bProductFound = FALSE; 2240 2241 /* Installer::Products */ 2242 hr = Installer_Products(&pStringList); 2243 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr); 2244 if (hr == S_OK) 2245 { 2246 /* StringList::_NewEnum */ 2247 hr = StringList__NewEnum(pStringList, &pUnk); 2248 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr); 2249 if (hr == S_OK) 2250 { 2251 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum); 2252 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr); 2253 } 2254 if (!pEnum) 2255 skip("IEnumVARIANT tests\n"); 2256 2257 /* StringList::Count */ 2258 hr = StringList_Count(pStringList, &iCount); 2259 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr); 2260 2261 for (idx=0; idx<iCount; idx++) 2262 { 2263 /* StringList::Item */ 2264 memset(szString, 0, sizeof(szString)); 2265 hr = StringList_Item(pStringList, idx, szString); 2266 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr); 2267 2268 if (hr == S_OK) 2269 { 2270 /* Installer::ProductState */ 2271 hr = Installer_ProductState(szString, &iValue); 2272 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr); 2273 if (hr == S_OK) 2274 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED); 2275 2276 /* Not found our product code yet? Check */ 2277 if (!bProductFound && !lstrcmpW(szString, szProductCode)) 2278 bProductFound = TRUE; 2279 2280 /* IEnumVARIANT::Next */ 2281 if (pEnum) 2282 { 2283 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt); 2284 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr); 2285 ok(celt == 1, "%d items were retrieved, expected 1\n", celt); 2286 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR); 2287 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var)); 2288 VariantClear(&var); 2289 } 2290 } 2291 } 2292 2293 if (bProductInstalled) 2294 { 2295 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n", 2296 bProductInstalled ? "be" : "not be", 2297 bProductFound ? "found" : "not found"); 2298 } 2299 2300 if (pEnum) 2301 { 2302 IEnumVARIANT *pEnum2 = NULL; 2303 2304 if (0) /* Crashes on Windows XP */ 2305 { 2306 /* IEnumVARIANT::Clone, NULL pointer */ 2307 IEnumVARIANT_Clone(pEnum, NULL); 2308 } 2309 2310 /* IEnumVARIANT::Clone */ 2311 hr = IEnumVARIANT_Clone(pEnum, &pEnum2); 2312 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr); 2313 if (hr == S_OK) 2314 { 2315 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */ 2316 2317 /* IEnumVARIANT::Next of the clone */ 2318 if (iCount) 2319 { 2320 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt); 2321 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr); 2322 ok(celt == 1, "%d items were retrieved, expected 0\n", celt); 2323 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR); 2324 VariantClear(&var); 2325 } 2326 else 2327 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n"); 2328 2329 IEnumVARIANT_Release(pEnum2); 2330 } 2331 2332 /* IEnumVARIANT::Skip should fail */ 2333 hr = IEnumVARIANT_Skip(pEnum, 1); 2334 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr); 2335 2336 /* IEnumVARIANT::Next, NULL variant pointer */ 2337 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt); 2338 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr); 2339 ok(celt == 0, "%d items were retrieved, expected 0\n", celt); 2340 2341 /* IEnumVARIANT::Next, should not return any more items */ 2342 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt); 2343 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr); 2344 ok(celt == 0, "%d items were retrieved, expected 0\n", celt); 2345 VariantClear(&var); 2346 2347 /* IEnumVARIANT::Reset */ 2348 hr = IEnumVARIANT_Reset(pEnum); 2349 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr); 2350 2351 if (iCount) 2352 { 2353 /* IEnumVARIANT::Skip to the last product */ 2354 hr = IEnumVARIANT_Skip(pEnum, iCount-1); 2355 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr); 2356 2357 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with 2358 * NULL celt pointer. */ 2359 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL); 2360 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr); 2361 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR); 2362 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var)); 2363 VariantClear(&var); 2364 } 2365 else 2366 skip("IEnumVARIANT::Skip impossible for 0 products\n"); 2367 } 2368 2369 /* StringList::Item using an invalid index */ 2370 memset(szString, 0, sizeof(szString)); 2371 hr = StringList_Item(pStringList, iCount, szString); 2372 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr); 2373 2374 if (pEnum) IEnumVARIANT_Release(pEnum); 2375 if (pUnk) IUnknown_Release(pUnk); 2376 IDispatch_Release(pStringList); 2377 } 2378 } 2379 2380 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without 2381 * deleting the subkeys first) */ 2382 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey, REGSAM access) 2383 { 2384 UINT ret; 2385 CHAR *string = NULL; 2386 HKEY hkey; 2387 DWORD dwSize; 2388 2389 ret = RegOpenKeyExA(hkeyParent, subkey, 0, access, &hkey); 2390 if (ret != ERROR_SUCCESS) return ret; 2391 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL); 2392 if (ret != ERROR_SUCCESS) return ret; 2393 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY; 2394 2395 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS) 2396 delete_registry_key(hkey, string, access); 2397 2398 RegCloseKey(hkey); 2399 HeapFree(GetProcessHeap(), 0, string); 2400 delete_key_portable(hkeyParent, subkey, access); 2401 return ERROR_SUCCESS; 2402 } 2403 2404 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */ 2405 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, REGSAM access, HKEY *phkey) 2406 { 2407 UINT ret; 2408 CHAR *string = NULL; 2409 int idx = 0; 2410 HKEY hkey; 2411 DWORD dwSize; 2412 BOOL found = FALSE; 2413 2414 *phkey = 0; 2415 2416 ret = RegOpenKeyExA(hkeyParent, subkey, 0, access, &hkey); 2417 if (ret != ERROR_SUCCESS) return ret; 2418 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL); 2419 if (ret != ERROR_SUCCESS) return ret; 2420 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY; 2421 2422 while (!found && 2423 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS) 2424 { 2425 if (!strcmp(string, findkey)) 2426 { 2427 *phkey = hkey; 2428 found = TRUE; 2429 } 2430 else if (find_registry_key(hkey, string, findkey, access, phkey) == ERROR_SUCCESS) found = TRUE; 2431 } 2432 2433 if (*phkey != hkey) RegCloseKey(hkey); 2434 HeapFree(GetProcessHeap(), 0, string); 2435 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND); 2436 } 2437 2438 static void test_Installer_InstallProduct(void) 2439 { 2440 HRESULT hr; 2441 CHAR path[MAX_PATH]; 2442 WCHAR szString[MAX_PATH]; 2443 LONG res; 2444 HKEY hkey; 2445 DWORD num, size, type; 2446 int iValue, iCount; 2447 IDispatch *pStringList = NULL; 2448 REGSAM access = KEY_ALL_ACCESS; 2449 2450 if (is_process_limited()) 2451 { 2452 /* In fact InstallProduct would succeed but then Windows XP 2453 * would not allow us to clean up the registry! 2454 */ 2455 skip("Installer_InstallProduct (insufficient privileges)\n"); 2456 return; 2457 } 2458 2459 if (is_wow64) 2460 access |= KEY_WOW64_64KEY; 2461 2462 create_test_files(); 2463 2464 /* Avoid an interactive dialog in case of insufficient privileges. */ 2465 hr = Installer_UILevelPut(INSTALLUILEVEL_NONE); 2466 ok(hr == S_OK, "Expected UILevel property put invoke to return S_OK, got 0x%08x\n", hr); 2467 2468 /* Installer::InstallProduct */ 2469 hr = Installer_InstallProduct(szMsifile, NULL); 2470 if (hr == DISP_E_EXCEPTION) 2471 { 2472 skip("InstallProduct failed, insufficient rights?\n"); 2473 delete_test_files(); 2474 return; 2475 } 2476 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr); 2477 2478 /* Installer::ProductState for our product code, which has been installed */ 2479 hr = Installer_ProductState(szProductCode, &iValue); 2480 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr); 2481 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT); 2482 2483 /* Installer::ProductInfo for our product code */ 2484 2485 /* NULL attribute */ 2486 memset(szString, 0, sizeof(szString)); 2487 hr = Installer_ProductInfo(szProductCode, NULL, szString); 2488 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr); 2489 ok_exception(hr, szProductInfoException); 2490 2491 /* Nonexistent attribute */ 2492 memset(szString, 0, sizeof(szString)); 2493 hr = Installer_ProductInfo(szProductCode, szMsifile, szString); 2494 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr); 2495 ok_exception(hr, szProductInfoException); 2496 2497 /* Package name */ 2498 memset(szString, 0, sizeof(szString)); 2499 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szString); 2500 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr); 2501 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile); 2502 2503 /* Product name */ 2504 memset(szString, 0, sizeof(szString)); 2505 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PRODUCTNAMEW, szString); 2506 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr); 2507 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST); 2508 2509 /* Installer::Products */ 2510 test_Installer_Products(TRUE); 2511 2512 /* Installer::RelatedProducts for our upgrade code */ 2513 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList); 2514 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr); 2515 if (hr == S_OK) 2516 { 2517 /* StringList::Count */ 2518 hr = StringList_Count(pStringList, &iCount); 2519 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr); 2520 ok(iCount == 1, "Expected one related product but found %d\n", iCount); 2521 2522 /* StringList::Item */ 2523 memset(szString, 0, sizeof(szString)); 2524 hr = StringList_Item(pStringList, 0, szString); 2525 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr); 2526 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode); 2527 2528 IDispatch_Release(pStringList); 2529 } 2530 2531 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_LOCALPACKAGEW, szString); 2532 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr); 2533 DeleteFileW( szString ); 2534 2535 /* Check & clean up installed files & registry keys */ 2536 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n"); 2537 ok(delete_pf("msitest\\cabout\\new", FALSE), "Directory not created\n"); 2538 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n"); 2539 ok(delete_pf("msitest\\cabout", FALSE), "Directory not created\n"); 2540 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n"); 2541 ok(delete_pf("msitest\\changed", FALSE), "Directory not created\n"); 2542 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n"); 2543 ok(delete_pf("msitest\\first", FALSE), "Directory not created\n"); 2544 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n"); 2545 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n"); 2546 ok(delete_pf("msitest", FALSE), "Directory not created\n"); 2547 2548 res = RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest", &hkey); 2549 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); 2550 2551 size = MAX_PATH; 2552 type = REG_SZ; 2553 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size); 2554 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); 2555 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path); 2556 2557 size = MAX_PATH; 2558 type = REG_SZ; 2559 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size); 2560 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); 2561 2562 size = sizeof(num); 2563 type = REG_DWORD; 2564 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size); 2565 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); 2566 ok(num == 314, "Expected 314, got %d\n", num); 2567 2568 size = MAX_PATH; 2569 type = REG_SZ; 2570 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size); 2571 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); 2572 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path); 2573 2574 RegCloseKey(hkey); 2575 2576 res = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest"); 2577 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); 2578 2579 /* Remove registry keys written by RegisterProduct standard action */ 2580 res = delete_key_portable(HKEY_LOCAL_MACHINE, 2581 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{837450fa-a39b-4bc8-b321-08b393f784b3}", 2582 KEY_WOW64_32KEY); 2583 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); 2584 2585 res = delete_key_portable(HKEY_LOCAL_MACHINE, 2586 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656", access); 2587 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); 2588 2589 res = find_registry_key(HKEY_LOCAL_MACHINE, 2590 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "af054738b93a8cb43b12803b397f483b", access, &hkey); 2591 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); 2592 2593 res = delete_registry_key(hkey, "af054738b93a8cb43b12803b397f483b", access); 2594 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); 2595 RegCloseKey(hkey); 2596 2597 res = delete_key_portable(HKEY_LOCAL_MACHINE, 2598 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\af054738b93a8cb43b12803b397f483b", access); 2599 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res); 2600 2601 /* Remove registry keys written by PublishProduct standard action */ 2602 res = RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey); 2603 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); 2604 2605 res = delete_registry_key(hkey, "Products\\af054738b93a8cb43b12803b397f483b", KEY_ALL_ACCESS); 2606 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); 2607 2608 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656"); 2609 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res); 2610 2611 RegCloseKey(hkey); 2612 2613 /* Delete installation files we created */ 2614 delete_test_files(); 2615 } 2616 2617 static void test_Installer(void) 2618 { 2619 static const WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 }; 2620 static const WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 }; 2621 WCHAR szPath[MAX_PATH]; 2622 HRESULT hr; 2623 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL, *pSumInfo = NULL; 2624 int iValue, iCount; 2625 2626 if (!pInstaller) return; 2627 2628 /* Installer::CreateRecord */ 2629 2630 /* Test for error */ 2631 hr = Installer_CreateRecord(-1, &pRecord); 2632 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr); 2633 ok_exception(hr, szCreateRecordException); 2634 2635 /* Test for success */ 2636 hr = Installer_CreateRecord(1, &pRecord); 2637 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr); 2638 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n"); 2639 if (pRecord) 2640 { 2641 /* Record::FieldCountGet */ 2642 hr = Record_FieldCountGet(pRecord, &iValue); 2643 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr); 2644 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue); 2645 2646 /* Record::IntegerDataGet */ 2647 hr = Record_IntegerDataGet(pRecord, 1, &iValue); 2648 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr); 2649 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER); 2650 2651 /* Record::IntegerDataGet, bad index */ 2652 hr = Record_IntegerDataGet(pRecord, 10, &iValue); 2653 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr); 2654 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER); 2655 2656 /* Record::IntegerDataPut */ 2657 hr = Record_IntegerDataPut(pRecord, 1, 100); 2658 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr); 2659 2660 /* Record::IntegerDataPut, bad index */ 2661 hr = Record_IntegerDataPut(pRecord, 10, 100); 2662 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr); 2663 ok_exception(hr, szIntegerDataException); 2664 2665 /* Record::IntegerDataGet */ 2666 hr = Record_IntegerDataGet(pRecord, 1, &iValue); 2667 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr); 2668 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue); 2669 2670 IDispatch_Release(pRecord); 2671 } 2672 2673 create_package(szPath); 2674 2675 /* Installer::OpenPackage */ 2676 hr = Installer_OpenPackage(szPath, 0, &pSession); 2677 if (hr == DISP_E_EXCEPTION) 2678 { 2679 skip("OpenPackage failed, insufficient rights?\n"); 2680 DeleteFileW(szPath); 2681 return; 2682 } 2683 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr); 2684 if (hr == S_OK) 2685 { 2686 test_Session(pSession); 2687 IDispatch_Release(pSession); 2688 } 2689 2690 /* Installer::OpenDatabase */ 2691 hr = Installer_OpenDatabase(szPath, (INT_PTR)MSIDBOPEN_TRANSACT, &pDatabase); 2692 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr); 2693 if (hr == S_OK) 2694 { 2695 test_Database(pDatabase, FALSE); 2696 IDispatch_Release(pDatabase); 2697 } 2698 2699 /* Installer::SummaryInformation */ 2700 hr = Installer_SummaryInformation(szPath, 0, &pSumInfo); 2701 ok(hr == S_OK, "Installer_SummaryInformation failed, hresult 0x%08x\n", hr); 2702 if (hr == S_OK) 2703 { 2704 test_SummaryInfo(pSumInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), TRUE); 2705 IDispatch_Release(pSumInfo); 2706 } 2707 2708 hr = Installer_SummaryInformation(NULL, 0, &pSumInfo); 2709 ok(hr == DISP_E_EXCEPTION, "Installer_SummaryInformation failed, hresult 0x%08x\n", hr); 2710 2711 /* Installer::RegistryValue */ 2712 test_Installer_RegistryValue(); 2713 2714 /* Installer::ProductState for our product code, which should not be installed */ 2715 hr = Installer_ProductState(szProductCode, &iValue); 2716 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr); 2717 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN); 2718 2719 /* Installer::ProductInfo for our product code, which should not be installed */ 2720 2721 /* Package name */ 2722 memset(szPath, 0, sizeof(szPath)); 2723 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szPath); 2724 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr); 2725 ok_exception(hr, szProductInfoException); 2726 2727 /* NULL attribute and NULL product code */ 2728 memset(szPath, 0, sizeof(szPath)); 2729 hr = Installer_ProductInfo(NULL, NULL, szPath); 2730 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr); 2731 ok_exception(hr, szProductInfoException); 2732 2733 /* Installer::Products */ 2734 test_Installer_Products(FALSE); 2735 2736 /* Installer::RelatedProducts for our upgrade code, should not find anything */ 2737 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList); 2738 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr); 2739 if (hr == S_OK) 2740 { 2741 /* StringList::Count */ 2742 hr = StringList_Count(pStringList, &iCount); 2743 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr); 2744 ok(!iCount, "Expected no related products but found %d\n", iCount); 2745 2746 IDispatch_Release(pStringList); 2747 } 2748 2749 /* Installer::Version */ 2750 memset(szPath, 0, sizeof(szPath)); 2751 hr = Installer_VersionGet(szPath); 2752 ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr); 2753 2754 /* Installer::InstallProduct and other tests that depend on our product being installed */ 2755 test_Installer_InstallProduct(); 2756 } 2757 2758 START_TEST(automation) 2759 { 2760 DWORD len; 2761 char temp_path[MAX_PATH], prev_path[MAX_PATH]; 2762 HRESULT hr; 2763 CLSID clsid; 2764 IUnknown *pUnk; 2765 2766 init_functionpointers(); 2767 2768 if (pIsWow64Process) 2769 pIsWow64Process(GetCurrentProcess(), &is_wow64); 2770 2771 GetSystemTimeAsFileTime(&systemtime); 2772 2773 GetCurrentDirectoryA(MAX_PATH, prev_path); 2774 GetTempPathA(MAX_PATH, temp_path); 2775 SetCurrentDirectoryA(temp_path); 2776 2777 lstrcpyA(CURR_DIR, temp_path); 2778 len = lstrlenA(CURR_DIR); 2779 2780 if(len && (CURR_DIR[len - 1] == '\\')) 2781 CURR_DIR[len - 1] = 0; 2782 2783 get_program_files_dir(PROG_FILES_DIR); 2784 2785 hr = OleInitialize(NULL); 2786 ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr); 2787 hr = CLSIDFromProgID(szProgId, &clsid); 2788 ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr); 2789 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk); 2790 ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr); 2791 2792 if (pUnk) 2793 { 2794 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller); 2795 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr); 2796 2797 test_dispid(); 2798 test_dispatch(); 2799 test_Installer(); 2800 2801 IDispatch_Release(pInstaller); 2802 IUnknown_Release(pUnk); 2803 } 2804 2805 OleUninitialize(); 2806 2807 SetCurrentDirectoryA(prev_path); 2808 } 2809