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