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