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