push b0b97fcd59eff07f047585692fa36859b459324f
[wine/hacks.git] / dlls / msi / tests / automation.c
blob8ea639af56268aab116134d13619c59ede70d510
1 /*
2 * Copyright (C) 2007 Mike McCormack for CodeWeavers
3 * Copyright (C) 2007 Misha Koshelev
5 * A test program for Microsoft Installer OLE automation functionality.
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.
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.
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
22 #define COBJMACROS
24 #include <stdio.h>
26 #include <initguid.h>
27 #include <windows.h>
28 #include <msiquery.h>
29 #include <msidefs.h>
30 #include <msi.h>
31 #include <fci.h>
33 #include "wine/test.h"
35 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
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;
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;
55 /* msi database data */
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";
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";
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";
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";
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";
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";
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";
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}";
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";
156 typedef struct _msi_table
158 const CHAR *filename;
159 const CHAR *data;
160 int size;
161 } msi_table;
163 #define ADD_TABLE(x) {#x".idt", x##_dat, sizeof(x##_dat)}
165 static const msi_table tables[] =
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)
178 typedef struct _msi_summary_info
180 UINT property;
181 UINT datatype;
182 INT iValue;
183 FILETIME *pftValue;
184 const CHAR *szValue;
185 } msi_summary_info;
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}
192 static const msi_summary_info summary_info[] =
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)
203 * Database Helpers
206 static void write_file(const CHAR *filename, const char *data, int data_size)
208 DWORD size;
210 HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL,
211 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
213 WriteFile(hf, data, data_size, &size, NULL);
214 CloseHandle(hf);
217 static void write_msi_summary_info(MSIHANDLE db, const msi_summary_info *info, int num_info)
219 MSIHANDLE summary;
220 UINT r;
221 int j;
223 r = MsiGetSummaryInformationA(db, NULL, num_info, &summary);
224 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
226 /* import summary information into the stream */
227 for (j = 0; j < num_info; j++)
229 const msi_summary_info *entry = &info[j];
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);
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);
240 MsiCloseHandle(summary);
243 static void create_database(const CHAR *name, const msi_table *tables, int num_tables,
244 const msi_summary_info *info, int num_info)
246 MSIHANDLE db;
247 UINT r;
248 int j;
250 r = MsiOpenDatabaseA(name, MSIDBOPEN_CREATE, &db);
251 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
253 /* import the tables into the database */
254 for (j = 0; j < num_tables; j++)
256 const msi_table *table = &tables[j];
258 write_file(table->filename, table->data, (table->size - 1) * sizeof(char));
260 r = MsiDatabaseImportA(db, CURR_DIR, table->filename);
261 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
263 DeleteFileA(table->filename);
266 write_msi_summary_info(db, info, num_info);
268 r = MsiDatabaseCommit(db);
269 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
271 MsiCloseHandle(db);
275 * Installation helpers
278 static char PROG_FILES_DIR[MAX_PATH];
280 static BOOL get_program_files_dir(LPSTR buf)
282 HKEY hkey;
283 DWORD type = REG_EXPAND_SZ, size;
285 if (RegOpenKey(HKEY_LOCAL_MACHINE,
286 "Software\\Microsoft\\Windows\\CurrentVersion", &hkey))
287 return FALSE;
289 size = MAX_PATH;
290 if (RegQueryValueEx(hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size))
291 return FALSE;
293 RegCloseKey(hkey);
294 return TRUE;
297 static void create_file(const CHAR *name, DWORD size)
299 HANDLE file;
300 DWORD written, left;
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);
307 left = size - lstrlen(name) - 1;
309 SetFilePointer(file, left, NULL, FILE_CURRENT);
310 SetEndOfFile(file);
312 CloseHandle(file);
315 static void create_test_files(void)
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);
330 static BOOL delete_pf(const CHAR *rel_path, BOOL is_file)
332 CHAR path[MAX_PATH];
334 lstrcpyA(path, PROG_FILES_DIR);
335 lstrcatA(path, "\\");
336 lstrcatA(path, rel_path);
338 if (is_file)
339 return DeleteFileA(path);
340 else
341 return RemoveDirectoryA(path);
344 static void delete_test_files(void)
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");
361 * Automation helpers and tests
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];
367 #define ok_w2(format, szString1, szString2) \
369 if (lstrcmpW(szString1, szString2) != 0) \
371 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
372 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
373 ok(0, format, string1, string2); \
376 #define ok_aw(format, aString, wString) \
378 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
379 if (lstrcmpA(string1, aString) != 0) \
380 ok(0, format, string1, aString); \
382 #define ok_awplus(format, extra, aString, wString) \
384 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
385 if (lstrcmpA(string1, aString) != 0) \
386 ok(0, format, extra, string1, aString); \
388 /* exception checker */
389 static WCHAR szSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
391 #define ok_exception(hr, szDescription) \
392 if (hr == DISP_E_EXCEPTION) \
394 /* Compare wtype, source, and destination */ \
395 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
397 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
398 if (excepinfo.bstrSource) \
399 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, szSource); \
401 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
402 if (excepinfo.bstrDescription) \
403 ok_w2("Exception description was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrDescription, szDescription); \
405 SysFreeString(excepinfo.bstrSource); \
406 SysFreeString(excepinfo.bstrDescription); \
407 SysFreeString(excepinfo.bstrHelpFile); \
410 static DISPID get_dispid( IDispatch *disp, const char *name )
412 LPOLESTR str;
413 UINT len;
414 DISPID id = -1;
415 HRESULT r;
417 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
418 str = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
419 if (str)
421 len = MultiByteToWideChar(CP_ACP, 0, name, -1, str, len );
422 r = IDispatch_GetIDsOfNames( disp, &IID_NULL, &str, 1, 0, &id );
423 HeapFree(GetProcessHeap(), 0, str);
424 if (r != S_OK)
425 return -1;
428 return id;
431 static void test_dispid(void)
433 DISPID dispid;
435 dispid = get_dispid(pInstaller, "CreateRecord");
436 ok(dispid == 1, "Expected 1, got %d\n", dispid);
437 dispid = get_dispid(pInstaller, "OpenPackage");
438 ok(dispid == 2, "Expected 2, got %d\n", dispid);
439 dispid = get_dispid(pInstaller, "OpenDatabase");
440 ok(dispid == 4, "Expected 4, got %d\n", dispid);
441 dispid = get_dispid( pInstaller, "UILevel" );
442 ok(dispid == 6, "Expected 6, got %d\n", dispid);
443 dispid = get_dispid(pInstaller, "InstallProduct");
444 ok(dispid == 8, "Expected 8, got %d\n", dispid);
445 dispid = get_dispid(pInstaller, "Version");
446 ok(dispid == 9, "Expected 9, got %d\n", dispid);
447 dispid = get_dispid(pInstaller, "RegistryValue");
448 ok(dispid == 11, "Expected 11, got %d\n", dispid);
449 todo_wine
451 dispid = get_dispid(pInstaller, "OpenProduct");
452 ok(dispid == 3, "Expected 3, got %d\n", dispid);
453 dispid = get_dispid(pInstaller, "SummaryInformation");
454 ok(dispid == 5, "Expected 5, got %d\n", dispid);
455 dispid = get_dispid(pInstaller, "EnableLog");
456 ok(dispid == 7, "Expected 7, got %d\n", dispid);
457 dispid = get_dispid(pInstaller, "LastErrorRecord");
458 ok(dispid == 10, "Expected 10, got %d\n", dispid);
459 dispid = get_dispid(pInstaller, "Environment");
460 ok(dispid == 12, "Expected 12, got %d\n", dispid);
461 dispid = get_dispid(pInstaller, "FileAttributes");
462 ok(dispid == 13, "Expected 13, got %d\n", dispid);
463 dispid = get_dispid(pInstaller, "FileSize");
464 ok(dispid == 15, "Expected 15, got %d\n", dispid);
465 dispid = get_dispid(pInstaller, "FileVersion");
466 ok(dispid == 16, "Expected 16, got %d\n", dispid);
468 dispid = get_dispid(pInstaller, "ProductState");
469 ok(dispid == 17, "Expected 17, got %d\n", dispid);
470 dispid = get_dispid(pInstaller, "ProductInfo");
471 ok(dispid == 18, "Expected 18, got %d\n", dispid);
472 todo_wine
474 dispid = get_dispid(pInstaller, "ConfigureProduct");
475 ok(dispid == 19, "Expected 19, got %d\n", dispid);
476 dispid = get_dispid(pInstaller, "ReinstallProduct");
477 ok(dispid == 20 , "Expected 20, got %d\n", dispid);
478 dispid = get_dispid(pInstaller, "CollectUserInfo");
479 ok(dispid == 21, "Expected 21, got %d\n", dispid);
480 dispid = get_dispid(pInstaller, "ApplyPatch");
481 ok(dispid == 22, "Expected 22, got %d\n", dispid);
482 dispid = get_dispid(pInstaller, "FeatureParent");
483 ok(dispid == 23, "Expected 23, got %d\n", dispid);
484 dispid = get_dispid(pInstaller, "FeatureState");
485 ok(dispid == 24, "Expected 24, got %d\n", dispid);
486 dispid = get_dispid(pInstaller, "UseFeature");
487 ok(dispid == 25, "Expected 25, got %d\n", dispid);
488 dispid = get_dispid(pInstaller, "FeatureUsageCount");
489 ok(dispid == 26, "Expected 26, got %d\n", dispid);
490 dispid = get_dispid(pInstaller, "FeatureUsageDate");
491 ok(dispid == 27, "Expected 27, got %d\n", dispid);
492 dispid = get_dispid(pInstaller, "ConfigureFeature");
493 ok(dispid == 28, "Expected 28, got %d\n", dispid);
494 dispid = get_dispid(pInstaller, "ReinstallFeature");
495 ok(dispid == 29, "Expected 29, got %d\n", dispid);
496 dispid = get_dispid(pInstaller, "ProvideComponent");
497 ok(dispid == 30, "Expected 30, got %d\n", dispid);
498 dispid = get_dispid(pInstaller, "ComponentPath");
499 ok(dispid == 31, "Expected 31, got %d\n", dispid);
500 dispid = get_dispid(pInstaller, "ProvideQualifiedComponent");
501 ok(dispid == 32, "Expected 32, got %d\n", dispid);
502 dispid = get_dispid(pInstaller, "QualifierDescription");
503 ok(dispid == 33, "Expected 33, got %d\n", dispid);
504 dispid = get_dispid(pInstaller, "ComponentQualifiers");
505 ok(dispid == 34, "Expected 34, got %d\n", dispid);
507 dispid = get_dispid(pInstaller, "Products");
508 ok(dispid == 35, "Expected 35, got %d\n", dispid);
509 todo_wine
511 dispid = get_dispid(pInstaller, "Features");
512 ok(dispid == 36, "Expected 36, got %d\n", dispid);
513 dispid = get_dispid(pInstaller, "Components");
514 ok(dispid == 37, "Expected 37, got %d\n", dispid);
515 dispid = get_dispid(pInstaller, "ComponentClients");
516 ok(dispid == 38, "Expected 38, got %d\n", dispid);
517 dispid = get_dispid(pInstaller, "Patches");
518 ok(dispid == 39, "Expected 39, got %d\n", dispid);
520 dispid = get_dispid(pInstaller, "RelatedProducts");
521 ok(dispid == 40, "Expected 40, got %d\n", dispid);
522 todo_wine
524 dispid = get_dispid(pInstaller, "PatchInfo");
525 ok(dispid == 41, "Expected 41, got %d\n", dispid);
526 dispid = get_dispid(pInstaller, "PatchTransforms");
527 ok(dispid == 42, "Expected 42, got %d\n", dispid);
528 dispid = get_dispid(pInstaller, "AddSource");
529 ok(dispid == 43, "Expected 43, got %d\n", dispid);
530 dispid = get_dispid(pInstaller, "ClearSourceList");
531 ok(dispid == 44, "Expected 44, got %d\n", dispid);
532 dispid = get_dispid(pInstaller, "ForceSourceListResolution");
533 ok(dispid == 45, "Expected 45, got %d\n", dispid);
534 dispid = get_dispid(pInstaller, "ShortcutTarget");
535 ok(dispid == 46, "Expected 46, got %d\n", dispid);
536 dispid = get_dispid(pInstaller, "FileHash");
537 ok(dispid == 47, "Expected 47, got %d\n", dispid);
538 dispid = get_dispid(pInstaller, "FileSignatureInfo");
539 ok(dispid == 48, "Expected 48, got %d\n", dispid);
541 dispid = get_dispid(pInstaller, "RemovePatches");
542 ok(dispid == 49 || dispid == -1, "Expected 49 or -1, got %d\n", dispid);
543 dispid = get_dispid(pInstaller, "ApplyMultiplePatches");
544 ok(dispid == 51 || dispid == -1, "Expected 51 or -1, got %d\n", dispid);
545 dispid = get_dispid(pInstaller, "ProductsEx");
546 ok(dispid == 52 || dispid == -1, "Expected 52 or -1, got %d\n", dispid);
547 dispid = get_dispid(pInstaller, "PatchesEx");
548 ok(dispid == 55 || dispid == -1, "Expected 55 or -1, got %d\n", dispid);
549 dispid = get_dispid(pInstaller, "ExtractPatchXMLData");
550 ok(dispid == 57 || dispid == -1, "Expected 57 or -1, got %d\n", dispid);
551 dispid = get_dispid( pInstaller, "ProductElevated" );
552 ok(dispid == 59 || dispid == -1, "Expected 59 or -1, got %d\n", dispid);
553 dispid = get_dispid( pInstaller, "ProvideAssembly" );
554 ok(dispid == 60 || dispid == -1, "Expected 60 or -1, got %d\n", dispid);
555 dispid = get_dispid( pInstaller, "ProductInfoFromScript" );
556 ok(dispid == 61 || dispid == -1, "Expected 61 or -1, got %d\n", dispid);
557 dispid = get_dispid( pInstaller, "AdvertiseProduct" );
558 ok(dispid == 62 || dispid == -1, "Expected 62 or -1, got %d\n", dispid);
559 dispid = get_dispid( pInstaller, "CreateAdvertiseScript" );
560 ok(dispid == 63 || dispid == -1, "Expected 63 or -1, got %d\n", dispid);
561 dispid = get_dispid( pInstaller, "PatchFiles" );
562 ok(dispid == 65 || dispid == -1, "Expected 65 or -1, got %d\n", dispid);
565 /* Test basic IDispatch functions */
566 static void test_dispatch(void)
568 static WCHAR szOpenPackage[] = { 'O','p','e','n','P','a','c','k','a','g','e',0 };
569 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};
570 static WCHAR szProductState[] = { 'P','r','o','d','u','c','t','S','t','a','t','e',0 };
571 HRESULT hr;
572 DISPID dispid;
573 OLECHAR *name;
574 VARIANT varresult;
575 VARIANTARG vararg[2];
576 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
578 /* Test getting ID of a function name that does not exist */
579 name = (WCHAR *)szMsifile;
580 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
581 ok(hr == DISP_E_UNKNOWNNAME, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
583 /* Test invoking this function */
584 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
585 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
587 /* Test getting ID of a function name that does exist */
588 name = (WCHAR *)szOpenPackage;
589 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
590 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
592 /* Test invoking this function (without parameters passed) */
593 if (0) /* All of these crash MSI on Windows XP */
595 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
596 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL);
597 VariantInit(&varresult);
598 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, &varresult, &excepinfo, NULL);
601 /* Try with NULL params */
602 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
603 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
605 /* Try one empty parameter */
606 dispparams.rgvarg = vararg;
607 dispparams.cArgs = 1;
608 VariantInit(&vararg[0]);
609 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
610 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
612 /* Try one parameter, function requires two */
613 VariantInit(&vararg[0]);
614 V_VT(&vararg[0]) = VT_BSTR;
615 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
616 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
617 VariantClear(&vararg[0]);
619 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
620 ok_exception(hr, szOpenPackageException);
622 /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
623 VariantInit(&vararg[0]);
624 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
625 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
627 VariantInit(&vararg[0]);
628 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
629 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
631 /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
632 name = (WCHAR *)szProductState;
633 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
634 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
636 dispparams.rgvarg = NULL;
637 dispparams.cArgs = 0;
638 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
639 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
641 dispparams.rgvarg = NULL;
642 dispparams.cArgs = 0;
643 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
644 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
647 /* invocation helper function */
648 static int _invoke_todo_vtResult = 0;
650 static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult)
652 OLECHAR *name = NULL;
653 DISPID dispid;
654 HRESULT hr;
655 UINT i;
656 UINT len;
658 memset(pVarResult, 0, sizeof(VARIANT));
659 VariantInit(pVarResult);
661 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 );
662 name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
663 if (!name) return E_FAIL;
664 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len );
665 hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
666 HeapFree(GetProcessHeap(), 0, name);
667 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
668 if (!hr == S_OK) return hr;
670 memset(&excepinfo, 0, sizeof(excepinfo));
671 hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL);
673 if (hr == S_OK)
675 if (_invoke_todo_vtResult) todo_wine
676 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
677 else
678 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
679 if (vtResult != VT_EMPTY)
681 hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult);
682 ok(hr == S_OK, "VariantChangeTypeEx returned 0x%08x\n", hr);
686 for (i=0; i<pDispParams->cArgs; i++)
687 VariantClear(&pDispParams->rgvarg[i]);
689 return hr;
692 /* Object_Property helper functions */
694 static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord)
696 VARIANT varresult;
697 VARIANTARG vararg[1];
698 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
699 HRESULT hr;
701 VariantInit(&vararg[0]);
702 V_VT(&vararg[0]) = VT_I4;
703 V_I4(&vararg[0]) = count;
705 hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
706 *pRecord = V_DISPATCH(&varresult);
707 return hr;
710 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
712 VARIANTARG vararg[3];
713 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
715 VariantInit(&vararg[2]);
716 V_VT(&vararg[2]) = VT_I4;
717 V_I4(&vararg[2]) = (int)hkey;
718 VariantInit(&vararg[1]);
719 V_VT(&vararg[1]) = VT_BSTR;
720 V_BSTR(&vararg[1]) = SysAllocString(szKey);
721 VariantInit(&vararg[0]);
722 VariantCopy(&vararg[0], &vValue);
723 VariantClear(&vValue);
725 return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect);
728 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
730 VARIANT varresult;
731 VARIANTARG vararg;
732 HRESULT hr;
734 VariantInit(&vararg);
735 V_VT(&vararg) = VT_EMPTY;
736 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL);
737 *pBool = V_BOOL(&varresult);
738 VariantClear(&varresult);
739 return hr;
742 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
744 VARIANT varresult;
745 VARIANTARG vararg;
746 HRESULT hr;
748 VariantInit(&vararg);
749 V_VT(&vararg) = VT_BSTR;
750 V_BSTR(&vararg) = SysAllocString(szValue);
752 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR);
753 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
754 VariantClear(&varresult);
755 return hr;
758 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
760 VARIANT varresult;
761 VARIANTARG vararg;
762 HRESULT hr;
764 VariantInit(&vararg);
765 V_VT(&vararg) = VT_I4;
766 V_I4(&vararg) = iValue;
768 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult);
769 if (SUCCEEDED(hr) && vtResult == VT_BSTR) lstrcpyW(szString, V_BSTR(&varresult));
770 VariantClear(&varresult);
771 return hr;
774 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
776 VARIANT varresult;
777 VARIANTARG vararg[2];
778 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
779 HRESULT hr;
781 VariantInit(&vararg[1]);
782 V_VT(&vararg[1]) = VT_BSTR;
783 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
784 VariantInit(&vararg[0]);
785 V_VT(&vararg[0]) = VT_I4;
786 V_I4(&vararg[0]) = options;
788 hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
789 *pSession = V_DISPATCH(&varresult);
790 return hr;
793 static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase)
795 VARIANT varresult;
796 VARIANTARG vararg[2];
797 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
798 HRESULT hr;
800 VariantInit(&vararg[1]);
801 V_VT(&vararg[1]) = VT_BSTR;
802 V_BSTR(&vararg[1]) = SysAllocString(szDatabasePath);
803 VariantInit(&vararg[0]);
804 V_VT(&vararg[0]) = VT_I4;
805 V_I4(&vararg[0]) = openmode;
807 hr = invoke(pInstaller, "OpenDatabase", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
808 *pDatabase = V_DISPATCH(&varresult);
809 return hr;
812 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
814 VARIANT varresult;
815 VARIANTARG vararg[2];
816 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
818 VariantInit(&vararg[1]);
819 V_VT(&vararg[1]) = VT_BSTR;
820 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
821 VariantInit(&vararg[0]);
822 V_VT(&vararg[0]) = VT_BSTR;
823 V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues);
825 return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
828 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
830 VARIANT varresult;
831 VARIANTARG vararg[1];
832 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
833 HRESULT hr;
835 VariantInit(&vararg[0]);
836 V_VT(&vararg[0]) = VT_BSTR;
837 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
839 hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
840 *pInstallState = V_I4(&varresult);
841 VariantClear(&varresult);
842 return hr;
845 static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szString)
847 VARIANT varresult;
848 VARIANTARG vararg[2];
849 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
850 HRESULT hr;
852 VariantInit(&vararg[1]);
853 V_VT(&vararg[1]) = VT_BSTR;
854 V_BSTR(&vararg[1]) = SysAllocString(szProduct);
855 VariantInit(&vararg[0]);
856 V_VT(&vararg[0]) = VT_BSTR;
857 V_BSTR(&vararg[0]) = SysAllocString(szAttribute);
859 hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
860 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
861 VariantClear(&varresult);
862 return hr;
865 static HRESULT Installer_Products(IDispatch **pStringList)
867 VARIANT varresult;
868 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
869 HRESULT hr;
871 hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
872 *pStringList = V_DISPATCH(&varresult);
873 return hr;
876 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
878 VARIANT varresult;
879 VARIANTARG vararg[1];
880 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
881 HRESULT hr;
883 VariantInit(&vararg[0]);
884 V_VT(&vararg[0]) = VT_BSTR;
885 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
887 hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
888 *pStringList = V_DISPATCH(&varresult);
889 return hr;
892 static HRESULT Installer_VersionGet(LPWSTR szVersion)
894 VARIANT varresult;
895 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
896 HRESULT hr;
898 hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
899 if (V_BSTR(&varresult)) lstrcpyW(szVersion, V_BSTR(&varresult));
900 VariantClear(&varresult);
901 return hr;
904 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
906 VARIANT varresult;
907 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
908 HRESULT hr;
910 hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
911 *pInst = V_DISPATCH(&varresult);
912 return hr;
915 static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn)
917 VARIANT varresult;
918 VARIANTARG vararg[1];
919 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
920 HRESULT hr;
922 VariantInit(&vararg[0]);
923 V_VT(&vararg[0]) = VT_BSTR;
924 V_BSTR(&vararg[0]) = SysAllocString(szName);
926 hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
927 if (V_BSTR(&varresult)) lstrcpyW(szReturn, V_BSTR(&varresult));
928 VariantClear(&varresult);
929 return hr;
932 static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue)
934 VARIANT varresult;
935 VARIANTARG vararg[2];
936 DISPID dispid = DISPID_PROPERTYPUT;
937 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
939 VariantInit(&vararg[1]);
940 V_VT(&vararg[1]) = VT_BSTR;
941 V_BSTR(&vararg[1]) = SysAllocString(szName);
942 VariantInit(&vararg[0]);
943 V_VT(&vararg[0]) = VT_BSTR;
944 V_BSTR(&vararg[0]) = SysAllocString(szValue);
946 return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
949 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
951 VARIANT varresult;
952 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
953 HRESULT hr;
955 hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
956 *pLangId = V_I4(&varresult);
957 VariantClear(&varresult);
958 return hr;
961 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, BOOL *pMode)
963 VARIANT varresult;
964 VARIANTARG vararg[1];
965 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
966 HRESULT hr;
968 VariantInit(&vararg[0]);
969 V_VT(&vararg[0]) = VT_I4;
970 V_I4(&vararg[0]) = iFlag;
972 hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL);
973 *pMode = V_BOOL(&varresult);
974 VariantClear(&varresult);
975 return hr;
978 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, BOOL bMode)
980 VARIANT varresult;
981 VARIANTARG vararg[2];
982 DISPID dispid = DISPID_PROPERTYPUT;
983 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
985 VariantInit(&vararg[1]);
986 V_VT(&vararg[1]) = VT_I4;
987 V_I4(&vararg[1]) = iFlag;
988 VariantInit(&vararg[0]);
989 V_VT(&vararg[0]) = VT_BOOL;
990 V_BOOL(&vararg[0]) = bMode;
992 return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
995 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
997 VARIANT varresult;
998 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
999 HRESULT hr;
1001 hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1002 *pDatabase = V_DISPATCH(&varresult);
1003 return hr;
1006 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn)
1008 VARIANT varresult;
1009 VARIANTARG vararg[1];
1010 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1011 HRESULT hr;
1013 VariantInit(&vararg[0]);
1014 V_VT(&vararg[0]) = VT_BSTR;
1015 V_BSTR(&vararg[0]) = SysAllocString(szAction);
1017 hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1018 *iReturn = V_I4(&varresult);
1019 VariantClear(&varresult);
1020 return hr;
1023 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
1025 VARIANT varresult;
1026 VARIANTARG vararg[1];
1027 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1028 HRESULT hr;
1030 VariantInit(&vararg[0]);
1031 V_VT(&vararg[0]) = VT_BSTR;
1032 V_BSTR(&vararg[0]) = SysAllocString(szCondition);
1034 hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1035 *iReturn = V_I4(&varresult);
1036 VariantClear(&varresult);
1037 return hr;
1040 static HRESULT Session_Message(IDispatch *pSession, long kind, IDispatch *record, int *ret)
1042 VARIANT varresult;
1043 VARIANTARG vararg[2];
1044 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1045 HRESULT hr;
1047 VariantInit(&varresult);
1048 V_VT(vararg) = VT_DISPATCH;
1049 V_DISPATCH(vararg) = record;
1050 V_VT(vararg+1) = VT_I4;
1051 V_I4(vararg+1) = kind;
1053 hr = invoke(pSession, "Message", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1055 ok(V_VT(&varresult) == VT_I4, "V_VT(varresult) = %d\n", V_VT(&varresult));
1056 *ret = V_I4(&varresult);
1058 return hr;
1061 static HRESULT Session_SetInstallLevel(IDispatch *pSession, long iInstallLevel)
1063 VARIANT varresult;
1064 VARIANTARG vararg[1];
1065 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1067 VariantInit(&vararg[0]);
1068 V_VT(&vararg[0]) = VT_I4;
1069 V_I4(&vararg[0]) = iInstallLevel;
1071 return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1074 static HRESULT Session_FeatureCurrentState(IDispatch *pSession, LPCWSTR szName, int *pState)
1076 VARIANT varresult;
1077 VARIANTARG vararg[1];
1078 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1079 HRESULT hr;
1081 VariantInit(&vararg[0]);
1082 V_VT(&vararg[0]) = VT_BSTR;
1083 V_BSTR(&vararg[0]) = SysAllocString(szName);
1085 hr = invoke(pSession, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1086 *pState = V_I4(&varresult);
1087 VariantClear(&varresult);
1088 return hr;
1091 static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState)
1093 VARIANT varresult;
1094 VARIANTARG vararg[1];
1095 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1096 HRESULT hr;
1098 VariantInit(&vararg[0]);
1099 V_VT(&vararg[0]) = VT_BSTR;
1100 V_BSTR(&vararg[0]) = SysAllocString(szName);
1102 hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1103 *pState = V_I4(&varresult);
1104 VariantClear(&varresult);
1105 return hr;
1108 static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState)
1110 VARIANT varresult;
1111 VARIANTARG vararg[2];
1112 DISPID dispid = DISPID_PROPERTYPUT;
1113 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1115 VariantInit(&vararg[1]);
1116 V_VT(&vararg[1]) = VT_BSTR;
1117 V_BSTR(&vararg[1]) = SysAllocString(szName);
1118 VariantInit(&vararg[0]);
1119 V_VT(&vararg[0]) = VT_I4;
1120 V_I4(&vararg[0]) = iState;
1122 return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1125 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
1127 VARIANT varresult;
1128 VARIANTARG vararg[1];
1129 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1130 HRESULT hr;
1132 VariantInit(&vararg[0]);
1133 V_VT(&vararg[0]) = VT_BSTR;
1134 V_BSTR(&vararg[0]) = SysAllocString(szSql);
1136 hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1137 *pView = V_DISPATCH(&varresult);
1138 return hr;
1141 static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo)
1143 VARIANT varresult;
1144 VARIANTARG vararg[1];
1145 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1146 HRESULT hr;
1148 VariantInit(&vararg[0]);
1149 V_VT(&vararg[0]) = VT_I4;
1150 V_I4(&vararg[0]) = iUpdateCount;
1152 hr = invoke(pDatabase, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1153 *pSummaryInfo = V_DISPATCH(&varresult);
1154 return hr;
1157 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
1159 VARIANT varresult;
1160 VARIANTARG vararg[1];
1161 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1163 VariantInit(&vararg[0]);
1164 V_VT(&vararg[0]) = VT_DISPATCH;
1165 V_DISPATCH(&vararg[0]) = pRecord;
1167 return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1170 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
1172 VARIANT varresult;
1173 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1174 HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1175 *ppRecord = V_DISPATCH(&varresult);
1176 return hr;
1179 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
1181 VARIANT varresult;
1182 VARIANTARG vararg[2];
1183 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1185 VariantInit(&vararg[1]);
1186 V_VT(&vararg[1]) = VT_I4;
1187 V_I4(&vararg[1]) = iMode;
1188 VariantInit(&vararg[0]);
1189 V_VT(&vararg[0]) = VT_DISPATCH;
1190 V_DISPATCH(&vararg[0]) = pRecord;
1191 if (pRecord)
1192 IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */
1194 return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1197 static HRESULT View_Close(IDispatch *pView)
1199 VARIANT varresult;
1200 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1201 return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1204 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
1206 VARIANT varresult;
1207 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1208 HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1209 *pFieldCount = V_I4(&varresult);
1210 VariantClear(&varresult);
1211 return hr;
1214 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString)
1216 VARIANT varresult;
1217 VARIANTARG vararg[1];
1218 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1219 HRESULT hr;
1221 VariantInit(&vararg[0]);
1222 V_VT(&vararg[0]) = VT_I4;
1223 V_I4(&vararg[0]) = iField;
1225 hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1226 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1227 VariantClear(&varresult);
1228 return hr;
1231 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
1233 VARIANT varresult;
1234 VARIANTARG vararg[2];
1235 DISPID dispid = DISPID_PROPERTYPUT;
1236 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1238 VariantInit(&vararg[1]);
1239 V_VT(&vararg[1]) = VT_I4;
1240 V_I4(&vararg[1]) = iField;
1241 VariantInit(&vararg[0]);
1242 V_VT(&vararg[0]) = VT_BSTR;
1243 V_BSTR(&vararg[0]) = SysAllocString(szString);
1245 return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1248 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
1250 VARIANT varresult;
1251 VARIANTARG vararg[1];
1252 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1253 HRESULT hr;
1255 VariantInit(&vararg[0]);
1256 V_VT(&vararg[0]) = VT_I4;
1257 V_I4(&vararg[0]) = iField;
1259 hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1260 *pValue = V_I4(&varresult);
1261 VariantClear(&varresult);
1262 return hr;
1265 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
1267 VARIANT varresult;
1268 VARIANTARG vararg[2];
1269 DISPID dispid = DISPID_PROPERTYPUT;
1270 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1272 VariantInit(&vararg[1]);
1273 V_VT(&vararg[1]) = VT_I4;
1274 V_I4(&vararg[1]) = iField;
1275 VariantInit(&vararg[0]);
1276 V_VT(&vararg[0]) = VT_I4;
1277 V_I4(&vararg[0]) = iValue;
1279 return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1282 static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT)
1284 VARIANT varresult;
1285 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1286 HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN);
1287 *ppEnumVARIANT = V_UNKNOWN(&varresult);
1288 return hr;
1291 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
1293 VARIANT varresult;
1294 VARIANTARG vararg[1];
1295 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1296 HRESULT hr;
1298 VariantInit(&vararg[0]);
1299 V_VT(&vararg[0]) = VT_I4;
1300 V_I4(&vararg[0]) = iIndex;
1302 hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1303 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1304 VariantClear(&varresult);
1305 return hr;
1308 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
1310 VARIANT varresult;
1311 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1312 HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1313 *pCount = V_I4(&varresult);
1314 VariantClear(&varresult);
1315 return hr;
1318 static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect)
1320 VARIANTARG vararg[1];
1321 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1323 VariantInit(&vararg[0]);
1324 V_VT(&vararg[0]) = VT_I4;
1325 V_I4(&vararg[0]) = pid;
1326 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYGET, &dispparams, pVarResult, vtExpect);
1329 static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant)
1331 VARIANT varresult;
1332 VARIANTARG vararg[2];
1333 DISPID dispid = DISPID_PROPERTYPUT;
1334 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1336 VariantInit(&vararg[1]);
1337 V_VT(&vararg[1]) = VT_I4;
1338 V_I4(&vararg[1]) = pid;
1339 VariantInit(&vararg[0]);
1340 VariantCopyInd(vararg, pVariant);
1342 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1345 static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount)
1347 VARIANT varresult;
1348 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1349 HRESULT hr;
1351 hr = invoke(pSummaryInfo, "PropertyCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1352 *pCount = V_I4(&varresult);
1353 VariantClear(&varresult);
1354 return hr;
1357 /* Test the various objects */
1359 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4
1361 static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly)
1363 static const WCHAR szPropertyException[] = { 'P','r','o','p','e','r','t','y',',','P','i','d',0 };
1364 static const WCHAR szTitle[] = { 'T','i','t','l','e',0 };
1365 VARIANT varresult, var;
1366 SYSTEMTIME st;
1367 HRESULT hr;
1368 int j;
1370 /* SummaryInfo::PropertyCount */
1371 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1372 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1373 ok(j == num_info, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1375 /* SummaryInfo::Property, get for properties we have set */
1376 for (j = 0; j < num_info; j++)
1378 const msi_summary_info *entry = &info[j];
1380 int vt = entry->datatype;
1381 if (vt == VT_LPSTR) vt = VT_BSTR;
1382 else if (vt == VT_FILETIME) vt = VT_DATE;
1383 else if (vt == VT_I2) vt = VT_I4;
1385 hr = SummaryInfo_PropertyGet(pSummaryInfo, entry->property, &varresult, vt);
1386 ok(hr == S_OK, "SummaryInfo_Property (pid %d) failed, hresult 0x%08x\n", entry->property, hr);
1387 if (V_VT(&varresult) != vt)
1388 skip("Skipping property tests due to type mismatch\n");
1389 else if (vt == VT_I4)
1390 ok(V_I4(&varresult) == entry->iValue, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %d\n",
1391 entry->property, entry->iValue, V_I4(&varresult));
1392 else if (vt == VT_DATE)
1394 FILETIME ft;
1395 DATE d;
1397 FileTimeToLocalFileTime(entry->pftValue, &ft);
1398 FileTimeToSystemTime(&ft, &st);
1399 SystemTimeToVariantTime(&st, &d);
1400 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));
1402 else if (vt == VT_BSTR)
1404 ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry->property, entry->szValue, V_BSTR(&varresult));
1406 else
1407 skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry->property, vt);
1409 VariantClear(&varresult);
1412 /* SummaryInfo::Property, get; invalid arguments */
1414 /* Invalid pids */
1415 hr = SummaryInfo_PropertyGet(pSummaryInfo, -1, &varresult, VT_EMPTY);
1416 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1417 ok_exception(hr, szPropertyException);
1419 hr = SummaryInfo_PropertyGet(pSummaryInfo, 1000, &varresult, VT_EMPTY);
1420 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1421 ok_exception(hr, szPropertyException);
1423 /* Unsupported pids */
1424 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_DICTIONARY, &varresult, VT_EMPTY);
1425 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1427 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY);
1428 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1430 /* Pids we have not set, one for each type */
1431 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_EMPTY);
1432 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1434 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY);
1435 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1437 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY);
1438 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1440 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY);
1441 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1443 if (!readonly)
1445 /* SummaryInfo::Property, put; one for each type */
1447 /* VT_I2 */
1448 VariantInit(&var);
1449 V_VT(&var) = VT_I2;
1450 V_I2(&var) = 1;
1451 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CODEPAGE, &var);
1452 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1454 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */);
1455 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1456 ok(V_I2(&var) == V_I2(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var), V_I2(&varresult));
1457 VariantClear(&varresult);
1458 VariantClear(&var);
1460 /* VT_BSTR */
1461 V_VT(&var) = VT_BSTR;
1462 V_BSTR(&var) = SysAllocString(szTitle);
1463 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_TITLE, &var);
1464 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1466 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var));
1467 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1468 ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var), V_BSTR(&varresult));
1469 VariantClear(&varresult);
1470 VariantClear(&var);
1472 /* VT_DATE */
1473 V_VT(&var) = VT_DATE;
1474 FileTimeToSystemTime(&systemtime, &st);
1475 SystemTimeToVariantTime(&st, &V_DATE(&var));
1476 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_LASTSAVE_DTM, &var);
1477 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1479 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var));
1480 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1481 /* FIXME: Off by one second */
1482 todo_wine ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1483 VariantClear(&varresult);
1484 VariantClear(&var);
1486 /* VT_I4 */
1487 V_VT(&var) = VT_I4;
1488 V_I4(&var) = 1000;
1489 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1490 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1492 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1493 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1494 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult));
1495 VariantClear(&varresult);
1496 VariantClear(&var);
1498 /* SummaryInfo::PropertyCount */
1499 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1500 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1501 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1505 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1507 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 };
1508 static WCHAR szThree[] = { 'T','h','r','e','e',0 };
1509 static WCHAR szTwo[] = { 'T','w','o',0 };
1510 static WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
1511 static WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 };
1512 IDispatch *pView = NULL, *pSummaryInfo = NULL;
1513 HRESULT hr;
1515 hr = Database_OpenView(pDatabase, szSql, &pView);
1516 ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr);
1517 if (hr == S_OK)
1519 IDispatch *pRecord = NULL;
1520 WCHAR szString[MAX_PATH];
1522 /* View::Execute */
1523 hr = View_Execute(pView, NULL);
1524 ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr);
1526 /* View::Fetch */
1527 hr = View_Fetch(pView, &pRecord);
1528 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1529 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1530 if (pRecord)
1532 /* Record::StringDataGet */
1533 memset(szString, 0, sizeof(szString));
1534 hr = Record_StringDataGet(pRecord, 1, szString);
1535 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1536 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1538 /* Record::StringDataPut with correct index */
1539 hr = Record_StringDataPut(pRecord, 1, szTwo);
1540 ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1542 /* Record::StringDataGet */
1543 memset(szString, 0, sizeof(szString));
1544 hr = Record_StringDataGet(pRecord, 1, szString);
1545 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1546 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1548 /* Record::StringDataPut with incorrect index */
1549 hr = Record_StringDataPut(pRecord, -1, szString);
1550 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1551 ok_exception(hr, szStringDataField);
1553 /* View::Modify with incorrect parameters */
1554 hr = View_Modify(pView, -5, NULL);
1555 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1556 ok_exception(hr, szModifyModeRecord);
1558 hr = View_Modify(pView, -5, pRecord);
1559 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1560 ok_exception(hr, szModifyModeRecord);
1562 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1563 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1564 ok_exception(hr, szModifyModeRecord);
1566 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1567 ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr);
1569 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1570 memset(szString, 0, sizeof(szString));
1571 hr = Record_StringDataGet(pRecord, 1, szString);
1572 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1573 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1575 IDispatch_Release(pRecord);
1578 /* View::Fetch */
1579 hr = View_Fetch(pView, &pRecord);
1580 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1581 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1582 if (pRecord)
1584 /* Record::StringDataGet */
1585 memset(szString, 0, sizeof(szString));
1586 hr = Record_StringDataGet(pRecord, 1, szString);
1587 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1588 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1590 IDispatch_Release(pRecord);
1593 /* View::Fetch */
1594 hr = View_Fetch(pView, &pRecord);
1595 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1596 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1597 if (pRecord)
1598 IDispatch_Release(pRecord);
1600 /* View::Close */
1601 hr = View_Close(pView);
1602 ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr);
1604 IDispatch_Release(pView);
1607 /* Database::SummaryInformation */
1608 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo);
1609 ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr);
1610 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1611 if (pSummaryInfo)
1613 test_SummaryInfo(pSummaryInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), readonly);
1614 IDispatch_Release(pSummaryInfo);
1618 static void test_Session(IDispatch *pSession)
1620 static WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
1621 static WCHAR szOne[] = { 'O','n','e',0 };
1622 static WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 };
1623 static WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 };
1624 static WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 };
1625 static WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 };
1626 static WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1627 static WCHAR szEmpty[] = { 0 };
1628 static WCHAR szEquals[] = { '=',0 };
1629 static WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
1630 WCHAR stringw[MAX_PATH];
1631 CHAR string[MAX_PATH];
1632 UINT len;
1633 BOOL bool;
1634 int myint;
1635 IDispatch *pDatabase = NULL, *pInst = NULL, *record = NULL;
1636 HRESULT hr;
1638 /* Session::Installer */
1639 hr = Session_Installer(pSession, &pInst);
1640 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1641 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1642 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1644 /* Session::Property, get */
1645 memset(stringw, 0, sizeof(stringw));
1646 hr = Session_PropertyGet(pSession, szProductName, stringw);
1647 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1648 if (lstrcmpW(stringw, szMSITEST) != 0)
1650 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1651 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1652 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1655 /* Session::Property, put */
1656 hr = Session_PropertyPut(pSession, szProductName, szProductName);
1657 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1658 memset(stringw, 0, sizeof(stringw));
1659 hr = Session_PropertyGet(pSession, szProductName, stringw);
1660 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1661 if (lstrcmpW(stringw, szProductName) != 0)
1663 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1664 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1665 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1668 /* Try putting a property using empty property identifier */
1669 hr = Session_PropertyPut(pSession, szEmpty, szProductName);
1670 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1671 ok_exception(hr, szPropertyName);
1673 /* Try putting a property using illegal property identifier */
1674 hr = Session_PropertyPut(pSession, szEquals, szProductName);
1675 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1677 /* Session::Language, get */
1678 hr = Session_LanguageGet(pSession, &len);
1679 ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1680 /* Not sure how to check the language is correct */
1682 /* Session::Mode, get */
1683 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1684 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1685 todo_wine ok(!bool, "Reboot at end session mode is %d\n", bool);
1687 /* Session::Mode, put */
1688 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE);
1689 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1690 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1691 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1692 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1693 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE); /* set it again so we don't reboot */
1694 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1696 /* Session::Database, get */
1697 hr = Session_Database(pSession, &pDatabase);
1698 ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr);
1699 if (hr == S_OK)
1701 test_Database(pDatabase, TRUE);
1702 IDispatch_Release(pDatabase);
1705 /* Session::EvaluateCondition */
1706 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1707 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1708 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1710 hr = Session_EvaluateCondition(pSession, szEmpty, &myint);
1711 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1712 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1714 hr = Session_EvaluateCondition(pSession, szEquals, &myint);
1715 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1716 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1718 /* Session::DoAction(CostInitialize) must occur before the next statements */
1719 hr = Session_DoAction(pSession, szCostInitialize, &myint);
1720 ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr);
1721 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1723 /* Session::SetInstallLevel */
1724 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1725 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
1727 /* Session::FeatureCurrentState, get */
1728 hr = Session_FeatureCurrentState(pSession, szOne, &myint);
1729 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
1730 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1732 /* Session::Message */
1733 hr = Installer_CreateRecord(0, &record);
1734 ok(hr == S_OK, "Installer_CreateRecord failed: %08x\n", hr);
1735 hr = Session_Message(pSession, INSTALLMESSAGE_INFO, record, &myint);
1736 ok(hr == S_OK, "Session_Message failed: %08x\n", hr);
1737 ok(myint == 0, "Session_Message returned %x\n", myint);
1739 /* Session::EvaluateCondition */
1740 hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint);
1741 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1742 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1744 hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint);
1745 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1746 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1748 /* Session::FeatureRequestState, put */
1749 hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED);
1750 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
1751 hr = Session_FeatureRequestStateGet(pSession, szOne, &myint);
1752 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
1753 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
1755 /* Session::EvaluateCondition */
1756 hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint);
1757 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1758 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1760 hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint);
1761 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1762 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1765 /* delete key and all its subkeys */
1766 static DWORD delete_key( HKEY hkey )
1768 char name[MAX_PATH];
1769 DWORD ret;
1771 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
1773 HKEY tmp;
1774 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
1776 ret = delete_key( tmp );
1777 RegCloseKey( tmp );
1779 if (ret) break;
1781 if (ret != ERROR_NO_MORE_ITEMS) return ret;
1782 RegDeleteKeyA( hkey, "" );
1783 return 0;
1786 static void test_Installer_RegistryValue(void)
1788 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
1789 static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 };
1790 static const WCHAR szOne[] = { 'O','n','e',0 };
1791 static const WCHAR szTwo[] = { 'T','w','o',0 };
1792 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
1793 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1794 static const WCHAR szFour[] = { 'F','o','u','r',0 };
1795 static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 };
1796 static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 };
1797 static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 };
1798 static const WCHAR szSix[] = { 'S','i','x',0 };
1799 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1800 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
1801 static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
1802 static const WCHAR szBlank[] = { 0 };
1803 VARIANT varresult;
1804 VARIANTARG vararg;
1805 WCHAR szString[MAX_PATH];
1806 HKEY hkey, hkey_sub;
1807 HKEY curr_user = (HKEY)1;
1808 HRESULT hr;
1809 BOOL bRet;
1811 /* Delete keys */
1812 if (!RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey )) delete_key( hkey );
1814 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
1815 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
1816 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1817 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
1819 memset(szString, 0, sizeof(szString));
1820 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
1821 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1823 memset(szString, 0, sizeof(szString));
1824 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
1825 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1827 /* Create key */
1828 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
1830 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1831 "RegSetValueExW failed\n");
1832 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
1833 "RegSetValueExW failed\n");
1834 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
1835 "RegSetValueExW failed\n");
1836 ok(SetEnvironmentVariableA("MSITEST", "Four"), "SetEnvironmentVariableA failed %d\n", GetLastError());
1837 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
1838 "RegSetValueExW failed\n");
1839 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
1840 "RegSetValueExW failed\n");
1841 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
1842 "RegSetValueExW failed\n");
1843 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, (const BYTE *)NULL, 0),
1844 "RegSetValueExW failed\n");
1846 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1847 "RegSetValueExW failed\n");
1849 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
1851 /* Does our key exist? It should, and make sure we retrieve the correct default value */
1852 bRet = FALSE;
1853 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
1854 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1855 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
1857 memset(szString, 0, sizeof(szString));
1858 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
1859 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1860 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1862 /* Ask for the value of a nonexistent key */
1863 memset(szString, 0, sizeof(szString));
1864 hr = Installer_RegistryValueW(curr_user, szKey, szExpand, szString);
1865 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1867 /* Get values of keys */
1868 memset(szString, 0, sizeof(szString));
1869 hr = Installer_RegistryValueW(curr_user, szKey, szOne, szString);
1870 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1871 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1873 VariantInit(&vararg);
1874 V_VT(&vararg) = VT_BSTR;
1875 V_BSTR(&vararg) = SysAllocString(szTwo);
1876 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_I4);
1877 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1878 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
1879 VariantClear(&varresult);
1881 memset(szString, 0, sizeof(szString));
1882 hr = Installer_RegistryValueW(curr_user, szKey, szThree, szString);
1883 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1884 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
1886 memset(szString, 0, sizeof(szString));
1887 hr = Installer_RegistryValueW(curr_user, szKey, szFour, szString);
1888 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1889 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
1891 memset(szString, 0, sizeof(szString));
1892 hr = Installer_RegistryValueW(curr_user, szKey, szFive, szString);
1893 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1894 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFiveHi);
1896 memset(szString, 0, sizeof(szString));
1897 hr = Installer_RegistryValueW(curr_user, szKey, szSix, szString);
1898 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1899 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_);
1901 VariantInit(&vararg);
1902 V_VT(&vararg) = VT_BSTR;
1903 V_BSTR(&vararg) = SysAllocString(szSeven);
1904 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_EMPTY);
1905 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1907 /* Get string class name for the key */
1908 memset(szString, 0, sizeof(szString));
1909 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
1910 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1911 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank);
1913 /* Get name of a value by positive number (RegEnumValue like), valid index */
1914 memset(szString, 0, sizeof(szString));
1915 hr = Installer_RegistryValueI(curr_user, szKey, 2, szString, VT_BSTR);
1916 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1917 /* RegEnumValue order seems different on wine */
1918 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
1920 /* Get name of a value by positive number (RegEnumValue like), invalid index */
1921 memset(szString, 0, sizeof(szString));
1922 hr = Installer_RegistryValueI(curr_user, szKey, 10, szString, VT_EMPTY);
1923 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1925 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
1926 memset(szString, 0, sizeof(szString));
1927 hr = Installer_RegistryValueI(curr_user, szKey, -1, szString, VT_BSTR);
1928 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1929 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
1931 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
1932 memset(szString, 0, sizeof(szString));
1933 hr = Installer_RegistryValueI(curr_user, szKey, -10, szString, VT_EMPTY);
1934 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1936 /* clean up */
1937 delete_key(hkey);
1940 static void test_Installer_Products(BOOL bProductInstalled)
1942 WCHAR szString[MAX_PATH];
1943 HRESULT hr;
1944 int idx;
1945 IUnknown *pUnk = NULL;
1946 IEnumVARIANT *pEnum = NULL;
1947 VARIANT var;
1948 ULONG celt;
1949 int iCount, iValue;
1950 IDispatch *pStringList = NULL;
1951 BOOL bProductFound = FALSE;
1953 /* Installer::Products */
1954 hr = Installer_Products(&pStringList);
1955 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
1956 if (hr == S_OK)
1958 /* StringList::_NewEnum */
1959 hr = StringList__NewEnum(pStringList, &pUnk);
1960 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
1961 if (hr == S_OK)
1963 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
1964 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
1966 if (!pEnum)
1967 skip("IEnumVARIANT tests\n");
1969 /* StringList::Count */
1970 hr = StringList_Count(pStringList, &iCount);
1971 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
1973 for (idx=0; idx<iCount; idx++)
1975 /* StringList::Item */
1976 memset(szString, 0, sizeof(szString));
1977 hr = StringList_Item(pStringList, idx, szString);
1978 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
1980 if (hr == S_OK)
1982 /* Installer::ProductState */
1983 hr = Installer_ProductState(szString, &iValue);
1984 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
1985 if (hr == S_OK)
1986 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
1988 /* Not found our product code yet? Check */
1989 if (!bProductFound && !lstrcmpW(szString, szProductCode))
1990 bProductFound = TRUE;
1992 /* IEnumVARIANT::Next */
1993 if (pEnum)
1995 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
1996 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
1997 ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
1998 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
1999 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2000 VariantClear(&var);
2005 if (bProductInstalled) todo_wine
2007 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
2008 bProductInstalled ? "be" : "not be",
2009 bProductFound ? "found" : "not found");
2012 if (pEnum)
2014 IEnumVARIANT *pEnum2 = NULL;
2016 if (0) /* Crashes on Windows XP */
2018 /* IEnumVARIANT::Clone, NULL pointer */
2019 hr = IEnumVARIANT_Clone(pEnum, NULL);
2022 /* IEnumVARIANT::Clone */
2023 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
2024 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
2025 if (hr == S_OK)
2027 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
2029 /* IEnumVARIANT::Next of the clone */
2030 if (iCount)
2032 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
2033 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2034 ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
2035 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2036 VariantClear(&var);
2038 else
2039 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
2041 IEnumVARIANT_Release(pEnum2);
2044 /* IEnumVARIANT::Skip should fail */
2045 hr = IEnumVARIANT_Skip(pEnum, 1);
2046 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2048 /* IEnumVARIANT::Next, NULL variant pointer */
2049 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2050 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2051 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2053 /* IEnumVARIANT::Next, should not return any more items */
2054 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2055 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2056 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2057 VariantClear(&var);
2059 /* IEnumVARIANT::Reset */
2060 hr = IEnumVARIANT_Reset(pEnum);
2061 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2063 if (iCount)
2065 /* IEnumVARIANT::Skip to the last product */
2066 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2067 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2069 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2070 * NULL celt pointer. */
2071 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2072 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2073 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2074 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2075 VariantClear(&var);
2077 else
2078 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2081 /* StringList::Item using an invalid index */
2082 memset(szString, 0, sizeof(szString));
2083 hr = StringList_Item(pStringList, iCount, szString);
2084 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2086 if (pEnum) IEnumVARIANT_Release(pEnum);
2087 if (pUnk) IUnknown_Release(pUnk);
2088 IDispatch_Release(pStringList);
2092 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2093 * deleting the subkeys first) */
2094 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey)
2096 UINT ret;
2097 CHAR *string = NULL;
2098 HKEY hkey;
2099 DWORD dwSize;
2101 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2102 if (ret != ERROR_SUCCESS) return ret;
2103 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2104 if (ret != ERROR_SUCCESS) return ret;
2105 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2107 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2108 delete_registry_key(hkey, string);
2110 RegCloseKey(hkey);
2111 HeapFree(GetProcessHeap(), 0, string);
2112 RegDeleteKeyA(hkeyParent, subkey);
2113 return ERROR_SUCCESS;
2116 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2117 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, HKEY *phkey)
2119 UINT ret;
2120 CHAR *string = NULL;
2121 int idx = 0;
2122 HKEY hkey;
2123 DWORD dwSize;
2124 BOOL found = FALSE;
2126 *phkey = 0;
2128 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2129 if (ret != ERROR_SUCCESS) return ret;
2130 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2131 if (ret != ERROR_SUCCESS) return ret;
2132 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2134 while (!found &&
2135 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2137 if (!strcmp(string, findkey))
2139 *phkey = hkey;
2140 found = TRUE;
2142 else if (find_registry_key(hkey, string, findkey, phkey) == ERROR_SUCCESS) found = TRUE;
2145 if (*phkey != hkey) RegCloseKey(hkey);
2146 HeapFree(GetProcessHeap(), 0, string);
2147 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2150 static void test_Installer_InstallProduct(void)
2152 HRESULT hr;
2153 CHAR path[MAX_PATH];
2154 WCHAR szString[MAX_PATH];
2155 LONG res;
2156 HKEY hkey;
2157 DWORD num, size, type;
2158 int iValue, iCount;
2159 IDispatch *pStringList = NULL;
2161 create_test_files();
2163 /* Installer::InstallProduct */
2164 hr = Installer_InstallProduct(szMsifile, NULL);
2165 if (hr == DISP_E_EXCEPTION)
2167 skip("Installer object not supported.\n");
2168 delete_test_files();
2169 return;
2171 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2173 /* Installer::ProductState for our product code, which has been installed */
2174 hr = Installer_ProductState(szProductCode, &iValue);
2175 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2176 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2178 /* Installer::ProductInfo for our product code */
2180 /* NULL attribute */
2181 memset(szString, 0, sizeof(szString));
2182 hr = Installer_ProductInfo(szProductCode, NULL, szString);
2183 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2184 ok_exception(hr, szProductInfoException);
2186 /* Nonexistent attribute */
2187 memset(szString, 0, sizeof(szString));
2188 hr = Installer_ProductInfo(szProductCode, szMsifile, szString);
2189 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2190 ok_exception(hr, szProductInfoException);
2192 /* Package name */
2193 memset(szString, 0, sizeof(szString));
2194 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szString);
2195 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2196 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile);
2198 /* Product name */
2199 memset(szString, 0, sizeof(szString));
2200 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PRODUCTNAMEW, szString);
2201 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2202 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST);
2204 /* Installer::Products */
2205 test_Installer_Products(TRUE);
2207 /* Installer::RelatedProducts for our upgrade code */
2208 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2209 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2210 if (hr == S_OK)
2212 /* StringList::Count */
2213 hr = StringList_Count(pStringList, &iCount);
2214 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2215 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2217 /* StringList::Item */
2218 memset(szString, 0, sizeof(szString));
2219 hr = StringList_Item(pStringList, 0, szString);
2220 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2221 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
2223 IDispatch_Release(pStringList);
2226 /* Check & clean up installed files & registry keys */
2227 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2228 ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
2229 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2230 ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
2231 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2232 ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
2233 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2234 ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
2235 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2236 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2237 ok(delete_pf("msitest", FALSE), "File not installed\n");
2239 res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
2240 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2242 size = MAX_PATH;
2243 type = REG_SZ;
2244 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2245 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2246 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2248 size = MAX_PATH;
2249 type = REG_SZ;
2250 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2251 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2253 size = sizeof(num);
2254 type = REG_DWORD;
2255 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2256 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2257 ok(num == 314, "Expected 314, got %d\n", num);
2259 size = MAX_PATH;
2260 type = REG_SZ;
2261 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2262 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2263 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2265 RegCloseKey(hkey);
2267 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest");
2268 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2270 /* Remove registry keys written by RegisterProduct standard action */
2271 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F1C3AF50-8B56-4A69-A00C-00773FE42F30}");
2272 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2274 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2275 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2277 res = find_registry_key(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "05FA3C1F65B896A40AC00077F34EF203", &hkey);
2278 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2279 if (res == ERROR_SUCCESS)
2281 res = delete_registry_key(hkey, "05FA3C1F65B896A40AC00077F34EF203");
2282 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2283 RegCloseKey(hkey);
2286 /* Remove registry keys written by PublishProduct standard action */
2287 res = RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2288 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2290 res = delete_registry_key(hkey, "Products\\05FA3C1F65B896A40AC00077F34EF203");
2291 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2293 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2294 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2296 RegCloseKey(hkey);
2298 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203");
2299 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2301 /* Delete installation files we installed */
2302 delete_test_files();
2305 static void test_Installer(void)
2307 static WCHAR szBackslash[] = { '\\',0 };
2308 static WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
2309 static WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
2310 WCHAR szPath[MAX_PATH];
2311 HRESULT hr;
2312 UINT len;
2313 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL;
2314 int iValue, iCount;
2316 if (!pInstaller) return;
2318 /* Installer::CreateRecord */
2320 /* Test for error */
2321 hr = Installer_CreateRecord(-1, &pRecord);
2322 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2323 ok_exception(hr, szCreateRecordException);
2325 /* Test for success */
2326 hr = Installer_CreateRecord(1, &pRecord);
2327 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2328 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2329 if (pRecord)
2331 /* Record::FieldCountGet */
2332 hr = Record_FieldCountGet(pRecord, &iValue);
2333 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2334 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2336 /* Record::IntegerDataGet */
2337 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2338 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2339 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2341 /* Record::IntegerDataGet, bad index */
2342 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2343 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2344 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2346 /* Record::IntegerDataPut */
2347 hr = Record_IntegerDataPut(pRecord, 1, 100);
2348 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2350 /* Record::IntegerDataPut, bad index */
2351 hr = Record_IntegerDataPut(pRecord, 10, 100);
2352 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2353 ok_exception(hr, szIntegerDataException);
2355 /* Record::IntegerDataGet */
2356 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2357 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2358 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2360 IDispatch_Release(pRecord);
2363 /* Prepare package */
2364 create_database(msifile, tables, sizeof(tables) / sizeof(msi_table),
2365 summary_info, sizeof(summary_info) / sizeof(msi_summary_info));
2367 len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, CURR_DIR, -1, szPath, MAX_PATH);
2368 ok(len, "MultiByteToWideChar returned error %d\n", GetLastError());
2369 if (!len) return;
2371 lstrcatW(szPath, szBackslash);
2372 lstrcatW(szPath, szMsifile);
2374 /* Installer::OpenPackage */
2375 hr = Installer_OpenPackage(szPath, 0, &pSession);
2376 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2377 if (hr == S_OK)
2379 test_Session(pSession);
2380 IDispatch_Release(pSession);
2383 /* Installer::OpenDatabase */
2384 hr = Installer_OpenDatabase(szPath, (int)MSIDBOPEN_TRANSACT, &pDatabase);
2385 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2386 if (hr == S_OK)
2388 test_Database(pDatabase, FALSE);
2389 IDispatch_Release(pDatabase);
2392 /* Installer::RegistryValue */
2393 test_Installer_RegistryValue();
2395 /* Installer::ProductState for our product code, which should not be installed */
2396 hr = Installer_ProductState(szProductCode, &iValue);
2397 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2398 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2400 /* Installer::ProductInfo for our product code, which should not be installed */
2402 /* Package name */
2403 memset(szPath, 0, sizeof(szPath));
2404 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szPath);
2405 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2406 ok_exception(hr, szProductInfoException);
2408 /* NULL attribute and NULL product code */
2409 memset(szPath, 0, sizeof(szPath));
2410 hr = Installer_ProductInfo(NULL, NULL, szPath);
2411 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2412 ok_exception(hr, szProductInfoException);
2414 /* Installer::Products */
2415 test_Installer_Products(FALSE);
2417 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2418 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2419 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2420 if (hr == S_OK)
2422 /* StringList::Count */
2423 hr = StringList_Count(pStringList, &iCount);
2424 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2425 ok(!iCount, "Expected no related products but found %d\n", iCount);
2427 IDispatch_Release(pStringList);
2430 /* Installer::Version */
2431 memset(szPath, 0, sizeof(szPath));
2432 hr = Installer_VersionGet(szPath);
2433 ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr);
2435 /* Installer::InstallProduct and other tests that depend on our product being installed */
2436 test_Installer_InstallProduct();
2439 START_TEST(automation)
2441 DWORD len;
2442 char temp_path[MAX_PATH], prev_path[MAX_PATH];
2443 HRESULT hr;
2444 CLSID clsid;
2445 IUnknown *pUnk;
2447 GetSystemTimeAsFileTime(&systemtime);
2449 GetCurrentDirectoryA(MAX_PATH, prev_path);
2450 GetTempPath(MAX_PATH, temp_path);
2451 SetCurrentDirectoryA(temp_path);
2453 lstrcpyA(CURR_DIR, temp_path);
2454 len = lstrlenA(CURR_DIR);
2456 if(len && (CURR_DIR[len - 1] == '\\'))
2457 CURR_DIR[len - 1] = 0;
2459 get_program_files_dir(PROG_FILES_DIR);
2461 hr = OleInitialize(NULL);
2462 ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr);
2463 hr = CLSIDFromProgID(szProgId, &clsid);
2464 ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr);
2465 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2466 ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr);
2468 if (pUnk)
2470 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2471 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2473 test_dispid();
2474 test_dispatch();
2475 test_Installer();
2477 IDispatch_Release(pInstaller);
2478 IUnknown_Release(pUnk);
2481 OleUninitialize();
2483 SetCurrentDirectoryA(prev_path);