msi: Simplify MsiQueryComponentState, with more tests.
[wine/hacks.git] / dlls / msi / tests / automation.c
blobd2aac28f2c717589e8d1a58c9b1aceba2dfd106c
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 <windows.h>
27 #include <msiquery.h>
28 #include <msidefs.h>
29 #include <msi.h>
30 #include <fci.h>
32 #include "wine/test.h"
34 static const char *msifile = "winetest.msi";
35 static const WCHAR szMsifile[] = {'w','i','n','e','t','e','s','t','.','m','s','i',0};
36 static const WCHAR szMSITEST[] = { 'M','S','I','T','E','S','T',0 };
37 static const WCHAR szProductCode[] = { '{','F','1','C','3','A','F','5','0','-','8','B','5','6','-','4','A','6','9','-','A','0','0','C','-','0','0','7','7','3','F','E','4','2','F','3','0','}',0 };
38 static const WCHAR szUpgradeCode[] = { '{','C','E','0','6','7','E','8','D','-','2','E','1','A','-','4','3','6','7','-','B','7','3','4','-','4','E','B','2','B','D','A','D','6','5','6','5','}',0 };
39 static const WCHAR szProductInfoException[] = { 'P','r','o','d','u','c','t','I','n','f','o',',','P','r','o','d','u','c','t',',','A','t','t','r','i','b','u','t','e',0 };
40 static const WCHAR WINE_INSTALLPROPERTY_PACKAGENAMEW[] = {'P','a','c','k','a','g','e','N','a','m','e',0};
41 static const WCHAR WINE_INSTALLPROPERTY_PRODUCTNAMEW[] = {'P','r','o','d','u','c','t','N','a','m','e',0};
42 static FILETIME systemtime;
43 static CHAR CURR_DIR[MAX_PATH];
44 static EXCEPINFO excepinfo;
47 * OLE automation data
48 **/
49 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 };
50 static IDispatch *pInstaller;
52 /* msi database data */
54 static const CHAR component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
55 "s72\tS38\ts72\ti2\tS255\tS72\n"
56 "Component\tComponent\n"
57 "Five\t{8CC92E9D-14B2-4CA4-B2AA-B11D02078087}\tNEWDIR\t2\t\tfive.txt\n"
58 "Four\t{FD37B4EA-7209-45C0-8917-535F35A2F080}\tCABOUTDIR\t2\t\tfour.txt\n"
59 "One\t{783B242E-E185-4A56-AF86-C09815EC053C}\tMSITESTDIR\t2\t\tone.txt\n"
60 "Three\t{010B6ADD-B27D-4EDD-9B3D-34C4F7D61684}\tCHANGEDDIR\t2\t\tthree.txt\n"
61 "Two\t{BF03D1A6-20DA-4A65-82F3-6CAC995915CE}\tFIRSTDIR\t2\t\ttwo.txt\n"
62 "dangler\t{6091DF25-EF96-45F1-B8E9-A9B1420C7A3C}\tTARGETDIR\t4\t\tregdata\n"
63 "component\t\tMSITESTDIR\t0\t1\tfile\n"
64 "service_comp\t\tMSITESTDIR\t0\t1\tservice_file";
66 static const CHAR directory_dat[] = "Directory\tDirectory_Parent\tDefaultDir\n"
67 "s72\tS72\tl255\n"
68 "Directory\tDirectory\n"
69 "CABOUTDIR\tMSITESTDIR\tcabout\n"
70 "CHANGEDDIR\tMSITESTDIR\tchanged:second\n"
71 "FIRSTDIR\tMSITESTDIR\tfirst\n"
72 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
73 "NEWDIR\tCABOUTDIR\tnew\n"
74 "ProgramFilesFolder\tTARGETDIR\t.\n"
75 "TARGETDIR\t\tSourceDir";
77 static const CHAR feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
78 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
79 "Feature\tFeature\n"
80 "Five\t\tFive\tThe Five Feature\t5\t3\tNEWDIR\t0\n"
81 "Four\t\tFour\tThe Four Feature\t4\t3\tCABOUTDIR\t0\n"
82 "One\t\tOne\tThe One Feature\t1\t3\tMSITESTDIR\t0\n"
83 "Three\tOne\tThree\tThe Three Feature\t3\t3\tCHANGEDDIR\t0\n"
84 "Two\tOne\tTwo\tThe Two Feature\t2\t3\tFIRSTDIR\t0\n"
85 "feature\t\t\t\t2\t1\tTARGETDIR\t0\n"
86 "service_feature\t\t\t\t2\t1\tTARGETDIR\t0";
88 static const CHAR feature_comp_dat[] = "Feature_\tComponent_\n"
89 "s38\ts72\n"
90 "FeatureComponents\tFeature_\tComponent_\n"
91 "Five\tFive\n"
92 "Four\tFour\n"
93 "One\tOne\n"
94 "Three\tThree\n"
95 "Two\tTwo\n"
96 "feature\tcomponent\n"
97 "service_feature\tservice_comp\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"
108 "service_file\tservice_comp\tservice.exe\t100\t\t\t8192\t1";
110 static const CHAR install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
111 "s72\tS255\tI2\n"
112 "InstallExecuteSequence\tAction\n"
113 "AllocateRegistrySpace\tNOT Installed\t1550\n"
114 "CostFinalize\t\t1000\n"
115 "CostInitialize\t\t800\n"
116 "FileCost\t\t900\n"
117 "InstallFiles\t\t4000\n"
118 "InstallServices\t\t5000\n"
119 "RegisterProduct\t\t6100\n"
120 "PublishProduct\t\t6400\n"
121 "InstallFinalize\t\t6600\n"
122 "InstallInitialize\t\t1500\n"
123 "InstallValidate\t\t1400\n"
124 "LaunchConditions\t\t100\n"
125 "WriteRegistryValues\tSourceDir And SOURCEDIR\t5000";
127 static const CHAR media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
128 "i2\ti4\tL64\tS255\tS32\tS72\n"
129 "Media\tDiskId\n"
130 "1\t5\t\t\tDISK1\t\n";
132 static const CHAR property_dat[] = "Property\tValue\n"
133 "s72\tl0\n"
134 "Property\tProperty\n"
135 "DefaultUIFont\tDlgFont8\n"
136 "HASUIRUN\t0\n"
137 "INSTALLLEVEL\t3\n"
138 "InstallMode\tTypical\n"
139 "Manufacturer\tWine\n"
140 "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n"
141 "ProductCode\t{F1C3AF50-8B56-4A69-A00C-00773FE42F30}\n"
142 "ProductID\tnone\n"
143 "ProductLanguage\t1033\n"
144 "ProductName\tMSITEST\n"
145 "ProductVersion\t1.1.1\n"
146 "PROMPTROLLBACKCOST\tP\n"
147 "Setup\tSetup\n"
148 "UpgradeCode\t{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}";
150 static const CHAR registry_dat[] = "Registry\tRoot\tKey\tName\tValue\tComponent_\n"
151 "s72\ti2\tl255\tL255\tL0\ts72\n"
152 "Registry\tRegistry\n"
153 "Apples\t2\tSOFTWARE\\Wine\\msitest\tName\timaname\tOne\n"
154 "Oranges\t2\tSOFTWARE\\Wine\\msitest\tnumber\t#314\tTwo\n"
155 "regdata\t2\tSOFTWARE\\Wine\\msitest\tblah\tbad\tdangler\n"
156 "OrderTest\t2\tSOFTWARE\\Wine\\msitest\tOrderTestName\tOrderTestValue\tcomponent";
158 static const CHAR service_install_dat[] = "ServiceInstall\tName\tDisplayName\tServiceType\tStartType\tErrorControl\t"
159 "LoadOrderGroup\tDependencies\tStartName\tPassword\tArguments\tComponent_\tDescription\n"
160 "s72\ts255\tL255\ti4\ti4\ti4\tS255\tS255\tS255\tS255\tS255\ts72\tL255\n"
161 "ServiceInstall\tServiceInstall\n"
162 "TestService\tTestService\tTestService\t2\t3\t0\t\t\tTestService\t\t\tservice_comp\t\t";
164 static const CHAR service_control_dat[] = "ServiceControl\tName\tEvent\tArguments\tWait\tComponent_\n"
165 "s72\tl255\ti2\tL255\tI2\ts72\n"
166 "ServiceControl\tServiceControl\n"
167 "ServiceControl\tTestService\t8\t\t0\tservice_comp";
169 typedef struct _msi_table
171 const CHAR *filename;
172 const CHAR *data;
173 int size;
174 } msi_table;
176 #define ADD_TABLE(x) {#x".idt", x##_dat, sizeof(x##_dat)}
178 static const msi_table tables[] =
180 ADD_TABLE(component),
181 ADD_TABLE(directory),
182 ADD_TABLE(feature),
183 ADD_TABLE(feature_comp),
184 ADD_TABLE(file),
185 ADD_TABLE(install_exec_seq),
186 ADD_TABLE(media),
187 ADD_TABLE(property),
188 ADD_TABLE(registry),
189 ADD_TABLE(service_install),
190 ADD_TABLE(service_control)
193 typedef struct _msi_summary_info
195 UINT property;
196 UINT datatype;
197 INT iValue;
198 FILETIME *pftValue;
199 const CHAR *szValue;
200 } msi_summary_info;
202 #define ADD_INFO_I2(property, iValue) {property, VT_I2, iValue, NULL, NULL}
203 #define ADD_INFO_I4(property, iValue) {property, VT_I4, iValue, NULL, NULL}
204 #define ADD_INFO_LPSTR(property, szValue) {property, VT_LPSTR, 0, NULL, szValue}
205 #define ADD_INFO_FILETIME(property, pftValue) {property, VT_FILETIME, 0, pftValue, NULL}
207 static const msi_summary_info summary_info[] =
209 ADD_INFO_LPSTR(PID_TEMPLATE, ";1033"),
210 ADD_INFO_LPSTR(PID_REVNUMBER, "{004757CA-5092-49c2-AD20-28E1CE0DF5F2}"),
211 ADD_INFO_I4(PID_PAGECOUNT, 100),
212 ADD_INFO_I4(PID_WORDCOUNT, 0),
213 ADD_INFO_FILETIME(PID_CREATE_DTM, &systemtime),
214 ADD_INFO_FILETIME(PID_LASTPRINTED, &systemtime)
218 * Database Helpers
221 static void write_file(const CHAR *filename, const char *data, int data_size)
223 DWORD size;
225 HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL,
226 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
228 WriteFile(hf, data, data_size, &size, NULL);
229 CloseHandle(hf);
232 static void write_msi_summary_info(MSIHANDLE db, const msi_summary_info *info, int num_info)
234 MSIHANDLE summary;
235 UINT r;
236 int j;
238 r = MsiGetSummaryInformationA(db, NULL, num_info, &summary);
239 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
241 /* import summary information into the stream */
242 for (j = 0; j < num_info; j++)
244 const msi_summary_info *entry = &info[j];
246 r = MsiSummaryInfoSetPropertyA(summary, entry->property, entry->datatype,
247 entry->iValue, entry->pftValue, entry->szValue);
248 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
251 /* write the summary changes back to the stream */
252 r = MsiSummaryInfoPersist(summary);
253 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
255 MsiCloseHandle(summary);
258 static void create_database(const CHAR *name, const msi_table *tables, int num_tables,
259 const msi_summary_info *info, int num_info)
261 MSIHANDLE db;
262 UINT r;
263 int j;
265 r = MsiOpenDatabaseA(name, MSIDBOPEN_CREATE, &db);
266 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
268 /* import the tables into the database */
269 for (j = 0; j < num_tables; j++)
271 const msi_table *table = &tables[j];
273 write_file(table->filename, table->data, (table->size - 1) * sizeof(char));
275 r = MsiDatabaseImportA(db, CURR_DIR, table->filename);
276 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
278 DeleteFileA(table->filename);
281 write_msi_summary_info(db, info, num_info);
283 r = MsiDatabaseCommit(db);
284 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
286 MsiCloseHandle(db);
290 * Installation helpers
293 static char PROG_FILES_DIR[MAX_PATH];
295 static BOOL get_program_files_dir(LPSTR buf)
297 HKEY hkey;
298 DWORD type = REG_EXPAND_SZ, size;
300 if (RegOpenKey(HKEY_LOCAL_MACHINE,
301 "Software\\Microsoft\\Windows\\CurrentVersion", &hkey))
302 return FALSE;
304 size = MAX_PATH;
305 if (RegQueryValueEx(hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size))
306 return FALSE;
308 RegCloseKey(hkey);
309 return TRUE;
312 static void create_file(const CHAR *name, DWORD size)
314 HANDLE file;
315 DWORD written, left;
317 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
318 ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
319 WriteFile(file, name, strlen(name), &written, NULL);
320 WriteFile(file, "\n", strlen("\n"), &written, NULL);
322 left = size - lstrlen(name) - 1;
324 SetFilePointer(file, left, NULL, FILE_CURRENT);
325 SetEndOfFile(file);
327 CloseHandle(file);
330 static void create_test_files(void)
332 CreateDirectoryA("msitest", NULL);
333 create_file("msitest\\one.txt", 100);
334 CreateDirectoryA("msitest\\first", NULL);
335 create_file("msitest\\first\\two.txt", 100);
336 CreateDirectoryA("msitest\\second", NULL);
337 create_file("msitest\\second\\three.txt", 100);
338 CreateDirectoryA("msitest\\cabout",NULL);
339 create_file("msitest\\cabout\\four.txt", 100);
340 CreateDirectoryA("msitest\\cabout\\new",NULL);
341 create_file("msitest\\cabout\\new\\five.txt", 100);
342 create_file("msitest\\filename", 100);
343 create_file("msitest\\service.exe", 100);
346 static BOOL delete_pf(const CHAR *rel_path, BOOL is_file)
348 CHAR path[MAX_PATH];
350 lstrcpyA(path, PROG_FILES_DIR);
351 lstrcatA(path, "\\");
352 lstrcatA(path, rel_path);
354 if (is_file)
355 return DeleteFileA(path);
356 else
357 return RemoveDirectoryA(path);
360 static void delete_test_files(void)
362 DeleteFileA(msifile);
363 DeleteFileA("msitest\\cabout\\new\\five.txt");
364 DeleteFileA("msitest\\cabout\\four.txt");
365 DeleteFileA("msitest\\second\\three.txt");
366 DeleteFileA("msitest\\first\\two.txt");
367 DeleteFileA("msitest\\one.txt");
368 DeleteFileA("msitest\\service.exe");
369 DeleteFileA("msitest\\filename");
370 RemoveDirectoryA("msitest\\cabout\\new");
371 RemoveDirectoryA("msitest\\cabout");
372 RemoveDirectoryA("msitest\\second");
373 RemoveDirectoryA("msitest\\first");
374 RemoveDirectoryA("msitest");
377 static void check_service_is_installed(void)
379 SC_HANDLE scm, service;
380 BOOL res;
382 scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
383 ok(scm != NULL, "Failed to open the SC Manager\n");
385 service = OpenService(scm, "TestService", SC_MANAGER_ALL_ACCESS);
386 ok(service != NULL, "Failed to open TestService\n");
388 res = DeleteService(service);
389 ok(res, "Failed to delete TestService\n");
393 * Automation helpers and tests
396 /* ok-like statement which takes two unicode strings or one unicode and one ANSI string as arguments */
397 static CHAR string1[MAX_PATH], string2[MAX_PATH];
399 #define ok_w2(format, szString1, szString2) \
401 if (lstrcmpW(szString1, szString2) != 0) \
403 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
404 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
405 ok(0, format, string1, string2); \
408 #define ok_aw(format, aString, wString) \
410 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
411 if (lstrcmpA(string1, aString) != 0) \
412 ok(0, format, string1, aString); \
414 #define ok_awplus(format, extra, aString, wString) \
416 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
417 if (lstrcmpA(string1, aString) != 0) \
418 ok(0, format, extra, string1, aString); \
420 /* exception checker */
421 static WCHAR szSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
423 #define ok_exception(hr, szDescription) \
424 if (hr == DISP_E_EXCEPTION) \
426 /* Compare wtype, source, and destination */ \
427 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
429 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
430 if (excepinfo.bstrSource) \
431 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, szSource); \
433 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
434 if (excepinfo.bstrDescription) \
435 ok_w2("Exception description was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrDescription, szDescription); \
437 SysFreeString(excepinfo.bstrSource); \
438 SysFreeString(excepinfo.bstrDescription); \
439 SysFreeString(excepinfo.bstrHelpFile); \
442 static DISPID get_dispid( IDispatch *disp, const char *name )
444 LPOLESTR str;
445 UINT len;
446 DISPID id = -1;
447 HRESULT r;
449 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
450 str = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
451 if (str)
453 len = MultiByteToWideChar(CP_ACP, 0, name, -1, str, len );
454 r = IDispatch_GetIDsOfNames( disp, &IID_NULL, &str, 1, 0, &id );
455 HeapFree(GetProcessHeap(), 0, str);
456 if (r != S_OK)
457 return -1;
460 return id;
463 static void test_dispid(void)
465 ok( get_dispid( pInstaller, "CreateRecord" ) == 1, "dispid wrong\n");
466 ok( get_dispid( pInstaller, "OpenPackage" ) == 2, "dispid wrong\n");
467 todo_wine ok( get_dispid( pInstaller, "OpenProduct" ) == 3, "dispid wrong\n");
468 ok( get_dispid( pInstaller, "OpenDatabase" ) == 4, "dispid wrong\n");
469 todo_wine {
470 ok( get_dispid( pInstaller, "SummaryInformation" ) == 5, "dispid wrong\n");
471 ok( get_dispid( pInstaller, "UILevel" ) == 6, "dispid wrong\n");
472 ok( get_dispid( pInstaller, "EnableLog" ) == 7, "dispid wrong\n");
474 ok( get_dispid( pInstaller, "InstallProduct" ) == 8, "dispid wrong\n");
475 todo_wine {
476 ok( get_dispid( pInstaller, "Version" ) == 9, "dispid wrong\n");
477 ok( get_dispid( pInstaller, "LastErrorRecord" ) == 10, "dispid wrong\n");
479 ok( get_dispid( pInstaller, "RegistryValue" ) == 11, "dispid wrong\n");
480 todo_wine {
481 ok( get_dispid( pInstaller, "Environment" ) == 12, "dispid wrong\n");
482 ok( get_dispid( pInstaller, "FileAttributes" ) == 13, "dispid wrong\n");
484 ok( get_dispid( pInstaller, "FileSize" ) == 15, "dispid wrong\n");
485 ok( get_dispid( pInstaller, "FileVersion" ) == 16, "dispid wrong\n");
487 ok( get_dispid( pInstaller, "ProductState" ) == 17, "dispid wrong\n");
488 ok( get_dispid( pInstaller, "ProductInfo" ) == 18, "dispid wrong\n");
489 todo_wine {
490 ok( get_dispid( pInstaller, "ConfigureProduct" ) == 19, "dispid wrong\n");
491 ok( get_dispid( pInstaller, "ReinstallProduct" ) == 20 , "dispid wrong\n");
492 ok( get_dispid( pInstaller, "CollectUserInfo" ) == 21, "dispid wrong\n");
493 ok( get_dispid( pInstaller, "ApplyPatch" ) == 22, "dispid wrong\n");
494 ok( get_dispid( pInstaller, "FeatureParent" ) == 23, "dispid wrong\n");
495 ok( get_dispid( pInstaller, "FeatureState" ) == 24, "dispid wrong\n");
496 ok( get_dispid( pInstaller, "UseFeature" ) == 25, "dispid wrong\n");
497 ok( get_dispid( pInstaller, "FeatureUsageCount" ) == 26, "dispid wrong\n");
498 ok( get_dispid( pInstaller, "FeatureUsageDate" ) == 27, "dispid wrong\n");
499 ok( get_dispid( pInstaller, "ConfigureFeature" ) == 28, "dispid wrong\n");
500 ok( get_dispid( pInstaller, "ReinstallFeature" ) == 29, "dispid wrong\n");
501 ok( get_dispid( pInstaller, "ProvideComponent" ) == 30, "dispid wrong\n");
502 ok( get_dispid( pInstaller, "ComponentPath" ) == 31, "dispid wrong\n");
503 ok( get_dispid( pInstaller, "ProvideQualifiedComponent" ) == 32, "dispid wrong\n");
504 ok( get_dispid( pInstaller, "QualifierDescription" ) == 33, "dispid wrong\n");
505 ok( get_dispid( pInstaller, "ComponentQualifiers" ) == 34, "dispid wrong\n");
507 ok( get_dispid( pInstaller, "Products" ) == 35, "dispid wrong\n");
508 todo_wine {
509 ok( get_dispid( pInstaller, "Features" ) == 36, "dispid wrong\n");
510 ok( get_dispid( pInstaller, "Components" ) == 37, "dispid wrong\n");
511 ok( get_dispid( pInstaller, "ComponentClients" ) == 38, "dispid wrong\n");
512 ok( get_dispid( pInstaller, "Patches" ) == 39, "dispid wrong\n");
514 ok( get_dispid( pInstaller, "RelatedProducts" ) == 40, "dispid wrong\n");
515 todo_wine {
516 ok( get_dispid( pInstaller, "PatchInfo" ) == 41, "dispid wrong\n");
517 ok( get_dispid( pInstaller, "PatchTransforms" ) == 42, "dispid wrong\n");
518 ok( get_dispid( pInstaller, "AddSource" ) == 43, "dispid wrong\n");
519 ok( get_dispid( pInstaller, "ClearSourceList" ) == 44, "dispid wrong\n");
520 ok( get_dispid( pInstaller, "ForceSourceListResolution" ) == 45, "dispid wrong\n");
521 ok( get_dispid( pInstaller, "ShortcutTarget" ) == 46, "dispid wrong\n");
522 ok( get_dispid( pInstaller, "FileHash" ) == 47, "dispid wrong\n");
523 ok( get_dispid( pInstaller, "FileSignatureInfo" ) == 48, "dispid wrong\n");
524 ok( get_dispid( pInstaller, "RemovePatches" ) == 49, "dispid wrong\n");
526 ok( get_dispid( pInstaller, "ApplyMultiplePatches" ) == 51, "dispid wrong\n");
527 ok( get_dispid( pInstaller, "ProductsEx" ) == 52, "dispid wrong\n");
529 ok( get_dispid( pInstaller, "PatchesEx" ) == 55, "dispid wrong\n");
531 ok( get_dispid( pInstaller, "ExtractPatchXMLData" ) == 57, "dispid wrong\n");
534 /* MSDN claims the following functions exist but IDispatch->GetIDsOfNames disagrees */
535 if (0)
537 get_dispid( pInstaller, "ProductElevated" );
538 get_dispid( pInstaller, "ProductInfoFromScript" );
539 get_dispid( pInstaller, "ProvideAssembly" );
540 get_dispid( pInstaller, "CreateAdvertiseScript" );
541 get_dispid( pInstaller, "AdvertiseProduct" );
542 get_dispid( pInstaller, "PatchFiles" );
546 /* Test basic IDispatch functions */
547 static void test_dispatch(void)
549 static WCHAR szOpenPackage[] = { 'O','p','e','n','P','a','c','k','a','g','e',0 };
550 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};
551 static WCHAR szProductState[] = { 'P','r','o','d','u','c','t','S','t','a','t','e',0 };
552 HRESULT hr;
553 DISPID dispid;
554 OLECHAR *name;
555 VARIANT varresult;
556 VARIANTARG vararg[2];
557 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
559 /* Test getting ID of a function name that does not exist */
560 name = (WCHAR *)szMsifile;
561 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
562 ok(hr == DISP_E_UNKNOWNNAME, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
564 /* Test invoking this function */
565 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
566 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
568 /* Test getting ID of a function name that does exist */
569 name = (WCHAR *)szOpenPackage;
570 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
571 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
573 /* Test invoking this function (without parameters passed) */
574 if (0) /* All of these crash MSI on Windows XP */
576 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
577 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL);
578 VariantInit(&varresult);
579 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, &varresult, &excepinfo, NULL);
582 /* Try with NULL params */
583 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
584 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
586 /* Try one empty parameter */
587 dispparams.rgvarg = vararg;
588 dispparams.cArgs = 1;
589 VariantInit(&vararg[0]);
590 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
591 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
593 /* Try one parameter, function requires two */
594 VariantInit(&vararg[0]);
595 V_VT(&vararg[0]) = VT_BSTR;
596 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
597 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
598 VariantClear(&vararg[0]);
600 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
601 ok_exception(hr, szOpenPackageException);
603 /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
604 VariantInit(&vararg[0]);
605 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
606 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
608 VariantInit(&vararg[0]);
609 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
610 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
612 /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
613 name = (WCHAR *)szProductState;
614 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
615 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
617 dispparams.rgvarg = NULL;
618 dispparams.cArgs = 0;
619 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
620 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
622 dispparams.rgvarg = NULL;
623 dispparams.cArgs = 0;
624 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
625 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
628 /* invocation helper function */
629 static int _invoke_todo_vtResult = 0;
631 static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult)
633 OLECHAR *name = NULL;
634 DISPID dispid;
635 HRESULT hr;
636 UINT i;
637 UINT len;
639 memset(pVarResult, 0, sizeof(VARIANT));
640 VariantInit(pVarResult);
642 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 );
643 name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
644 if (!name) return E_FAIL;
645 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len );
646 hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
647 HeapFree(GetProcessHeap(), 0, name);
648 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
649 if (!hr == S_OK) return hr;
651 memset(&excepinfo, 0, sizeof(excepinfo));
652 hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL);
654 if (hr == S_OK)
656 if (_invoke_todo_vtResult) todo_wine
657 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
658 else
659 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
660 if (vtResult != VT_EMPTY)
662 hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult);
663 ok(hr == S_OK, "VariantChangeTypeEx returned 0x%08x\n", hr);
667 for (i=0; i<pDispParams->cArgs; i++)
668 VariantClear(&pDispParams->rgvarg[i]);
670 return hr;
673 /* Object_Property helper functions */
675 static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord)
677 VARIANT varresult;
678 VARIANTARG vararg[1];
679 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
680 HRESULT hr;
682 VariantInit(&vararg[0]);
683 V_VT(&vararg[0]) = VT_I4;
684 V_I4(&vararg[0]) = count;
686 hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
687 *pRecord = V_DISPATCH(&varresult);
688 return hr;
691 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
693 VARIANTARG vararg[3];
694 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
696 VariantInit(&vararg[2]);
697 V_VT(&vararg[2]) = VT_I4;
698 V_I4(&vararg[2]) = (int)hkey;
699 VariantInit(&vararg[1]);
700 V_VT(&vararg[1]) = VT_BSTR;
701 V_BSTR(&vararg[1]) = SysAllocString(szKey);
702 VariantInit(&vararg[0]);
703 VariantCopy(&vararg[0], &vValue);
704 VariantClear(&vValue);
706 return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect);
709 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
711 VARIANT varresult;
712 VARIANTARG vararg;
713 HRESULT hr;
715 VariantInit(&vararg);
716 V_VT(&vararg) = VT_EMPTY;
717 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL);
718 *pBool = V_BOOL(&varresult);
719 VariantClear(&varresult);
720 return hr;
723 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
725 VARIANT varresult;
726 VARIANTARG vararg;
727 HRESULT hr;
729 VariantInit(&vararg);
730 V_VT(&vararg) = VT_BSTR;
731 V_BSTR(&vararg) = SysAllocString(szValue);
733 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR);
734 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
735 VariantClear(&varresult);
736 return hr;
739 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
741 VARIANT varresult;
742 VARIANTARG vararg;
743 HRESULT hr;
745 VariantInit(&vararg);
746 V_VT(&vararg) = VT_I4;
747 V_I4(&vararg) = iValue;
749 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult);
750 if (vtResult == VT_BSTR) lstrcpyW(szString, V_BSTR(&varresult));
751 VariantClear(&varresult);
752 return hr;
755 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
757 VARIANT varresult;
758 VARIANTARG vararg[2];
759 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
760 HRESULT hr;
762 VariantInit(&vararg[1]);
763 V_VT(&vararg[1]) = VT_BSTR;
764 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
765 VariantInit(&vararg[0]);
766 V_VT(&vararg[0]) = VT_I4;
767 V_I4(&vararg[0]) = options;
769 hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
770 *pSession = V_DISPATCH(&varresult);
771 return hr;
774 static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase)
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(szDatabasePath);
784 VariantInit(&vararg[0]);
785 V_VT(&vararg[0]) = VT_I4;
786 V_I4(&vararg[0]) = openmode;
788 hr = invoke(pInstaller, "OpenDatabase", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
789 *pDatabase = V_DISPATCH(&varresult);
790 return hr;
793 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
795 VARIANT varresult;
796 VARIANTARG vararg[2];
797 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
799 VariantInit(&vararg[1]);
800 V_VT(&vararg[1]) = VT_BSTR;
801 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
802 VariantInit(&vararg[0]);
803 V_VT(&vararg[0]) = VT_BSTR;
804 V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues);
806 return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
809 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
811 VARIANT varresult;
812 VARIANTARG vararg[1];
813 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
814 HRESULT hr;
816 VariantInit(&vararg[0]);
817 V_VT(&vararg[0]) = VT_BSTR;
818 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
820 hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
821 *pInstallState = V_I4(&varresult);
822 VariantClear(&varresult);
823 return hr;
826 static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szString)
828 VARIANT varresult;
829 VARIANTARG vararg[2];
830 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
831 HRESULT hr;
833 VariantInit(&vararg[1]);
834 V_VT(&vararg[1]) = VT_BSTR;
835 V_BSTR(&vararg[1]) = SysAllocString(szProduct);
836 VariantInit(&vararg[0]);
837 V_VT(&vararg[0]) = VT_BSTR;
838 V_BSTR(&vararg[0]) = SysAllocString(szAttribute);
840 hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
841 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
842 VariantClear(&varresult);
843 return hr;
846 static HRESULT Installer_Products(IDispatch **pStringList)
848 VARIANT varresult;
849 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
850 HRESULT hr;
852 hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
853 *pStringList = V_DISPATCH(&varresult);
854 return hr;
857 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
859 VARIANT varresult;
860 VARIANTARG vararg[1];
861 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
862 HRESULT hr;
864 VariantInit(&vararg[0]);
865 V_VT(&vararg[0]) = VT_BSTR;
866 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
868 hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
869 *pStringList = V_DISPATCH(&varresult);
870 return hr;
873 static HRESULT Installer_VersionGet(LPWSTR szVersion)
875 VARIANT varresult;
876 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
877 HRESULT hr;
879 hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
880 if (V_BSTR(&varresult)) lstrcpyW(szVersion, V_BSTR(&varresult));
881 VariantClear(&varresult);
882 return hr;
885 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
887 VARIANT varresult;
888 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
889 HRESULT hr;
891 hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
892 *pInst = V_DISPATCH(&varresult);
893 return hr;
896 static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn)
898 VARIANT varresult;
899 VARIANTARG vararg[1];
900 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
901 HRESULT hr;
903 VariantInit(&vararg[0]);
904 V_VT(&vararg[0]) = VT_BSTR;
905 V_BSTR(&vararg[0]) = SysAllocString(szName);
907 hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
908 if (V_BSTR(&varresult)) lstrcpyW(szReturn, V_BSTR(&varresult));
909 VariantClear(&varresult);
910 return hr;
913 static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue)
915 VARIANT varresult;
916 VARIANTARG vararg[2];
917 DISPID dispid = DISPID_PROPERTYPUT;
918 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
920 VariantInit(&vararg[1]);
921 V_VT(&vararg[1]) = VT_BSTR;
922 V_BSTR(&vararg[1]) = SysAllocString(szName);
923 VariantInit(&vararg[0]);
924 V_VT(&vararg[0]) = VT_BSTR;
925 V_BSTR(&vararg[0]) = SysAllocString(szValue);
927 return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
930 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
932 VARIANT varresult;
933 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
934 HRESULT hr;
936 hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
937 *pLangId = V_I4(&varresult);
938 VariantClear(&varresult);
939 return hr;
942 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, BOOL *pMode)
944 VARIANT varresult;
945 VARIANTARG vararg[1];
946 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
947 HRESULT hr;
949 VariantInit(&vararg[0]);
950 V_VT(&vararg[0]) = VT_I4;
951 V_I4(&vararg[0]) = iFlag;
953 hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL);
954 *pMode = V_BOOL(&varresult);
955 VariantClear(&varresult);
956 return hr;
959 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, BOOL bMode)
961 VARIANT varresult;
962 VARIANTARG vararg[2];
963 DISPID dispid = DISPID_PROPERTYPUT;
964 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
966 VariantInit(&vararg[1]);
967 V_VT(&vararg[1]) = VT_I4;
968 V_I4(&vararg[1]) = iFlag;
969 VariantInit(&vararg[0]);
970 V_VT(&vararg[0]) = VT_BOOL;
971 V_BOOL(&vararg[0]) = bMode;
973 return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
976 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
978 VARIANT varresult;
979 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
980 HRESULT hr;
982 hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
983 *pDatabase = V_DISPATCH(&varresult);
984 return hr;
987 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn)
989 VARIANT varresult;
990 VARIANTARG vararg[1];
991 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
992 HRESULT hr;
994 VariantInit(&vararg[0]);
995 V_VT(&vararg[0]) = VT_BSTR;
996 V_BSTR(&vararg[0]) = SysAllocString(szAction);
998 hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
999 *iReturn = V_I4(&varresult);
1000 VariantClear(&varresult);
1001 return hr;
1004 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
1006 VARIANT varresult;
1007 VARIANTARG vararg[1];
1008 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1009 HRESULT hr;
1011 VariantInit(&vararg[0]);
1012 V_VT(&vararg[0]) = VT_BSTR;
1013 V_BSTR(&vararg[0]) = SysAllocString(szCondition);
1015 hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1016 *iReturn = V_I4(&varresult);
1017 VariantClear(&varresult);
1018 return hr;
1021 static HRESULT Session_SetInstallLevel(IDispatch *pSession, long iInstallLevel)
1023 VARIANT varresult;
1024 VARIANTARG vararg[1];
1025 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1027 VariantInit(&vararg[0]);
1028 V_VT(&vararg[0]) = VT_I4;
1029 V_I4(&vararg[0]) = iInstallLevel;
1031 return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1034 static HRESULT Session_FeatureCurrentState(IDispatch *pSession, LPCWSTR szName, int *pState)
1036 VARIANT varresult;
1037 VARIANTARG vararg[1];
1038 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1039 HRESULT hr;
1041 VariantInit(&vararg[0]);
1042 V_VT(&vararg[0]) = VT_BSTR;
1043 V_BSTR(&vararg[0]) = SysAllocString(szName);
1045 hr = invoke(pSession, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1046 *pState = V_I4(&varresult);
1047 VariantClear(&varresult);
1048 return hr;
1051 static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState)
1053 VARIANT varresult;
1054 VARIANTARG vararg[1];
1055 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1056 HRESULT hr;
1058 VariantInit(&vararg[0]);
1059 V_VT(&vararg[0]) = VT_BSTR;
1060 V_BSTR(&vararg[0]) = SysAllocString(szName);
1062 hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1063 *pState = V_I4(&varresult);
1064 VariantClear(&varresult);
1065 return hr;
1068 static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState)
1070 VARIANT varresult;
1071 VARIANTARG vararg[2];
1072 DISPID dispid = DISPID_PROPERTYPUT;
1073 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1075 VariantInit(&vararg[1]);
1076 V_VT(&vararg[1]) = VT_BSTR;
1077 V_BSTR(&vararg[1]) = SysAllocString(szName);
1078 VariantInit(&vararg[0]);
1079 V_VT(&vararg[0]) = VT_I4;
1080 V_I4(&vararg[0]) = iState;
1082 return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1085 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
1087 VARIANT varresult;
1088 VARIANTARG vararg[1];
1089 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1090 HRESULT hr;
1092 VariantInit(&vararg[0]);
1093 V_VT(&vararg[0]) = VT_BSTR;
1094 V_BSTR(&vararg[0]) = SysAllocString(szSql);
1096 hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1097 *pView = V_DISPATCH(&varresult);
1098 return hr;
1101 static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo)
1103 VARIANT varresult;
1104 VARIANTARG vararg[1];
1105 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1106 HRESULT hr;
1108 VariantInit(&vararg[0]);
1109 V_VT(&vararg[0]) = VT_I4;
1110 V_I4(&vararg[0]) = iUpdateCount;
1112 hr = invoke(pDatabase, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1113 *pSummaryInfo = V_DISPATCH(&varresult);
1114 return hr;
1117 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
1119 VARIANT varresult;
1120 VARIANTARG vararg[1];
1121 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1123 VariantInit(&vararg[0]);
1124 V_VT(&vararg[0]) = VT_DISPATCH;
1125 V_DISPATCH(&vararg[0]) = pRecord;
1127 return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1130 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
1132 VARIANT varresult;
1133 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1134 HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1135 *ppRecord = V_DISPATCH(&varresult);
1136 return hr;
1139 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
1141 VARIANT varresult;
1142 VARIANTARG vararg[2];
1143 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1145 VariantInit(&vararg[1]);
1146 V_VT(&vararg[1]) = VT_I4;
1147 V_I4(&vararg[1]) = iMode;
1148 VariantInit(&vararg[0]);
1149 V_VT(&vararg[0]) = VT_DISPATCH;
1150 V_DISPATCH(&vararg[0]) = pRecord;
1151 if (pRecord)
1152 IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */
1154 return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1157 static HRESULT View_Close(IDispatch *pView)
1159 VARIANT varresult;
1160 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1161 return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1164 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
1166 VARIANT varresult;
1167 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1168 HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1169 *pFieldCount = V_I4(&varresult);
1170 VariantClear(&varresult);
1171 return hr;
1174 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString)
1176 VARIANT varresult;
1177 VARIANTARG vararg[1];
1178 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1179 HRESULT hr;
1181 VariantInit(&vararg[0]);
1182 V_VT(&vararg[0]) = VT_I4;
1183 V_I4(&vararg[0]) = iField;
1185 hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1186 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1187 VariantClear(&varresult);
1188 return hr;
1191 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
1193 VARIANT varresult;
1194 VARIANTARG vararg[2];
1195 DISPID dispid = DISPID_PROPERTYPUT;
1196 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1198 VariantInit(&vararg[1]);
1199 V_VT(&vararg[1]) = VT_I4;
1200 V_I4(&vararg[1]) = iField;
1201 VariantInit(&vararg[0]);
1202 V_VT(&vararg[0]) = VT_BSTR;
1203 V_BSTR(&vararg[0]) = SysAllocString(szString);
1205 return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1208 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
1210 VARIANT varresult;
1211 VARIANTARG vararg[1];
1212 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1213 HRESULT hr;
1215 VariantInit(&vararg[0]);
1216 V_VT(&vararg[0]) = VT_I4;
1217 V_I4(&vararg[0]) = iField;
1219 hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1220 *pValue = V_I4(&varresult);
1221 VariantClear(&varresult);
1222 return hr;
1225 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
1227 VARIANT varresult;
1228 VARIANTARG vararg[2];
1229 DISPID dispid = DISPID_PROPERTYPUT;
1230 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1232 VariantInit(&vararg[1]);
1233 V_VT(&vararg[1]) = VT_I4;
1234 V_I4(&vararg[1]) = iField;
1235 VariantInit(&vararg[0]);
1236 V_VT(&vararg[0]) = VT_I4;
1237 V_I4(&vararg[0]) = iValue;
1239 return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1242 static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT)
1244 VARIANT varresult;
1245 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1246 HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN);
1247 *ppEnumVARIANT = V_UNKNOWN(&varresult);
1248 return hr;
1251 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
1253 VARIANT varresult;
1254 VARIANTARG vararg[1];
1255 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1256 HRESULT hr;
1258 VariantInit(&vararg[0]);
1259 V_VT(&vararg[0]) = VT_I4;
1260 V_I4(&vararg[0]) = iIndex;
1262 hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1263 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1264 VariantClear(&varresult);
1265 return hr;
1268 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
1270 VARIANT varresult;
1271 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1272 HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1273 *pCount = V_I4(&varresult);
1274 VariantClear(&varresult);
1275 return hr;
1278 static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect)
1280 VARIANTARG vararg[1];
1281 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1283 VariantInit(&vararg[0]);
1284 V_VT(&vararg[0]) = VT_I4;
1285 V_I4(&vararg[0]) = pid;
1286 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYGET, &dispparams, pVarResult, vtExpect);
1289 static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant)
1291 VARIANT varresult;
1292 VARIANTARG vararg[2];
1293 DISPID dispid = DISPID_PROPERTYPUT;
1294 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1296 VariantInit(&vararg[1]);
1297 V_VT(&vararg[1]) = VT_I4;
1298 V_I4(&vararg[1]) = pid;
1299 VariantInit(&vararg[0]);
1300 VariantCopyInd(vararg, pVariant);
1302 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1305 static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount)
1307 VARIANT varresult;
1308 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1309 HRESULT hr;
1311 hr = invoke(pSummaryInfo, "PropertyCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1312 *pCount = V_I4(&varresult);
1313 VariantClear(&varresult);
1314 return hr;
1317 /* Test the various objects */
1319 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4
1321 static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly)
1323 static const WCHAR szPropertyException[] = { 'P','r','o','p','e','r','t','y',',','P','i','d',0 };
1324 static const WCHAR szTitle[] = { 'T','i','t','l','e',0 };
1325 VARIANT varresult, var;
1326 SYSTEMTIME st;
1327 HRESULT hr;
1328 int j;
1330 /* SummaryInfo::PropertyCount */
1331 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1332 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1333 ok(j == num_info, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1335 /* SummaryInfo::Property, get for properties we have set */
1336 for (j = 0; j < num_info; j++)
1338 const msi_summary_info *entry = &info[j];
1340 int vt = entry->datatype;
1341 if (vt == VT_LPSTR) vt = VT_BSTR;
1342 else if (vt == VT_FILETIME) vt = VT_DATE;
1343 else if (vt == VT_I2) vt = VT_I4;
1345 hr = SummaryInfo_PropertyGet(pSummaryInfo, entry->property, &varresult, vt);
1346 ok(hr == S_OK, "SummaryInfo_Property (pid %d) failed, hresult 0x%08x\n", entry->property, hr);
1347 if (V_VT(&varresult) != vt)
1348 skip("Skipping property tests due to type mismatch\n");
1349 else if (vt == VT_I4)
1350 ok(V_I4(&varresult) == entry->iValue, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %d\n",
1351 entry->property, entry->iValue, V_I4(&varresult));
1352 else if (vt == VT_DATE)
1354 FILETIME ft;
1355 DATE d;
1357 FileTimeToLocalFileTime(entry->pftValue, &ft);
1358 FileTimeToSystemTime(&ft, &st);
1359 SystemTimeToVariantTime(&st, &d);
1360 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));
1362 else if (vt == VT_BSTR)
1364 ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry->property, entry->szValue, V_BSTR(&varresult));
1366 else
1367 skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry->property, vt);
1370 /* SummaryInfo::Property, get; invalid arguments */
1372 /* Invalid pids */
1373 hr = SummaryInfo_PropertyGet(pSummaryInfo, -1, &varresult, VT_EMPTY);
1374 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1375 ok_exception(hr, szPropertyException);
1377 hr = SummaryInfo_PropertyGet(pSummaryInfo, 1000, &varresult, VT_EMPTY);
1378 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1379 ok_exception(hr, szPropertyException);
1381 /* Unsupported pids */
1382 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_DICTIONARY, &varresult, VT_EMPTY);
1383 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1385 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY);
1386 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1388 /* Pids we have not set, one for each type */
1389 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_EMPTY);
1390 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1392 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY);
1393 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1395 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY);
1396 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1398 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY);
1399 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1401 if (!readonly)
1403 /* SummaryInfo::Property, put; one for each type */
1405 /* VT_I2 */
1406 VariantInit(&var);
1407 V_VT(&var) = VT_I2;
1408 V_I2(&var) = 1;
1409 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CODEPAGE, &var);
1410 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1412 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */);
1413 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1414 ok(V_I2(&var) == V_I2(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var), V_I2(&varresult));
1415 VariantClear(&varresult);
1416 VariantClear(&var);
1418 /* VT_BSTR */
1419 V_VT(&var) = VT_BSTR;
1420 V_BSTR(&var) = SysAllocString(szTitle);
1421 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_TITLE, &var);
1422 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1424 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var));
1425 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1426 ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var), V_BSTR(&varresult));
1427 VariantClear(&varresult);
1428 VariantClear(&var);
1430 /* VT_DATE */
1431 V_VT(&var) = VT_DATE;
1432 FileTimeToSystemTime(&systemtime, &st);
1433 SystemTimeToVariantTime(&st, &V_DATE(&var));
1434 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_LASTSAVE_DTM, &var);
1435 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1437 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var));
1438 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1439 /* FIXME: Off by one second */
1440 todo_wine ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1441 VariantClear(&varresult);
1442 VariantClear(&var);
1444 /* VT_I4 */
1445 V_VT(&var) = VT_I4;
1446 V_I4(&var) = 1000;
1447 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1448 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1450 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1451 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1452 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult));
1453 VariantClear(&varresult);
1454 VariantClear(&var);
1456 /* SummaryInfo::PropertyCount */
1457 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1458 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1459 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1463 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1465 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 };
1466 static WCHAR szThree[] = { 'T','h','r','e','e',0 };
1467 static WCHAR szTwo[] = { 'T','w','o',0 };
1468 static WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
1469 static WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 };
1470 IDispatch *pView = NULL, *pSummaryInfo = NULL;
1471 HRESULT hr;
1473 hr = Database_OpenView(pDatabase, szSql, &pView);
1474 ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr);
1475 if (hr == S_OK)
1477 IDispatch *pRecord = NULL;
1478 WCHAR szString[MAX_PATH];
1480 /* View::Execute */
1481 hr = View_Execute(pView, NULL);
1482 ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr);
1484 /* View::Fetch */
1485 hr = View_Fetch(pView, &pRecord);
1486 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1487 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1488 if (pRecord)
1490 /* Record::StringDataGet */
1491 memset(szString, 0, sizeof(szString));
1492 hr = Record_StringDataGet(pRecord, 1, szString);
1493 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1494 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1496 /* Record::StringDataPut with correct index */
1497 hr = Record_StringDataPut(pRecord, 1, szTwo);
1498 ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1500 /* Record::StringDataGet */
1501 memset(szString, 0, sizeof(szString));
1502 hr = Record_StringDataGet(pRecord, 1, szString);
1503 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1504 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1506 /* Record::StringDataPut with incorrect index */
1507 hr = Record_StringDataPut(pRecord, -1, szString);
1508 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1509 ok_exception(hr, szStringDataField);
1511 /* View::Modify with incorrect parameters */
1512 hr = View_Modify(pView, -5, NULL);
1513 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1514 ok_exception(hr, szModifyModeRecord);
1516 hr = View_Modify(pView, -5, pRecord);
1517 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1518 ok_exception(hr, szModifyModeRecord);
1520 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1521 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1522 ok_exception(hr, szModifyModeRecord);
1524 /* View::Modify with MSIMODIFY_REFRESH should undo our changes */
1525 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1526 /* Wine's MsiViewModify currently does not support MSIMODIFY_REFRESH */
1527 todo_wine ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr);
1529 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1530 memset(szString, 0, sizeof(szString));
1531 hr = Record_StringDataGet(pRecord, 1, szString);
1532 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1533 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1535 IDispatch_Release(pRecord);
1538 /* View::Fetch */
1539 hr = View_Fetch(pView, &pRecord);
1540 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1541 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1542 if (pRecord)
1544 /* Record::StringDataGet */
1545 memset(szString, 0, sizeof(szString));
1546 hr = Record_StringDataGet(pRecord, 1, szString);
1547 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1548 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1550 IDispatch_Release(pRecord);
1553 /* View::Fetch */
1554 hr = View_Fetch(pView, &pRecord);
1555 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1556 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1557 if (pRecord)
1558 IDispatch_Release(pRecord);
1560 /* View::Close */
1561 hr = View_Close(pView);
1562 ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr);
1564 IDispatch_Release(pView);
1567 /* Database::SummaryInformation */
1568 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo);
1569 ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr);
1570 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1571 if (pSummaryInfo)
1573 test_SummaryInfo(pSummaryInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), readonly);
1574 IDispatch_Release(pSummaryInfo);
1578 static void test_Session(IDispatch *pSession)
1580 static WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
1581 static WCHAR szOne[] = { 'O','n','e',0 };
1582 static WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 };
1583 static WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 };
1584 static WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 };
1585 static WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 };
1586 static WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1587 static WCHAR szEmpty[] = { 0 };
1588 static WCHAR szEquals[] = { '=',0 };
1589 static WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
1590 WCHAR stringw[MAX_PATH];
1591 CHAR string[MAX_PATH];
1592 UINT len;
1593 BOOL bool;
1594 int myint;
1595 IDispatch *pDatabase = NULL, *pInst = NULL;
1596 HRESULT hr;
1598 /* Session::Installer */
1599 hr = Session_Installer(pSession, &pInst);
1600 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1601 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1602 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1604 /* Session::Property, get */
1605 memset(stringw, 0, sizeof(stringw));
1606 hr = Session_PropertyGet(pSession, szProductName, stringw);
1607 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1608 if (lstrcmpW(stringw, szMSITEST) != 0)
1610 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1611 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1612 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1615 /* Session::Property, put */
1616 hr = Session_PropertyPut(pSession, szProductName, szProductName);
1617 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1618 memset(stringw, 0, sizeof(stringw));
1619 hr = Session_PropertyGet(pSession, szProductName, stringw);
1620 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1621 if (lstrcmpW(stringw, szProductName) != 0)
1623 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1624 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1625 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1628 /* Try putting a property using empty property identifier */
1629 hr = Session_PropertyPut(pSession, szEmpty, szProductName);
1630 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1631 ok_exception(hr, szPropertyName);
1633 /* Try putting a property using illegal property identifier */
1634 hr = Session_PropertyPut(pSession, szEquals, szProductName);
1635 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1637 /* Session::Language, get */
1638 hr = Session_LanguageGet(pSession, &len);
1639 ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1640 /* Not sure how to check the language is correct */
1642 /* Session::Mode, get */
1643 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1644 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1645 todo_wine ok(!bool, "Reboot at end session mode is %d\n", bool);
1647 /* Session::Mode, put */
1648 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE);
1649 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1650 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1651 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1652 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1653 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE); /* set it again so we don't reboot */
1654 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1656 /* Session::Database, get */
1657 hr = Session_Database(pSession, &pDatabase);
1658 ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr);
1659 if (hr == S_OK)
1661 test_Database(pDatabase, TRUE);
1662 IDispatch_Release(pDatabase);
1665 /* Session::EvaluateCondition */
1666 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1667 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1668 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1670 hr = Session_EvaluateCondition(pSession, szEmpty, &myint);
1671 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1672 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1674 hr = Session_EvaluateCondition(pSession, szEquals, &myint);
1675 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1676 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1678 /* Session::DoAction(CostInitialize) must occur before the next statements */
1679 hr = Session_DoAction(pSession, szCostInitialize, &myint);
1680 ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr);
1681 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1683 /* Session::SetInstallLevel */
1684 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1685 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
1687 /* Session::FeatureCurrentState, get */
1688 hr = Session_FeatureCurrentState(pSession, szOne, &myint);
1689 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
1690 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1692 /* Session::EvaluateCondition */
1693 hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint);
1694 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1695 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1697 hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint);
1698 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1699 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1701 /* Session::FeatureRequestState, put */
1702 hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED);
1703 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
1704 hr = Session_FeatureRequestStateGet(pSession, szOne, &myint);
1705 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
1706 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
1708 /* Session::EvaluateCondition */
1709 hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint);
1710 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1711 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1713 hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint);
1714 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1715 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1718 /* delete key and all its subkeys */
1719 static DWORD delete_key( HKEY hkey )
1721 char name[MAX_PATH];
1722 DWORD ret;
1724 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
1726 HKEY tmp;
1727 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
1729 ret = delete_key( tmp );
1730 RegCloseKey( tmp );
1732 if (ret) break;
1734 if (ret != ERROR_NO_MORE_ITEMS) return ret;
1735 RegDeleteKeyA( hkey, "" );
1736 return 0;
1739 static void test_Installer_RegistryValue(void)
1741 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
1742 static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 };
1743 static const WCHAR szOne[] = { 'O','n','e',0 };
1744 static const WCHAR szTwo[] = { 'T','w','o',0 };
1745 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
1746 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1747 static const WCHAR szFour[] = { 'F','o','u','r',0 };
1748 static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 };
1749 static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 };
1750 static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 };
1751 static const WCHAR szSix[] = { 'S','i','x',0 };
1752 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1753 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
1754 static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
1755 static const WCHAR szBlank[] = { 0 };
1756 VARIANT varresult;
1757 VARIANTARG vararg;
1758 WCHAR szString[MAX_PATH];
1759 HKEY hkey, hkey_sub;
1760 HRESULT hr;
1761 BOOL bRet;
1763 /* Delete keys */
1764 if (!RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey )) delete_key( hkey );
1766 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
1767 hr = Installer_RegistryValueE(HKEY_CURRENT_USER, szKey, &bRet);
1768 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1769 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
1771 memset(szString, 0, sizeof(szString));
1772 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, NULL, szString);
1773 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1775 memset(szString, 0, sizeof(szString));
1776 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 0, szString, VT_BSTR);
1777 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1779 /* Create key */
1780 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
1782 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1783 "RegSetValueExW failed\n");
1784 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
1785 "RegSetValueExW failed\n");
1786 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
1787 "RegSetValueExW failed\n");
1788 ok(SetEnvironmentVariableA("MSITEST", "Four"), "SetEnvironmentVariableA failed %d\n", GetLastError());
1789 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
1790 "RegSetValueExW failed\n");
1791 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
1792 "RegSetValueExW failed\n");
1793 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
1794 "RegSetValueExW failed\n");
1795 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, (const BYTE *)NULL, 0),
1796 "RegSetValueExW failed\n");
1798 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1799 "RegSetValueExW failed\n");
1801 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
1803 /* Does our key exist? It should, and make sure we retrieve the correct default value */
1804 bRet = FALSE;
1805 hr = Installer_RegistryValueE(HKEY_CURRENT_USER, szKey, &bRet);
1806 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1807 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
1809 memset(szString, 0, sizeof(szString));
1810 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, NULL, szString);
1811 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1812 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1814 /* Ask for the value of a nonexistent key */
1815 memset(szString, 0, sizeof(szString));
1816 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szExpand, szString);
1817 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1819 /* Get values of keys */
1820 memset(szString, 0, sizeof(szString));
1821 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szOne, szString);
1822 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1823 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1825 VariantInit(&vararg);
1826 V_VT(&vararg) = VT_BSTR;
1827 V_BSTR(&vararg) = SysAllocString(szTwo);
1828 hr = Installer_RegistryValue(HKEY_CURRENT_USER, szKey, vararg, &varresult, VT_I4);
1829 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1830 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
1831 VariantClear(&varresult);
1833 memset(szString, 0, sizeof(szString));
1834 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szThree, szString);
1835 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1836 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
1838 memset(szString, 0, sizeof(szString));
1839 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szFour, szString);
1840 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1841 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
1843 memset(szString, 0, sizeof(szString));
1844 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szFive, szString);
1845 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1846 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFiveHi);
1848 memset(szString, 0, sizeof(szString));
1849 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szSix, szString);
1850 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1851 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_);
1853 VariantInit(&vararg);
1854 V_VT(&vararg) = VT_BSTR;
1855 V_BSTR(&vararg) = SysAllocString(szSeven);
1856 hr = Installer_RegistryValue(HKEY_CURRENT_USER, szKey, vararg, &varresult, VT_EMPTY);
1857 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1859 /* Get string class name for the key */
1860 memset(szString, 0, sizeof(szString));
1861 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 0, szString, VT_BSTR);
1862 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1863 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank);
1865 /* Get name of a value by positive number (RegEnumValue like), valid index */
1866 memset(szString, 0, sizeof(szString));
1867 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 2, szString, VT_BSTR);
1868 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1869 /* RegEnumValue order seems different on wine */
1870 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
1872 /* Get name of a value by positive number (RegEnumValue like), invalid index */
1873 memset(szString, 0, sizeof(szString));
1874 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 10, szString, VT_EMPTY);
1875 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1877 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
1878 memset(szString, 0, sizeof(szString));
1879 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, -1, szString, VT_BSTR);
1880 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1881 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
1883 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
1884 memset(szString, 0, sizeof(szString));
1885 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, -10, szString, VT_EMPTY);
1886 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1888 /* clean up */
1889 delete_key(hkey);
1892 static void test_Installer_Products(BOOL bProductInstalled)
1894 WCHAR szString[MAX_PATH];
1895 HRESULT hr;
1896 int idx;
1897 IUnknown *pUnk = NULL;
1898 IEnumVARIANT *pEnum = NULL;
1899 VARIANT var;
1900 ULONG celt;
1901 int iCount, iValue;
1902 IDispatch *pStringList = NULL;
1903 BOOL bProductFound = FALSE;
1905 /* Installer::Products */
1906 hr = Installer_Products(&pStringList);
1907 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
1908 if (hr == S_OK)
1910 /* StringList::_NewEnum */
1911 hr = StringList__NewEnum(pStringList, &pUnk);
1912 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
1913 if (hr == S_OK)
1915 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
1916 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
1918 if (!pEnum)
1919 skip("IEnumVARIANT tests\n");
1921 /* StringList::Count */
1922 hr = StringList_Count(pStringList, &iCount);
1923 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
1925 for (idx=0; idx<iCount; idx++)
1927 /* StringList::Item */
1928 memset(szString, 0, sizeof(szString));
1929 hr = StringList_Item(pStringList, idx, szString);
1930 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
1932 if (hr == S_OK)
1934 /* Installer::ProductState */
1935 hr = Installer_ProductState(szString, &iValue);
1936 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
1937 if (hr == S_OK)
1938 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
1940 /* Not found our product code yet? Check */
1941 if (!bProductFound && !lstrcmpW(szString, szProductCode))
1942 bProductFound = TRUE;
1944 /* IEnumVARIANT::Next */
1945 if (pEnum)
1947 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
1948 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
1949 ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
1950 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
1951 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
1952 VariantClear(&var);
1957 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
1958 bProductInstalled ? "be" : "not be",
1959 bProductFound ? "found" : "not found");
1961 if (pEnum)
1963 IEnumVARIANT *pEnum2 = NULL;
1965 if (0) /* Crashes on Windows XP */
1967 /* IEnumVARIANT::Clone, NULL pointer */
1968 hr = IEnumVARIANT_Clone(pEnum, NULL);
1971 /* IEnumVARIANT::Clone */
1972 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
1973 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
1974 if (hr == S_OK)
1976 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
1978 /* IEnumVARIANT::Next of the clone */
1979 if (iCount)
1981 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
1982 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
1983 ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
1984 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
1985 VariantClear(&var);
1987 else
1988 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
1990 IEnumVARIANT_Release(pEnum2);
1993 /* IEnumVARIANT::Skip should fail */
1994 hr = IEnumVARIANT_Skip(pEnum, 1);
1995 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
1997 /* IEnumVARIANT::Next, NULL variant pointer */
1998 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
1999 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2000 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2002 /* IEnumVARIANT::Next, should not return any more items */
2003 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2004 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2005 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2006 VariantClear(&var);
2008 /* IEnumVARIANT::Reset */
2009 hr = IEnumVARIANT_Reset(pEnum);
2010 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2012 if (iCount)
2014 /* IEnumVARIANT::Skip to the last product */
2015 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2016 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2018 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2019 * NULL celt pointer. */
2020 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2021 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2022 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2023 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2024 VariantClear(&var);
2026 else
2027 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2030 /* StringList::Item using an invalid index */
2031 memset(szString, 0, sizeof(szString));
2032 hr = StringList_Item(pStringList, iCount, szString);
2033 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2035 if (pEnum) IEnumVARIANT_Release(pEnum);
2036 if (pUnk) IUnknown_Release(pUnk);
2037 IDispatch_Release(pStringList);
2041 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2042 * deleting the subkeys first) */
2043 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey)
2045 UINT ret;
2046 CHAR *string = NULL;
2047 HKEY hkey;
2048 DWORD dwSize;
2050 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2051 if (ret != ERROR_SUCCESS) return ret;
2052 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2053 if (ret != ERROR_SUCCESS) return ret;
2054 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2056 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2057 delete_registry_key(hkey, string);
2059 RegCloseKey(hkey);
2060 HeapFree(GetProcessHeap(), 0, string);
2061 RegDeleteKeyA(hkeyParent, subkey);
2062 return ERROR_SUCCESS;
2065 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2066 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, HKEY *phkey)
2068 UINT ret;
2069 CHAR *string = NULL;
2070 int idx = 0;
2071 HKEY hkey;
2072 DWORD dwSize;
2073 BOOL found = FALSE;
2075 *phkey = 0;
2077 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2078 if (ret != ERROR_SUCCESS) return ret;
2079 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2080 if (ret != ERROR_SUCCESS) return ret;
2081 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2083 while (!found &&
2084 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2086 if (!strcmp(string, findkey))
2088 *phkey = hkey;
2089 found = TRUE;
2091 else if (find_registry_key(hkey, string, findkey, phkey) == ERROR_SUCCESS) found = TRUE;
2094 if (*phkey != hkey) RegCloseKey(hkey);
2095 HeapFree(GetProcessHeap(), 0, string);
2096 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2099 static void test_Installer_InstallProduct(LPCWSTR szPath)
2101 HRESULT hr;
2102 CHAR path[MAX_PATH];
2103 WCHAR szString[MAX_PATH];
2104 LONG res;
2105 HKEY hkey;
2106 DWORD num, size, type;
2107 int iValue, iCount;
2108 IDispatch *pStringList = NULL;
2110 create_test_files();
2112 /* Installer::InstallProduct */
2113 hr = Installer_InstallProduct(szMsifile, NULL);
2114 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2116 /* Installer::ProductState for our product code, which has been installed */
2117 hr = Installer_ProductState(szProductCode, &iValue);
2118 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2119 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2121 /* Installer::ProductInfo for our product code */
2123 /* NULL attribute */
2124 memset(szString, 0, sizeof(szString));
2125 hr = Installer_ProductInfo(szProductCode, NULL, szString);
2126 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2127 ok_exception(hr, szProductInfoException);
2129 /* Nonexistent attribute */
2130 memset(szString, 0, sizeof(szString));
2131 hr = Installer_ProductInfo(szProductCode, szMsifile, szString);
2132 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2133 ok_exception(hr, szProductInfoException);
2135 /* Package name */
2136 memset(szString, 0, sizeof(szString));
2137 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szString);
2138 todo_wine ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2139 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile);
2141 /* Product name */
2142 memset(szString, 0, sizeof(szString));
2143 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PRODUCTNAMEW, szString);
2144 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2145 ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST);
2147 /* Installer::Products */
2148 test_Installer_Products(TRUE);
2150 /* Installer::RelatedProducts for our upgrade code */
2151 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2152 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2153 if (hr == S_OK)
2155 /* StringList::Count */
2156 hr = StringList_Count(pStringList, &iCount);
2157 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2158 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2160 /* StringList::Item */
2161 memset(szString, 0, sizeof(szString));
2162 hr = StringList_Item(pStringList, 0, szString);
2163 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2164 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
2166 IDispatch_Release(pStringList);
2169 /* Check & clean up installed files & registry keys */
2170 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2171 ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
2172 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2173 ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
2174 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2175 ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
2176 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2177 ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
2178 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2179 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2180 ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
2181 ok(delete_pf("msitest", FALSE), "File not installed\n");
2183 res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
2184 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2186 size = MAX_PATH;
2187 type = REG_SZ;
2188 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2189 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2190 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2192 size = MAX_PATH;
2193 type = REG_SZ;
2194 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2195 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2197 size = sizeof(num);
2198 type = REG_DWORD;
2199 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2200 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2201 ok(num == 314, "Expected 314, got %d\n", num);
2203 size = MAX_PATH;
2204 type = REG_SZ;
2205 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2206 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2207 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2209 RegCloseKey(hkey);
2211 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest");
2212 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2214 check_service_is_installed();
2216 /* Remove registry keys written by RegisterProduct standard action */
2217 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F1C3AF50-8B56-4A69-A00C-00773FE42F30}");
2218 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2220 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2221 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2223 res = find_registry_key(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "05FA3C1F65B896A40AC00077F34EF203", &hkey);
2224 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2225 if (res == ERROR_SUCCESS)
2227 res = delete_registry_key(hkey, "05FA3C1F65B896A40AC00077F34EF203");
2228 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2229 RegCloseKey(hkey);
2232 /* Remove registry keys written by PublishProduct standard action */
2233 res = RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2234 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2236 res = delete_registry_key(hkey, "Products\\05FA3C1F65B896A40AC00077F34EF203");
2237 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2239 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2240 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2242 RegCloseKey(hkey);
2244 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203");
2245 todo_wine ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_SUCCESS, got %d\n", res);
2247 /* Delete installation files we installed */
2248 delete_test_files();
2251 static void test_Installer(void)
2253 static WCHAR szBackslash[] = { '\\',0 };
2254 static WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
2255 static WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
2256 WCHAR szPath[MAX_PATH];
2257 HRESULT hr;
2258 UINT len;
2259 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL;
2260 int iValue, iCount;
2262 if (!pInstaller) return;
2264 /* Installer::CreateRecord */
2266 /* Test for error */
2267 hr = Installer_CreateRecord(-1, &pRecord);
2268 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2269 ok_exception(hr, szCreateRecordException);
2271 /* Test for success */
2272 hr = Installer_CreateRecord(1, &pRecord);
2273 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2274 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2275 if (pRecord)
2277 /* Record::FieldCountGet */
2278 hr = Record_FieldCountGet(pRecord, &iValue);
2279 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2280 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2282 /* Record::IntegerDataGet */
2283 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2284 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2285 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2287 /* Record::IntegerDataGet, bad index */
2288 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2289 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2290 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2292 /* Record::IntegerDataPut */
2293 hr = Record_IntegerDataPut(pRecord, 1, 100);
2294 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2296 /* Record::IntegerDataPut, bad index */
2297 hr = Record_IntegerDataPut(pRecord, 10, 100);
2298 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2299 ok_exception(hr, szIntegerDataException);
2301 /* Record::IntegerDataGet */
2302 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2303 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2304 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2306 IDispatch_Release(pRecord);
2309 /* Prepare package */
2310 create_database(msifile, tables, sizeof(tables) / sizeof(msi_table),
2311 summary_info, sizeof(summary_info) / sizeof(msi_summary_info));
2313 len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, CURR_DIR, -1, szPath, MAX_PATH);
2314 ok(len, "MultiByteToWideChar returned error %d\n", GetLastError());
2315 if (!len) return;
2317 lstrcatW(szPath, szBackslash);
2318 lstrcatW(szPath, szMsifile);
2320 /* Installer::OpenPackage */
2321 hr = Installer_OpenPackage(szPath, 0, &pSession);
2322 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2323 if (hr == S_OK)
2325 test_Session(pSession);
2326 IDispatch_Release(pSession);
2329 /* Installer::OpenDatabase */
2330 hr = Installer_OpenDatabase(szPath, (int)MSIDBOPEN_TRANSACT, &pDatabase);
2331 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2332 if (hr == S_OK)
2334 test_Database(pDatabase, FALSE);
2335 IDispatch_Release(pDatabase);
2338 /* Installer::RegistryValue */
2339 test_Installer_RegistryValue();
2341 /* Installer::ProductState for our product code, which should not be installed */
2342 hr = Installer_ProductState(szProductCode, &iValue);
2343 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2344 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2346 /* Installer::ProductInfo for our product code, which should not be installed */
2348 /* Package name */
2349 memset(szPath, 0, sizeof(szPath));
2350 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szPath);
2351 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2352 ok_exception(hr, szProductInfoException);
2354 /* NULL attribute and NULL product code */
2355 memset(szPath, 0, sizeof(szPath));
2356 hr = Installer_ProductInfo(NULL, NULL, szPath);
2357 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2358 ok_exception(hr, szProductInfoException);
2360 /* Installer::Products */
2361 test_Installer_Products(FALSE);
2363 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2364 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2365 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2366 if (hr == S_OK)
2368 /* StringList::Count */
2369 hr = StringList_Count(pStringList, &iCount);
2370 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2371 ok(!iCount, "Expected no related products but found %d\n", iCount);
2373 IDispatch_Release(pStringList);
2376 /* Installer::Version */
2377 todo_wine {
2378 memset(szPath, 0, sizeof(szPath));
2379 hr = Installer_VersionGet(szPath);
2380 ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr);
2383 /* Installer::InstallProduct and other tests that depend on our product being installed */
2384 test_Installer_InstallProduct(szPath);
2387 START_TEST(automation)
2389 DWORD len;
2390 char temp_path[MAX_PATH], prev_path[MAX_PATH];
2391 HRESULT hr;
2392 CLSID clsid;
2393 IUnknown *pUnk;
2395 GetSystemTimeAsFileTime(&systemtime);
2397 GetCurrentDirectoryA(MAX_PATH, prev_path);
2398 GetTempPath(MAX_PATH, temp_path);
2399 SetCurrentDirectoryA(temp_path);
2401 lstrcpyA(CURR_DIR, temp_path);
2402 len = lstrlenA(CURR_DIR);
2404 if(len && (CURR_DIR[len - 1] == '\\'))
2405 CURR_DIR[len - 1] = 0;
2407 get_program_files_dir(PROG_FILES_DIR);
2409 hr = OleInitialize(NULL);
2410 ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr);
2411 hr = CLSIDFromProgID(szProgId, &clsid);
2412 ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr);
2413 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2414 ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr);
2416 if (pUnk)
2418 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2419 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2421 test_dispid();
2422 test_dispatch();
2423 test_Installer();
2425 IDispatch_Release(pInstaller);
2426 IUnknown_Release(pUnk);
2429 OleUninitialize();
2431 SetCurrentDirectoryA(prev_path);