2 * Copyright (C) 2007 Mike McCormack for CodeWeavers
3 * Copyright (C) 2007 Misha Koshelev
5 * A test program for Microsoft Installer OLE automation functionality.
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.
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.
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
34 #include "wine/test.h"
38 static LONG (WINAPI
*pRegDeleteKeyExA
)(HKEY
, LPCSTR
, REGSAM
, DWORD
);
39 static BOOL (WINAPI
*pIsWow64Process
)(HANDLE
, PBOOL
);
41 DEFINE_GUID(GUID_NULL
,0,0,0,0,0,0,0,0,0,0,0);
43 static const char *msifile
= "winetest-automation.msi";
44 static FILETIME systemtime
;
45 static CHAR CURR_DIR
[MAX_PATH
];
46 static EXCEPINFO excepinfo
;
51 static IDispatch
*pInstaller
;
53 /* msi database data */
55 static const CHAR component_dat
[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
56 "s72\tS38\ts72\ti2\tS255\tS72\n"
57 "Component\tComponent\n"
58 "Five\t{8CC92E9D-14B2-4CA4-B2AA-B11D02078087}\tNEWDIR\t2\t\tfive.txt\n"
59 "Four\t{FD37B4EA-7209-45C0-8917-535F35A2F080}\tCABOUTDIR\t2\t\tfour.txt\n"
60 "One\t{783B242E-E185-4A56-AF86-C09815EC053C}\tMSITESTDIR\t2\t\tone.txt\n"
61 "Three\t{010B6ADD-B27D-4EDD-9B3D-34C4F7D61684}\tCHANGEDDIR\t2\t\tthree.txt\n"
62 "Two\t{BF03D1A6-20DA-4A65-82F3-6CAC995915CE}\tFIRSTDIR\t2\t\ttwo.txt\n"
63 "dangler\t{6091DF25-EF96-45F1-B8E9-A9B1420C7A3C}\tTARGETDIR\t4\t\tregdata\n"
64 "component\t\tMSITESTDIR\t0\t1\tfile\n";
66 static const CHAR directory_dat
[] = "Directory\tDirectory_Parent\tDefaultDir\n"
68 "Directory\tDirectory\n"
69 "CABOUTDIR\tMSITESTDIR\tcabout\n"
70 "CHANGEDDIR\tMSITESTDIR\tchanged:second\n"
71 "FIRSTDIR\tMSITESTDIR\tfirst\n"
72 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
73 "NEWDIR\tCABOUTDIR\tnew\n"
74 "ProgramFilesFolder\tTARGETDIR\t.\n"
75 "TARGETDIR\t\tSourceDir\n";
77 static const CHAR feature_dat
[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
78 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
80 "Five\t\tFive\tThe Five Feature\t5\t3\tNEWDIR\t0\n"
81 "Four\t\tFour\tThe Four Feature\t4\t3\tCABOUTDIR\t0\n"
82 "One\t\tOne\tThe One Feature\t1\t3\tMSITESTDIR\t0\n"
83 "Three\tOne\tThree\tThe Three Feature\t3\t3\tCHANGEDDIR\t0\n"
84 "Two\tOne\tTwo\tThe Two Feature\t2\t3\tFIRSTDIR\t0\n"
85 "feature\t\t\t\t2\t1\tTARGETDIR\t0\n";
87 static const CHAR feature_comp_dat
[] = "Feature_\tComponent_\n"
89 "FeatureComponents\tFeature_\tComponent_\n"
95 "feature\tcomponent\n";
97 static const CHAR file_dat
[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
98 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
100 "five.txt\tFive\tfive.txt\t1000\t\t\t0\t5\n"
101 "four.txt\tFour\tfour.txt\t1000\t\t\t0\t4\n"
102 "one.txt\tOne\tone.txt\t1000\t\t\t0\t1\n"
103 "three.txt\tThree\tthree.txt\t1000\t\t\t0\t3\n"
104 "two.txt\tTwo\ttwo.txt\t1000\t\t\t0\t2\n"
105 "file\tcomponent\tfilename\t100\t\t\t8192\t1\n";
107 static const CHAR install_exec_seq_dat
[] = "Action\tCondition\tSequence\n"
109 "InstallExecuteSequence\tAction\n"
110 "AllocateRegistrySpace\tNOT Installed\t1550\n"
111 "CostFinalize\t\t1000\n"
112 "CostInitialize\t\t800\n"
114 "InstallFiles\t\t4000\n"
115 "RegisterProduct\t\t6100\n"
116 "PublishProduct\t\t6400\n"
117 "InstallFinalize\t\t6600\n"
118 "InstallInitialize\t\t1500\n"
119 "InstallValidate\t\t1400\n"
120 "LaunchConditions\t\t100\n"
121 "WriteRegistryValues\tSourceDir And SOURCEDIR\t5000\n";
123 static const CHAR media_dat
[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
124 "i2\ti4\tL64\tS255\tS32\tS72\n"
126 "1\t5\t\t\tDISK1\t\n";
128 static const CHAR property_dat
[] = "Property\tValue\n"
130 "Property\tProperty\n"
131 "DefaultUIFont\tDlgFont8\n"
134 "InstallMode\tTypical\n"
135 "Manufacturer\tWine\n"
136 "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n"
137 "ProductCode\t{837450fa-a39b-4bc8-b321-08b393f784b3}\n"
139 "ProductLanguage\t1033\n"
140 "ProductName\tMSITEST\n"
141 "ProductVersion\t1.1.1\n"
142 "PROMPTROLLBACKCOST\tP\n"
144 "UpgradeCode\t{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}\n"
145 "MSIFASTINSTALL\t1\n";
147 static const CHAR registry_dat
[] = "Registry\tRoot\tKey\tName\tValue\tComponent_\n"
148 "s72\ti2\tl255\tL255\tL0\ts72\n"
149 "Registry\tRegistry\n"
150 "Apples\t1\tSOFTWARE\\Wine\\msitest\tName\timaname\tOne\n"
151 "Oranges\t1\tSOFTWARE\\Wine\\msitest\tnumber\t#314\tTwo\n"
152 "regdata\t1\tSOFTWARE\\Wine\\msitest\tblah\tbad\tdangler\n"
153 "OrderTest\t1\tSOFTWARE\\Wine\\msitest\tOrderTestName\tOrderTestValue\tcomponent\n";
155 typedef struct _msi_table
157 const CHAR
*filename
;
162 #define ADD_TABLE(x) {#x".idt", x##_dat, sizeof(x##_dat)}
164 static const msi_table tables
[] =
166 ADD_TABLE(component
),
167 ADD_TABLE(directory
),
169 ADD_TABLE(feature_comp
),
171 ADD_TABLE(install_exec_seq
),
177 typedef struct _msi_summary_info
186 #define ADD_INFO_I2(property, iValue) {property, VT_I2, iValue, NULL, NULL}
187 #define ADD_INFO_I4(property, iValue) {property, VT_I4, iValue, NULL, NULL}
188 #define ADD_INFO_LPSTR(property, szValue) {property, VT_LPSTR, 0, NULL, szValue}
189 #define ADD_INFO_FILETIME(property, pftValue) {property, VT_FILETIME, 0, pftValue, NULL}
191 static const msi_summary_info summary_info
[] =
193 ADD_INFO_LPSTR(PID_TEMPLATE
, ";1033"),
194 ADD_INFO_LPSTR(PID_REVNUMBER
, "{004757CA-5092-49C2-AD20-28E1CE0DF5F2}"),
195 ADD_INFO_I4(PID_PAGECOUNT
, 100),
196 ADD_INFO_I4(PID_WORDCOUNT
, 0),
197 ADD_INFO_FILETIME(PID_CREATE_DTM
, &systemtime
),
198 ADD_INFO_FILETIME(PID_LASTPRINTED
, &systemtime
)
201 static void init_functionpointers(void)
203 HMODULE hadvapi32
= GetModuleHandleA("advapi32.dll");
204 HMODULE hkernel32
= GetModuleHandleA("kernel32.dll");
206 #define GET_PROC(dll, func) \
207 p ## func = (void *)GetProcAddress(dll, #func); \
209 trace("GetProcAddress(%s) failed\n", #func);
211 GET_PROC(hadvapi32
, RegDeleteKeyExA
)
212 GET_PROC(hkernel32
, IsWow64Process
)
217 static BOOL
is_process_limited(void)
219 SID_IDENTIFIER_AUTHORITY NtAuthority
= {SECURITY_NT_AUTHORITY
};
224 if (!AllocateAndInitializeSid(&NtAuthority
, 2, SECURITY_BUILTIN_DOMAIN_RID
,
225 DOMAIN_ALIAS_RID_ADMINS
, 0, 0, 0, 0, 0, 0, &Group
) ||
226 !CheckTokenMembership(NULL
, Group
, &IsInGroup
))
228 trace("Could not check if the current user is an administrator\n");
236 /* Only administrators have enough privileges for these tests */
240 if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
, &token
))
243 TOKEN_ELEVATION_TYPE type
= TokenElevationTypeDefault
;
246 ret
= GetTokenInformation(token
, TokenElevationType
, &type
, sizeof(type
), &size
);
248 return (ret
&& type
== TokenElevationTypeLimited
);
253 static LONG
delete_key_portable( HKEY key
, LPCSTR subkey
, REGSAM access
)
255 if (pRegDeleteKeyExA
)
256 return pRegDeleteKeyExA( key
, subkey
, access
, 0 );
257 return RegDeleteKeyA( key
, subkey
);
264 static void write_file(const CHAR
*filename
, const char *data
, int data_size
)
268 HANDLE hf
= CreateFileA(filename
, GENERIC_WRITE
, 0, NULL
,
269 CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
270 WriteFile(hf
, data
, data_size
, &size
, NULL
);
274 static void write_msi_summary_info(MSIHANDLE db
, const msi_summary_info
*info
, int num_info
)
280 r
= MsiGetSummaryInformationA(db
, NULL
, num_info
, &summary
);
281 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
283 /* import summary information into the stream */
284 for (j
= 0; j
< num_info
; j
++)
286 const msi_summary_info
*entry
= &info
[j
];
288 r
= MsiSummaryInfoSetPropertyA(summary
, entry
->property
, entry
->datatype
,
289 entry
->iValue
, entry
->pftValue
, entry
->szValue
);
290 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
293 /* write the summary changes back to the stream */
294 r
= MsiSummaryInfoPersist(summary
);
295 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
297 MsiCloseHandle(summary
);
300 static void create_database(const CHAR
*name
, const msi_table
*tables
, int num_tables
,
301 const msi_summary_info
*info
, int num_info
)
308 len
= MultiByteToWideChar( CP_ACP
, 0, name
, -1, NULL
, 0 );
309 if (!(nameW
= malloc( len
* sizeof(WCHAR
) ))) return;
310 MultiByteToWideChar( CP_ACP
, 0, name
, -1, nameW
, len
);
312 r
= MsiOpenDatabaseW(nameW
, MSIDBOPEN_CREATE
, &db
);
313 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
315 /* import the tables into the database */
316 for (j
= 0; j
< num_tables
; j
++)
318 const msi_table
*table
= &tables
[j
];
320 write_file(table
->filename
, table
->data
, (table
->size
- 1) * sizeof(char));
322 r
= MsiDatabaseImportA(db
, CURR_DIR
, table
->filename
);
323 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
325 DeleteFileA(table
->filename
);
328 write_msi_summary_info(db
, info
, num_info
);
330 r
= MsiDatabaseCommit(db
);
331 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
337 static BOOL
create_package(LPWSTR path
)
341 /* Prepare package */
342 create_database(msifile
, tables
, ARRAY_SIZE(tables
), summary_info
, ARRAY_SIZE(summary_info
));
344 len
= MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
,
345 CURR_DIR
, -1, path
, MAX_PATH
);
346 ok(len
, "MultiByteToWideChar returned error %lu\n", GetLastError());
350 lstrcatW(path
, L
"\\winetest-automation.msi");
355 * Installation helpers
358 static char PROG_FILES_DIR
[MAX_PATH
];
360 static BOOL
get_program_files_dir(LPSTR buf
)
363 DWORD type
= REG_EXPAND_SZ
, size
;
365 if (RegOpenKeyA(HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows\\CurrentVersion", &hkey
))
369 if (RegQueryValueExA(hkey
, "ProgramFilesDir (x86)", 0, &type
, (LPBYTE
)buf
, &size
) &&
370 RegQueryValueExA(hkey
, "ProgramFilesDir", 0, &type
, (LPBYTE
)buf
, &size
))
377 static void create_file(const CHAR
*name
, DWORD size
)
382 file
= CreateFileA(name
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, 0, NULL
);
383 ok(file
!= INVALID_HANDLE_VALUE
, "Failure to open file %s\n", name
);
384 WriteFile(file
, name
, strlen(name
), &written
, NULL
);
385 WriteFile(file
, "\n", strlen("\n"), &written
, NULL
);
387 left
= size
- lstrlenA(name
) - 1;
389 SetFilePointer(file
, left
, NULL
, FILE_CURRENT
);
395 static void create_test_files(void)
397 CreateDirectoryA("msitest", NULL
);
398 create_file("msitest\\one.txt", 100);
399 CreateDirectoryA("msitest\\first", NULL
);
400 create_file("msitest\\first\\two.txt", 100);
401 CreateDirectoryA("msitest\\second", NULL
);
402 create_file("msitest\\second\\three.txt", 100);
403 CreateDirectoryA("msitest\\cabout",NULL
);
404 create_file("msitest\\cabout\\four.txt", 100);
405 CreateDirectoryA("msitest\\cabout\\new",NULL
);
406 create_file("msitest\\cabout\\new\\five.txt", 100);
407 create_file("msitest\\filename", 100);
410 static BOOL
delete_pf(const CHAR
*rel_path
, BOOL is_file
)
414 lstrcpyA(path
, PROG_FILES_DIR
);
415 lstrcatA(path
, "\\");
416 lstrcatA(path
, rel_path
);
419 return DeleteFileA(path
);
421 return RemoveDirectoryA(path
);
424 static void delete_test_files(void)
426 DeleteFileA("msitest\\cabout\\new\\five.txt");
427 DeleteFileA("msitest\\cabout\\four.txt");
428 DeleteFileA("msitest\\second\\three.txt");
429 DeleteFileA("msitest\\first\\two.txt");
430 DeleteFileA("msitest\\one.txt");
431 DeleteFileA("msitest\\filename");
432 RemoveDirectoryA("msitest\\cabout\\new");
433 RemoveDirectoryA("msitest\\cabout");
434 RemoveDirectoryA("msitest\\second");
435 RemoveDirectoryA("msitest\\first");
436 RemoveDirectoryA("msitest");
440 * Automation helpers and tests
443 /* ok-like statement which takes two unicode strings or one unicode and one ANSI string as arguments */
444 static CHAR string1
[MAX_PATH
], string2
[MAX_PATH
];
446 #define ok_w2(format, szString1, szString2) \
449 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
450 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
451 if (lstrcmpA(string1, string2) != 0) \
452 ok(0, format, string1, string2); \
455 #define ok_w2n(format, szString1, szString2, len) \
457 if (memcmp(szString1, szString2, len * sizeof(WCHAR)) != 0) \
459 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
460 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
461 ok(0, format, string1, string2); \
464 #define ok_aw(format, aString, wString) \
466 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
467 if (lstrcmpA(string1, aString) != 0) \
468 ok(0, format, string1, aString); \
470 #define ok_awplus(format, extra, aString, wString) \
472 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
473 if (lstrcmpA(string1, aString) != 0) \
474 ok(0, format, extra, string1, aString); \
476 /* exception checker */
477 #define ok_exception(hr, szDescription) \
478 if (hr == DISP_E_EXCEPTION) \
480 /* Compare wtype, source, and destination */ \
481 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
483 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
484 if (excepinfo.bstrSource) \
485 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, L"Msi API Error"); \
487 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
488 if (excepinfo.bstrDescription) \
489 ok_w2("Exception description was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrDescription, szDescription); \
491 SysFreeString(excepinfo.bstrSource); \
492 SysFreeString(excepinfo.bstrDescription); \
493 SysFreeString(excepinfo.bstrHelpFile); \
496 static DISPID
get_dispid( IDispatch
*disp
, const char *name
)
503 len
= MultiByteToWideChar(CP_ACP
, 0, name
, -1, NULL
, 0 );
504 str
= malloc( len
* sizeof(WCHAR
) );
507 MultiByteToWideChar(CP_ACP
, 0, name
, -1, str
, len
);
508 r
= IDispatch_GetIDsOfNames( disp
, &IID_NULL
, &str
, 1, 0, &id
);
523 static const get_did_t get_did_data
[] = {
524 { 1, "CreateRecord" },
525 { 2, "OpenPackage" },
526 { 3, "OpenProduct" },
527 { 4, "OpenDatabase" },
528 { 5, "SummaryInformation" },
531 { 8, "InstallProduct" },
533 { 10, "LastErrorRecord" },
534 { 11, "RegistryValue" },
535 { 12, "Environment" },
536 { 13, "FileAttributes" },
538 { 16, "FileVersion" },
539 { 17, "ProductState" },
540 { 18, "ProductInfo" },
541 { 19, "ConfigureProduct", TRUE
},
542 { 20, "ReinstallProduct", TRUE
},
543 { 21, "CollectUserInfo", TRUE
},
544 { 22, "ApplyPatch", TRUE
},
545 { 23, "FeatureParent", TRUE
},
546 { 24, "FeatureState", TRUE
},
547 { 25, "UseFeature", TRUE
},
548 { 26, "FeatureUsageCount", TRUE
},
549 { 27, "FeatureUsageDate", TRUE
},
550 { 28, "ConfigureFeature", TRUE
},
551 { 29, "ReinstallFeature", TRUE
},
552 { 30, "ProvideComponent", TRUE
},
553 { 31, "ComponentPath", TRUE
},
554 { 32, "ProvideQualifiedComponent", TRUE
},
555 { 33, "QualifierDescription", TRUE
},
556 { 34, "ComponentQualifiers", TRUE
},
558 { 36, "Features", TRUE
},
559 { 37, "Components", TRUE
},
560 { 38, "ComponentClients", TRUE
},
561 { 39, "Patches", TRUE
},
562 { 40, "RelatedProducts" },
563 { 41, "PatchInfo", TRUE
},
564 { 42, "PatchTransforms", TRUE
},
565 { 43, "AddSource", TRUE
},
566 { 44, "ClearSourceList", TRUE
},
567 { 45, "ForceSourceListResolution", TRUE
},
568 { 46, "ShortcutTarget", TRUE
},
569 { 47, "FileHash", TRUE
},
570 { 48, "FileSignatureInfo", TRUE
},
574 static void test_dispid(void)
576 const get_did_t
*ptr
= get_did_data
;
581 dispid
= get_dispid(pInstaller
, ptr
->name
);
582 todo_wine_if (ptr
->todo
)
583 ok(dispid
== ptr
->did
, "%s: expected %ld, got %ld\n", ptr
->name
, ptr
->did
, dispid
);
587 dispid
= get_dispid(pInstaller
, "RemovePatches");
588 ok(dispid
== 49 || dispid
== -1, "Expected 49 or -1, got %ld\n", dispid
);
589 dispid
= get_dispid(pInstaller
, "ApplyMultiplePatches");
590 ok(dispid
== 51 || dispid
== -1, "Expected 51 or -1, got %ld\n", dispid
);
591 dispid
= get_dispid(pInstaller
, "ProductsEx");
592 ok(dispid
== 52 || dispid
== -1, "Expected 52 or -1, got %ld\n", dispid
);
593 dispid
= get_dispid(pInstaller
, "PatchesEx");
594 ok(dispid
== 55 || dispid
== -1, "Expected 55 or -1, got %ld\n", dispid
);
595 dispid
= get_dispid(pInstaller
, "ExtractPatchXMLData");
596 ok(dispid
== 57 || dispid
== -1, "Expected 57 or -1, got %ld\n", dispid
);
597 dispid
= get_dispid( pInstaller
, "ProductElevated" );
598 ok(dispid
== 59 || dispid
== -1, "Expected 59 or -1, got %ld\n", dispid
);
599 dispid
= get_dispid( pInstaller
, "ProvideAssembly" );
600 ok(dispid
== 60 || dispid
== -1, "Expected 60 or -1, got %ld\n", dispid
);
601 dispid
= get_dispid( pInstaller
, "ProductInfoFromScript" );
602 ok(dispid
== 61 || dispid
== -1, "Expected 61 or -1, got %ld\n", dispid
);
603 dispid
= get_dispid( pInstaller
, "AdvertiseProduct" );
604 ok(dispid
== 62 || dispid
== -1, "Expected 62 or -1, got %ld\n", dispid
);
605 dispid
= get_dispid( pInstaller
, "CreateAdvertiseScript" );
606 ok(dispid
== 63 || dispid
== -1, "Expected 63 or -1, got %ld\n", dispid
);
607 dispid
= get_dispid( pInstaller
, "PatchFiles" );
608 ok(dispid
== 65 || dispid
== -1, "Expected 65 or -1, got %ld\n", dispid
);
611 /* Test basic IDispatch functions */
612 static void test_dispatch(void)
618 VARIANTARG vararg
[3];
619 WCHAR path
[MAX_PATH
];
620 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
622 /* Test getting ID of a function name that does not exist */
623 name
= (WCHAR
*)L
"winetest-automation.msi";
624 hr
= IDispatch_GetIDsOfNames(pInstaller
, &IID_NULL
, &name
, 1, LOCALE_USER_DEFAULT
, &dispid
);
625 ok(hr
== DISP_E_UNKNOWNNAME
, "IDispatch::GetIDsOfNames returned %#lx\n", hr
);
627 /* Test invoking this function */
628 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, NULL
, NULL
, NULL
, NULL
);
629 ok(hr
== DISP_E_MEMBERNOTFOUND
, "IDispatch::Invoke returned %#lx\n", hr
);
631 /* Test getting ID of a function name that does exist */
632 name
= (WCHAR
*)L
"OpenPackage";
633 hr
= IDispatch_GetIDsOfNames(pInstaller
, &IID_NULL
, &name
, 1, LOCALE_USER_DEFAULT
, &dispid
);
634 ok(hr
== S_OK
, "IDispatch::GetIDsOfNames returned %#lx\n", hr
);
636 /* Test invoking this function (without parameters passed) */
637 if (0) /* All of these crash MSI on Windows XP */
639 IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, NULL
, NULL
, NULL
, NULL
);
640 IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, NULL
, NULL
, &excepinfo
, NULL
);
641 VariantInit(&varresult
);
642 IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, NULL
, &varresult
, &excepinfo
, NULL
);
645 /* Try with NULL params */
646 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, &dispparams
, &varresult
, &excepinfo
, NULL
);
647 ok(hr
== DISP_E_TYPEMISMATCH
, "IDispatch::Invoke returned %#lx\n", hr
);
649 /* Try one empty parameter */
650 dispparams
.rgvarg
= vararg
;
651 dispparams
.cArgs
= 1;
652 VariantInit(&vararg
[0]);
653 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, &dispparams
, &varresult
, &excepinfo
, NULL
);
654 ok(hr
== DISP_E_TYPEMISMATCH
, "IDispatch::Invoke returned %#lx\n", hr
);
656 /* Try two empty parameters */
657 dispparams
.cArgs
= 2;
658 VariantInit(&vararg
[0]);
659 VariantInit(&vararg
[1]);
660 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, &dispparams
, &varresult
, &excepinfo
, NULL
);
661 ok(hr
== DISP_E_TYPEMISMATCH
, "IDispatch::Invoke returned %#lx\n", hr
);
663 /* Try one parameter, the required BSTR. Second parameter is optional.
664 * NOTE: The specified package does not exist, which is why the call fails.
666 dispparams
.cArgs
= 1;
667 VariantInit(&vararg
[0]);
668 V_VT(&vararg
[0]) = VT_BSTR
;
669 V_BSTR(&vararg
[0]) = SysAllocString(L
"winetest-automation.msi");
670 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, &dispparams
, &varresult
, &excepinfo
, NULL
);
671 ok(hr
== DISP_E_EXCEPTION
, "IDispatch::Invoke returned %#lx\n", hr
);
672 ok_exception(hr
, L
"OpenPackage,PackagePath,Options");
673 VariantClear(&vararg
[0]);
675 /* Provide the required BSTR and an empty second parameter.
676 * NOTE: The specified package does not exist, which is why the call fails.
678 dispparams
.cArgs
= 2;
679 VariantInit(&vararg
[1]);
680 V_VT(&vararg
[1]) = VT_BSTR
;
681 V_BSTR(&vararg
[1]) = SysAllocString(L
"winetest-automation.msi");
682 VariantInit(&vararg
[0]);
683 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, &dispparams
, &varresult
, &excepinfo
, NULL
);
684 ok(hr
== DISP_E_EXCEPTION
, "IDispatch::Invoke returned %#lx\n", hr
);
685 ok_exception(hr
, L
"OpenPackage,PackagePath,Options");
686 VariantClear(&vararg
[1]);
688 /* Provide the required BSTR and two empty parameters.
689 * NOTE: The specified package does not exist, which is why the call fails.
691 dispparams
.cArgs
= 3;
692 VariantInit(&vararg
[2]);
693 V_VT(&vararg
[2]) = VT_BSTR
;
694 V_BSTR(&vararg
[2]) = SysAllocString(L
"winetest-automation.msi");
695 VariantInit(&vararg
[1]);
696 VariantInit(&vararg
[0]);
697 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, &dispparams
, &varresult
, &excepinfo
, NULL
);
698 ok(hr
== DISP_E_EXCEPTION
, "IDispatch::Invoke returned %#lx\n", hr
);
699 ok_exception(hr
, L
"OpenPackage,PackagePath,Options");
700 VariantClear(&vararg
[2]);
702 /* Provide the required BSTR and a second parameter with the wrong type. */
703 dispparams
.cArgs
= 2;
704 VariantInit(&vararg
[1]);
705 V_VT(&vararg
[1]) = VT_BSTR
;
706 V_BSTR(&vararg
[1]) = SysAllocString(L
"winetest-automation.msi");
707 VariantInit(&vararg
[0]);
708 V_VT(&vararg
[0]) = VT_BSTR
;
709 V_BSTR(&vararg
[0]) = SysAllocString(L
"winetest-automation.msi");
710 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, &dispparams
, &varresult
, &excepinfo
, NULL
);
711 ok(hr
== DISP_E_TYPEMISMATCH
, "IDispatch::Invoke returned %#lx\n", hr
);
712 VariantClear(&vararg
[0]);
713 VariantClear(&vararg
[1]);
715 /* Create a proper installer package. */
716 create_package(path
);
718 /* Try one parameter, the required BSTR. Second parameter is optional.
719 * Proper installer package exists. Path to the package is relative.
721 dispparams
.cArgs
= 1;
722 VariantInit(&vararg
[0]);
723 V_VT(&vararg
[0]) = VT_BSTR
;
724 V_BSTR(&vararg
[0]) = SysAllocString(L
"winetest-automation.msi");
725 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, &dispparams
, &varresult
, &excepinfo
, NULL
);
726 todo_wine
ok(hr
== DISP_E_EXCEPTION
, "IDispatch::Invoke returned %#lx\n", hr
);
727 ok_exception(hr
, L
"OpenPackage,PackagePath,Options");
728 VariantClear(&vararg
[0]);
729 if (hr
!= DISP_E_EXCEPTION
)
730 VariantClear(&varresult
);
732 /* Try one parameter, the required BSTR. Second parameter is optional.
733 * Proper installer package exists. Path to the package is absolute.
735 dispparams
.cArgs
= 1;
736 VariantInit(&vararg
[0]);
737 V_VT(&vararg
[0]) = VT_BSTR
;
738 V_BSTR(&vararg
[0]) = SysAllocString(path
);
739 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, &dispparams
, &varresult
, &excepinfo
, NULL
);
740 if (hr
== DISP_E_EXCEPTION
)
742 skip("OpenPackage failed, insufficient rights?\n");
746 ok(hr
== S_OK
, "IDispatch::Invoke returned %#lx\n", hr
);
747 VariantClear(&vararg
[0]);
748 VariantClear(&varresult
);
750 /* Provide the required BSTR and an empty second parameter. Proper
751 * installation package exists.
753 dispparams
.cArgs
= 2;
754 VariantInit(&vararg
[1]);
755 V_VT(&vararg
[1]) = VT_BSTR
;
756 V_BSTR(&vararg
[1]) = SysAllocString(path
);
757 VariantInit(&vararg
[0]);
758 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, &dispparams
, &varresult
, &excepinfo
, NULL
);
759 ok(hr
== S_OK
, "IDispatch::Invoke returned %#lx\n", hr
);
760 VariantClear(&vararg
[1]);
761 VariantClear(&varresult
);
763 /* Provide the required BSTR and two empty parameters. Proper
764 * installation package exists.
766 dispparams
.cArgs
= 3;
767 VariantInit(&vararg
[2]);
768 V_VT(&vararg
[2]) = VT_BSTR
;
769 V_BSTR(&vararg
[2]) = SysAllocString(path
);
770 VariantInit(&vararg
[1]);
771 VariantInit(&vararg
[0]);
772 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, &dispparams
, &varresult
, &excepinfo
, NULL
);
773 ok(hr
== S_OK
, "IDispatch::Invoke returned %#lx\n", hr
);
774 VariantClear(&vararg
[2]);
775 VariantClear(&varresult
);
777 /* Provide the required BSTR and a second parameter with the wrong type. */
778 dispparams
.cArgs
= 2;
779 VariantInit(&vararg
[1]);
780 V_VT(&vararg
[1]) = VT_BSTR
;
781 V_BSTR(&vararg
[1]) = SysAllocString(path
);
782 VariantInit(&vararg
[0]);
783 V_VT(&vararg
[0]) = VT_BSTR
;
784 V_BSTR(&vararg
[0]) = SysAllocString(path
);
785 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, &dispparams
, &varresult
, &excepinfo
, NULL
);
786 ok(hr
== DISP_E_TYPEMISMATCH
, "IDispatch::Invoke returned %#lx\n", hr
);
787 VariantClear(&vararg
[0]);
788 VariantClear(&vararg
[1]);
790 /* Provide the required BSTR and a second parameter that can be coerced to
793 dispparams
.cArgs
= 2;
794 VariantInit(&vararg
[1]);
795 V_VT(&vararg
[1]) = VT_BSTR
;
796 V_BSTR(&vararg
[1]) = SysAllocString(path
);
797 VariantInit(&vararg
[0]);
798 V_VT(&vararg
[0]) = VT_I2
;
799 V_BSTR(&vararg
[0]) = 0;
800 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, &dispparams
, &varresult
, &excepinfo
, NULL
);
801 ok(hr
== S_OK
, "IDispatch::Invoke returned %#lx\n", hr
);
802 VariantClear(&vararg
[1]);
803 VariantClear(&varresult
);
807 /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
808 VariantInit(&vararg
[0]);
809 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, &excepinfo
, NULL
);
810 ok(hr
== DISP_E_MEMBERNOTFOUND
, "IDispatch::Invoke returned %#lx\n", hr
);
812 VariantInit(&vararg
[0]);
813 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_PROPERTYPUT
, &dispparams
, &varresult
, &excepinfo
, NULL
);
814 ok(hr
== DISP_E_MEMBERNOTFOUND
, "IDispatch::Invoke returned %#lx\n", hr
);
816 /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
817 name
= (WCHAR
*)L
"ProductState";
818 hr
= IDispatch_GetIDsOfNames(pInstaller
, &IID_NULL
, &name
, 1, LOCALE_USER_DEFAULT
, &dispid
);
819 ok(hr
== S_OK
, "IDispatch::GetIDsOfNames returned %#lx\n", hr
);
821 dispparams
.rgvarg
= NULL
;
822 dispparams
.cArgs
= 0;
823 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_PROPERTYPUT
, &dispparams
, &varresult
, &excepinfo
, NULL
);
824 ok(hr
== DISP_E_MEMBERNOTFOUND
, "IDispatch::Invoke returned %#lx\n", hr
);
826 dispparams
.rgvarg
= NULL
;
827 dispparams
.cArgs
= 0;
828 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, &dispparams
, &varresult
, &excepinfo
, NULL
);
829 ok(hr
== DISP_E_MEMBERNOTFOUND
, "IDispatch::Invoke returned %#lx\n", hr
);
832 /* invocation helper function */
833 static int _invoke_todo_vtResult
= 0;
835 static HRESULT
invoke(IDispatch
*pDispatch
, LPCSTR szName
, WORD wFlags
, DISPPARAMS
*pDispParams
, VARIANT
*pVarResult
, VARTYPE vtResult
)
837 OLECHAR
*name
= NULL
;
843 memset(pVarResult
, 0, sizeof(VARIANT
));
844 VariantInit(pVarResult
);
846 len
= MultiByteToWideChar(CP_ACP
, 0, szName
, -1, NULL
, 0 );
847 name
= malloc(len
* sizeof(WCHAR
));
848 if (!name
) return E_FAIL
;
849 MultiByteToWideChar(CP_ACP
, 0, szName
, -1, name
, len
);
850 hr
= IDispatch_GetIDsOfNames(pDispatch
, &IID_NULL
, &name
, 1, LOCALE_USER_DEFAULT
, &dispid
);
852 ok(hr
== S_OK
, "IDispatch::GetIDsOfNames returned %#lx\n", hr
);
853 if (hr
!= S_OK
) return hr
;
855 memset(&excepinfo
, 0, sizeof(excepinfo
));
856 hr
= IDispatch_Invoke(pDispatch
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, wFlags
, pDispParams
, pVarResult
, &excepinfo
, NULL
);
860 todo_wine_if (_invoke_todo_vtResult
)
861 ok(V_VT(pVarResult
) == vtResult
, "Variant result type is %d, expected %d\n", V_VT(pVarResult
), vtResult
);
862 if (vtResult
!= VT_EMPTY
)
864 hr
= VariantChangeTypeEx(pVarResult
, pVarResult
, LOCALE_NEUTRAL
, 0, vtResult
);
865 ok(hr
== S_OK
, "VariantChangeTypeEx returned %#lx\n", hr
);
869 for (i
=0; i
<pDispParams
->cArgs
; i
++)
870 VariantClear(&pDispParams
->rgvarg
[i
]);
875 /* Object_Property helper functions */
877 static HRESULT
Installer_CreateRecord(int count
, IDispatch
**pRecord
)
880 VARIANTARG vararg
[1];
881 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
884 VariantInit(&vararg
[0]);
885 V_VT(&vararg
[0]) = VT_I4
;
886 V_I4(&vararg
[0]) = count
;
888 hr
= invoke(pInstaller
, "CreateRecord", DISPATCH_METHOD
, &dispparams
, &varresult
, VT_DISPATCH
);
889 *pRecord
= V_DISPATCH(&varresult
);
893 static HRESULT
Installer_RegistryValue(HKEY hkey
, LPCWSTR szKey
, VARIANT vValue
, VARIANT
*pVarResult
, VARTYPE vtExpect
)
895 VARIANTARG vararg
[3];
896 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
898 VariantInit(&vararg
[2]);
899 V_VT(&vararg
[2]) = VT_I4
;
900 V_I4(&vararg
[2]) = (INT_PTR
)hkey
;
901 VariantInit(&vararg
[1]);
902 V_VT(&vararg
[1]) = VT_BSTR
;
903 V_BSTR(&vararg
[1]) = SysAllocString(szKey
);
904 VariantInit(&vararg
[0]);
905 VariantCopy(&vararg
[0], &vValue
);
906 VariantClear(&vValue
);
908 return invoke(pInstaller
, "RegistryValue", DISPATCH_METHOD
, &dispparams
, pVarResult
, vtExpect
);
911 static HRESULT
Installer_RegistryValueE(HKEY hkey
, LPCWSTR szKey
, BOOL
*pBool
)
917 VariantInit(&vararg
);
918 V_VT(&vararg
) = VT_EMPTY
;
919 hr
= Installer_RegistryValue(hkey
, szKey
, vararg
, &varresult
, VT_BOOL
);
920 *pBool
= V_BOOL(&varresult
);
921 VariantClear(&varresult
);
925 static HRESULT
Installer_RegistryValueW(HKEY hkey
, LPCWSTR szKey
, LPCWSTR szValue
, LPWSTR szString
)
931 VariantInit(&vararg
);
932 V_VT(&vararg
) = VT_BSTR
;
933 V_BSTR(&vararg
) = SysAllocString(szValue
);
935 hr
= Installer_RegistryValue(hkey
, szKey
, vararg
, &varresult
, VT_BSTR
);
936 if (V_BSTR(&varresult
)) lstrcpyW(szString
, V_BSTR(&varresult
));
937 VariantClear(&varresult
);
941 static HRESULT
Installer_RegistryValueI(HKEY hkey
, LPCWSTR szKey
, int iValue
, LPWSTR szString
, VARTYPE vtResult
)
947 VariantInit(&vararg
);
948 V_VT(&vararg
) = VT_I4
;
949 V_I4(&vararg
) = iValue
;
951 hr
= Installer_RegistryValue(hkey
, szKey
, vararg
, &varresult
, vtResult
);
952 if (SUCCEEDED(hr
) && vtResult
== VT_BSTR
) lstrcpyW(szString
, V_BSTR(&varresult
));
953 VariantClear(&varresult
);
957 static HRESULT
Installer_OpenPackage(LPCWSTR szPackagePath
, int options
, IDispatch
**pSession
)
960 VARIANTARG vararg
[2];
961 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
964 VariantInit(&vararg
[1]);
965 V_VT(&vararg
[1]) = VT_BSTR
;
966 V_BSTR(&vararg
[1]) = SysAllocString(szPackagePath
);
967 VariantInit(&vararg
[0]);
968 V_VT(&vararg
[0]) = VT_I4
;
969 V_I4(&vararg
[0]) = options
;
971 hr
= invoke(pInstaller
, "OpenPackage", DISPATCH_METHOD
, &dispparams
, &varresult
, VT_DISPATCH
);
972 *pSession
= V_DISPATCH(&varresult
);
976 static HRESULT
Installer_OpenDatabase(LPCWSTR szDatabasePath
, int openmode
, IDispatch
**pDatabase
)
979 VARIANTARG vararg
[2];
980 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
983 VariantInit(&vararg
[1]);
984 V_VT(&vararg
[1]) = VT_BSTR
;
985 V_BSTR(&vararg
[1]) = SysAllocString(szDatabasePath
);
986 VariantInit(&vararg
[0]);
987 V_VT(&vararg
[0]) = VT_I4
;
988 V_I4(&vararg
[0]) = openmode
;
990 hr
= invoke(pInstaller
, "OpenDatabase", DISPATCH_METHOD
, &dispparams
, &varresult
, VT_DISPATCH
);
991 *pDatabase
= V_DISPATCH(&varresult
);
995 static HRESULT
Installer_InstallProduct(LPCWSTR szPackagePath
, LPCWSTR szPropertyValues
)
998 VARIANTARG vararg
[2];
999 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
1001 VariantInit(&vararg
[1]);
1002 V_VT(&vararg
[1]) = VT_BSTR
;
1003 V_BSTR(&vararg
[1]) = SysAllocString(szPackagePath
);
1004 VariantInit(&vararg
[0]);
1005 V_VT(&vararg
[0]) = VT_BSTR
;
1006 V_BSTR(&vararg
[0]) = SysAllocString(szPropertyValues
);
1008 return invoke(pInstaller
, "InstallProduct", DISPATCH_METHOD
, &dispparams
, &varresult
, VT_EMPTY
);
1011 static HRESULT
Installer_ProductState(LPCWSTR szProduct
, int *pInstallState
)
1014 VARIANTARG vararg
[1];
1015 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
1018 VariantInit(&vararg
[0]);
1019 V_VT(&vararg
[0]) = VT_BSTR
;
1020 V_BSTR(&vararg
[0]) = SysAllocString(szProduct
);
1022 hr
= invoke(pInstaller
, "ProductState", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_I4
);
1023 *pInstallState
= V_I4(&varresult
);
1024 VariantClear(&varresult
);
1028 static HRESULT
Installer_ProductInfo(LPCWSTR szProduct
, LPCWSTR szAttribute
, LPWSTR szString
)
1031 VARIANTARG vararg
[2];
1032 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
1035 VariantInit(&vararg
[1]);
1036 V_VT(&vararg
[1]) = VT_BSTR
;
1037 V_BSTR(&vararg
[1]) = SysAllocString(szProduct
);
1038 VariantInit(&vararg
[0]);
1039 V_VT(&vararg
[0]) = VT_BSTR
;
1040 V_BSTR(&vararg
[0]) = SysAllocString(szAttribute
);
1042 hr
= invoke(pInstaller
, "ProductInfo", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_BSTR
);
1043 if (V_BSTR(&varresult
)) lstrcpyW(szString
, V_BSTR(&varresult
));
1044 VariantClear(&varresult
);
1048 static HRESULT
Installer_Products(IDispatch
**pStringList
)
1051 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
1054 hr
= invoke(pInstaller
, "Products", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_DISPATCH
);
1055 *pStringList
= V_DISPATCH(&varresult
);
1059 static HRESULT
Installer_RelatedProducts(LPCWSTR szProduct
, IDispatch
**pStringList
)
1062 VARIANTARG vararg
[1];
1063 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
1066 VariantInit(&vararg
[0]);
1067 V_VT(&vararg
[0]) = VT_BSTR
;
1068 V_BSTR(&vararg
[0]) = SysAllocString(szProduct
);
1070 hr
= invoke(pInstaller
, "RelatedProducts", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_DISPATCH
);
1071 *pStringList
= V_DISPATCH(&varresult
);
1075 static HRESULT
Installer_VersionGet(LPWSTR szVersion
)
1078 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
1081 hr
= invoke(pInstaller
, "Version", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_BSTR
);
1082 if (V_BSTR(&varresult
)) lstrcpyW(szVersion
, V_BSTR(&varresult
));
1083 VariantClear(&varresult
);
1087 static HRESULT
Installer_UILevelPut(int level
)
1091 DISPID dispid
= DISPID_PROPERTYPUT
;
1092 DISPPARAMS dispparams
= {&vararg
, &dispid
, sizeof(vararg
)/sizeof(VARIANTARG
), 1};
1094 VariantInit(&vararg
);
1095 V_VT(&vararg
) = VT_I4
;
1096 V_I4(&vararg
) = level
;
1098 return invoke(pInstaller
, "UILevel", DISPATCH_PROPERTYPUT
, &dispparams
, &varresult
, VT_EMPTY
);
1101 static HRESULT
Installer_SummaryInformation(BSTR PackagePath
, int UpdateCount
, IDispatch
**pSumInfo
)
1104 VARIANTARG vararg
[2];
1105 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
1108 VariantInit(&vararg
[1]);
1109 V_VT(&vararg
[1]) = VT_BSTR
;
1110 V_BSTR(&vararg
[1]) = SysAllocString(PackagePath
);
1111 VariantInit(&vararg
[0]);
1112 V_VT(&vararg
[0]) = VT_I4
;
1113 V_I4(&vararg
[0]) = UpdateCount
;
1115 hr
= invoke(pInstaller
, "SummaryInformation", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_DISPATCH
);
1116 *pSumInfo
= V_DISPATCH(&varresult
);
1120 static HRESULT
Session_Installer(IDispatch
*pSession
, IDispatch
**pInst
)
1123 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
1126 hr
= invoke(pSession
, "Installer", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_DISPATCH
);
1127 *pInst
= V_DISPATCH(&varresult
);
1131 static HRESULT
Session_PropertyGet(IDispatch
*pSession
, LPCWSTR szName
, LPWSTR szReturn
)
1134 VARIANTARG vararg
[1];
1135 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
1138 VariantInit(&vararg
[0]);
1139 V_VT(&vararg
[0]) = VT_BSTR
;
1140 V_BSTR(&vararg
[0]) = SysAllocString(szName
);
1142 hr
= invoke(pSession
, "Property", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_BSTR
);
1143 if (V_BSTR(&varresult
)) lstrcpyW(szReturn
, V_BSTR(&varresult
));
1144 VariantClear(&varresult
);
1148 static HRESULT
Session_PropertyPut(IDispatch
*pSession
, LPCWSTR szName
, LPCWSTR szValue
)
1151 VARIANTARG vararg
[2];
1152 DISPID dispid
= DISPID_PROPERTYPUT
;
1153 DISPPARAMS dispparams
= {vararg
, &dispid
, ARRAY_SIZE(vararg
), 1};
1155 VariantInit(&vararg
[1]);
1156 V_VT(&vararg
[1]) = VT_BSTR
;
1157 V_BSTR(&vararg
[1]) = SysAllocString(szName
);
1158 VariantInit(&vararg
[0]);
1159 V_VT(&vararg
[0]) = VT_BSTR
;
1160 V_BSTR(&vararg
[0]) = SysAllocString(szValue
);
1162 return invoke(pSession
, "Property", DISPATCH_PROPERTYPUT
, &dispparams
, &varresult
, VT_EMPTY
);
1165 static HRESULT
Session_LanguageGet(IDispatch
*pSession
, UINT
*pLangId
)
1168 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
1171 hr
= invoke(pSession
, "Language", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_I4
);
1172 *pLangId
= V_I4(&varresult
);
1173 VariantClear(&varresult
);
1177 static HRESULT
Session_ModeGet(IDispatch
*pSession
, int iFlag
, VARIANT_BOOL
*mode
)
1180 VARIANTARG vararg
[1];
1181 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
1184 VariantInit(&vararg
[0]);
1185 V_VT(&vararg
[0]) = VT_I4
;
1186 V_I4(&vararg
[0]) = iFlag
;
1188 hr
= invoke(pSession
, "Mode", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_BOOL
);
1189 *mode
= V_BOOL(&varresult
);
1190 VariantClear(&varresult
);
1194 static HRESULT
Session_ModePut(IDispatch
*pSession
, int iFlag
, VARIANT_BOOL mode
)
1197 VARIANTARG vararg
[2];
1198 DISPID dispid
= DISPID_PROPERTYPUT
;
1199 DISPPARAMS dispparams
= {vararg
, &dispid
, ARRAY_SIZE(vararg
), 1};
1201 VariantInit(&vararg
[1]);
1202 V_VT(&vararg
[1]) = VT_I4
;
1203 V_I4(&vararg
[1]) = iFlag
;
1204 VariantInit(&vararg
[0]);
1205 V_VT(&vararg
[0]) = VT_BOOL
;
1206 V_BOOL(&vararg
[0]) = mode
;
1208 return invoke(pSession
, "Mode", DISPATCH_PROPERTYPUT
, &dispparams
, &varresult
, VT_EMPTY
);
1211 static HRESULT
Session_Database(IDispatch
*pSession
, IDispatch
**pDatabase
)
1214 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
1217 hr
= invoke(pSession
, "Database", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_DISPATCH
);
1218 *pDatabase
= V_DISPATCH(&varresult
);
1222 static HRESULT
Session_DoAction(IDispatch
*pSession
, LPCWSTR szAction
, int *iReturn
)
1225 VARIANTARG vararg
[1];
1226 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
1229 VariantInit(&vararg
[0]);
1230 V_VT(&vararg
[0]) = VT_BSTR
;
1231 V_BSTR(&vararg
[0]) = SysAllocString(szAction
);
1233 hr
= invoke(pSession
, "DoAction", DISPATCH_METHOD
, &dispparams
, &varresult
, VT_I4
);
1234 *iReturn
= V_I4(&varresult
);
1235 VariantClear(&varresult
);
1239 static HRESULT
Session_EvaluateCondition(IDispatch
*pSession
, LPCWSTR szCondition
, int *iReturn
)
1242 VARIANTARG vararg
[1];
1243 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
1246 VariantInit(&vararg
[0]);
1247 V_VT(&vararg
[0]) = VT_BSTR
;
1248 V_BSTR(&vararg
[0]) = SysAllocString(szCondition
);
1250 hr
= invoke(pSession
, "EvaluateCondition", DISPATCH_METHOD
, &dispparams
, &varresult
, VT_I4
);
1251 *iReturn
= V_I4(&varresult
);
1252 VariantClear(&varresult
);
1256 static HRESULT
Session_Message(IDispatch
*pSession
, LONG kind
, IDispatch
*record
, int *ret
)
1259 VARIANTARG vararg
[2];
1260 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
1263 VariantInit(&varresult
);
1264 V_VT(vararg
) = VT_DISPATCH
;
1265 V_DISPATCH(vararg
) = record
;
1266 V_VT(vararg
+1) = VT_I4
;
1267 V_I4(vararg
+1) = kind
;
1269 hr
= invoke(pSession
, "Message", DISPATCH_METHOD
, &dispparams
, &varresult
, VT_I4
);
1271 ok(V_VT(&varresult
) == VT_I4
, "V_VT(varresult) = %d\n", V_VT(&varresult
));
1272 *ret
= V_I4(&varresult
);
1277 static HRESULT
Session_SetInstallLevel(IDispatch
*pSession
, LONG iInstallLevel
)
1280 VARIANTARG vararg
[1];
1281 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
1283 VariantInit(&vararg
[0]);
1284 V_VT(&vararg
[0]) = VT_I4
;
1285 V_I4(&vararg
[0]) = iInstallLevel
;
1287 return invoke(pSession
, "SetInstallLevel", DISPATCH_METHOD
, &dispparams
, &varresult
, VT_EMPTY
);
1290 static HRESULT
Session_FeatureCurrentState(IDispatch
*pSession
, LPCWSTR szName
, int *pState
)
1293 VARIANTARG vararg
[1];
1294 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
1297 VariantInit(&vararg
[0]);
1298 V_VT(&vararg
[0]) = VT_BSTR
;
1299 V_BSTR(&vararg
[0]) = SysAllocString(szName
);
1301 hr
= invoke(pSession
, "FeatureCurrentState", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_I4
);
1302 *pState
= V_I4(&varresult
);
1303 VariantClear(&varresult
);
1307 static HRESULT
Session_FeatureRequestStateGet(IDispatch
*pSession
, LPCWSTR szName
, int *pState
)
1310 VARIANTARG vararg
[1];
1311 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
1314 VariantInit(&vararg
[0]);
1315 V_VT(&vararg
[0]) = VT_BSTR
;
1316 V_BSTR(&vararg
[0]) = SysAllocString(szName
);
1318 hr
= invoke(pSession
, "FeatureRequestState", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_I4
);
1319 *pState
= V_I4(&varresult
);
1320 VariantClear(&varresult
);
1324 static HRESULT
Session_FeatureRequestStatePut(IDispatch
*pSession
, LPCWSTR szName
, int iState
)
1327 VARIANTARG vararg
[2];
1328 DISPID dispid
= DISPID_PROPERTYPUT
;
1329 DISPPARAMS dispparams
= {vararg
, &dispid
, ARRAY_SIZE(vararg
), 1};
1331 VariantInit(&vararg
[1]);
1332 V_VT(&vararg
[1]) = VT_BSTR
;
1333 V_BSTR(&vararg
[1]) = SysAllocString(szName
);
1334 VariantInit(&vararg
[0]);
1335 V_VT(&vararg
[0]) = VT_I4
;
1336 V_I4(&vararg
[0]) = iState
;
1338 return invoke(pSession
, "FeatureRequestState", DISPATCH_PROPERTYPUT
, &dispparams
, &varresult
, VT_EMPTY
);
1341 static HRESULT
Database_OpenView(IDispatch
*pDatabase
, LPCWSTR szSql
, IDispatch
**pView
)
1344 VARIANTARG vararg
[1];
1345 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
1348 VariantInit(&vararg
[0]);
1349 V_VT(&vararg
[0]) = VT_BSTR
;
1350 V_BSTR(&vararg
[0]) = SysAllocString(szSql
);
1352 hr
= invoke(pDatabase
, "OpenView", DISPATCH_METHOD
, &dispparams
, &varresult
, VT_DISPATCH
);
1353 *pView
= V_DISPATCH(&varresult
);
1357 static HRESULT
Database_SummaryInformation(IDispatch
*pDatabase
, int iUpdateCount
, IDispatch
**pSummaryInfo
)
1360 VARIANTARG vararg
[1];
1361 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
1364 VariantInit(&vararg
[0]);
1365 V_VT(&vararg
[0]) = VT_I4
;
1366 V_I4(&vararg
[0]) = iUpdateCount
;
1368 hr
= invoke(pDatabase
, "SummaryInformation", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_DISPATCH
);
1369 *pSummaryInfo
= V_DISPATCH(&varresult
);
1373 static HRESULT
View_Execute(IDispatch
*pView
, IDispatch
*pRecord
)
1376 VARIANTARG vararg
[1];
1377 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
1379 VariantInit(&vararg
[0]);
1380 V_VT(&vararg
[0]) = VT_DISPATCH
;
1381 V_DISPATCH(&vararg
[0]) = pRecord
;
1383 return invoke(pView
, "Execute", DISPATCH_METHOD
, &dispparams
, &varresult
, VT_EMPTY
);
1386 static HRESULT
View_Fetch(IDispatch
*pView
, IDispatch
**ppRecord
)
1389 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
1390 HRESULT hr
= invoke(pView
, "Fetch", DISPATCH_METHOD
, &dispparams
, &varresult
, VT_DISPATCH
);
1391 *ppRecord
= V_DISPATCH(&varresult
);
1395 static HRESULT
View_Modify(IDispatch
*pView
, int iMode
, IDispatch
*pRecord
)
1398 VARIANTARG vararg
[2];
1399 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
1401 VariantInit(&vararg
[1]);
1402 V_VT(&vararg
[1]) = VT_I4
;
1403 V_I4(&vararg
[1]) = iMode
;
1404 VariantInit(&vararg
[0]);
1405 V_VT(&vararg
[0]) = VT_DISPATCH
;
1406 V_DISPATCH(&vararg
[0]) = pRecord
;
1408 IDispatch_AddRef(pRecord
); /* VariantClear in invoke will call IDispatch_Release */
1410 return invoke(pView
, "Modify", DISPATCH_METHOD
, &dispparams
, &varresult
, VT_EMPTY
);
1413 static HRESULT
View_Close(IDispatch
*pView
)
1416 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
1417 return invoke(pView
, "Close", DISPATCH_METHOD
, &dispparams
, &varresult
, VT_EMPTY
);
1420 static HRESULT
Record_FieldCountGet(IDispatch
*pRecord
, int *pFieldCount
)
1423 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
1424 HRESULT hr
= invoke(pRecord
, "FieldCount", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_I4
);
1425 *pFieldCount
= V_I4(&varresult
);
1426 VariantClear(&varresult
);
1430 static HRESULT
Record_StringDataGet(IDispatch
*pRecord
, int iField
, LPWSTR szString
)
1433 VARIANTARG vararg
[1];
1434 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
1437 VariantInit(&vararg
[0]);
1438 V_VT(&vararg
[0]) = VT_I4
;
1439 V_I4(&vararg
[0]) = iField
;
1441 hr
= invoke(pRecord
, "StringData", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_BSTR
);
1442 if (V_BSTR(&varresult
)) lstrcpyW(szString
, V_BSTR(&varresult
));
1443 VariantClear(&varresult
);
1447 static HRESULT
Record_StringDataPut(IDispatch
*pRecord
, int iField
, LPCWSTR szString
)
1450 VARIANTARG vararg
[2];
1451 DISPID dispid
= DISPID_PROPERTYPUT
;
1452 DISPPARAMS dispparams
= {vararg
, &dispid
, ARRAY_SIZE(vararg
), 1};
1454 VariantInit(&vararg
[1]);
1455 V_VT(&vararg
[1]) = VT_I4
;
1456 V_I4(&vararg
[1]) = iField
;
1457 VariantInit(&vararg
[0]);
1458 V_VT(&vararg
[0]) = VT_BSTR
;
1459 V_BSTR(&vararg
[0]) = SysAllocString(szString
);
1461 return invoke(pRecord
, "StringData", DISPATCH_PROPERTYPUT
, &dispparams
, &varresult
, VT_EMPTY
);
1464 static HRESULT
Record_IntegerDataGet(IDispatch
*pRecord
, int iField
, int *pValue
)
1467 VARIANTARG vararg
[1];
1468 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
1471 VariantInit(&vararg
[0]);
1472 V_VT(&vararg
[0]) = VT_I4
;
1473 V_I4(&vararg
[0]) = iField
;
1475 hr
= invoke(pRecord
, "IntegerData", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_I4
);
1476 *pValue
= V_I4(&varresult
);
1477 VariantClear(&varresult
);
1481 static HRESULT
Record_IntegerDataPut(IDispatch
*pRecord
, int iField
, int iValue
)
1484 VARIANTARG vararg
[2];
1485 DISPID dispid
= DISPID_PROPERTYPUT
;
1486 DISPPARAMS dispparams
= {vararg
, &dispid
, ARRAY_SIZE(vararg
), 1};
1488 VariantInit(&vararg
[1]);
1489 V_VT(&vararg
[1]) = VT_I4
;
1490 V_I4(&vararg
[1]) = iField
;
1491 VariantInit(&vararg
[0]);
1492 V_VT(&vararg
[0]) = VT_I4
;
1493 V_I4(&vararg
[0]) = iValue
;
1495 return invoke(pRecord
, "IntegerData", DISPATCH_PROPERTYPUT
, &dispparams
, &varresult
, VT_EMPTY
);
1498 static HRESULT
StringList__NewEnum(IDispatch
*pList
, IUnknown
**ppEnumVARIANT
)
1501 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
1502 HRESULT hr
= invoke(pList
, "_NewEnum", DISPATCH_METHOD
, &dispparams
, &varresult
, VT_UNKNOWN
);
1503 *ppEnumVARIANT
= V_UNKNOWN(&varresult
);
1507 static HRESULT
StringList_Item(IDispatch
*pStringList
, int iIndex
, LPWSTR szString
)
1510 VARIANTARG vararg
[1];
1511 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
1514 VariantInit(&vararg
[0]);
1515 V_VT(&vararg
[0]) = VT_I4
;
1516 V_I4(&vararg
[0]) = iIndex
;
1518 hr
= invoke(pStringList
, "Item", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_BSTR
);
1519 if (V_BSTR(&varresult
)) lstrcpyW(szString
, V_BSTR(&varresult
));
1520 VariantClear(&varresult
);
1524 static HRESULT
StringList_Count(IDispatch
*pStringList
, int *pCount
)
1527 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
1528 HRESULT hr
= invoke(pStringList
, "Count", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_I4
);
1529 *pCount
= V_I4(&varresult
);
1530 VariantClear(&varresult
);
1534 static HRESULT
SummaryInfo_PropertyGet(IDispatch
*pSummaryInfo
, int pid
, VARIANT
*pVarResult
, VARTYPE vtExpect
)
1536 VARIANTARG vararg
[1];
1537 DISPPARAMS dispparams
= {vararg
, NULL
, ARRAY_SIZE(vararg
), 0};
1539 VariantInit(&vararg
[0]);
1540 V_VT(&vararg
[0]) = VT_I4
;
1541 V_I4(&vararg
[0]) = pid
;
1542 return invoke(pSummaryInfo
, "Property", DISPATCH_PROPERTYGET
, &dispparams
, pVarResult
, vtExpect
);
1545 static HRESULT
SummaryInfo_PropertyPut(IDispatch
*pSummaryInfo
, int pid
, VARIANT
*pVariant
)
1548 VARIANTARG vararg
[2];
1549 DISPID dispid
= DISPID_PROPERTYPUT
;
1550 DISPPARAMS dispparams
= {vararg
, &dispid
, ARRAY_SIZE(vararg
), 1};
1552 VariantInit(&vararg
[1]);
1553 V_VT(&vararg
[1]) = VT_I4
;
1554 V_I4(&vararg
[1]) = pid
;
1555 VariantInit(&vararg
[0]);
1556 VariantCopyInd(vararg
, pVariant
);
1558 return invoke(pSummaryInfo
, "Property", DISPATCH_PROPERTYPUT
, &dispparams
, &varresult
, VT_EMPTY
);
1561 static HRESULT
SummaryInfo_PropertyCountGet(IDispatch
*pSummaryInfo
, int *pCount
)
1564 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
1567 hr
= invoke(pSummaryInfo
, "PropertyCount", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_I4
);
1568 *pCount
= V_I4(&varresult
);
1569 VariantClear(&varresult
);
1573 /* Test the various objects */
1575 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4
1577 static void test_SummaryInfo(IDispatch
*pSummaryInfo
, const msi_summary_info
*info
, int num_info
, BOOL readonly
)
1579 VARIANT varresult
, var
;
1584 /* SummaryInfo::PropertyCount */
1585 hr
= SummaryInfo_PropertyCountGet(pSummaryInfo
, &j
);
1586 ok(hr
== S_OK
, "SummaryInfo_PropertyCount failed, hresult %#lx\n", hr
);
1587 ok(j
== num_info
, "SummaryInfo_PropertyCount returned %d, expected %d\n", j
, num_info
);
1589 /* SummaryInfo::Property, get for properties we have set */
1590 for (j
= 0; j
< num_info
; j
++)
1592 const msi_summary_info
*entry
= &info
[j
];
1594 int vt
= entry
->datatype
;
1595 if (vt
== VT_LPSTR
) vt
= VT_BSTR
;
1596 else if (vt
== VT_FILETIME
) vt
= VT_DATE
;
1597 else if (vt
== VT_I2
) vt
= VT_I4
;
1599 hr
= SummaryInfo_PropertyGet(pSummaryInfo
, entry
->property
, &varresult
, vt
);
1600 ok(hr
== S_OK
, "SummaryInfo_Property (pid %d) failed, hresult %#lx\n", entry
->property
, hr
);
1601 if (V_VT(&varresult
) != vt
)
1602 skip("Skipping property tests due to type mismatch\n");
1603 else if (vt
== VT_I4
)
1604 ok(V_I4(&varresult
) == entry
->iValue
, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %ld\n",
1605 entry
->property
, entry
->iValue
, V_I4(&varresult
));
1606 else if (vt
== VT_DATE
)
1611 FileTimeToLocalFileTime(entry
->pftValue
, &ft
);
1612 FileTimeToSystemTime(&ft
, &st
);
1613 SystemTimeToVariantTime(&st
, &d
);
1614 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
));
1616 else if (vt
== VT_BSTR
)
1618 ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry
->property
, entry
->szValue
, V_BSTR(&varresult
));
1621 skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry
->property
, vt
);
1623 VariantClear(&varresult
);
1626 /* SummaryInfo::Property, get; invalid arguments */
1629 hr
= SummaryInfo_PropertyGet(pSummaryInfo
, -1, &varresult
, VT_EMPTY
);
1630 ok(hr
== DISP_E_EXCEPTION
, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr
);
1631 ok_exception(hr
, L
"Property,Pid");
1633 hr
= SummaryInfo_PropertyGet(pSummaryInfo
, 1000, &varresult
, VT_EMPTY
);
1634 ok(hr
== DISP_E_EXCEPTION
, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr
);
1635 ok_exception(hr
, L
"Property,Pid");
1637 /* Unsupported pids */
1638 hr
= SummaryInfo_PropertyGet(pSummaryInfo
, PID_DICTIONARY
, &varresult
, VT_EMPTY
);
1639 ok(hr
== S_OK
, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr
);
1641 hr
= SummaryInfo_PropertyGet(pSummaryInfo
, PID_THUMBNAIL
, &varresult
, VT_EMPTY
);
1642 ok(hr
== S_OK
, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr
);
1644 /* Pids we have not set, one for each type */
1645 hr
= SummaryInfo_PropertyGet(pSummaryInfo
, PID_CODEPAGE
, &varresult
, VT_EMPTY
);
1646 ok(hr
== S_OK
, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr
);
1648 hr
= SummaryInfo_PropertyGet(pSummaryInfo
, PID_TITLE
, &varresult
, VT_EMPTY
);
1649 ok(hr
== S_OK
, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr
);
1651 hr
= SummaryInfo_PropertyGet(pSummaryInfo
, PID_EDITTIME
, &varresult
, VT_EMPTY
);
1652 ok(hr
== S_OK
, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr
);
1654 hr
= SummaryInfo_PropertyGet(pSummaryInfo
, PID_CHARCOUNT
, &varresult
, VT_EMPTY
);
1655 ok(hr
== S_OK
, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr
);
1659 /* SummaryInfo::Property, put; one for each type */
1665 hr
= SummaryInfo_PropertyPut(pSummaryInfo
, PID_CODEPAGE
, &var
);
1666 ok(hr
== S_OK
, "SummaryInfo_PropertyPut failed, hresult %#lx\n", hr
);
1668 hr
= SummaryInfo_PropertyGet(pSummaryInfo
, PID_CODEPAGE
, &varresult
, VT_I4
/* NOT VT_I2 */);
1669 ok(hr
== S_OK
, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr
);
1670 ok(V_I2(&var
) == V_I2(&varresult
), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var
), V_I2(&varresult
));
1671 VariantClear(&varresult
);
1675 V_VT(&var
) = VT_BSTR
;
1676 V_BSTR(&var
) = SysAllocString(L
"Title");
1677 hr
= SummaryInfo_PropertyPut(pSummaryInfo
, PID_TITLE
, &var
);
1678 ok(hr
== S_OK
, "SummaryInfo_PropertyPut failed, hresult %#lx\n", hr
);
1680 hr
= SummaryInfo_PropertyGet(pSummaryInfo
, PID_TITLE
, &varresult
, V_VT(&var
));
1681 ok(hr
== S_OK
, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr
);
1682 ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var
), V_BSTR(&varresult
));
1683 VariantClear(&varresult
);
1687 V_VT(&var
) = VT_DATE
;
1688 FileTimeToSystemTime(&systemtime
, &st
);
1689 SystemTimeToVariantTime(&st
, &V_DATE(&var
));
1690 hr
= SummaryInfo_PropertyPut(pSummaryInfo
, PID_LASTSAVE_DTM
, &var
);
1691 ok(hr
== S_OK
, "SummaryInfo_PropertyPut failed, hresult %#lx\n", hr
);
1693 hr
= SummaryInfo_PropertyGet(pSummaryInfo
, PID_LASTSAVE_DTM
, &varresult
, V_VT(&var
));
1694 ok(hr
== S_OK
, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr
);
1695 ok(V_DATE(&var
) == V_DATE(&varresult
), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var
), V_DATE(&varresult
));
1696 VariantClear(&varresult
);
1702 hr
= SummaryInfo_PropertyPut(pSummaryInfo
, PID_CHARCOUNT
, &var
);
1703 ok(hr
== S_OK
, "SummaryInfo_PropertyPut failed, hresult %#lx\n", hr
);
1705 hr
= SummaryInfo_PropertyGet(pSummaryInfo
, PID_CHARCOUNT
, &varresult
, V_VT(&var
));
1706 ok(hr
== S_OK
, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr
);
1707 ok(V_I4(&var
) == V_I4(&varresult
), "SummaryInfo_PropertyGet expected %ld, but returned %ld\n", V_I4(&var
), V_I4(&varresult
));
1708 VariantClear(&varresult
);
1711 /* SummaryInfo::PropertyCount */
1712 hr
= SummaryInfo_PropertyCountGet(pSummaryInfo
, &j
);
1713 ok(hr
== S_OK
, "SummaryInfo_PropertyCount failed, hresult %#lx\n", hr
);
1714 ok(j
== num_info
+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j
, num_info
);
1718 static void test_Database(IDispatch
*pDatabase
, BOOL readonly
)
1720 IDispatch
*pView
= NULL
, *pSummaryInfo
= NULL
;
1723 hr
= Database_OpenView(pDatabase
, L
"SELECT `Feature` FROM `Feature` WHERE `Feature_Parent`='One'", &pView
);
1724 ok(hr
== S_OK
, "Database_OpenView failed, hresult %#lx\n", hr
);
1727 IDispatch
*pRecord
= NULL
;
1728 WCHAR szString
[MAX_PATH
];
1731 hr
= View_Execute(pView
, NULL
);
1732 ok(hr
== S_OK
, "View_Execute failed, hresult %#lx\n", hr
);
1735 hr
= View_Fetch(pView
, &pRecord
);
1736 ok(hr
== S_OK
, "View_Fetch failed, hresult %#lx\n", hr
);
1737 ok(pRecord
!= NULL
, "View_Fetch should not have returned NULL record\n");
1740 /* Record::StringDataGet */
1741 memset(szString
, 0, sizeof(szString
));
1742 hr
= Record_StringDataGet(pRecord
, 1, szString
);
1743 ok(hr
== S_OK
, "Record_StringDataGet failed, hresult %#lx\n", hr
);
1744 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString
, L
"Three");
1746 /* Record::StringDataPut with correct index */
1747 hr
= Record_StringDataPut(pRecord
, 1, L
"Two");
1748 ok(hr
== S_OK
, "Record_StringDataPut failed, hresult %#lx\n", hr
);
1750 /* Record::StringDataGet */
1751 memset(szString
, 0, sizeof(szString
));
1752 hr
= Record_StringDataGet(pRecord
, 1, szString
);
1753 ok(hr
== S_OK
, "Record_StringDataGet failed, hresult %#lx\n", hr
);
1754 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString
, L
"Two");
1756 /* Record::StringDataPut with incorrect index */
1757 hr
= Record_StringDataPut(pRecord
, -1, szString
);
1758 ok(hr
== DISP_E_EXCEPTION
, "Record_StringDataPut failed, hresult %#lx\n", hr
);
1759 ok_exception(hr
, L
"StringData,Field");
1761 /* View::Modify with incorrect parameters */
1762 hr
= View_Modify(pView
, -5, NULL
);
1763 ok(hr
== DISP_E_EXCEPTION
, "View_Modify failed, hresult %#lx\n", hr
);
1764 ok_exception(hr
, L
"Modify,Mode,Record");
1766 hr
= View_Modify(pView
, -5, pRecord
);
1767 ok(hr
== DISP_E_EXCEPTION
, "View_Modify failed, hresult %#lx\n", hr
);
1768 ok_exception(hr
, L
"Modify,Mode,Record");
1770 hr
= View_Modify(pView
, MSIMODIFY_REFRESH
, NULL
);
1771 ok(hr
== DISP_E_EXCEPTION
, "View_Modify failed, hresult %#lx\n", hr
);
1772 ok_exception(hr
, L
"Modify,Mode,Record");
1774 hr
= View_Modify(pView
, MSIMODIFY_REFRESH
, pRecord
);
1775 ok(hr
== S_OK
, "View_Modify failed, hresult %#lx\n", hr
);
1777 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1778 memset(szString
, 0, sizeof(szString
));
1779 hr
= Record_StringDataGet(pRecord
, 1, szString
);
1780 ok(hr
== S_OK
, "Record_StringDataGet failed, hresult %#lx\n", hr
);
1781 todo_wine
ok_w2("Record_StringDataGet result was %s but expected %s\n", szString
, L
"Three");
1783 IDispatch_Release(pRecord
);
1787 hr
= View_Fetch(pView
, &pRecord
);
1788 ok(hr
== S_OK
, "View_Fetch failed, hresult %#lx\n", hr
);
1789 ok(pRecord
!= NULL
, "View_Fetch should not have returned NULL record\n");
1792 /* Record::StringDataGet */
1793 memset(szString
, 0, sizeof(szString
));
1794 hr
= Record_StringDataGet(pRecord
, 1, szString
);
1795 ok(hr
== S_OK
, "Record_StringDataGet failed, hresult %#lx\n", hr
);
1796 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString
, L
"Two");
1798 IDispatch_Release(pRecord
);
1802 hr
= View_Fetch(pView
, &pRecord
);
1803 ok(hr
== S_OK
, "View_Fetch failed, hresult %#lx\n", hr
);
1804 ok(pRecord
== NULL
, "View_Fetch should have returned NULL record\n");
1806 IDispatch_Release(pRecord
);
1809 hr
= View_Close(pView
);
1810 ok(hr
== S_OK
, "View_Close failed, hresult %#lx\n", hr
);
1812 IDispatch_Release(pView
);
1815 /* Database::SummaryInformation */
1816 hr
= Database_SummaryInformation(pDatabase
, TEST_SUMMARYINFO_PROPERTIES_MODIFIED
, &pSummaryInfo
);
1817 ok(hr
== S_OK
, "Database_SummaryInformation failed, hresult %#lx\n", hr
);
1818 ok(pSummaryInfo
!= NULL
, "Database_SummaryInformation should not have returned NULL record\n");
1821 test_SummaryInfo(pSummaryInfo
, summary_info
, ARRAY_SIZE(summary_info
), readonly
);
1822 IDispatch_Release(pSummaryInfo
);
1826 static void test_Session(IDispatch
*pSession
)
1828 WCHAR stringw
[MAX_PATH
];
1829 CHAR string
[MAX_PATH
];
1833 IDispatch
*pDatabase
= NULL
, *pInst
= NULL
, *record
= NULL
;
1834 ULONG refs_before
, refs_after
;
1837 /* Session::Installer */
1838 hr
= Session_Installer(pSession
, &pInst
);
1839 ok(hr
== S_OK
, "Session_Installer failed, hresult %#lx\n", hr
);
1840 ok(pInst
!= NULL
, "Session_Installer returned NULL IDispatch pointer\n");
1841 ok(pInst
== pInstaller
, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1842 refs_before
= IDispatch_AddRef(pInst
);
1844 hr
= Session_Installer(pSession
, &pInst
);
1845 ok(hr
== S_OK
, "Session_Installer failed, hresult %#lx\n", hr
);
1846 ok(pInst
!= NULL
, "Session_Installer returned NULL IDispatch pointer\n");
1847 ok(pInst
== pInstaller
, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1848 refs_after
= IDispatch_Release(pInst
);
1849 ok(refs_before
== refs_after
, "got %lu and %lu\n", refs_before
, refs_after
);
1851 /* Session::Property, get */
1852 memset(stringw
, 0, sizeof(stringw
));
1853 hr
= Session_PropertyGet(pSession
, L
"ProductName", stringw
);
1854 ok(hr
== S_OK
, "Session_PropertyGet failed, hresult %#lx\n", hr
);
1855 if (lstrcmpW(stringw
, L
"MSITEST") != 0)
1857 len
= WideCharToMultiByte(CP_ACP
, 0, stringw
, -1, string
, MAX_PATH
, NULL
, NULL
);
1858 ok(len
, "WideCharToMultiByteChar returned error %lu\n", GetLastError());
1859 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string
);
1862 /* Session::Property, put */
1863 hr
= Session_PropertyPut(pSession
, L
"ProductName", L
"ProductName");
1864 ok(hr
== S_OK
, "Session_PropertyPut failed, hresult %#lx\n", hr
);
1865 memset(stringw
, 0, sizeof(stringw
));
1866 hr
= Session_PropertyGet(pSession
, L
"ProductName", stringw
);
1867 ok(hr
== S_OK
, "Session_PropertyGet failed, hresult %#lx\n", hr
);
1868 if (lstrcmpW(stringw
, L
"ProductName") != 0)
1870 len
= WideCharToMultiByte(CP_ACP
, 0, stringw
, -1, string
, MAX_PATH
, NULL
, NULL
);
1871 ok(len
, "WideCharToMultiByteChar returned error %lu\n", GetLastError());
1872 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string
);
1875 /* Try putting a property using empty property identifier */
1876 hr
= Session_PropertyPut(pSession
, L
"", L
"ProductName");
1877 ok(hr
== DISP_E_EXCEPTION
, "Session_PropertyPut failed, hresult %#lx\n", hr
);
1878 ok_exception(hr
, L
"Property,Name");
1880 /* Try putting a property using illegal property identifier */
1881 hr
= Session_PropertyPut(pSession
, L
"=", L
"ProductName");
1882 ok(hr
== S_OK
, "Session_PropertyPut failed, hresult %#lx\n", hr
);
1884 /* Session::Language, get */
1885 hr
= Session_LanguageGet(pSession
, &len
);
1886 ok(hr
== S_OK
, "Session_LanguageGet failed, hresult %#lx\n", hr
);
1887 /* Not sure how to check the language is correct */
1889 /* Session::Mode, get */
1890 hr
= Session_ModeGet(pSession
, MSIRUNMODE_REBOOTATEND
, &bool);
1891 ok(hr
== S_OK
, "Session_ModeGet failed, hresult %#lx\n", hr
);
1892 ok(!bool, "Reboot at end session mode is %d\n", bool);
1894 hr
= Session_ModeGet(pSession
, MSIRUNMODE_MAINTENANCE
, &bool);
1895 ok(hr
== S_OK
, "Session_ModeGet failed, hresult %#lx\n", hr
);
1896 ok(!bool, "Maintenance mode is %d\n", bool);
1898 /* Session::Mode, put */
1899 hr
= Session_ModePut(pSession
, MSIRUNMODE_REBOOTATEND
, VARIANT_TRUE
);
1900 ok(hr
== S_OK
, "Session_ModePut failed, hresult %#lx\n", hr
);
1901 hr
= Session_ModeGet(pSession
, MSIRUNMODE_REBOOTATEND
, &bool);
1902 ok(hr
== S_OK
, "Session_ModeGet failed, hresult %#lx\n", hr
);
1903 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1904 hr
= Session_ModePut(pSession
, MSIRUNMODE_REBOOTATEND
, VARIANT_FALSE
); /* set it again so we don't reboot */
1905 ok(hr
== S_OK
, "Session_ModePut failed, hresult %#lx\n", hr
);
1907 hr
= Session_ModePut(pSession
, MSIRUNMODE_REBOOTNOW
, VARIANT_TRUE
);
1908 ok(hr
== S_OK
, "Session_ModePut failed, hresult %#lx\n", hr
);
1909 ok_exception(hr
, L
"Mode,Flag");
1911 hr
= Session_ModeGet(pSession
, MSIRUNMODE_REBOOTNOW
, &bool);
1912 ok(hr
== S_OK
, "Session_ModeGet failed, hresult %#lx\n", hr
);
1913 ok(bool, "Reboot now mode is %d, expected 1\n", bool);
1915 hr
= Session_ModePut(pSession
, MSIRUNMODE_REBOOTNOW
, VARIANT_FALSE
); /* set it again so we don't reboot */
1916 ok(hr
== S_OK
, "Session_ModePut failed, hresult %#lx\n", hr
);
1917 ok_exception(hr
, L
"Mode,Flag");
1919 hr
= Session_ModePut(pSession
, MSIRUNMODE_MAINTENANCE
, VARIANT_TRUE
);
1920 ok(hr
== DISP_E_EXCEPTION
, "Session_ModePut failed, hresult %#lx\n", hr
);
1921 ok_exception(hr
, L
"Mode,Flag");
1923 /* Session::Database, get */
1924 hr
= Session_Database(pSession
, &pDatabase
);
1925 ok(hr
== S_OK
, "Session_Database failed, hresult %#lx\n", hr
);
1928 test_Database(pDatabase
, TRUE
);
1929 IDispatch_Release(pDatabase
);
1932 /* Session::EvaluateCondition */
1933 hr
= Session_EvaluateCondition(pSession
, NULL
, &myint
);
1934 ok(hr
== S_OK
, "Session_EvaluateCondition failed, hresult %#lx\n", hr
);
1935 ok(myint
== MSICONDITION_NONE
, "Feature current state was %d but expected %d\n", myint
, INSTALLSTATE_UNKNOWN
);
1937 hr
= Session_EvaluateCondition(pSession
, L
"", &myint
);
1938 ok(hr
== S_OK
, "Session_EvaluateCondition failed, hresult %#lx\n", hr
);
1939 ok(myint
== MSICONDITION_NONE
, "Feature current state was %d but expected %d\n", myint
, INSTALLSTATE_UNKNOWN
);
1941 hr
= Session_EvaluateCondition(pSession
, L
"=", &myint
);
1942 ok(hr
== S_OK
, "Session_EvaluateCondition failed, hresult %#lx\n", hr
);
1943 ok(myint
== MSICONDITION_ERROR
, "Feature current state was %d but expected %d\n", myint
, INSTALLSTATE_UNKNOWN
);
1945 /* Session::DoAction(CostInitialize) must occur before the next statements */
1946 hr
= Session_DoAction(pSession
, L
"CostInitialize", &myint
);
1947 ok(hr
== S_OK
, "Session_DoAction failed, hresult %#lx\n", hr
);
1948 ok(myint
== IDOK
, "DoAction(CostInitialize) returned %d, %d expected\n", myint
, IDOK
);
1950 /* Session::SetInstallLevel */
1951 hr
= Session_SetInstallLevel(pSession
, INSTALLLEVEL_MINIMUM
);
1952 ok(hr
== S_OK
, "Session_SetInstallLevel failed, hresult %#lx\n", hr
);
1954 /* Session::FeatureCurrentState, get */
1955 hr
= Session_FeatureCurrentState(pSession
, L
"One", &myint
);
1956 ok(hr
== S_OK
, "Session_FeatureCurrentState failed, hresult %#lx\n", hr
);
1957 ok(myint
== INSTALLSTATE_UNKNOWN
, "Feature current state was %d but expected %d\n", myint
, INSTALLSTATE_UNKNOWN
);
1959 /* Session::Message */
1960 hr
= Installer_CreateRecord(0, &record
);
1961 ok(hr
== S_OK
, "Installer_CreateRecord failed: %#lx\n", hr
);
1962 hr
= Session_Message(pSession
, INSTALLMESSAGE_INFO
, record
, &myint
);
1963 ok(hr
== S_OK
, "Session_Message failed: %#lx\n", hr
);
1964 ok(myint
== 0, "Session_Message returned %x\n", myint
);
1966 /* Session::EvaluateCondition */
1967 hr
= Session_EvaluateCondition(pSession
, L
"!One>0", &myint
);
1968 ok(hr
== S_OK
, "Session_EvaluateCondition failed, hresult %#lx\n", hr
);
1969 ok(myint
== MSICONDITION_FALSE
, "Feature current state was %d but expected %d\n", myint
, INSTALLSTATE_UNKNOWN
);
1971 hr
= Session_EvaluateCondition(pSession
, L
"!One=-1", &myint
);
1972 ok(hr
== S_OK
, "Session_EvaluateCondition failed, hresult %#lx\n", hr
);
1973 ok(myint
== MSICONDITION_TRUE
, "Feature current state was %d but expected %d\n", myint
, INSTALLSTATE_UNKNOWN
);
1975 /* Session::FeatureRequestState, put */
1976 hr
= Session_FeatureRequestStatePut(pSession
, L
"One", INSTALLSTATE_ADVERTISED
);
1977 ok(hr
== S_OK
, "Session_FeatureRequestStatePut failed, hresult %#lx\n", hr
);
1978 hr
= Session_FeatureRequestStateGet(pSession
, L
"One", &myint
);
1979 ok(hr
== S_OK
, "Session_FeatureRequestStateGet failed, hresult %#lx\n", hr
);
1980 ok(myint
== INSTALLSTATE_ADVERTISED
, "Feature request state was %d but expected %d\n", myint
, INSTALLSTATE_ADVERTISED
);
1982 /* Session::EvaluateCondition */
1983 hr
= Session_EvaluateCondition(pSession
, L
"$One=-1", &myint
);
1984 ok(hr
== S_OK
, "Session_EvaluateCondition failed, hresult %#lx\n", hr
);
1985 ok(myint
== MSICONDITION_FALSE
, "Feature current state was %d but expected %d\n", myint
, INSTALLSTATE_UNKNOWN
);
1987 hr
= Session_EvaluateCondition(pSession
, L
"$One>0", &myint
);
1988 ok(hr
== S_OK
, "Session_EvaluateCondition failed, hresult %#lx\n", hr
);
1989 ok(myint
== MSICONDITION_TRUE
, "Feature current state was %d but expected %d\n", myint
, INSTALLSTATE_UNKNOWN
);
1992 /* delete key and all its subkeys */
1993 static DWORD
delete_key( HKEY hkey
)
1995 char name
[MAX_PATH
];
1998 while (!(ret
= RegEnumKeyA(hkey
, 0, name
, sizeof(name
))))
2001 if (!(ret
= RegOpenKeyExA( hkey
, name
, 0, KEY_ENUMERATE_SUB_KEYS
, &tmp
)))
2003 ret
= delete_key( tmp
);
2008 if (ret
!= ERROR_NO_MORE_ITEMS
) return ret
;
2009 RegDeleteKeyA( hkey
, "" );
2013 static void test_Installer_RegistryValue(void)
2015 static const DWORD qw
[2] = { 0x12345678, 0x87654321 };
2018 WCHAR szString
[MAX_PATH
];
2019 HKEY hkey
, hkey_sub
;
2020 HKEY curr_user
= (HKEY
)1;
2026 SetLastError(0xdeadbeef);
2027 lRet
= RegOpenKeyW( HKEY_CURRENT_USER
, L
"Software\\Wine\\Test", &hkey
);
2028 if (!lRet
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
2030 win_skip("Needed W-functions are not implemented\n");
2036 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
2037 hr
= Installer_RegistryValueE(curr_user
, L
"Software\\Wine\\Test", &bRet
);
2038 ok(hr
== S_OK
, "Installer_RegistryValueE failed, hresult %#lx\n", hr
);
2039 ok(!bRet
, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
2041 memset(szString
, 0, sizeof(szString
));
2042 hr
= Installer_RegistryValueW(curr_user
, L
"Software\\Wine\\Test", NULL
, szString
);
2043 ok(hr
== DISP_E_BADINDEX
, "Installer_RegistryValueW failed, hresult %#lx\n", hr
);
2045 memset(szString
, 0, sizeof(szString
));
2046 hr
= Installer_RegistryValueI(curr_user
, L
"Software\\Wine\\Test", 0, szString
, VT_BSTR
);
2047 ok(hr
== DISP_E_BADINDEX
, "Installer_RegistryValueI failed, hresult %#lx\n", hr
);
2050 ok(!RegCreateKeyW( HKEY_CURRENT_USER
, L
"Software\\Wine\\Test", &hkey
), "RegCreateKeyW failed\n");
2052 ok(!RegSetValueExW(hkey
, L
"One", 0, REG_SZ
, (const BYTE
*)L
"One", sizeof(L
"one")),
2053 "RegSetValueExW failed\n");
2054 ok(!RegSetValueExW(hkey
, L
"Two", 0, REG_DWORD
, (const BYTE
*)qw
, 4),
2055 "RegSetValueExW failed\n");
2056 ok(!RegSetValueExW(hkey
, L
"Three", 0, REG_BINARY
, (const BYTE
*)qw
, 4),
2057 "RegSetValueExW failed\n");
2058 bRet
= SetEnvironmentVariableA("MSITEST", "Four");
2059 ok(bRet
, "SetEnvironmentVariableA failed %lu\n", GetLastError());
2060 ok(!RegSetValueExW(hkey
, L
"Four", 0, REG_EXPAND_SZ
, (const BYTE
*)L
"%MSITEST%", sizeof(L
"%MSITEST%")),
2061 "RegSetValueExW failed\n");
2062 ok(!RegSetValueExW(hkey
, L
"Five\0Hi\0", 0, REG_MULTI_SZ
, (const BYTE
*)L
"Five\0Hi\0", sizeof(L
"Five\0Hi\0")),
2063 "RegSetValueExW failed\n");
2064 ok(!RegSetValueExW(hkey
, L
"Six", 0, REG_QWORD
, (const BYTE
*)qw
, 8),
2065 "RegSetValueExW failed\n");
2066 ok(!RegSetValueExW(hkey
, L
"Seven", 0, REG_NONE
, NULL
, 0),
2067 "RegSetValueExW failed\n");
2069 ok(!RegSetValueExW(hkey
, NULL
, 0, REG_SZ
, (const BYTE
*)L
"One", sizeof(L
"One")),
2070 "RegSetValueExW failed\n");
2072 ok(!RegCreateKeyW( hkey
, L
"Eight", &hkey_sub
), "RegCreateKeyW failed\n");
2074 /* Does our key exist? It should, and make sure we retrieve the correct default value */
2076 hr
= Installer_RegistryValueE(curr_user
, L
"Software\\Wine\\Test", &bRet
);
2077 ok(hr
== S_OK
, "Installer_RegistryValueE failed, hresult %#lx\n", hr
);
2078 ok(bRet
, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
2080 memset(szString
, 0, sizeof(szString
));
2081 hr
= Installer_RegistryValueW(curr_user
, L
"Software\\Wine\\Test", NULL
, szString
);
2082 ok(hr
== S_OK
, "Installer_RegistryValueW failed, hresult %#lx\n", hr
);
2083 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString
, L
"One");
2085 /* Ask for the value of a nonexistent key */
2086 memset(szString
, 0, sizeof(szString
));
2087 hr
= Installer_RegistryValueW(curr_user
, L
"Software\\Wine\\Test", L
"%MSITEST%", szString
);
2088 ok(hr
== DISP_E_BADINDEX
, "Installer_RegistryValueW failed, hresult %#lx\n", hr
);
2090 /* Get values of keys */
2091 memset(szString
, 0, sizeof(szString
));
2092 hr
= Installer_RegistryValueW(curr_user
, L
"Software\\Wine\\Test", L
"One", szString
);
2093 ok(hr
== S_OK
, "Installer_RegistryValueW failed, hresult %#lx\n", hr
);
2094 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString
, L
"One");
2096 VariantInit(&vararg
);
2097 V_VT(&vararg
) = VT_BSTR
;
2098 V_BSTR(&vararg
) = SysAllocString(L
"Two");
2099 hr
= Installer_RegistryValue(curr_user
, L
"Software\\Wine\\Test", vararg
, &varresult
, VT_I4
);
2100 ok(hr
== S_OK
, "Installer_RegistryValue failed, hresult %#lx\n", hr
);
2101 ok(V_I4(&varresult
) == 305419896, "Registry value %ld does not match expected value\n", V_I4(&varresult
));
2102 VariantClear(&varresult
);
2104 memset(szString
, 0, sizeof(szString
));
2105 hr
= Installer_RegistryValueW(curr_user
, L
"Software\\Wine\\Test", L
"Three", szString
);
2106 ok(hr
== S_OK
, "Installer_RegistryValueW failed, hresult %#lx\n", hr
);
2107 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString
, L
"(REG_BINARY)");
2109 memset(szString
, 0, sizeof(szString
));
2110 hr
= Installer_RegistryValueW(curr_user
, L
"Software\\Wine\\Test", L
"Four", szString
);
2111 ok(hr
== S_OK
, "Installer_RegistryValueW failed, hresult %#lx\n", hr
);
2112 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString
, L
"Four");
2114 /* Vista does not NULL-terminate this case */
2115 memset(szString
, 0, sizeof(szString
));
2116 hr
= Installer_RegistryValueW(curr_user
, L
"Software\\Wine\\Test", L
"Five\0Hi\0", szString
);
2117 ok(hr
== S_OK
, "Installer_RegistryValueW failed, hresult %#lx\n", hr
);
2118 ok_w2n("Registry value \"%s\" does not match expected \"%s\"\n",
2119 szString
, L
"Five\nHi", lstrlenW(L
"Five\nHi"));
2121 memset(szString
, 0, sizeof(szString
));
2122 hr
= Installer_RegistryValueW(curr_user
, L
"Software\\Wine\\Test", L
"Six", szString
);
2123 ok(hr
== S_OK
, "Installer_RegistryValueW failed, hresult %#lx\n", hr
);
2124 ok(!lstrcmpW(szString
, L
"(REG_\?\?)") || broken(!lstrcmpW(szString
, L
"(REG_]")),
2125 "Registry value does not match\n");
2127 VariantInit(&vararg
);
2128 V_VT(&vararg
) = VT_BSTR
;
2129 V_BSTR(&vararg
) = SysAllocString(L
"Seven");
2130 hr
= Installer_RegistryValue(curr_user
, L
"Software\\Wine\\Test", vararg
, &varresult
, VT_EMPTY
);
2131 ok(hr
== S_OK
, "Installer_RegistryValue failed, hresult %#lx\n", hr
);
2133 /* Get string class name for the key */
2134 memset(szString
, 0, sizeof(szString
));
2135 hr
= Installer_RegistryValueI(curr_user
, L
"Software\\Wine\\Test", 0, szString
, VT_BSTR
);
2136 ok(hr
== S_OK
, "Installer_RegistryValueI failed, hresult %#lx\n", hr
);
2137 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString
, L
"");
2139 /* Get name of a value by positive number (RegEnumValue like), valid index */
2140 memset(szString
, 0, sizeof(szString
));
2141 hr
= Installer_RegistryValueI(curr_user
, L
"Software\\Wine\\Test", 2, szString
, VT_BSTR
);
2142 ok(hr
== S_OK
, "Installer_RegistryValueI failed, hresult %#lx\n", hr
);
2143 /* RegEnumValue order seems different on wine */
2144 todo_wine
ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString
, L
"Two");
2146 /* Get name of a value by positive number (RegEnumValue like), invalid index */
2147 memset(szString
, 0, sizeof(szString
));
2148 hr
= Installer_RegistryValueI(curr_user
, L
"Software\\Wine\\Test", 10, szString
, VT_EMPTY
);
2149 ok(hr
== S_OK
, "Installer_RegistryValueI failed, hresult %#lx\n", hr
);
2151 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
2152 memset(szString
, 0, sizeof(szString
));
2153 hr
= Installer_RegistryValueI(curr_user
, L
"Software\\Wine\\Test", -1, szString
, VT_BSTR
);
2154 ok(hr
== S_OK
, "Installer_RegistryValueI failed, hresult %#lx\n", hr
);
2155 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString
, L
"Eight");
2157 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
2158 memset(szString
, 0, sizeof(szString
));
2159 hr
= Installer_RegistryValueI(curr_user
, L
"Software\\Wine\\Test", -10, szString
, VT_EMPTY
);
2160 ok(hr
== S_OK
, "Installer_RegistryValueI failed, hresult %#lx\n", hr
);
2166 static void test_Installer_Products(BOOL bProductInstalled
)
2168 WCHAR szString
[MAX_PATH
];
2171 IUnknown
*pUnk
= NULL
;
2172 IEnumVARIANT
*pEnum
= NULL
;
2176 IDispatch
*pStringList
= NULL
;
2177 BOOL bProductFound
= FALSE
;
2179 /* Installer::Products */
2180 hr
= Installer_Products(&pStringList
);
2181 ok(hr
== S_OK
, "Installer_Products failed, hresult %#lx\n", hr
);
2184 /* StringList::_NewEnum */
2185 hr
= StringList__NewEnum(pStringList
, &pUnk
);
2186 ok(hr
== S_OK
, "StringList_NewEnum failed, hresult %#lx\n", hr
);
2189 hr
= IUnknown_QueryInterface(pUnk
, &IID_IEnumVARIANT
, (void **)&pEnum
);
2190 ok (hr
== S_OK
, "IUnknown::QueryInterface returned %#lx\n", hr
);
2193 skip("IEnumVARIANT tests\n");
2195 /* StringList::Count */
2196 hr
= StringList_Count(pStringList
, &iCount
);
2197 ok(hr
== S_OK
, "StringList_Count failed, hresult %#lx\n", hr
);
2199 for (idx
=0; idx
<iCount
; idx
++)
2201 /* StringList::Item */
2202 memset(szString
, 0, sizeof(szString
));
2203 hr
= StringList_Item(pStringList
, idx
, szString
);
2204 ok(hr
== S_OK
, "StringList_Item failed (idx %d, count %d), hresult %#lx\n", idx
, iCount
, hr
);
2208 /* Installer::ProductState */
2209 hr
= Installer_ProductState(szString
, &iValue
);
2210 ok(hr
== S_OK
, "Installer_ProductState failed, hresult %#lx\n", hr
);
2212 ok(iValue
== INSTALLSTATE_DEFAULT
|| iValue
== INSTALLSTATE_ADVERTISED
,
2213 "Installer_ProductState returned %d, expected %d or %d\n", iValue
, INSTALLSTATE_DEFAULT
, INSTALLSTATE_ADVERTISED
);
2215 /* Not found our product code yet? Check */
2216 if (!bProductFound
&& !lstrcmpW(szString
, L
"{837450fa-a39b-4bc8-b321-08b393f784b3}"))
2217 bProductFound
= TRUE
;
2219 /* IEnumVARIANT::Next */
2222 hr
= IEnumVARIANT_Next(pEnum
, 1, &var
, &celt
);
2223 ok(hr
== S_OK
, "IEnumVARIANT_Next failed (idx %d, count %d), hresult %#lx\n", idx
, iCount
, hr
);
2224 ok(celt
== 1, "%lu items were retrieved, expected 1\n", celt
);
2225 ok(V_VT(&var
) == VT_BSTR
, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var
), VT_BSTR
);
2226 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString
, V_BSTR(&var
));
2232 if (bProductInstalled
)
2234 ok(bProductInstalled
== bProductFound
, "Product expected to %s installed but product code was %s\n",
2235 bProductInstalled
? "be" : "not be",
2236 bProductFound
? "found" : "not found");
2241 IEnumVARIANT
*pEnum2
= NULL
;
2243 if (0) /* Crashes on Windows XP */
2245 /* IEnumVARIANT::Clone, NULL pointer */
2246 IEnumVARIANT_Clone(pEnum
, NULL
);
2249 /* IEnumVARIANT::Clone */
2250 hr
= IEnumVARIANT_Clone(pEnum
, &pEnum2
);
2251 ok(hr
== S_OK
, "IEnumVARIANT_Clone failed, hresult %#lx\n", hr
);
2254 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
2256 /* IEnumVARIANT::Next of the clone */
2259 hr
= IEnumVARIANT_Next(pEnum2
, 1, &var
, &celt
);
2260 ok(hr
== S_OK
, "IEnumVARIANT_Next failed, hresult %#lx\n", hr
);
2261 ok(celt
== 1, "%lu items were retrieved, expected 0\n", celt
);
2262 ok(V_VT(&var
) == VT_BSTR
, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var
), VT_BSTR
);
2266 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
2268 IEnumVARIANT_Release(pEnum2
);
2271 /* IEnumVARIANT::Skip should fail */
2272 hr
= IEnumVARIANT_Skip(pEnum
, 1);
2273 ok(hr
== S_FALSE
, "IEnumVARIANT_Skip failed, hresult %#lx\n", hr
);
2275 /* IEnumVARIANT::Next, NULL variant pointer */
2276 hr
= IEnumVARIANT_Next(pEnum
, 1, NULL
, &celt
);
2277 ok(hr
== S_FALSE
, "IEnumVARIANT_Next failed, hresult %#lx\n", hr
);
2278 ok(celt
== 0, "%lu items were retrieved, expected 0\n", celt
);
2280 /* IEnumVARIANT::Next, should not return any more items */
2281 hr
= IEnumVARIANT_Next(pEnum
, 1, &var
, &celt
);
2282 ok(hr
== S_FALSE
, "IEnumVARIANT_Next failed, hresult %#lx\n", hr
);
2283 ok(celt
== 0, "%lu items were retrieved, expected 0\n", celt
);
2286 /* IEnumVARIANT::Reset */
2287 hr
= IEnumVARIANT_Reset(pEnum
);
2288 ok(hr
== S_OK
, "IEnumVARIANT_Reset failed, hresult %#lx\n", hr
);
2292 /* IEnumVARIANT::Skip to the last product */
2293 hr
= IEnumVARIANT_Skip(pEnum
, iCount
-1);
2294 ok(hr
== S_OK
, "IEnumVARIANT_Skip failed, hresult %#lx\n", hr
);
2296 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2297 * NULL celt pointer. */
2298 hr
= IEnumVARIANT_Next(pEnum
, 1, &var
, NULL
);
2299 ok(hr
== S_OK
, "IEnumVARIANT_Next failed (idx %d, count %d), hresult %#lx\n", idx
, iCount
, hr
);
2300 ok(V_VT(&var
) == VT_BSTR
, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var
), VT_BSTR
);
2301 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString
, V_BSTR(&var
));
2305 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2308 /* StringList::Item using an invalid index */
2309 memset(szString
, 0, sizeof(szString
));
2310 hr
= StringList_Item(pStringList
, iCount
, szString
);
2311 ok(hr
== DISP_E_BADINDEX
, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult %#lx\n", hr
);
2313 if (pEnum
) IEnumVARIANT_Release(pEnum
);
2314 if (pUnk
) IUnknown_Release(pUnk
);
2315 IDispatch_Release(pStringList
);
2319 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2320 * deleting the subkeys first) */
2321 static UINT
delete_registry_key(HKEY hkeyParent
, LPCSTR subkey
, REGSAM access
)
2324 CHAR
*string
= NULL
;
2328 ret
= RegOpenKeyExA(hkeyParent
, subkey
, 0, access
, &hkey
);
2329 if (ret
!= ERROR_SUCCESS
) return ret
;
2330 ret
= RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, &dwSize
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
2331 if (ret
!= ERROR_SUCCESS
) return ret
;
2332 if (!(string
= malloc(++dwSize
))) return ERROR_NOT_ENOUGH_MEMORY
;
2334 while (RegEnumKeyA(hkey
, 0, string
, dwSize
) == ERROR_SUCCESS
)
2335 delete_registry_key(hkey
, string
, access
);
2339 delete_key_portable(hkeyParent
, subkey
, access
);
2340 return ERROR_SUCCESS
;
2343 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2344 static UINT
find_registry_key(HKEY hkeyParent
, LPCSTR subkey
, LPCSTR findkey
, REGSAM access
, HKEY
*phkey
)
2347 CHAR
*string
= NULL
;
2355 ret
= RegOpenKeyExA(hkeyParent
, subkey
, 0, access
, &hkey
);
2356 if (ret
!= ERROR_SUCCESS
) return ret
;
2357 ret
= RegQueryInfoKeyA(hkey
, NULL
, NULL
, NULL
, NULL
, &dwSize
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
2358 if (ret
!= ERROR_SUCCESS
) return ret
;
2359 if (!(string
= malloc(++dwSize
))) return ERROR_NOT_ENOUGH_MEMORY
;
2362 RegEnumKeyA(hkey
, idx
++, string
, dwSize
) == ERROR_SUCCESS
)
2364 if (!strcmp(string
, findkey
))
2369 else if (find_registry_key(hkey
, string
, findkey
, access
, phkey
) == ERROR_SUCCESS
) found
= TRUE
;
2372 if (*phkey
!= hkey
) RegCloseKey(hkey
);
2374 return (found
? ERROR_SUCCESS
: ERROR_FILE_NOT_FOUND
);
2377 static void test_Installer_InstallProduct(void)
2380 CHAR path
[MAX_PATH
];
2381 WCHAR szString
[MAX_PATH
];
2384 DWORD num
, size
, type
;
2386 IDispatch
*pStringList
= NULL
;
2387 REGSAM access
= KEY_ALL_ACCESS
;
2389 if (is_process_limited())
2391 /* In fact InstallProduct would succeed but then Windows XP
2392 * would not allow us to clean up the registry!
2394 skip("Installer_InstallProduct (insufficient privileges)\n");
2399 access
|= KEY_WOW64_64KEY
;
2401 create_test_files();
2403 /* Avoid an interactive dialog in case of insufficient privileges. */
2404 hr
= Installer_UILevelPut(INSTALLUILEVEL_NONE
);
2405 ok(hr
== S_OK
, "Expected UILevel property put invoke to return S_OK, got %#lx\n", hr
);
2407 /* Installer::InstallProduct */
2408 hr
= Installer_InstallProduct(L
"winetest-automation.msi", NULL
);
2409 if (hr
== DISP_E_EXCEPTION
)
2411 skip("InstallProduct failed, insufficient rights?\n");
2412 delete_test_files();
2415 ok(hr
== S_OK
, "Installer_InstallProduct failed, hresult %#lx\n", hr
);
2417 /* Installer::ProductState for our product code, which has been installed */
2418 hr
= Installer_ProductState(L
"{837450fa-a39b-4bc8-b321-08b393f784b3}", &iValue
);
2419 ok(hr
== S_OK
, "Installer_ProductState failed, hresult %#lx\n", hr
);
2420 ok(iValue
== INSTALLSTATE_DEFAULT
, "Installer_ProductState returned %d, expected %d\n", iValue
, INSTALLSTATE_DEFAULT
);
2422 /* Installer::ProductInfo for our product code */
2424 /* NULL attribute */
2425 memset(szString
, 0, sizeof(szString
));
2426 hr
= Installer_ProductInfo(L
"{837450fa-a39b-4bc8-b321-08b393f784b3}", NULL
, szString
);
2427 ok(hr
== DISP_E_EXCEPTION
, "Installer_ProductInfo failed, hresult %#lx\n", hr
);
2428 ok_exception(hr
, L
"ProductInfo,Product,Attribute");
2430 /* Nonexistent attribute */
2431 memset(szString
, 0, sizeof(szString
));
2432 hr
= Installer_ProductInfo(L
"{837450fa-a39b-4bc8-b321-08b393f784b3}", L
"winetest-automation.msi", szString
);
2433 ok(hr
== DISP_E_EXCEPTION
, "Installer_ProductInfo failed, hresult %#lx\n", hr
);
2434 ok_exception(hr
, L
"ProductInfo,Product,Attribute");
2437 memset(szString
, 0, sizeof(szString
));
2438 hr
= Installer_ProductInfo(L
"{837450fa-a39b-4bc8-b321-08b393f784b3}", L
"PackageName", szString
);
2439 ok(hr
== S_OK
, "Installer_ProductInfo failed, hresult %#lx\n", hr
);
2440 todo_wine
ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString
, L
"winetest-automation.msi");
2443 memset(szString
, 0, sizeof(szString
));
2444 hr
= Installer_ProductInfo(L
"{837450fa-a39b-4bc8-b321-08b393f784b3}", L
"ProductName", szString
);
2445 ok(hr
== S_OK
, "Installer_ProductInfo failed, hresult %#lx\n", hr
);
2446 todo_wine
ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString
, L
"MSITEST");
2448 /* Installer::Products */
2449 test_Installer_Products(TRUE
);
2451 /* Installer::RelatedProducts for our upgrade code */
2452 hr
= Installer_RelatedProducts(L
"{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}", &pStringList
);
2453 ok(hr
== S_OK
, "Installer_RelatedProducts failed, hresult %#lx\n", hr
);
2456 /* StringList::Count */
2457 hr
= StringList_Count(pStringList
, &iCount
);
2458 ok(hr
== S_OK
, "StringList_Count failed, hresult %#lx\n", hr
);
2459 ok(iCount
== 1, "Expected one related product but found %d\n", iCount
);
2461 /* StringList::Item */
2462 memset(szString
, 0, sizeof(szString
));
2463 hr
= StringList_Item(pStringList
, 0, szString
);
2464 ok(hr
== S_OK
, "StringList_Item failed (idx 0, count %d), hresult %#lx\n", iCount
, hr
);
2465 ok_w2("StringList_Item returned %s but expected %s\n", szString
, L
"{837450fa-a39b-4bc8-b321-08b393f784b3}");
2467 IDispatch_Release(pStringList
);
2470 hr
= Installer_ProductInfo(L
"{837450fa-a39b-4bc8-b321-08b393f784b3}", L
"LocalPackage", szString
);
2471 ok(hr
== S_OK
, "Installer_ProductInfo failed, hresult %#lx\n", hr
);
2472 DeleteFileW( szString
);
2474 /* Check & clean up installed files & registry keys */
2475 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE
), "File not installed\n");
2476 ok(delete_pf("msitest\\cabout\\new", FALSE
), "Directory not created\n");
2477 ok(delete_pf("msitest\\cabout\\four.txt", TRUE
), "File not installed\n");
2478 ok(delete_pf("msitest\\cabout", FALSE
), "Directory not created\n");
2479 ok(delete_pf("msitest\\changed\\three.txt", TRUE
), "File not installed\n");
2480 ok(delete_pf("msitest\\changed", FALSE
), "Directory not created\n");
2481 ok(delete_pf("msitest\\first\\two.txt", TRUE
), "File not installed\n");
2482 ok(delete_pf("msitest\\first", FALSE
), "Directory not created\n");
2483 ok(delete_pf("msitest\\one.txt", TRUE
), "File not installed\n");
2484 ok(delete_pf("msitest\\filename", TRUE
), "File not installed\n");
2485 ok(delete_pf("msitest", FALSE
), "Directory not created\n");
2487 res
= RegOpenKeyA(HKEY_CURRENT_USER
, "SOFTWARE\\Wine\\msitest", &hkey
);
2488 ok(res
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %ld\n", res
);
2492 res
= RegQueryValueExA(hkey
, "Name", NULL
, &type
, (LPBYTE
)path
, &size
);
2493 ok(res
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %ld\n", res
);
2494 ok(!lstrcmpA(path
, "imaname"), "Expected imaname, got %s\n", path
);
2498 res
= RegQueryValueExA(hkey
, "blah", NULL
, &type
, (LPBYTE
)path
, &size
);
2499 ok(res
== ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %ld\n", res
);
2503 res
= RegQueryValueExA(hkey
, "number", NULL
, &type
, (LPBYTE
)&num
, &size
);
2504 ok(res
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %ld\n", res
);
2505 ok(num
== 314, "Expected 314, got %lu\n", num
);
2509 res
= RegQueryValueExA(hkey
, "OrderTestName", NULL
, &type
, (LPBYTE
)path
, &size
);
2510 ok(res
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %ld\n", res
);
2511 ok(!lstrcmpA(path
, "OrderTestValue"), "Expected imaname, got %s\n", path
);
2515 res
= RegDeleteKeyA(HKEY_CURRENT_USER
, "SOFTWARE\\Wine\\msitest");
2516 ok(res
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %ld\n", res
);
2518 /* Remove registry keys written by RegisterProduct standard action */
2519 res
= delete_key_portable(HKEY_LOCAL_MACHINE
,
2520 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{837450fa-a39b-4bc8-b321-08b393f784b3}",
2522 ok(res
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %ld\n", res
);
2524 res
= delete_key_portable(HKEY_LOCAL_MACHINE
,
2525 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656", access
);
2526 ok(res
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %ld\n", res
);
2528 res
= find_registry_key(HKEY_LOCAL_MACHINE
,
2529 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "af054738b93a8cb43b12803b397f483b", access
, &hkey
);
2530 ok(res
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %ld\n", res
);
2532 res
= delete_registry_key(hkey
, "af054738b93a8cb43b12803b397f483b", access
);
2533 ok(res
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %ld\n", res
);
2536 res
= delete_key_portable(HKEY_LOCAL_MACHINE
,
2537 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\af054738b93a8cb43b12803b397f483b", access
);
2538 ok(res
== ERROR_FILE_NOT_FOUND
, "Expected ERROR_FILE_NOT_FOUND, got %ld\n", res
);
2540 /* Remove registry keys written by PublishProduct standard action */
2541 res
= RegOpenKeyA(HKEY_CURRENT_USER
, "SOFTWARE\\Microsoft\\Installer", &hkey
);
2542 ok(res
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %ld\n", res
);
2544 res
= delete_registry_key(hkey
, "Products\\af054738b93a8cb43b12803b397f483b", KEY_ALL_ACCESS
);
2545 ok(res
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %ld\n", res
);
2547 res
= RegDeleteKeyA(hkey
, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2548 ok(res
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %ld\n", res
);
2552 /* Delete installation files we created */
2553 delete_test_files();
2556 static void test_Installer(void)
2558 WCHAR szPath
[MAX_PATH
];
2560 IDispatch
*pSession
= NULL
, *pDatabase
= NULL
, *pRecord
= NULL
, *pStringList
= NULL
, *pSumInfo
= NULL
;
2563 if (!pInstaller
) return;
2565 /* Installer::CreateRecord */
2567 /* Test for error */
2568 hr
= Installer_CreateRecord(-1, &pRecord
);
2569 ok(hr
== DISP_E_EXCEPTION
, "Installer_CreateRecord failed, hresult %#lx\n", hr
);
2570 ok_exception(hr
, L
"CreateRecord,Count");
2572 /* Test for success */
2573 hr
= Installer_CreateRecord(1, &pRecord
);
2574 ok(hr
== S_OK
, "Installer_CreateRecord failed, hresult %#lx\n", hr
);
2575 ok(pRecord
!= NULL
, "Installer_CreateRecord should not have returned NULL record\n");
2578 /* Record::FieldCountGet */
2579 hr
= Record_FieldCountGet(pRecord
, &iValue
);
2580 ok(hr
== S_OK
, "Record_FiledCountGet failed, hresult %#lx\n", hr
);
2581 ok(iValue
== 1, "Record_FieldCountGet result was %d but expected 1\n", iValue
);
2583 /* Record::IntegerDataGet */
2584 hr
= Record_IntegerDataGet(pRecord
, 1, &iValue
);
2585 ok(hr
== S_OK
, "Record_IntegerDataGet failed, hresult %#lx\n", hr
);
2586 ok(iValue
== MSI_NULL_INTEGER
, "Record_IntegerDataGet result was %d but expected %d\n", iValue
, MSI_NULL_INTEGER
);
2588 /* Record::IntegerDataGet, bad index */
2589 hr
= Record_IntegerDataGet(pRecord
, 10, &iValue
);
2590 ok(hr
== S_OK
, "Record_IntegerDataGet failed, hresult %#lx\n", hr
);
2591 ok(iValue
== MSI_NULL_INTEGER
, "Record_IntegerDataGet result was %d but expected %d\n", iValue
, MSI_NULL_INTEGER
);
2593 /* Record::IntegerDataPut */
2594 hr
= Record_IntegerDataPut(pRecord
, 1, 100);
2595 ok(hr
== S_OK
, "Record_IntegerDataPut failed, hresult %#lx\n", hr
);
2597 /* Record::IntegerDataPut, bad index */
2598 hr
= Record_IntegerDataPut(pRecord
, 10, 100);
2599 ok(hr
== DISP_E_EXCEPTION
, "Record_IntegerDataPut failed, hresult %#lx\n", hr
);
2600 ok_exception(hr
, L
"IntegerData,Field");
2602 /* Record::IntegerDataGet */
2603 hr
= Record_IntegerDataGet(pRecord
, 1, &iValue
);
2604 ok(hr
== S_OK
, "Record_IntegerDataGet failed, hresult %#lx\n", hr
);
2605 ok(iValue
== 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue
);
2607 IDispatch_Release(pRecord
);
2610 create_package(szPath
);
2612 /* Installer::OpenPackage */
2613 hr
= Installer_OpenPackage(szPath
, 0, &pSession
);
2614 if (hr
== DISP_E_EXCEPTION
)
2616 skip("OpenPackage failed, insufficient rights?\n");
2617 DeleteFileW(szPath
);
2620 ok(hr
== S_OK
, "Installer_OpenPackage failed, hresult %#lx\n", hr
);
2623 test_Session(pSession
);
2624 IDispatch_Release(pSession
);
2627 /* Installer::OpenDatabase */
2628 hr
= Installer_OpenDatabase(szPath
, (INT_PTR
)MSIDBOPEN_TRANSACT
, &pDatabase
);
2629 ok(hr
== S_OK
, "Installer_OpenDatabase failed, hresult %#lx\n", hr
);
2632 test_Database(pDatabase
, FALSE
);
2633 IDispatch_Release(pDatabase
);
2636 /* Installer::SummaryInformation */
2637 hr
= Installer_SummaryInformation(szPath
, 0, &pSumInfo
);
2638 ok(hr
== S_OK
, "Installer_SummaryInformation failed, hresult %#lx\n", hr
);
2641 test_SummaryInfo(pSumInfo
, summary_info
, ARRAY_SIZE(summary_info
), TRUE
);
2642 IDispatch_Release(pSumInfo
);
2645 hr
= Installer_SummaryInformation(NULL
, 0, &pSumInfo
);
2646 ok(hr
== DISP_E_EXCEPTION
, "Installer_SummaryInformation failed, hresult %#lx\n", hr
);
2648 /* Installer::RegistryValue */
2649 test_Installer_RegistryValue();
2651 /* Installer::ProductState for our product code, which should not be installed */
2652 hr
= Installer_ProductState(L
"{837450fa-a39b-4bc8-b321-08b393f784b3}", &iValue
);
2653 ok(hr
== S_OK
, "Installer_ProductState failed, hresult %#lx\n", hr
);
2654 ok(iValue
== INSTALLSTATE_UNKNOWN
, "Installer_ProductState returned %d, expected %d\n", iValue
, INSTALLSTATE_UNKNOWN
);
2656 /* Installer::ProductInfo for our product code, which should not be installed */
2659 memset(szPath
, 0, sizeof(szPath
));
2660 hr
= Installer_ProductInfo(L
"{837450fa-a39b-4bc8-b321-08b393f784b3}", L
"PackageName", szPath
);
2661 ok(hr
== DISP_E_EXCEPTION
, "Installer_ProductInfo failed, hresult %#lx\n", hr
);
2662 ok_exception(hr
, L
"ProductInfo,Product,Attribute");
2664 /* NULL attribute and NULL product code */
2665 memset(szPath
, 0, sizeof(szPath
));
2666 hr
= Installer_ProductInfo(NULL
, NULL
, szPath
);
2667 ok(hr
== DISP_E_EXCEPTION
, "Installer_ProductInfo failed, hresult %#lx\n", hr
);
2668 ok_exception(hr
, L
"ProductInfo,Product,Attribute");
2670 /* Installer::Products */
2671 test_Installer_Products(FALSE
);
2673 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2674 hr
= Installer_RelatedProducts(L
"{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}", &pStringList
);
2675 ok(hr
== S_OK
, "Installer_RelatedProducts failed, hresult %#lx\n", hr
);
2678 /* StringList::Count */
2679 hr
= StringList_Count(pStringList
, &iCount
);
2680 ok(hr
== S_OK
, "StringList_Count failed, hresult %#lx\n", hr
);
2681 ok(!iCount
, "Expected no related products but found %d\n", iCount
);
2683 IDispatch_Release(pStringList
);
2686 /* Installer::Version */
2687 memset(szPath
, 0, sizeof(szPath
));
2688 hr
= Installer_VersionGet(szPath
);
2689 ok(hr
== S_OK
, "Installer_VersionGet failed, hresult %#lx\n", hr
);
2691 /* Installer::InstallProduct and other tests that depend on our product being installed */
2692 test_Installer_InstallProduct();
2693 DeleteFileA(msifile
);
2696 START_TEST(automation
)
2699 char temp_path
[MAX_PATH
], prev_path
[MAX_PATH
];
2704 init_functionpointers();
2706 if (pIsWow64Process
)
2707 pIsWow64Process(GetCurrentProcess(), &is_wow64
);
2709 GetSystemTimeAsFileTime(&systemtime
);
2711 GetCurrentDirectoryA(MAX_PATH
, prev_path
);
2712 GetTempPathA(MAX_PATH
, temp_path
);
2713 SetCurrentDirectoryA(temp_path
);
2715 lstrcpyA(CURR_DIR
, temp_path
);
2716 len
= lstrlenA(CURR_DIR
);
2718 if(len
&& (CURR_DIR
[len
- 1] == '\\'))
2719 CURR_DIR
[len
- 1] = 0;
2721 get_program_files_dir(PROG_FILES_DIR
);
2723 hr
= OleInitialize(NULL
);
2724 ok (hr
== S_OK
, "OleInitialize returned %#lx\n", hr
);
2725 hr
= CLSIDFromProgID(L
"WindowsInstaller.Installer", &clsid
);
2726 ok (hr
== S_OK
, "CLSIDFromProgID returned %#lx\n", hr
);
2727 hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IUnknown
, (void **)&pUnk
);
2728 ok(hr
== S_OK
, "CoCreateInstance returned %#lx\n", hr
);
2732 hr
= IUnknown_QueryInterface(pUnk
, &IID_IDispatch
, (void **)&pInstaller
);
2733 ok (hr
== S_OK
, "IUnknown::QueryInterface returned %#lx\n", hr
);
2739 IDispatch_Release(pInstaller
);
2740 IUnknown_Release(pUnk
);
2745 SetCurrentDirectoryA(prev_path
);