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