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