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