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