[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 static void test_dispid(void)
493 {
494 DISPID dispid;
495
496 dispid = get_dispid(pInstaller, "CreateRecord");
497 ok(dispid == 1, "Expected 1, got %d\n", dispid);
498 dispid = get_dispid(pInstaller, "OpenPackage");
499 ok(dispid == 2, "Expected 2, got %d\n", dispid);
500 dispid = get_dispid(pInstaller, "OpenProduct");
501 ok(dispid == 3, "Expected 3, got %d\n", dispid);
502 dispid = get_dispid(pInstaller, "OpenDatabase");
503 ok(dispid == 4, "Expected 4, got %d\n", dispid);
504 dispid = get_dispid(pInstaller, "SummaryInformation");
505 ok(dispid == 5, "Expected 5, got %d\n", dispid);
506 dispid = get_dispid( pInstaller, "UILevel" );
507 ok(dispid == 6, "Expected 6, got %d\n", dispid);
508 dispid = get_dispid(pInstaller, "EnableLog");
509 ok(dispid == 7, "Expected 7, got %d\n", dispid);
510 dispid = get_dispid(pInstaller, "InstallProduct");
511 ok(dispid == 8, "Expected 8, got %d\n", dispid);
512 dispid = get_dispid(pInstaller, "Version");
513 ok(dispid == 9, "Expected 9, got %d\n", dispid);
514 dispid = get_dispid(pInstaller, "LastErrorRecord");
515 ok(dispid == 10, "Expected 10, got %d\n", dispid);
516 dispid = get_dispid(pInstaller, "RegistryValue");
517 ok(dispid == 11, "Expected 11, got %d\n", dispid);
518 dispid = get_dispid(pInstaller, "Environment");
519 ok(dispid == 12, "Expected 12, got %d\n", dispid);
520 dispid = get_dispid(pInstaller, "FileAttributes");
521 ok(dispid == 13, "Expected 13, got %d\n", dispid);
522 dispid = get_dispid(pInstaller, "FileSize");
523 ok(dispid == 15, "Expected 15, got %d\n", dispid);
524 dispid = get_dispid(pInstaller, "FileVersion");
525 ok(dispid == 16, "Expected 16, got %d\n", dispid);
526 dispid = get_dispid(pInstaller, "ProductState");
527 ok(dispid == 17, "Expected 17, got %d\n", dispid);
528 dispid = get_dispid(pInstaller, "ProductInfo");
529 ok(dispid == 18, "Expected 18, got %d\n", dispid);
530 todo_wine
531 {
532 dispid = get_dispid(pInstaller, "ConfigureProduct");
533 ok(dispid == 19, "Expected 19, got %d\n", dispid);
534 dispid = get_dispid(pInstaller, "ReinstallProduct");
535 ok(dispid == 20 , "Expected 20, got %d\n", dispid);
536 dispid = get_dispid(pInstaller, "CollectUserInfo");
537 ok(dispid == 21, "Expected 21, got %d\n", dispid);
538 dispid = get_dispid(pInstaller, "ApplyPatch");
539 ok(dispid == 22, "Expected 22, got %d\n", dispid);
540 dispid = get_dispid(pInstaller, "FeatureParent");
541 ok(dispid == 23, "Expected 23, got %d\n", dispid);
542 dispid = get_dispid(pInstaller, "FeatureState");
543 ok(dispid == 24, "Expected 24, got %d\n", dispid);
544 dispid = get_dispid(pInstaller, "UseFeature");
545 ok(dispid == 25, "Expected 25, got %d\n", dispid);
546 dispid = get_dispid(pInstaller, "FeatureUsageCount");
547 ok(dispid == 26, "Expected 26, got %d\n", dispid);
548 dispid = get_dispid(pInstaller, "FeatureUsageDate");
549 ok(dispid == 27, "Expected 27, got %d\n", dispid);
550 dispid = get_dispid(pInstaller, "ConfigureFeature");
551 ok(dispid == 28, "Expected 28, got %d\n", dispid);
552 dispid = get_dispid(pInstaller, "ReinstallFeature");
553 ok(dispid == 29, "Expected 29, got %d\n", dispid);
554 dispid = get_dispid(pInstaller, "ProvideComponent");
555 ok(dispid == 30, "Expected 30, got %d\n", dispid);
556 dispid = get_dispid(pInstaller, "ComponentPath");
557 ok(dispid == 31, "Expected 31, got %d\n", dispid);
558 dispid = get_dispid(pInstaller, "ProvideQualifiedComponent");
559 ok(dispid == 32, "Expected 32, got %d\n", dispid);
560 dispid = get_dispid(pInstaller, "QualifierDescription");
561 ok(dispid == 33, "Expected 33, got %d\n", dispid);
562 dispid = get_dispid(pInstaller, "ComponentQualifiers");
563 ok(dispid == 34, "Expected 34, got %d\n", dispid);
564 }
565 dispid = get_dispid(pInstaller, "Products");
566 ok(dispid == 35, "Expected 35, got %d\n", dispid);
567 todo_wine
568 {
569 dispid = get_dispid(pInstaller, "Features");
570 ok(dispid == 36, "Expected 36, got %d\n", dispid);
571 dispid = get_dispid(pInstaller, "Components");
572 ok(dispid == 37, "Expected 37, got %d\n", dispid);
573 dispid = get_dispid(pInstaller, "ComponentClients");
574 ok(dispid == 38, "Expected 38, got %d\n", dispid);
575 dispid = get_dispid(pInstaller, "Patches");
576 ok(dispid == 39, "Expected 39, got %d\n", dispid);
577 }
578 dispid = get_dispid(pInstaller, "RelatedProducts");
579 ok(dispid == 40, "Expected 40, got %d\n", dispid);
580 todo_wine
581 {
582 dispid = get_dispid(pInstaller, "PatchInfo");
583 ok(dispid == 41, "Expected 41, got %d\n", dispid);
584 dispid = get_dispid(pInstaller, "PatchTransforms");
585 ok(dispid == 42, "Expected 42, got %d\n", dispid);
586 dispid = get_dispid(pInstaller, "AddSource");
587 ok(dispid == 43, "Expected 43, got %d\n", dispid);
588 dispid = get_dispid(pInstaller, "ClearSourceList");
589 ok(dispid == 44, "Expected 44, got %d\n", dispid);
590 dispid = get_dispid(pInstaller, "ForceSourceListResolution");
591 ok(dispid == 45, "Expected 45, got %d\n", dispid);
592 dispid = get_dispid(pInstaller, "ShortcutTarget");
593 ok(dispid == 46, "Expected 46, got %d\n", dispid);
594 dispid = get_dispid(pInstaller, "FileHash");
595 ok(dispid == 47, "Expected 47, got %d\n", dispid);
596 dispid = get_dispid(pInstaller, "FileSignatureInfo");
597 ok(dispid == 48, "Expected 48, got %d\n", dispid);
598 }
599 dispid = get_dispid(pInstaller, "RemovePatches");
600 ok(dispid == 49 || dispid == -1, "Expected 49 or -1, got %d\n", dispid);
601 dispid = get_dispid(pInstaller, "ApplyMultiplePatches");
602 ok(dispid == 51 || dispid == -1, "Expected 51 or -1, got %d\n", dispid);
603 dispid = get_dispid(pInstaller, "ProductsEx");
604 ok(dispid == 52 || dispid == -1, "Expected 52 or -1, got %d\n", dispid);
605 dispid = get_dispid(pInstaller, "PatchesEx");
606 ok(dispid == 55 || dispid == -1, "Expected 55 or -1, got %d\n", dispid);
607 dispid = get_dispid(pInstaller, "ExtractPatchXMLData");
608 ok(dispid == 57 || dispid == -1, "Expected 57 or -1, got %d\n", dispid);
609 dispid = get_dispid( pInstaller, "ProductElevated" );
610 ok(dispid == 59 || dispid == -1, "Expected 59 or -1, got %d\n", dispid);
611 dispid = get_dispid( pInstaller, "ProvideAssembly" );
612 ok(dispid == 60 || dispid == -1, "Expected 60 or -1, got %d\n", dispid);
613 dispid = get_dispid( pInstaller, "ProductInfoFromScript" );
614 ok(dispid == 61 || dispid == -1, "Expected 61 or -1, got %d\n", dispid);
615 dispid = get_dispid( pInstaller, "AdvertiseProduct" );
616 ok(dispid == 62 || dispid == -1, "Expected 62 or -1, got %d\n", dispid);
617 dispid = get_dispid( pInstaller, "CreateAdvertiseScript" );
618 ok(dispid == 63 || dispid == -1, "Expected 63 or -1, got %d\n", dispid);
619 dispid = get_dispid( pInstaller, "PatchFiles" );
620 ok(dispid == 65 || dispid == -1, "Expected 65 or -1, got %d\n", dispid);
621 }
622
623 /* Test basic IDispatch functions */
624 static void test_dispatch(void)
625 {
626 static WCHAR szOpenPackage[] = { 'O','p','e','n','P','a','c','k','a','g','e',0 };
627 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};
628 static WCHAR szProductState[] = { 'P','r','o','d','u','c','t','S','t','a','t','e',0 };
629 HRESULT hr;
630 DISPID dispid;
631 OLECHAR *name;
632 VARIANT varresult;
633 VARIANTARG vararg[3];
634 WCHAR path[MAX_PATH];
635 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
636
637 /* Test getting ID of a function name that does not exist */
638 name = (WCHAR *)szMsifile;
639 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
640 ok(hr == DISP_E_UNKNOWNNAME, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
641
642 /* Test invoking this function */
643 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
644 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
645
646 /* Test getting ID of a function name that does exist */
647 name = szOpenPackage;
648 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
649 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
650
651 /* Test invoking this function (without parameters passed) */
652 if (0) /* All of these crash MSI on Windows XP */
653 {
654 IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
655 IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL);
656 VariantInit(&varresult);
657 IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, &varresult, &excepinfo, NULL);
658 }
659
660 /* Try with NULL params */
661 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
662 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
663
664 /* Try one empty parameter */
665 dispparams.rgvarg = vararg;
666 dispparams.cArgs = 1;
667 VariantInit(&vararg[0]);
668 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
669 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
670
671 /* Try two empty parameters */
672 dispparams.cArgs = 2;
673 VariantInit(&vararg[0]);
674 VariantInit(&vararg[1]);
675 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
676 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
677
678 /* Try one parameter, the required BSTR. Second parameter is optional.
679 * NOTE: The specified package does not exist, which is why the call fails.
680 */
681 dispparams.cArgs = 1;
682 VariantInit(&vararg[0]);
683 V_VT(&vararg[0]) = VT_BSTR;
684 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
685 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
686 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
687 ok_exception(hr, szOpenPackageException);
688 VariantClear(&vararg[0]);
689
690 /* Provide the required BSTR and an empty second parameter.
691 * NOTE: The specified package does not exist, which is why the call fails.
692 */
693 dispparams.cArgs = 2;
694 VariantInit(&vararg[1]);
695 V_VT(&vararg[1]) = VT_BSTR;
696 V_BSTR(&vararg[1]) = SysAllocString(szMsifile);
697 VariantInit(&vararg[0]);
698 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
699 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
700 ok_exception(hr, szOpenPackageException);
701 VariantClear(&vararg[1]);
702
703 /* Provide the required BSTR and two empty parameters.
704 * NOTE: The specified package does not exist, which is why the call fails.
705 */
706 dispparams.cArgs = 3;
707 VariantInit(&vararg[2]);
708 V_VT(&vararg[2]) = VT_BSTR;
709 V_BSTR(&vararg[2]) = SysAllocString(szMsifile);
710 VariantInit(&vararg[1]);
711 VariantInit(&vararg[0]);
712 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
713 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
714 ok_exception(hr, szOpenPackageException);
715 VariantClear(&vararg[2]);
716
717 /* Provide the required BSTR and a second parameter with the wrong type. */
718 dispparams.cArgs = 2;
719 VariantInit(&vararg[1]);
720 V_VT(&vararg[1]) = VT_BSTR;
721 V_BSTR(&vararg[1]) = SysAllocString(szMsifile);
722 VariantInit(&vararg[0]);
723 V_VT(&vararg[0]) = VT_BSTR;
724 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
725 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
726 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
727 VariantClear(&vararg[0]);
728 VariantClear(&vararg[1]);
729
730 /* Create a proper installer package. */
731 create_package(path);
732
733 /* Try one parameter, the required BSTR. Second parameter is optional.
734 * Proper installer package exists. Path to the package is relative.
735 */
736 dispparams.cArgs = 1;
737 VariantInit(&vararg[0]);
738 V_VT(&vararg[0]) = VT_BSTR;
739 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
740 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
741 todo_wine ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
742 ok_exception(hr, szOpenPackageException);
743 VariantClear(&vararg[0]);
744 if (hr != DISP_E_EXCEPTION)
745 VariantClear(&varresult);
746
747 /* Try one parameter, the required BSTR. Second parameter is optional.
748 * Proper installer package exists. Path to the package is absolute.
749 */
750 dispparams.cArgs = 1;
751 VariantInit(&vararg[0]);
752 V_VT(&vararg[0]) = VT_BSTR;
753 V_BSTR(&vararg[0]) = SysAllocString(path);
754 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
755 if (hr == DISP_E_EXCEPTION)
756 {
757 skip("OpenPackage failed, insufficient rights?\n");
758 DeleteFileW(path);
759 return;
760 }
761 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
762 VariantClear(&vararg[0]);
763 VariantClear(&varresult);
764
765 /* Provide the required BSTR and an empty second parameter. Proper
766 * installation package exists.
767 */
768 dispparams.cArgs = 2;
769 VariantInit(&vararg[1]);
770 V_VT(&vararg[1]) = VT_BSTR;
771 V_BSTR(&vararg[1]) = SysAllocString(path);
772 VariantInit(&vararg[0]);
773 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
774 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
775 VariantClear(&vararg[1]);
776 VariantClear(&varresult);
777
778 /* Provide the required BSTR and two empty parameters. Proper
779 * installation package exists.
780 */
781 dispparams.cArgs = 3;
782 VariantInit(&vararg[2]);
783 V_VT(&vararg[2]) = VT_BSTR;
784 V_BSTR(&vararg[2]) = SysAllocString(path);
785 VariantInit(&vararg[1]);
786 VariantInit(&vararg[0]);
787 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
788 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
789 VariantClear(&vararg[2]);
790 VariantClear(&varresult);
791
792 /* Provide the required BSTR and a second parameter with the wrong type. */
793 dispparams.cArgs = 2;
794 VariantInit(&vararg[1]);
795 V_VT(&vararg[1]) = VT_BSTR;
796 V_BSTR(&vararg[1]) = SysAllocString(path);
797 VariantInit(&vararg[0]);
798 V_VT(&vararg[0]) = VT_BSTR;
799 V_BSTR(&vararg[0]) = SysAllocString(path);
800 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
801 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
802 VariantClear(&vararg[0]);
803 VariantClear(&vararg[1]);
804
805 /* Provide the required BSTR and a second parameter that can be coerced to
806 * VT_I4.
807 */
808 dispparams.cArgs = 2;
809 VariantInit(&vararg[1]);
810 V_VT(&vararg[1]) = VT_BSTR;
811 V_BSTR(&vararg[1]) = SysAllocString(path);
812 VariantInit(&vararg[0]);
813 V_VT(&vararg[0]) = VT_I2;
814 V_BSTR(&vararg[0]) = 0;
815 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
816 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
817 VariantClear(&vararg[1]);
818 VariantClear(&varresult);
819
820 DeleteFileW(path);
821
822 /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
823 VariantInit(&vararg[0]);
824 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
825 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
826
827 VariantInit(&vararg[0]);
828 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
829 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
830
831 /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
832 name = szProductState;
833 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
834 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
835
836 dispparams.rgvarg = NULL;
837 dispparams.cArgs = 0;
838 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
839 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
840
841 dispparams.rgvarg = NULL;
842 dispparams.cArgs = 0;
843 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
844 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
845 }
846
847 /* invocation helper function */
848 static int _invoke_todo_vtResult = 0;
849
850 static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult)
851 {
852 OLECHAR *name = NULL;
853 DISPID dispid;
854 HRESULT hr;
855 UINT i;
856 UINT len;
857
858 memset(pVarResult, 0, sizeof(VARIANT));
859 VariantInit(pVarResult);
860
861 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 );
862 name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
863 if (!name) return E_FAIL;
864 MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len );
865 hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
866 HeapFree(GetProcessHeap(), 0, name);
867 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
868 if (!hr == S_OK) return hr;
869
870 memset(&excepinfo, 0, sizeof(excepinfo));
871 hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL);
872
873 if (hr == S_OK)
874 {
875 if (_invoke_todo_vtResult) todo_wine
876 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
877 else
878 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
879 if (vtResult != VT_EMPTY)
880 {
881 hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult);
882 ok(hr == S_OK, "VariantChangeTypeEx returned 0x%08x\n", hr);
883 }
884 }
885
886 for (i=0; i<pDispParams->cArgs; i++)
887 VariantClear(&pDispParams->rgvarg[i]);
888
889 return hr;
890 }
891
892 /* Object_Property helper functions */
893
894 static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord)
895 {
896 VARIANT varresult;
897 VARIANTARG vararg[1];
898 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
899 HRESULT hr;
900
901 VariantInit(&vararg[0]);
902 V_VT(&vararg[0]) = VT_I4;
903 V_I4(&vararg[0]) = count;
904
905 hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
906 *pRecord = V_DISPATCH(&varresult);
907 return hr;
908 }
909
910 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
911 {
912 VARIANTARG vararg[3];
913 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
914
915 VariantInit(&vararg[2]);
916 V_VT(&vararg[2]) = VT_I4;
917 V_I4(&vararg[2]) = (INT_PTR)hkey;
918 VariantInit(&vararg[1]);
919 V_VT(&vararg[1]) = VT_BSTR;
920 V_BSTR(&vararg[1]) = SysAllocString(szKey);
921 VariantInit(&vararg[0]);
922 VariantCopy(&vararg[0], &vValue);
923 VariantClear(&vValue);
924
925 return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect);
926 }
927
928 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
929 {
930 VARIANT varresult;
931 VARIANTARG vararg;
932 HRESULT hr;
933
934 VariantInit(&vararg);
935 V_VT(&vararg) = VT_EMPTY;
936 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL);
937 *pBool = V_BOOL(&varresult);
938 VariantClear(&varresult);
939 return hr;
940 }
941
942 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
943 {
944 VARIANT varresult;
945 VARIANTARG vararg;
946 HRESULT hr;
947
948 VariantInit(&vararg);
949 V_VT(&vararg) = VT_BSTR;
950 V_BSTR(&vararg) = SysAllocString(szValue);
951
952 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR);
953 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
954 VariantClear(&varresult);
955 return hr;
956 }
957
958 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
959 {
960 VARIANT varresult;
961 VARIANTARG vararg;
962 HRESULT hr;
963
964 VariantInit(&vararg);
965 V_VT(&vararg) = VT_I4;
966 V_I4(&vararg) = iValue;
967
968 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult);
969 if (SUCCEEDED(hr) && vtResult == VT_BSTR) lstrcpyW(szString, V_BSTR(&varresult));
970 VariantClear(&varresult);
971 return hr;
972 }
973
974 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
975 {
976 VARIANT varresult;
977 VARIANTARG vararg[2];
978 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
979 HRESULT hr;
980
981 VariantInit(&vararg[1]);
982 V_VT(&vararg[1]) = VT_BSTR;
983 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
984 VariantInit(&vararg[0]);
985 V_VT(&vararg[0]) = VT_I4;
986 V_I4(&vararg[0]) = options;
987
988 hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
989 *pSession = V_DISPATCH(&varresult);
990 return hr;
991 }
992
993 static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase)
994 {
995 VARIANT varresult;
996 VARIANTARG vararg[2];
997 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
998 HRESULT hr;
999
1000 VariantInit(&vararg[1]);
1001 V_VT(&vararg[1]) = VT_BSTR;
1002 V_BSTR(&vararg[1]) = SysAllocString(szDatabasePath);
1003 VariantInit(&vararg[0]);
1004 V_VT(&vararg[0]) = VT_I4;
1005 V_I4(&vararg[0]) = openmode;
1006
1007 hr = invoke(pInstaller, "OpenDatabase", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1008 *pDatabase = V_DISPATCH(&varresult);
1009 return hr;
1010 }
1011
1012 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
1013 {
1014 VARIANT varresult;
1015 VARIANTARG vararg[2];
1016 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1017
1018 VariantInit(&vararg[1]);
1019 V_VT(&vararg[1]) = VT_BSTR;
1020 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
1021 VariantInit(&vararg[0]);
1022 V_VT(&vararg[0]) = VT_BSTR;
1023 V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues);
1024
1025 return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1026 }
1027
1028 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
1029 {
1030 VARIANT varresult;
1031 VARIANTARG vararg[1];
1032 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1033 HRESULT hr;
1034
1035 VariantInit(&vararg[0]);
1036 V_VT(&vararg[0]) = VT_BSTR;
1037 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
1038
1039 hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1040 *pInstallState = V_I4(&varresult);
1041 VariantClear(&varresult);
1042 return hr;
1043 }
1044
1045 static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szString)
1046 {
1047 VARIANT varresult;
1048 VARIANTARG vararg[2];
1049 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1050 HRESULT hr;
1051
1052 VariantInit(&vararg[1]);
1053 V_VT(&vararg[1]) = VT_BSTR;
1054 V_BSTR(&vararg[1]) = SysAllocString(szProduct);
1055 VariantInit(&vararg[0]);
1056 V_VT(&vararg[0]) = VT_BSTR;
1057 V_BSTR(&vararg[0]) = SysAllocString(szAttribute);
1058
1059 hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1060 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1061 VariantClear(&varresult);
1062 return hr;
1063 }
1064
1065 static HRESULT Installer_Products(IDispatch **pStringList)
1066 {
1067 VARIANT varresult;
1068 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1069 HRESULT hr;
1070
1071 hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1072 *pStringList = V_DISPATCH(&varresult);
1073 return hr;
1074 }
1075
1076 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
1077 {
1078 VARIANT varresult;
1079 VARIANTARG vararg[1];
1080 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1081 HRESULT hr;
1082
1083 VariantInit(&vararg[0]);
1084 V_VT(&vararg[0]) = VT_BSTR;
1085 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
1086
1087 hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1088 *pStringList = V_DISPATCH(&varresult);
1089 return hr;
1090 }
1091
1092 static HRESULT Installer_VersionGet(LPWSTR szVersion)
1093 {
1094 VARIANT varresult;
1095 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1096 HRESULT hr;
1097
1098 hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1099 if (V_BSTR(&varresult)) lstrcpyW(szVersion, V_BSTR(&varresult));
1100 VariantClear(&varresult);
1101 return hr;
1102 }
1103
1104 static HRESULT Installer_UILevelPut(int level)
1105 {
1106 VARIANT varresult;
1107 VARIANTARG vararg;
1108 DISPID dispid = DISPID_PROPERTYPUT;
1109 DISPPARAMS dispparams = {&vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1110
1111 VariantInit(&vararg);
1112 V_VT(&vararg) = VT_I4;
1113 V_I4(&vararg) = level;
1114
1115 return invoke(pInstaller, "UILevel", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1116 }
1117
1118 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
1119 {
1120 VARIANT varresult;
1121 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1122 HRESULT hr;
1123
1124 hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1125 *pInst = V_DISPATCH(&varresult);
1126 return hr;
1127 }
1128
1129 static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn)
1130 {
1131 VARIANT varresult;
1132 VARIANTARG vararg[1];
1133 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1134 HRESULT hr;
1135
1136 VariantInit(&vararg[0]);
1137 V_VT(&vararg[0]) = VT_BSTR;
1138 V_BSTR(&vararg[0]) = SysAllocString(szName);
1139
1140 hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1141 if (V_BSTR(&varresult)) lstrcpyW(szReturn, V_BSTR(&varresult));
1142 VariantClear(&varresult);
1143 return hr;
1144 }
1145
1146 static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue)
1147 {
1148 VARIANT varresult;
1149 VARIANTARG vararg[2];
1150 DISPID dispid = DISPID_PROPERTYPUT;
1151 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1152
1153 VariantInit(&vararg[1]);
1154 V_VT(&vararg[1]) = VT_BSTR;
1155 V_BSTR(&vararg[1]) = SysAllocString(szName);
1156 VariantInit(&vararg[0]);
1157 V_VT(&vararg[0]) = VT_BSTR;
1158 V_BSTR(&vararg[0]) = SysAllocString(szValue);
1159
1160 return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1161 }
1162
1163 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
1164 {
1165 VARIANT varresult;
1166 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1167 HRESULT hr;
1168
1169 hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1170 *pLangId = V_I4(&varresult);
1171 VariantClear(&varresult);
1172 return hr;
1173 }
1174
1175 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, BOOL *pMode)
1176 {
1177 VARIANT varresult;
1178 VARIANTARG vararg[1];
1179 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1180 HRESULT hr;
1181
1182 VariantInit(&vararg[0]);
1183 V_VT(&vararg[0]) = VT_I4;
1184 V_I4(&vararg[0]) = iFlag;
1185
1186 hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL);
1187 *pMode = V_BOOL(&varresult);
1188 VariantClear(&varresult);
1189 return hr;
1190 }
1191
1192 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, BOOL bMode)
1193 {
1194 VARIANT varresult;
1195 VARIANTARG vararg[2];
1196 DISPID dispid = DISPID_PROPERTYPUT;
1197 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1198
1199 VariantInit(&vararg[1]);
1200 V_VT(&vararg[1]) = VT_I4;
1201 V_I4(&vararg[1]) = iFlag;
1202 VariantInit(&vararg[0]);
1203 V_VT(&vararg[0]) = VT_BOOL;
1204 V_BOOL(&vararg[0]) = bMode;
1205
1206 return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1207 }
1208
1209 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
1210 {
1211 VARIANT varresult;
1212 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1213 HRESULT hr;
1214
1215 hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1216 *pDatabase = V_DISPATCH(&varresult);
1217 return hr;
1218 }
1219
1220 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn)
1221 {
1222 VARIANT varresult;
1223 VARIANTARG vararg[1];
1224 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1225 HRESULT hr;
1226
1227 VariantInit(&vararg[0]);
1228 V_VT(&vararg[0]) = VT_BSTR;
1229 V_BSTR(&vararg[0]) = SysAllocString(szAction);
1230
1231 hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1232 *iReturn = V_I4(&varresult);
1233 VariantClear(&varresult);
1234 return hr;
1235 }
1236
1237 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
1238 {
1239 VARIANT varresult;
1240 VARIANTARG vararg[1];
1241 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1242 HRESULT hr;
1243
1244 VariantInit(&vararg[0]);
1245 V_VT(&vararg[0]) = VT_BSTR;
1246 V_BSTR(&vararg[0]) = SysAllocString(szCondition);
1247
1248 hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1249 *iReturn = V_I4(&varresult);
1250 VariantClear(&varresult);
1251 return hr;
1252 }
1253
1254 static HRESULT Session_Message(IDispatch *pSession, LONG kind, IDispatch *record, int *ret)
1255 {
1256 VARIANT varresult;
1257 VARIANTARG vararg[2];
1258 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1259 HRESULT hr;
1260
1261 VariantInit(&varresult);
1262 V_VT(vararg) = VT_DISPATCH;
1263 V_DISPATCH(vararg) = record;
1264 V_VT(vararg+1) = VT_I4;
1265 V_I4(vararg+1) = kind;
1266
1267 hr = invoke(pSession, "Message", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1268
1269 ok(V_VT(&varresult) == VT_I4, "V_VT(varresult) = %d\n", V_VT(&varresult));
1270 *ret = V_I4(&varresult);
1271
1272 return hr;
1273 }
1274
1275 static HRESULT Session_SetInstallLevel(IDispatch *pSession, LONG iInstallLevel)
1276 {
1277 VARIANT varresult;
1278 VARIANTARG vararg[1];
1279 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1280
1281 VariantInit(&vararg[0]);
1282 V_VT(&vararg[0]) = VT_I4;
1283 V_I4(&vararg[0]) = iInstallLevel;
1284
1285 return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1286 }
1287
1288 static HRESULT Session_FeatureCurrentState(IDispatch *pSession, LPCWSTR szName, int *pState)
1289 {
1290 VARIANT varresult;
1291 VARIANTARG vararg[1];
1292 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1293 HRESULT hr;
1294
1295 VariantInit(&vararg[0]);
1296 V_VT(&vararg[0]) = VT_BSTR;
1297 V_BSTR(&vararg[0]) = SysAllocString(szName);
1298
1299 hr = invoke(pSession, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1300 *pState = V_I4(&varresult);
1301 VariantClear(&varresult);
1302 return hr;
1303 }
1304
1305 static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState)
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(szName);
1315
1316 hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1317 *pState = V_I4(&varresult);
1318 VariantClear(&varresult);
1319 return hr;
1320 }
1321
1322 static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState)
1323 {
1324 VARIANT varresult;
1325 VARIANTARG vararg[2];
1326 DISPID dispid = DISPID_PROPERTYPUT;
1327 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1328
1329 VariantInit(&vararg[1]);
1330 V_VT(&vararg[1]) = VT_BSTR;
1331 V_BSTR(&vararg[1]) = SysAllocString(szName);
1332 VariantInit(&vararg[0]);
1333 V_VT(&vararg[0]) = VT_I4;
1334 V_I4(&vararg[0]) = iState;
1335
1336 return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1337 }
1338
1339 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
1340 {
1341 VARIANT varresult;
1342 VARIANTARG vararg[1];
1343 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1344 HRESULT hr;
1345
1346 VariantInit(&vararg[0]);
1347 V_VT(&vararg[0]) = VT_BSTR;
1348 V_BSTR(&vararg[0]) = SysAllocString(szSql);
1349
1350 hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1351 *pView = V_DISPATCH(&varresult);
1352 return hr;
1353 }
1354
1355 static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo)
1356 {
1357 VARIANT varresult;
1358 VARIANTARG vararg[1];
1359 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1360 HRESULT hr;
1361
1362 VariantInit(&vararg[0]);
1363 V_VT(&vararg[0]) = VT_I4;
1364 V_I4(&vararg[0]) = iUpdateCount;
1365
1366 hr = invoke(pDatabase, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1367 *pSummaryInfo = V_DISPATCH(&varresult);
1368 return hr;
1369 }
1370
1371 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
1372 {
1373 VARIANT varresult;
1374 VARIANTARG vararg[1];
1375 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1376
1377 VariantInit(&vararg[0]);
1378 V_VT(&vararg[0]) = VT_DISPATCH;
1379 V_DISPATCH(&vararg[0]) = pRecord;
1380
1381 return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1382 }
1383
1384 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
1385 {
1386 VARIANT varresult;
1387 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1388 HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1389 *ppRecord = V_DISPATCH(&varresult);
1390 return hr;
1391 }
1392
1393 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
1394 {
1395 VARIANT varresult;
1396 VARIANTARG vararg[2];
1397 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1398
1399 VariantInit(&vararg[1]);
1400 V_VT(&vararg[1]) = VT_I4;
1401 V_I4(&vararg[1]) = iMode;
1402 VariantInit(&vararg[0]);
1403 V_VT(&vararg[0]) = VT_DISPATCH;
1404 V_DISPATCH(&vararg[0]) = pRecord;
1405 if (pRecord)
1406 IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */
1407
1408 return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1409 }
1410
1411 static HRESULT View_Close(IDispatch *pView)
1412 {
1413 VARIANT varresult;
1414 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1415 return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1416 }
1417
1418 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
1419 {
1420 VARIANT varresult;
1421 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1422 HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1423 *pFieldCount = V_I4(&varresult);
1424 VariantClear(&varresult);
1425 return hr;
1426 }
1427
1428 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString)
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, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1440 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1441 VariantClear(&varresult);
1442 return hr;
1443 }
1444
1445 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
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_BSTR;
1457 V_BSTR(&vararg[0]) = SysAllocString(szString);
1458
1459 return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1460 }
1461
1462 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
1463 {
1464 VARIANT varresult;
1465 VARIANTARG vararg[1];
1466 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1467 HRESULT hr;
1468
1469 VariantInit(&vararg[0]);
1470 V_VT(&vararg[0]) = VT_I4;
1471 V_I4(&vararg[0]) = iField;
1472
1473 hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1474 *pValue = V_I4(&varresult);
1475 VariantClear(&varresult);
1476 return hr;
1477 }
1478
1479 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
1480 {
1481 VARIANT varresult;
1482 VARIANTARG vararg[2];
1483 DISPID dispid = DISPID_PROPERTYPUT;
1484 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1485
1486 VariantInit(&vararg[1]);
1487 V_VT(&vararg[1]) = VT_I4;
1488 V_I4(&vararg[1]) = iField;
1489 VariantInit(&vararg[0]);
1490 V_VT(&vararg[0]) = VT_I4;
1491 V_I4(&vararg[0]) = iValue;
1492
1493 return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1494 }
1495
1496 static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT)
1497 {
1498 VARIANT varresult;
1499 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1500 HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN);
1501 *ppEnumVARIANT = V_UNKNOWN(&varresult);
1502 return hr;
1503 }
1504
1505 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
1506 {
1507 VARIANT varresult;
1508 VARIANTARG vararg[1];
1509 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1510 HRESULT hr;
1511
1512 VariantInit(&vararg[0]);
1513 V_VT(&vararg[0]) = VT_I4;
1514 V_I4(&vararg[0]) = iIndex;
1515
1516 hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1517 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1518 VariantClear(&varresult);
1519 return hr;
1520 }
1521
1522 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
1523 {
1524 VARIANT varresult;
1525 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1526 HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1527 *pCount = V_I4(&varresult);
1528 VariantClear(&varresult);
1529 return hr;
1530 }
1531
1532 static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect)
1533 {
1534 VARIANTARG vararg[1];
1535 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1536
1537 VariantInit(&vararg[0]);
1538 V_VT(&vararg[0]) = VT_I4;
1539 V_I4(&vararg[0]) = pid;
1540 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYGET, &dispparams, pVarResult, vtExpect);
1541 }
1542
1543 static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant)
1544 {
1545 VARIANT varresult;
1546 VARIANTARG vararg[2];
1547 DISPID dispid = DISPID_PROPERTYPUT;
1548 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1549
1550 VariantInit(&vararg[1]);
1551 V_VT(&vararg[1]) = VT_I4;
1552 V_I4(&vararg[1]) = pid;
1553 VariantInit(&vararg[0]);
1554 VariantCopyInd(vararg, pVariant);
1555
1556 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1557 }
1558
1559 static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount)
1560 {
1561 VARIANT varresult;
1562 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1563 HRESULT hr;
1564
1565 hr = invoke(pSummaryInfo, "PropertyCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1566 *pCount = V_I4(&varresult);
1567 VariantClear(&varresult);
1568 return hr;
1569 }
1570
1571 /* Test the various objects */
1572
1573 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4
1574
1575 static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly)
1576 {
1577 static const WCHAR szPropertyException[] = { 'P','r','o','p','e','r','t','y',',','P','i','d',0 };
1578 static const WCHAR szTitle[] = { 'T','i','t','l','e',0 };
1579 VARIANT varresult, var;
1580 SYSTEMTIME st;
1581 HRESULT hr;
1582 int j;
1583
1584 /* SummaryInfo::PropertyCount */
1585 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1586 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1587 ok(j == num_info, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1588
1589 /* SummaryInfo::Property, get for properties we have set */
1590 for (j = 0; j < num_info; j++)
1591 {
1592 const msi_summary_info *entry = &info[j];
1593
1594 int vt = entry->datatype;
1595 if (vt == VT_LPSTR) vt = VT_BSTR;
1596 else if (vt == VT_FILETIME) vt = VT_DATE;
1597 else if (vt == VT_I2) vt = VT_I4;
1598
1599 hr = SummaryInfo_PropertyGet(pSummaryInfo, entry->property, &varresult, vt);
1600 ok(hr == S_OK, "SummaryInfo_Property (pid %d) failed, hresult 0x%08x\n", entry->property, hr);
1601 if (V_VT(&varresult) != vt)
1602 skip("Skipping property tests due to type mismatch\n");
1603 else if (vt == VT_I4)
1604 ok(V_I4(&varresult) == entry->iValue, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %d\n",
1605 entry->property, entry->iValue, V_I4(&varresult));
1606 else if (vt == VT_DATE)
1607 {
1608 FILETIME ft;
1609 DATE d;
1610
1611 FileTimeToLocalFileTime(entry->pftValue, &ft);
1612 FileTimeToSystemTime(&ft, &st);
1613 SystemTimeToVariantTime(&st, &d);
1614 ok(d == V_DATE(&varresult), "SummaryInfo_Property (pid %d) DATE result expected to be %lf, but was %lf\n", entry->property, d, V_DATE(&varresult));
1615 }
1616 else if (vt == VT_BSTR)
1617 {
1618 ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry->property, entry->szValue, V_BSTR(&varresult));
1619 }
1620 else
1621 skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry->property, vt);
1622
1623 VariantClear(&varresult);
1624 }
1625
1626 /* SummaryInfo::Property, get; invalid arguments */
1627
1628 /* Invalid pids */
1629 hr = SummaryInfo_PropertyGet(pSummaryInfo, -1, &varresult, VT_EMPTY);
1630 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1631 ok_exception(hr, szPropertyException);
1632
1633 hr = SummaryInfo_PropertyGet(pSummaryInfo, 1000, &varresult, VT_EMPTY);
1634 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1635 ok_exception(hr, szPropertyException);
1636
1637 /* Unsupported pids */
1638 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_DICTIONARY, &varresult, VT_EMPTY);
1639 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1640
1641 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY);
1642 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1643
1644 /* Pids we have not set, one for each type */
1645 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_EMPTY);
1646 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1647
1648 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY);
1649 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1650
1651 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY);
1652 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1653
1654 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY);
1655 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1656
1657 if (!readonly)
1658 {
1659 /* SummaryInfo::Property, put; one for each type */
1660
1661 /* VT_I2 */
1662 VariantInit(&var);
1663 V_VT(&var) = VT_I2;
1664 V_I2(&var) = 1;
1665 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CODEPAGE, &var);
1666 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1667
1668 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */);
1669 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1670 ok(V_I2(&var) == V_I2(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var), V_I2(&varresult));
1671 VariantClear(&varresult);
1672 VariantClear(&var);
1673
1674 /* VT_BSTR */
1675 V_VT(&var) = VT_BSTR;
1676 V_BSTR(&var) = SysAllocString(szTitle);
1677 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_TITLE, &var);
1678 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1679
1680 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var));
1681 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1682 ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var), V_BSTR(&varresult));
1683 VariantClear(&varresult);
1684 VariantClear(&var);
1685
1686 /* VT_DATE */
1687 V_VT(&var) = VT_DATE;
1688 FileTimeToSystemTime(&systemtime, &st);
1689 SystemTimeToVariantTime(&st, &V_DATE(&var));
1690 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_LASTSAVE_DTM, &var);
1691 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1692
1693 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var));
1694 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1695 ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1696 VariantClear(&varresult);
1697 VariantClear(&var);
1698
1699 /* VT_I4 */
1700 V_VT(&var) = VT_I4;
1701 V_I4(&var) = 1000;
1702 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1703 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1704
1705 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1706 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1707 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult));
1708 VariantClear(&varresult);
1709 VariantClear(&var);
1710
1711 /* SummaryInfo::PropertyCount */
1712 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1713 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1714 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1715 }
1716 }
1717
1718 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1719 {
1720 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 };
1721 static WCHAR szThree[] = { 'T','h','r','e','e',0 };
1722 static WCHAR szTwo[] = { 'T','w','o',0 };
1723 static WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
1724 static WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 };
1725 IDispatch *pView = NULL, *pSummaryInfo = NULL;
1726 HRESULT hr;
1727
1728 hr = Database_OpenView(pDatabase, szSql, &pView);
1729 ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr);
1730 if (hr == S_OK)
1731 {
1732 IDispatch *pRecord = NULL;
1733 WCHAR szString[MAX_PATH];
1734
1735 /* View::Execute */
1736 hr = View_Execute(pView, NULL);
1737 ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr);
1738
1739 /* View::Fetch */
1740 hr = View_Fetch(pView, &pRecord);
1741 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1742 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1743 if (pRecord)
1744 {
1745 /* Record::StringDataGet */
1746 memset(szString, 0, sizeof(szString));
1747 hr = Record_StringDataGet(pRecord, 1, szString);
1748 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1749 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1750
1751 /* Record::StringDataPut with correct index */
1752 hr = Record_StringDataPut(pRecord, 1, szTwo);
1753 ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1754
1755 /* Record::StringDataGet */
1756 memset(szString, 0, sizeof(szString));
1757 hr = Record_StringDataGet(pRecord, 1, szString);
1758 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1759 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1760
1761 /* Record::StringDataPut with incorrect index */
1762 hr = Record_StringDataPut(pRecord, -1, szString);
1763 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1764 ok_exception(hr, szStringDataField);
1765
1766 /* View::Modify with incorrect parameters */
1767 hr = View_Modify(pView, -5, NULL);
1768 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1769 ok_exception(hr, szModifyModeRecord);
1770
1771 hr = View_Modify(pView, -5, pRecord);
1772 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1773 ok_exception(hr, szModifyModeRecord);
1774
1775 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1776 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1777 ok_exception(hr, szModifyModeRecord);
1778
1779 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1780 ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr);
1781
1782 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1783 memset(szString, 0, sizeof(szString));
1784 hr = Record_StringDataGet(pRecord, 1, szString);
1785 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1786 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1787
1788 IDispatch_Release(pRecord);
1789 }
1790
1791 /* View::Fetch */
1792 hr = View_Fetch(pView, &pRecord);
1793 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1794 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1795 if (pRecord)
1796 {
1797 /* Record::StringDataGet */
1798 memset(szString, 0, sizeof(szString));
1799 hr = Record_StringDataGet(pRecord, 1, szString);
1800 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1801 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1802
1803 IDispatch_Release(pRecord);
1804 }
1805
1806 /* View::Fetch */
1807 hr = View_Fetch(pView, &pRecord);
1808 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1809 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1810 if (pRecord)
1811 IDispatch_Release(pRecord);
1812
1813 /* View::Close */
1814 hr = View_Close(pView);
1815 ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr);
1816
1817 IDispatch_Release(pView);
1818 }
1819
1820 /* Database::SummaryInformation */
1821 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo);
1822 ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr);
1823 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1824 if (pSummaryInfo)
1825 {
1826 test_SummaryInfo(pSummaryInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), readonly);
1827 IDispatch_Release(pSummaryInfo);
1828 }
1829 }
1830
1831 static void test_Session(IDispatch *pSession)
1832 {
1833 static WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
1834 static WCHAR szOne[] = { 'O','n','e',0 };
1835 static WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 };
1836 static WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 };
1837 static WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 };
1838 static WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 };
1839 static WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1840 static WCHAR szEmpty[] = { 0 };
1841 static WCHAR szEquals[] = { '=',0 };
1842 static WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
1843 static WCHAR szModeFlag[] = { 'M','o','d','e',',','F','l','a','g',0 };
1844 WCHAR stringw[MAX_PATH];
1845 CHAR string[MAX_PATH];
1846 UINT len;
1847 BOOL bool;
1848 int myint;
1849 IDispatch *pDatabase = NULL, *pInst = NULL, *record = NULL;
1850 ULONG refs_before, refs_after;
1851 HRESULT hr;
1852
1853 /* Session::Installer */
1854 hr = Session_Installer(pSession, &pInst);
1855 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1856 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1857 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1858 refs_before = IDispatch_AddRef(pInst);
1859
1860 hr = Session_Installer(pSession, &pInst);
1861 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1862 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1863 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1864 refs_after = IDispatch_Release(pInst);
1865 ok(refs_before == refs_after, "got %u and %u\n", refs_before, refs_after);
1866
1867 /* Session::Property, get */
1868 memset(stringw, 0, sizeof(stringw));
1869 hr = Session_PropertyGet(pSession, szProductName, stringw);
1870 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1871 if (lstrcmpW(stringw, szMSITEST) != 0)
1872 {
1873 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1874 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1875 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1876 }
1877
1878 /* Session::Property, put */
1879 hr = Session_PropertyPut(pSession, szProductName, szProductName);
1880 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1881 memset(stringw, 0, sizeof(stringw));
1882 hr = Session_PropertyGet(pSession, szProductName, stringw);
1883 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1884 if (lstrcmpW(stringw, szProductName) != 0)
1885 {
1886 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1887 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1888 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1889 }
1890
1891 /* Try putting a property using empty property identifier */
1892 hr = Session_PropertyPut(pSession, szEmpty, szProductName);
1893 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1894 ok_exception(hr, szPropertyName);
1895
1896 /* Try putting a property using illegal property identifier */
1897 hr = Session_PropertyPut(pSession, szEquals, szProductName);
1898 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1899
1900 /* Session::Language, get */
1901 hr = Session_LanguageGet(pSession, &len);
1902 ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1903 /* Not sure how to check the language is correct */
1904
1905 /* Session::Mode, get */
1906 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1907 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1908 ok(!bool, "Reboot at end session mode is %d\n", bool);
1909
1910 hr = Session_ModeGet(pSession, MSIRUNMODE_MAINTENANCE, &bool);
1911 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1912 ok(!bool, "Maintenance mode is %d\n", bool);
1913
1914 /* Session::Mode, put */
1915 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE);
1916 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1917 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1918 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1919 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1920 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE); /* set it again so we don't reboot */
1921 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1922
1923 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, TRUE);
1924 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1925 if (hr == DISP_E_EXCEPTION) ok_exception(hr, szModeFlag);
1926
1927 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTNOW, &bool);
1928 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1929 ok(bool, "Reboot now mode is %d, expected 1\n", bool);
1930
1931 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, FALSE); /* set it again so we don't reboot */
1932 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1933 if (hr == DISP_E_EXCEPTION) ok_exception(hr, szModeFlag);
1934
1935 hr = Session_ModePut(pSession, MSIRUNMODE_MAINTENANCE, TRUE);
1936 ok(hr == DISP_E_EXCEPTION, "Session_ModePut failed, hresult 0x%08x\n", hr);
1937 ok_exception(hr, szModeFlag);
1938
1939 /* Session::Database, get */
1940 hr = Session_Database(pSession, &pDatabase);
1941 ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr);
1942 if (hr == S_OK)
1943 {
1944 test_Database(pDatabase, TRUE);
1945 IDispatch_Release(pDatabase);
1946 }
1947
1948 /* Session::EvaluateCondition */
1949 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1950 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1951 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1952
1953 hr = Session_EvaluateCondition(pSession, szEmpty, &myint);
1954 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1955 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1956
1957 hr = Session_EvaluateCondition(pSession, szEquals, &myint);
1958 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1959 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1960
1961 /* Session::DoAction(CostInitialize) must occur before the next statements */
1962 hr = Session_DoAction(pSession, szCostInitialize, &myint);
1963 ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr);
1964 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1965
1966 /* Session::SetInstallLevel */
1967 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1968 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
1969
1970 /* Session::FeatureCurrentState, get */
1971 hr = Session_FeatureCurrentState(pSession, szOne, &myint);
1972 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
1973 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1974
1975 /* Session::Message */
1976 hr = Installer_CreateRecord(0, &record);
1977 ok(hr == S_OK, "Installer_CreateRecord failed: %08x\n", hr);
1978 hr = Session_Message(pSession, INSTALLMESSAGE_INFO, record, &myint);
1979 ok(hr == S_OK, "Session_Message failed: %08x\n", hr);
1980 ok(myint == 0, "Session_Message returned %x\n", myint);
1981
1982 /* Session::EvaluateCondition */
1983 hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint);
1984 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1985 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1986
1987 hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint);
1988 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1989 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1990
1991 /* Session::FeatureRequestState, put */
1992 hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED);
1993 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
1994 hr = Session_FeatureRequestStateGet(pSession, szOne, &myint);
1995 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
1996 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
1997
1998 /* Session::EvaluateCondition */
1999 hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint);
2000 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2001 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2002
2003 hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint);
2004 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2005 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2006 }
2007
2008 /* delete key and all its subkeys */
2009 static DWORD delete_key( HKEY hkey )
2010 {
2011 char name[MAX_PATH];
2012 DWORD ret;
2013
2014 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
2015 {
2016 HKEY tmp;
2017 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
2018 {
2019 ret = delete_key( tmp );
2020 RegCloseKey( tmp );
2021 }
2022 if (ret) break;
2023 }
2024 if (ret != ERROR_NO_MORE_ITEMS) return ret;
2025 RegDeleteKeyA( hkey, "" );
2026 return 0;
2027 }
2028
2029 static void test_Installer_RegistryValue(void)
2030 {
2031 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
2032 static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 };
2033 static const WCHAR szOne[] = { 'O','n','e',0 };
2034 static const WCHAR szTwo[] = { 'T','w','o',0 };
2035 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
2036 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
2037 static const WCHAR szFour[] = { 'F','o','u','r',0 };
2038 static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 };
2039 static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 };
2040 static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 };
2041 static const WCHAR szSix[] = { 'S','i','x',0 };
2042 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
2043 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
2044 static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
2045 static const WCHAR szBlank[] = { 0 };
2046 VARIANT varresult;
2047 VARIANTARG vararg;
2048 WCHAR szString[MAX_PATH];
2049 HKEY hkey, hkey_sub;
2050 HKEY curr_user = (HKEY)1;
2051 HRESULT hr;
2052 BOOL bRet;
2053 LONG lRet;
2054
2055 /* Delete keys */
2056 SetLastError(0xdeadbeef);
2057 lRet = RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey );
2058 if (!lRet && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2059 {
2060 win_skip("Needed W-functions are not implemented\n");
2061 return;
2062 }
2063 if (!lRet)
2064 delete_key( hkey );
2065
2066 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
2067 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
2068 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
2069 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
2070
2071 memset(szString, 0, sizeof(szString));
2072 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
2073 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2074
2075 memset(szString, 0, sizeof(szString));
2076 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
2077 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2078
2079 /* Create key */
2080 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
2081
2082 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
2083 "RegSetValueExW failed\n");
2084 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
2085 "RegSetValueExW failed\n");
2086 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
2087 "RegSetValueExW failed\n");
2088 bRet = SetEnvironmentVariableA("MSITEST", "Four");
2089 ok(bRet, "SetEnvironmentVariableA failed %d\n", GetLastError());
2090 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
2091 "RegSetValueExW failed\n");
2092 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
2093 "RegSetValueExW failed\n");
2094 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
2095 "RegSetValueExW failed\n");
2096 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, NULL, 0),
2097 "RegSetValueExW failed\n");
2098
2099 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
2100 "RegSetValueExW failed\n");
2101
2102 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
2103
2104 /* Does our key exist? It should, and make sure we retrieve the correct default value */
2105 bRet = FALSE;
2106 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
2107 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
2108 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
2109
2110 memset(szString, 0, sizeof(szString));
2111 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
2112 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2113 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
2114
2115 /* Ask for the value of a nonexistent key */
2116 memset(szString, 0, sizeof(szString));
2117 hr = Installer_RegistryValueW(curr_user, szKey, szExpand, szString);
2118 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2119
2120 /* Get values of keys */
2121 memset(szString, 0, sizeof(szString));
2122 hr = Installer_RegistryValueW(curr_user, szKey, szOne, szString);
2123 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2124 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
2125
2126 VariantInit(&vararg);
2127 V_VT(&vararg) = VT_BSTR;
2128 V_BSTR(&vararg) = SysAllocString(szTwo);
2129 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_I4);
2130 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
2131 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
2132 VariantClear(&varresult);
2133
2134 memset(szString, 0, sizeof(szString));
2135 hr = Installer_RegistryValueW(curr_user, szKey, szThree, szString);
2136 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2137 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
2138
2139 memset(szString, 0, sizeof(szString));
2140 hr = Installer_RegistryValueW(curr_user, szKey, szFour, szString);
2141 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2142 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
2143
2144 /* Vista does not NULL-terminate this case */
2145 memset(szString, 0, sizeof(szString));
2146 hr = Installer_RegistryValueW(curr_user, szKey, szFive, szString);
2147 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2148 ok_w2n("Registry value \"%s\" does not match expected \"%s\"\n",
2149 szString, szFiveHi, lstrlenW(szFiveHi));
2150
2151 memset(szString, 0, sizeof(szString));
2152 hr = Installer_RegistryValueW(curr_user, szKey, szSix, szString);
2153 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2154 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_);
2155
2156 VariantInit(&vararg);
2157 V_VT(&vararg) = VT_BSTR;
2158 V_BSTR(&vararg) = SysAllocString(szSeven);
2159 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_EMPTY);
2160 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
2161
2162 /* Get string class name for the key */
2163 memset(szString, 0, sizeof(szString));
2164 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
2165 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2166 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank);
2167
2168 /* Get name of a value by positive number (RegEnumValue like), valid index */
2169 memset(szString, 0, sizeof(szString));
2170 hr = Installer_RegistryValueI(curr_user, szKey, 2, szString, VT_BSTR);
2171 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2172 /* RegEnumValue order seems different on wine */
2173 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
2174
2175 /* Get name of a value by positive number (RegEnumValue like), invalid index */
2176 memset(szString, 0, sizeof(szString));
2177 hr = Installer_RegistryValueI(curr_user, szKey, 10, szString, VT_EMPTY);
2178 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2179
2180 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
2181 memset(szString, 0, sizeof(szString));
2182 hr = Installer_RegistryValueI(curr_user, szKey, -1, szString, VT_BSTR);
2183 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2184 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
2185
2186 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
2187 memset(szString, 0, sizeof(szString));
2188 hr = Installer_RegistryValueI(curr_user, szKey, -10, szString, VT_EMPTY);
2189 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2190
2191 /* clean up */
2192 delete_key(hkey);
2193 }
2194
2195 static void test_Installer_Products(BOOL bProductInstalled)
2196 {
2197 WCHAR szString[MAX_PATH];
2198 HRESULT hr;
2199 int idx;
2200 IUnknown *pUnk = NULL;
2201 IEnumVARIANT *pEnum = NULL;
2202 VARIANT var;
2203 ULONG celt;
2204 int iCount, iValue;
2205 IDispatch *pStringList = NULL;
2206 BOOL bProductFound = FALSE;
2207
2208 /* Installer::Products */
2209 hr = Installer_Products(&pStringList);
2210 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
2211 if (hr == S_OK)
2212 {
2213 /* StringList::_NewEnum */
2214 hr = StringList__NewEnum(pStringList, &pUnk);
2215 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
2216 if (hr == S_OK)
2217 {
2218 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
2219 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2220 }
2221 if (!pEnum)
2222 skip("IEnumVARIANT tests\n");
2223
2224 /* StringList::Count */
2225 hr = StringList_Count(pStringList, &iCount);
2226 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2227
2228 for (idx=0; idx<iCount; idx++)
2229 {
2230 /* StringList::Item */
2231 memset(szString, 0, sizeof(szString));
2232 hr = StringList_Item(pStringList, idx, szString);
2233 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2234
2235 if (hr == S_OK)
2236 {
2237 /* Installer::ProductState */
2238 hr = Installer_ProductState(szString, &iValue);
2239 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2240 if (hr == S_OK)
2241 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
2242
2243 /* Not found our product code yet? Check */
2244 if (!bProductFound && !lstrcmpW(szString, szProductCode))
2245 bProductFound = TRUE;
2246
2247 /* IEnumVARIANT::Next */
2248 if (pEnum)
2249 {
2250 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2251 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2252 ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
2253 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2254 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2255 VariantClear(&var);
2256 }
2257 }
2258 }
2259
2260 if (bProductInstalled)
2261 {
2262 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
2263 bProductInstalled ? "be" : "not be",
2264 bProductFound ? "found" : "not found");
2265 }
2266
2267 if (pEnum)
2268 {
2269 IEnumVARIANT *pEnum2 = NULL;
2270
2271 if (0) /* Crashes on Windows XP */
2272 {
2273 /* IEnumVARIANT::Clone, NULL pointer */
2274 IEnumVARIANT_Clone(pEnum, NULL);
2275 }
2276
2277 /* IEnumVARIANT::Clone */
2278 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
2279 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
2280 if (hr == S_OK)
2281 {
2282 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
2283
2284 /* IEnumVARIANT::Next of the clone */
2285 if (iCount)
2286 {
2287 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
2288 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2289 ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
2290 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2291 VariantClear(&var);
2292 }
2293 else
2294 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
2295
2296 IEnumVARIANT_Release(pEnum2);
2297 }
2298
2299 /* IEnumVARIANT::Skip should fail */
2300 hr = IEnumVARIANT_Skip(pEnum, 1);
2301 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2302
2303 /* IEnumVARIANT::Next, NULL variant pointer */
2304 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2305 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2306 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2307
2308 /* IEnumVARIANT::Next, should not return any more items */
2309 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2310 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2311 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2312 VariantClear(&var);
2313
2314 /* IEnumVARIANT::Reset */
2315 hr = IEnumVARIANT_Reset(pEnum);
2316 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2317
2318 if (iCount)
2319 {
2320 /* IEnumVARIANT::Skip to the last product */
2321 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2322 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2323
2324 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2325 * NULL celt pointer. */
2326 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2327 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2328 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2329 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2330 VariantClear(&var);
2331 }
2332 else
2333 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2334 }
2335
2336 /* StringList::Item using an invalid index */
2337 memset(szString, 0, sizeof(szString));
2338 hr = StringList_Item(pStringList, iCount, szString);
2339 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2340
2341 if (pEnum) IEnumVARIANT_Release(pEnum);
2342 if (pUnk) IUnknown_Release(pUnk);
2343 IDispatch_Release(pStringList);
2344 }
2345 }
2346
2347 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2348 * deleting the subkeys first) */
2349 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey, REGSAM access)
2350 {
2351 UINT ret;
2352 CHAR *string = NULL;
2353 HKEY hkey;
2354 DWORD dwSize;
2355
2356 ret = RegOpenKeyEx(hkeyParent, subkey, 0, access, &hkey);
2357 if (ret != ERROR_SUCCESS) return ret;
2358 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2359 if (ret != ERROR_SUCCESS) return ret;
2360 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2361
2362 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2363 delete_registry_key(hkey, string, access);
2364
2365 RegCloseKey(hkey);
2366 HeapFree(GetProcessHeap(), 0, string);
2367 delete_key_portable(hkeyParent, subkey, access);
2368 return ERROR_SUCCESS;
2369 }
2370
2371 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2372 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, REGSAM access, HKEY *phkey)
2373 {
2374 UINT ret;
2375 CHAR *string = NULL;
2376 int idx = 0;
2377 HKEY hkey;
2378 DWORD dwSize;
2379 BOOL found = FALSE;
2380
2381 *phkey = 0;
2382
2383 ret = RegOpenKeyEx(hkeyParent, subkey, 0, access, &hkey);
2384 if (ret != ERROR_SUCCESS) return ret;
2385 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2386 if (ret != ERROR_SUCCESS) return ret;
2387 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2388
2389 while (!found &&
2390 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2391 {
2392 if (!strcmp(string, findkey))
2393 {
2394 *phkey = hkey;
2395 found = TRUE;
2396 }
2397 else if (find_registry_key(hkey, string, findkey, access, phkey) == ERROR_SUCCESS) found = TRUE;
2398 }
2399
2400 if (*phkey != hkey) RegCloseKey(hkey);
2401 HeapFree(GetProcessHeap(), 0, string);
2402 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2403 }
2404
2405 static void test_Installer_InstallProduct(void)
2406 {
2407 HRESULT hr;
2408 CHAR path[MAX_PATH];
2409 WCHAR szString[MAX_PATH];
2410 LONG res;
2411 HKEY hkey;
2412 DWORD num, size, type;
2413 int iValue, iCount;
2414 IDispatch *pStringList = NULL;
2415 REGSAM access = KEY_ALL_ACCESS;
2416
2417 if (is_wow64)
2418 access |= KEY_WOW64_64KEY;
2419
2420 create_test_files();
2421
2422 /* Avoid an interactive dialog in case of insufficient privileges. */
2423 hr = Installer_UILevelPut(INSTALLUILEVEL_NONE);
2424 ok(hr == S_OK, "Expected UILevel property put invoke to return S_OK, got 0x%08x\n", hr);
2425
2426 /* Installer::InstallProduct */
2427 hr = Installer_InstallProduct(szMsifile, NULL);
2428 if (hr == DISP_E_EXCEPTION)
2429 {
2430 skip("InstallProduct failed, insufficient rights?\n");
2431 delete_test_files();
2432 return;
2433 }
2434 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2435
2436 /* Installer::ProductState for our product code, which has been installed */
2437 hr = Installer_ProductState(szProductCode, &iValue);
2438 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2439 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2440
2441 /* Installer::ProductInfo for our product code */
2442
2443 /* NULL attribute */
2444 memset(szString, 0, sizeof(szString));
2445 hr = Installer_ProductInfo(szProductCode, NULL, szString);
2446 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2447 ok_exception(hr, szProductInfoException);
2448
2449 /* Nonexistent attribute */
2450 memset(szString, 0, sizeof(szString));
2451 hr = Installer_ProductInfo(szProductCode, szMsifile, szString);
2452 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2453 ok_exception(hr, szProductInfoException);
2454
2455 /* Package name */
2456 memset(szString, 0, sizeof(szString));
2457 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szString);
2458 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2459 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile);
2460
2461 /* Product name */
2462 memset(szString, 0, sizeof(szString));
2463 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PRODUCTNAMEW, szString);
2464 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2465 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST);
2466
2467 /* Installer::Products */
2468 test_Installer_Products(TRUE);
2469
2470 /* Installer::RelatedProducts for our upgrade code */
2471 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2472 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2473 if (hr == S_OK)
2474 {
2475 /* StringList::Count */
2476 hr = StringList_Count(pStringList, &iCount);
2477 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2478 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2479
2480 /* StringList::Item */
2481 memset(szString, 0, sizeof(szString));
2482 hr = StringList_Item(pStringList, 0, szString);
2483 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2484 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
2485
2486 IDispatch_Release(pStringList);
2487 }
2488
2489 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_LOCALPACKAGEW, szString);
2490 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2491 DeleteFileW( szString );
2492
2493 /* Check & clean up installed files & registry keys */
2494 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2495 ok(delete_pf("msitest\\cabout\\new", FALSE), "Directory not created\n");
2496 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2497 ok(delete_pf("msitest\\cabout", FALSE), "Directory not created\n");
2498 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2499 ok(delete_pf("msitest\\changed", FALSE), "Directory not created\n");
2500 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2501 ok(delete_pf("msitest\\first", FALSE), "Directory not created\n");
2502 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2503 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2504 ok(delete_pf("msitest", FALSE), "Directory not created\n");
2505
2506 res = RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest", &hkey);
2507 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2508
2509 size = MAX_PATH;
2510 type = REG_SZ;
2511 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2512 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2513 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2514
2515 size = MAX_PATH;
2516 type = REG_SZ;
2517 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2518 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2519
2520 size = sizeof(num);
2521 type = REG_DWORD;
2522 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2523 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2524 ok(num == 314, "Expected 314, got %d\n", num);
2525
2526 size = MAX_PATH;
2527 type = REG_SZ;
2528 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2529 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2530 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2531
2532 RegCloseKey(hkey);
2533
2534 res = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest");
2535 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2536
2537 /* Remove registry keys written by RegisterProduct standard action */
2538 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2539 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{837450fa-a39b-4bc8-b321-08b393f784b3}",
2540 KEY_WOW64_32KEY);
2541 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2542
2543 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2544 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656", access);
2545 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2546
2547 res = find_registry_key(HKEY_LOCAL_MACHINE,
2548 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "af054738b93a8cb43b12803b397f483b", access, &hkey);
2549 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2550
2551 res = delete_registry_key(hkey, "af054738b93a8cb43b12803b397f483b", access);
2552 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2553 RegCloseKey(hkey);
2554
2555 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2556 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\af054738b93a8cb43b12803b397f483b", access);
2557 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2558
2559 /* Remove registry keys written by PublishProduct standard action */
2560 res = RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2561 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2562
2563 res = delete_registry_key(hkey, "Products\\af054738b93a8cb43b12803b397f483b", KEY_ALL_ACCESS);
2564 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2565
2566 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2567 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2568
2569 RegCloseKey(hkey);
2570
2571 /* Delete installation files we created */
2572 delete_test_files();
2573 }
2574
2575 static void test_Installer(void)
2576 {
2577 static WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
2578 static WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
2579 WCHAR szPath[MAX_PATH];
2580 HRESULT hr;
2581 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL;
2582 int iValue, iCount;
2583
2584 if (!pInstaller) return;
2585
2586 /* Installer::CreateRecord */
2587
2588 /* Test for error */
2589 hr = Installer_CreateRecord(-1, &pRecord);
2590 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2591 ok_exception(hr, szCreateRecordException);
2592
2593 /* Test for success */
2594 hr = Installer_CreateRecord(1, &pRecord);
2595 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2596 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2597 if (pRecord)
2598 {
2599 /* Record::FieldCountGet */
2600 hr = Record_FieldCountGet(pRecord, &iValue);
2601 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2602 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2603
2604 /* Record::IntegerDataGet */
2605 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2606 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2607 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2608
2609 /* Record::IntegerDataGet, bad index */
2610 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2611 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2612 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2613
2614 /* Record::IntegerDataPut */
2615 hr = Record_IntegerDataPut(pRecord, 1, 100);
2616 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2617
2618 /* Record::IntegerDataPut, bad index */
2619 hr = Record_IntegerDataPut(pRecord, 10, 100);
2620 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2621 ok_exception(hr, szIntegerDataException);
2622
2623 /* Record::IntegerDataGet */
2624 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2625 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2626 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2627
2628 IDispatch_Release(pRecord);
2629 }
2630
2631 create_package(szPath);
2632
2633 /* Installer::OpenPackage */
2634 hr = Installer_OpenPackage(szPath, 0, &pSession);
2635 if (hr == DISP_E_EXCEPTION)
2636 {
2637 skip("OpenPackage failed, insufficient rights?\n");
2638 DeleteFileW(szPath);
2639 return;
2640 }
2641 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2642 if (hr == S_OK)
2643 {
2644 test_Session(pSession);
2645 IDispatch_Release(pSession);
2646 }
2647
2648 /* Installer::OpenDatabase */
2649 hr = Installer_OpenDatabase(szPath, (INT_PTR)MSIDBOPEN_TRANSACT, &pDatabase);
2650 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2651 if (hr == S_OK)
2652 {
2653 test_Database(pDatabase, FALSE);
2654 IDispatch_Release(pDatabase);
2655 }
2656
2657 /* Installer::RegistryValue */
2658 test_Installer_RegistryValue();
2659
2660 /* Installer::ProductState for our product code, which should not be installed */
2661 hr = Installer_ProductState(szProductCode, &iValue);
2662 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2663 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2664
2665 /* Installer::ProductInfo for our product code, which should not be installed */
2666
2667 /* Package name */
2668 memset(szPath, 0, sizeof(szPath));
2669 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szPath);
2670 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2671 ok_exception(hr, szProductInfoException);
2672
2673 /* NULL attribute and NULL product code */
2674 memset(szPath, 0, sizeof(szPath));
2675 hr = Installer_ProductInfo(NULL, NULL, szPath);
2676 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2677 ok_exception(hr, szProductInfoException);
2678
2679 /* Installer::Products */
2680 test_Installer_Products(FALSE);
2681
2682 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2683 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2684 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2685 if (hr == S_OK)
2686 {
2687 /* StringList::Count */
2688 hr = StringList_Count(pStringList, &iCount);
2689 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2690 ok(!iCount, "Expected no related products but found %d\n", iCount);
2691
2692 IDispatch_Release(pStringList);
2693 }
2694
2695 /* Installer::Version */
2696 memset(szPath, 0, sizeof(szPath));
2697 hr = Installer_VersionGet(szPath);
2698 ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr);
2699
2700 /* Installer::InstallProduct and other tests that depend on our product being installed */
2701 test_Installer_InstallProduct();
2702 }
2703
2704 START_TEST(automation)
2705 {
2706 DWORD len;
2707 char temp_path[MAX_PATH], prev_path[MAX_PATH];
2708 HRESULT hr;
2709 CLSID clsid;
2710 IUnknown *pUnk;
2711
2712 init_functionpointers();
2713
2714 if (pIsWow64Process)
2715 pIsWow64Process(GetCurrentProcess(), &is_wow64);
2716
2717 GetSystemTimeAsFileTime(&systemtime);
2718
2719 GetCurrentDirectoryA(MAX_PATH, prev_path);
2720 GetTempPath(MAX_PATH, temp_path);
2721 SetCurrentDirectoryA(temp_path);
2722
2723 lstrcpyA(CURR_DIR, temp_path);
2724 len = lstrlenA(CURR_DIR);
2725
2726 if(len && (CURR_DIR[len - 1] == '\\'))
2727 CURR_DIR[len - 1] = 0;
2728
2729 get_program_files_dir(PROG_FILES_DIR);
2730
2731 hr = OleInitialize(NULL);
2732 ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr);
2733 hr = CLSIDFromProgID(szProgId, &clsid);
2734 ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr);
2735 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2736 ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr);
2737
2738 if (pUnk)
2739 {
2740 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2741 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2742
2743 test_dispid();
2744 test_dispatch();
2745 test_Installer();
2746
2747 IDispatch_Release(pInstaller);
2748 IUnknown_Release(pUnk);
2749 }
2750
2751 OleUninitialize();
2752
2753 SetCurrentDirectoryA(prev_path);
2754 }