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