Merge HAL changes 34743, 34812, 34839, 34917, 35515, 35771, 35902, 35904,
[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 /* FIXME: Off by one second */
1510 todo_wine ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1511 VariantClear(&varresult);
1512 VariantClear(&var);
1513
1514 /* VT_I4 */
1515 V_VT(&var) = VT_I4;
1516 V_I4(&var) = 1000;
1517 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1518 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1519
1520 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1521 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1522 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult));
1523 VariantClear(&varresult);
1524 VariantClear(&var);
1525
1526 /* SummaryInfo::PropertyCount */
1527 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1528 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1529 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1530 }
1531 }
1532
1533 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1534 {
1535 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 };
1536 static WCHAR szThree[] = { 'T','h','r','e','e',0 };
1537 static WCHAR szTwo[] = { 'T','w','o',0 };
1538 static WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
1539 static WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 };
1540 IDispatch *pView = NULL, *pSummaryInfo = NULL;
1541 HRESULT hr;
1542
1543 hr = Database_OpenView(pDatabase, szSql, &pView);
1544 ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr);
1545 if (hr == S_OK)
1546 {
1547 IDispatch *pRecord = NULL;
1548 WCHAR szString[MAX_PATH];
1549
1550 /* View::Execute */
1551 hr = View_Execute(pView, NULL);
1552 ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr);
1553
1554 /* View::Fetch */
1555 hr = View_Fetch(pView, &pRecord);
1556 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1557 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1558 if (pRecord)
1559 {
1560 /* Record::StringDataGet */
1561 memset(szString, 0, sizeof(szString));
1562 hr = Record_StringDataGet(pRecord, 1, szString);
1563 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1564 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1565
1566 /* Record::StringDataPut with correct index */
1567 hr = Record_StringDataPut(pRecord, 1, szTwo);
1568 ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1569
1570 /* Record::StringDataGet */
1571 memset(szString, 0, sizeof(szString));
1572 hr = Record_StringDataGet(pRecord, 1, szString);
1573 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1574 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1575
1576 /* Record::StringDataPut with incorrect index */
1577 hr = Record_StringDataPut(pRecord, -1, szString);
1578 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1579 ok_exception(hr, szStringDataField);
1580
1581 /* View::Modify with incorrect parameters */
1582 hr = View_Modify(pView, -5, NULL);
1583 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1584 ok_exception(hr, szModifyModeRecord);
1585
1586 hr = View_Modify(pView, -5, pRecord);
1587 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1588 ok_exception(hr, szModifyModeRecord);
1589
1590 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1591 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1592 ok_exception(hr, szModifyModeRecord);
1593
1594 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1595 ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr);
1596
1597 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1598 memset(szString, 0, sizeof(szString));
1599 hr = Record_StringDataGet(pRecord, 1, szString);
1600 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1601 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1602
1603 IDispatch_Release(pRecord);
1604 }
1605
1606 /* View::Fetch */
1607 hr = View_Fetch(pView, &pRecord);
1608 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1609 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1610 if (pRecord)
1611 {
1612 /* Record::StringDataGet */
1613 memset(szString, 0, sizeof(szString));
1614 hr = Record_StringDataGet(pRecord, 1, szString);
1615 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1616 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1617
1618 IDispatch_Release(pRecord);
1619 }
1620
1621 /* View::Fetch */
1622 hr = View_Fetch(pView, &pRecord);
1623 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1624 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1625 if (pRecord)
1626 IDispatch_Release(pRecord);
1627
1628 /* View::Close */
1629 hr = View_Close(pView);
1630 ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr);
1631
1632 IDispatch_Release(pView);
1633 }
1634
1635 /* Database::SummaryInformation */
1636 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo);
1637 ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr);
1638 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1639 if (pSummaryInfo)
1640 {
1641 test_SummaryInfo(pSummaryInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), readonly);
1642 IDispatch_Release(pSummaryInfo);
1643 }
1644 }
1645
1646 static void test_Session(IDispatch *pSession)
1647 {
1648 static WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
1649 static WCHAR szOne[] = { 'O','n','e',0 };
1650 static WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 };
1651 static WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 };
1652 static WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 };
1653 static WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 };
1654 static WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1655 static WCHAR szEmpty[] = { 0 };
1656 static WCHAR szEquals[] = { '=',0 };
1657 static WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
1658 WCHAR stringw[MAX_PATH];
1659 CHAR string[MAX_PATH];
1660 UINT len;
1661 BOOL bool;
1662 int myint;
1663 IDispatch *pDatabase = NULL, *pInst = NULL, *record = NULL;
1664 HRESULT hr;
1665
1666 /* Session::Installer */
1667 hr = Session_Installer(pSession, &pInst);
1668 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1669 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1670 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1671
1672 /* Session::Property, get */
1673 memset(stringw, 0, sizeof(stringw));
1674 hr = Session_PropertyGet(pSession, szProductName, stringw);
1675 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1676 if (strcmp_ww(stringw, szMSITEST) != 0)
1677 {
1678 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1679 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1680 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1681 }
1682
1683 /* Session::Property, put */
1684 hr = Session_PropertyPut(pSession, szProductName, szProductName);
1685 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1686 memset(stringw, 0, sizeof(stringw));
1687 hr = Session_PropertyGet(pSession, szProductName, stringw);
1688 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1689 if (strcmp_ww(stringw, szProductName) != 0)
1690 {
1691 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1692 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1693 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1694 }
1695
1696 /* Try putting a property using empty property identifier */
1697 hr = Session_PropertyPut(pSession, szEmpty, szProductName);
1698 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1699 ok_exception(hr, szPropertyName);
1700
1701 /* Try putting a property using illegal property identifier */
1702 hr = Session_PropertyPut(pSession, szEquals, szProductName);
1703 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1704
1705 /* Session::Language, get */
1706 hr = Session_LanguageGet(pSession, &len);
1707 ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1708 /* Not sure how to check the language is correct */
1709
1710 /* Session::Mode, get */
1711 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1712 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1713 todo_wine ok(!bool, "Reboot at end session mode is %d\n", bool);
1714
1715 /* Session::Mode, put */
1716 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE);
1717 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1718 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1719 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1720 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1721 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE); /* set it again so we don't reboot */
1722 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1723
1724 /* Session::Database, get */
1725 hr = Session_Database(pSession, &pDatabase);
1726 ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr);
1727 if (hr == S_OK)
1728 {
1729 test_Database(pDatabase, TRUE);
1730 IDispatch_Release(pDatabase);
1731 }
1732
1733 /* Session::EvaluateCondition */
1734 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1735 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1736 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1737
1738 hr = Session_EvaluateCondition(pSession, szEmpty, &myint);
1739 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1740 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1741
1742 hr = Session_EvaluateCondition(pSession, szEquals, &myint);
1743 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1744 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1745
1746 /* Session::DoAction(CostInitialize) must occur before the next statements */
1747 hr = Session_DoAction(pSession, szCostInitialize, &myint);
1748 ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr);
1749 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1750
1751 /* Session::SetInstallLevel */
1752 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1753 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
1754
1755 /* Session::FeatureCurrentState, get */
1756 hr = Session_FeatureCurrentState(pSession, szOne, &myint);
1757 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
1758 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1759
1760 /* Session::Message */
1761 hr = Installer_CreateRecord(0, &record);
1762 ok(hr == S_OK, "Installer_CreateRecord failed: %08x\n", hr);
1763 hr = Session_Message(pSession, INSTALLMESSAGE_INFO, record, &myint);
1764 ok(hr == S_OK, "Session_Message failed: %08x\n", hr);
1765 ok(myint == 0, "Session_Message returned %x\n", myint);
1766
1767 /* Session::EvaluateCondition */
1768 hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint);
1769 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1770 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1771
1772 hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint);
1773 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1774 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1775
1776 /* Session::FeatureRequestState, put */
1777 hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED);
1778 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
1779 hr = Session_FeatureRequestStateGet(pSession, szOne, &myint);
1780 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
1781 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
1782
1783 /* Session::EvaluateCondition */
1784 hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint);
1785 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1786 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1787
1788 hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint);
1789 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1790 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1791 }
1792
1793 /* delete key and all its subkeys */
1794 static DWORD delete_key( HKEY hkey )
1795 {
1796 char name[MAX_PATH];
1797 DWORD ret;
1798
1799 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
1800 {
1801 HKEY tmp;
1802 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
1803 {
1804 ret = delete_key( tmp );
1805 RegCloseKey( tmp );
1806 }
1807 if (ret) break;
1808 }
1809 if (ret != ERROR_NO_MORE_ITEMS) return ret;
1810 RegDeleteKeyA( hkey, "" );
1811 return 0;
1812 }
1813
1814 static void test_Installer_RegistryValue(void)
1815 {
1816 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
1817 static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 };
1818 static const WCHAR szOne[] = { 'O','n','e',0 };
1819 static const WCHAR szTwo[] = { 'T','w','o',0 };
1820 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
1821 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1822 static const WCHAR szFour[] = { 'F','o','u','r',0 };
1823 static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 };
1824 static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 };
1825 static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 };
1826 static const WCHAR szSix[] = { 'S','i','x',0 };
1827 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1828 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
1829 static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
1830 static const WCHAR szBlank[] = { 0 };
1831 VARIANT varresult;
1832 VARIANTARG vararg;
1833 WCHAR szString[MAX_PATH];
1834 HKEY hkey, hkey_sub;
1835 HKEY curr_user = (HKEY)1;
1836 HRESULT hr;
1837 BOOL bRet;
1838 LONG lRet;
1839
1840 /* Delete keys */
1841 SetLastError(0xdeadbeef);
1842 lRet = RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey );
1843 if (!lRet && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1844 {
1845 win_skip("Needed W-functions are not implemented\n");
1846 return;
1847 }
1848 if (!lRet)
1849 delete_key( hkey );
1850
1851 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
1852 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
1853 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1854 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
1855
1856 memset(szString, 0, sizeof(szString));
1857 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
1858 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1859
1860 memset(szString, 0, sizeof(szString));
1861 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
1862 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1863
1864 /* Create key */
1865 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
1866
1867 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1868 "RegSetValueExW failed\n");
1869 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
1870 "RegSetValueExW failed\n");
1871 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
1872 "RegSetValueExW failed\n");
1873 ok(SetEnvironmentVariableA("MSITEST", "Four"), "SetEnvironmentVariableA failed %d\n", GetLastError());
1874 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
1875 "RegSetValueExW failed\n");
1876 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
1877 "RegSetValueExW failed\n");
1878 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
1879 "RegSetValueExW failed\n");
1880 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, NULL, 0),
1881 "RegSetValueExW failed\n");
1882
1883 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1884 "RegSetValueExW failed\n");
1885
1886 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
1887
1888 /* Does our key exist? It should, and make sure we retrieve the correct default value */
1889 bRet = FALSE;
1890 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
1891 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1892 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
1893
1894 memset(szString, 0, sizeof(szString));
1895 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
1896 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1897 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1898
1899 /* Ask for the value of a nonexistent key */
1900 memset(szString, 0, sizeof(szString));
1901 hr = Installer_RegistryValueW(curr_user, szKey, szExpand, szString);
1902 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1903
1904 /* Get values of keys */
1905 memset(szString, 0, sizeof(szString));
1906 hr = Installer_RegistryValueW(curr_user, szKey, szOne, szString);
1907 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1908 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1909
1910 VariantInit(&vararg);
1911 V_VT(&vararg) = VT_BSTR;
1912 V_BSTR(&vararg) = SysAllocString(szTwo);
1913 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_I4);
1914 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1915 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
1916 VariantClear(&varresult);
1917
1918 memset(szString, 0, sizeof(szString));
1919 hr = Installer_RegistryValueW(curr_user, szKey, szThree, szString);
1920 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1921 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
1922
1923 memset(szString, 0, sizeof(szString));
1924 hr = Installer_RegistryValueW(curr_user, szKey, szFour, szString);
1925 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1926 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
1927
1928 /* Vista does not NULL-terminate this case */
1929 memset(szString, 0, sizeof(szString));
1930 hr = Installer_RegistryValueW(curr_user, szKey, szFive, szString);
1931 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1932 ok_w2n("Registry value \"%s\" does not match expected \"%s\"\n",
1933 szString, szFiveHi, lstrlenW(szFiveHi));
1934
1935 memset(szString, 0, sizeof(szString));
1936 hr = Installer_RegistryValueW(curr_user, szKey, szSix, szString);
1937 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1938 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_);
1939
1940 VariantInit(&vararg);
1941 V_VT(&vararg) = VT_BSTR;
1942 V_BSTR(&vararg) = SysAllocString(szSeven);
1943 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_EMPTY);
1944 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1945
1946 /* Get string class name for the key */
1947 memset(szString, 0, sizeof(szString));
1948 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
1949 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1950 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank);
1951
1952 /* Get name of a value by positive number (RegEnumValue like), valid index */
1953 memset(szString, 0, sizeof(szString));
1954 hr = Installer_RegistryValueI(curr_user, szKey, 2, szString, VT_BSTR);
1955 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1956 /* RegEnumValue order seems different on wine */
1957 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
1958
1959 /* Get name of a value by positive number (RegEnumValue like), invalid index */
1960 memset(szString, 0, sizeof(szString));
1961 hr = Installer_RegistryValueI(curr_user, szKey, 10, szString, VT_EMPTY);
1962 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1963
1964 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
1965 memset(szString, 0, sizeof(szString));
1966 hr = Installer_RegistryValueI(curr_user, szKey, -1, szString, VT_BSTR);
1967 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1968 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
1969
1970 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
1971 memset(szString, 0, sizeof(szString));
1972 hr = Installer_RegistryValueI(curr_user, szKey, -10, szString, VT_EMPTY);
1973 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1974
1975 /* clean up */
1976 delete_key(hkey);
1977 }
1978
1979 static void test_Installer_Products(BOOL bProductInstalled)
1980 {
1981 WCHAR szString[MAX_PATH];
1982 HRESULT hr;
1983 int idx;
1984 IUnknown *pUnk = NULL;
1985 IEnumVARIANT *pEnum = NULL;
1986 VARIANT var;
1987 ULONG celt;
1988 int iCount, iValue;
1989 IDispatch *pStringList = NULL;
1990 BOOL bProductFound = FALSE;
1991
1992 /* Installer::Products */
1993 hr = Installer_Products(&pStringList);
1994 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
1995 if (hr == S_OK)
1996 {
1997 /* StringList::_NewEnum */
1998 hr = StringList__NewEnum(pStringList, &pUnk);
1999 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
2000 if (hr == S_OK)
2001 {
2002 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
2003 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2004 }
2005 if (!pEnum)
2006 skip("IEnumVARIANT tests\n");
2007
2008 /* StringList::Count */
2009 hr = StringList_Count(pStringList, &iCount);
2010 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2011
2012 for (idx=0; idx<iCount; idx++)
2013 {
2014 /* StringList::Item */
2015 memset(szString, 0, sizeof(szString));
2016 hr = StringList_Item(pStringList, idx, szString);
2017 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2018
2019 if (hr == S_OK)
2020 {
2021 /* Installer::ProductState */
2022 hr = Installer_ProductState(szString, &iValue);
2023 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2024 if (hr == S_OK)
2025 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
2026
2027 /* Not found our product code yet? Check */
2028 if (!bProductFound && !strcmp_ww(szString, szProductCode))
2029 bProductFound = TRUE;
2030
2031 /* IEnumVARIANT::Next */
2032 if (pEnum)
2033 {
2034 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2035 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2036 ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
2037 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2038 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2039 VariantClear(&var);
2040 }
2041 }
2042 }
2043
2044 if (bProductInstalled)
2045 {
2046 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
2047 bProductInstalled ? "be" : "not be",
2048 bProductFound ? "found" : "not found");
2049 }
2050
2051 if (pEnum)
2052 {
2053 IEnumVARIANT *pEnum2 = NULL;
2054
2055 if (0) /* Crashes on Windows XP */
2056 {
2057 /* IEnumVARIANT::Clone, NULL pointer */
2058 hr = IEnumVARIANT_Clone(pEnum, NULL);
2059 }
2060
2061 /* IEnumVARIANT::Clone */
2062 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
2063 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
2064 if (hr == S_OK)
2065 {
2066 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
2067
2068 /* IEnumVARIANT::Next of the clone */
2069 if (iCount)
2070 {
2071 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
2072 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2073 ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
2074 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2075 VariantClear(&var);
2076 }
2077 else
2078 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
2079
2080 IEnumVARIANT_Release(pEnum2);
2081 }
2082
2083 /* IEnumVARIANT::Skip should fail */
2084 hr = IEnumVARIANT_Skip(pEnum, 1);
2085 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2086
2087 /* IEnumVARIANT::Next, NULL variant pointer */
2088 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2089 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2090 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2091
2092 /* IEnumVARIANT::Next, should not return any more items */
2093 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2094 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2095 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2096 VariantClear(&var);
2097
2098 /* IEnumVARIANT::Reset */
2099 hr = IEnumVARIANT_Reset(pEnum);
2100 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2101
2102 if (iCount)
2103 {
2104 /* IEnumVARIANT::Skip to the last product */
2105 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2106 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2107
2108 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2109 * NULL celt pointer. */
2110 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2111 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2112 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2113 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2114 VariantClear(&var);
2115 }
2116 else
2117 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2118 }
2119
2120 /* StringList::Item using an invalid index */
2121 memset(szString, 0, sizeof(szString));
2122 hr = StringList_Item(pStringList, iCount, szString);
2123 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2124
2125 if (pEnum) IEnumVARIANT_Release(pEnum);
2126 if (pUnk) IUnknown_Release(pUnk);
2127 IDispatch_Release(pStringList);
2128 }
2129 }
2130
2131 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2132 * deleting the subkeys first) */
2133 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey)
2134 {
2135 UINT ret;
2136 CHAR *string = NULL;
2137 HKEY hkey;
2138 DWORD dwSize;
2139
2140 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2141 if (ret != ERROR_SUCCESS) return ret;
2142 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2143 if (ret != ERROR_SUCCESS) return ret;
2144 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2145
2146 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2147 delete_registry_key(hkey, string);
2148
2149 RegCloseKey(hkey);
2150 HeapFree(GetProcessHeap(), 0, string);
2151 RegDeleteKeyA(hkeyParent, subkey);
2152 return ERROR_SUCCESS;
2153 }
2154
2155 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2156 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, HKEY *phkey)
2157 {
2158 UINT ret;
2159 CHAR *string = NULL;
2160 int idx = 0;
2161 HKEY hkey;
2162 DWORD dwSize;
2163 BOOL found = FALSE;
2164
2165 *phkey = 0;
2166
2167 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2168 if (ret != ERROR_SUCCESS) return ret;
2169 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2170 if (ret != ERROR_SUCCESS) return ret;
2171 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2172
2173 while (!found &&
2174 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2175 {
2176 if (!strcmp(string, findkey))
2177 {
2178 *phkey = hkey;
2179 found = TRUE;
2180 }
2181 else if (find_registry_key(hkey, string, findkey, phkey) == ERROR_SUCCESS) found = TRUE;
2182 }
2183
2184 if (*phkey != hkey) RegCloseKey(hkey);
2185 HeapFree(GetProcessHeap(), 0, string);
2186 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2187 }
2188
2189 static void test_Installer_InstallProduct(void)
2190 {
2191 HRESULT hr;
2192 CHAR path[MAX_PATH];
2193 WCHAR szString[MAX_PATH];
2194 LONG res;
2195 HKEY hkey;
2196 DWORD num, size, type;
2197 int iValue, iCount;
2198 IDispatch *pStringList = NULL;
2199
2200 create_test_files();
2201
2202 /* Installer::InstallProduct */
2203 hr = Installer_InstallProduct(szMsifile, NULL);
2204 if (hr == DISP_E_EXCEPTION)
2205 {
2206 skip("Installer object not supported.\n");
2207 delete_test_files();
2208 return;
2209 }
2210 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2211
2212 /* Installer::ProductState for our product code, which has been installed */
2213 hr = Installer_ProductState(szProductCode, &iValue);
2214 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2215 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2216
2217 /* Installer::ProductInfo for our product code */
2218
2219 /* NULL attribute */
2220 memset(szString, 0, sizeof(szString));
2221 hr = Installer_ProductInfo(szProductCode, NULL, szString);
2222 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2223 ok_exception(hr, szProductInfoException);
2224
2225 /* Nonexistent attribute */
2226 memset(szString, 0, sizeof(szString));
2227 hr = Installer_ProductInfo(szProductCode, szMsifile, szString);
2228 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2229 ok_exception(hr, szProductInfoException);
2230
2231 /* Package name */
2232 memset(szString, 0, sizeof(szString));
2233 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szString);
2234 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2235 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile);
2236
2237 /* Product name */
2238 memset(szString, 0, sizeof(szString));
2239 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PRODUCTNAMEW, szString);
2240 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2241 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST);
2242
2243 /* Installer::Products */
2244 test_Installer_Products(TRUE);
2245
2246 /* Installer::RelatedProducts for our upgrade code */
2247 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2248 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2249 if (hr == S_OK)
2250 {
2251 /* StringList::Count */
2252 hr = StringList_Count(pStringList, &iCount);
2253 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2254 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2255
2256 /* StringList::Item */
2257 memset(szString, 0, sizeof(szString));
2258 hr = StringList_Item(pStringList, 0, szString);
2259 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2260 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
2261
2262 IDispatch_Release(pStringList);
2263 }
2264
2265 /* Check & clean up installed files & registry keys */
2266 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2267 ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
2268 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2269 ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
2270 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2271 ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
2272 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2273 ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
2274 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2275 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2276 ok(delete_pf("msitest", FALSE), "File not installed\n");
2277
2278 res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
2279 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2280
2281 size = MAX_PATH;
2282 type = REG_SZ;
2283 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2284 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2285 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2286
2287 size = MAX_PATH;
2288 type = REG_SZ;
2289 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2290 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2291
2292 size = sizeof(num);
2293 type = REG_DWORD;
2294 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2295 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2296 ok(num == 314, "Expected 314, got %d\n", num);
2297
2298 size = MAX_PATH;
2299 type = REG_SZ;
2300 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2301 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2302 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2303
2304 RegCloseKey(hkey);
2305
2306 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest");
2307 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2308
2309 /* Remove registry keys written by RegisterProduct standard action */
2310 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F1C3AF50-8B56-4A69-A00C-00773FE42F30}");
2311 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2312
2313 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2314 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2315
2316 res = find_registry_key(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "05FA3C1F65B896A40AC00077F34EF203", &hkey);
2317 ok(res == ERROR_SUCCESS ||
2318 broken(res == ERROR_FILE_NOT_FOUND), /* win9x */
2319 "Expected ERROR_SUCCESS, got %d\n", res);
2320 if (res == ERROR_SUCCESS)
2321 {
2322 res = delete_registry_key(hkey, "05FA3C1F65B896A40AC00077F34EF203");
2323 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2324 RegCloseKey(hkey);
2325
2326 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203");
2327 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2328 }
2329 else
2330 {
2331 /* win9x defaults to a per-machine install. */
2332 RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203");
2333 }
2334
2335 /* Remove registry keys written by PublishProduct standard action */
2336 res = RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2337 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2338
2339 res = delete_registry_key(hkey, "Products\\05FA3C1F65B896A40AC00077F34EF203");
2340 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2341
2342 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2343 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2344
2345 RegCloseKey(hkey);
2346
2347 /* Delete installation files we installed */
2348 delete_test_files();
2349 }
2350
2351 static void test_Installer(void)
2352 {
2353 static WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
2354 static WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
2355 WCHAR szPath[MAX_PATH];
2356 HRESULT hr;
2357 UINT len;
2358 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL;
2359 int iValue, iCount;
2360
2361 if (!pInstaller) return;
2362
2363 /* Installer::CreateRecord */
2364
2365 /* Test for error */
2366 hr = Installer_CreateRecord(-1, &pRecord);
2367 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2368 ok_exception(hr, szCreateRecordException);
2369
2370 /* Test for success */
2371 hr = Installer_CreateRecord(1, &pRecord);
2372 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2373 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2374 if (pRecord)
2375 {
2376 /* Record::FieldCountGet */
2377 hr = Record_FieldCountGet(pRecord, &iValue);
2378 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2379 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2380
2381 /* Record::IntegerDataGet */
2382 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2383 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2384 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2385
2386 /* Record::IntegerDataGet, bad index */
2387 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2388 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2389 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2390
2391 /* Record::IntegerDataPut */
2392 hr = Record_IntegerDataPut(pRecord, 1, 100);
2393 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2394
2395 /* Record::IntegerDataPut, bad index */
2396 hr = Record_IntegerDataPut(pRecord, 10, 100);
2397 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2398 ok_exception(hr, szIntegerDataException);
2399
2400 /* Record::IntegerDataGet */
2401 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2402 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2403 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2404
2405 IDispatch_Release(pRecord);
2406 }
2407
2408 /* Prepare package */
2409 create_database(msifile, tables, sizeof(tables) / sizeof(msi_table),
2410 summary_info, sizeof(summary_info) / sizeof(msi_summary_info));
2411
2412 len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, CURR_DIR, -1, szPath, MAX_PATH);
2413 ok(len, "MultiByteToWideChar returned error %d\n", GetLastError());
2414 if (!len) return;
2415
2416 /* lstrcatW does not work on win95 */
2417 szPath[len - 1] = '\\';
2418 memcpy(&szPath[len], szMsifile, sizeof(szMsifile));
2419
2420 /* Installer::OpenPackage */
2421 hr = Installer_OpenPackage(szPath, 0, &pSession);
2422 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2423 if (hr == S_OK)
2424 {
2425 test_Session(pSession);
2426 IDispatch_Release(pSession);
2427 }
2428
2429 /* Installer::OpenDatabase */
2430 hr = Installer_OpenDatabase(szPath, (INT_PTR)MSIDBOPEN_TRANSACT, &pDatabase);
2431 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2432 if (hr == S_OK)
2433 {
2434 test_Database(pDatabase, FALSE);
2435 IDispatch_Release(pDatabase);
2436 }
2437
2438 /* Installer::RegistryValue */
2439 test_Installer_RegistryValue();
2440
2441 /* Installer::ProductState for our product code, which should not be installed */
2442 hr = Installer_ProductState(szProductCode, &iValue);
2443 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2444 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2445
2446 /* Installer::ProductInfo for our product code, which should not be installed */
2447
2448 /* Package name */
2449 memset(szPath, 0, sizeof(szPath));
2450 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szPath);
2451 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2452 ok_exception(hr, szProductInfoException);
2453
2454 /* NULL attribute and NULL product code */
2455 memset(szPath, 0, sizeof(szPath));
2456 hr = Installer_ProductInfo(NULL, NULL, szPath);
2457 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2458 ok_exception(hr, szProductInfoException);
2459
2460 /* Installer::Products */
2461 test_Installer_Products(FALSE);
2462
2463 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2464 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2465 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2466 if (hr == S_OK)
2467 {
2468 /* StringList::Count */
2469 hr = StringList_Count(pStringList, &iCount);
2470 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2471 ok(!iCount, "Expected no related products but found %d\n", iCount);
2472
2473 IDispatch_Release(pStringList);
2474 }
2475
2476 /* Installer::Version */
2477 memset(szPath, 0, sizeof(szPath));
2478 hr = Installer_VersionGet(szPath);
2479 ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr);
2480
2481 /* Installer::InstallProduct and other tests that depend on our product being installed */
2482 test_Installer_InstallProduct();
2483 }
2484
2485 START_TEST(automation)
2486 {
2487 DWORD len;
2488 char temp_path[MAX_PATH], prev_path[MAX_PATH];
2489 HRESULT hr;
2490 CLSID clsid;
2491 IUnknown *pUnk;
2492
2493 GetSystemTimeAsFileTime(&systemtime);
2494
2495 GetCurrentDirectoryA(MAX_PATH, prev_path);
2496 GetTempPath(MAX_PATH, temp_path);
2497 SetCurrentDirectoryA(temp_path);
2498
2499 lstrcpyA(CURR_DIR, temp_path);
2500 len = lstrlenA(CURR_DIR);
2501
2502 if(len && (CURR_DIR[len - 1] == '\\'))
2503 CURR_DIR[len - 1] = 0;
2504
2505 get_program_files_dir(PROG_FILES_DIR);
2506
2507 hr = OleInitialize(NULL);
2508 ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr);
2509 hr = CLSIDFromProgID(szProgId, &clsid);
2510 ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr);
2511 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2512 ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr);
2513
2514 if (pUnk)
2515 {
2516 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2517 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2518
2519 test_dispid();
2520 test_dispatch();
2521 test_Installer();
2522
2523 IDispatch_Release(pInstaller);
2524 IUnknown_Release(pUnk);
2525 }
2526
2527 OleUninitialize();
2528
2529 SetCurrentDirectoryA(prev_path);
2530 }