msi: Implement the UILevel property of the Installer object.
[wine.git] / dlls / msi / tests / automation.c
blob089360be36f850d6fb97b4b0c5af3422b47edc1a
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 trace("table->filename: %s\n", table->filename);
276 r = MsiDatabaseImportA(db, CURR_DIR, table->filename);
277 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
279 DeleteFileA(table->filename);
282 write_msi_summary_info(db, info, num_info);
284 r = MsiDatabaseCommit(db);
285 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
287 MsiCloseHandle(db);
291 * Installation helpers
294 static char PROG_FILES_DIR[MAX_PATH];
296 static BOOL get_program_files_dir(LPSTR buf)
298 HKEY hkey;
299 DWORD type = REG_EXPAND_SZ, size;
301 if (RegOpenKey(HKEY_LOCAL_MACHINE,
302 "Software\\Microsoft\\Windows\\CurrentVersion", &hkey))
303 return FALSE;
305 size = MAX_PATH;
306 if (RegQueryValueEx(hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size))
307 return FALSE;
309 RegCloseKey(hkey);
310 return TRUE;
313 static void create_file(const CHAR *name, DWORD size)
315 HANDLE file;
316 DWORD written, left;
318 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
319 ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
320 WriteFile(file, name, strlen(name), &written, NULL);
321 WriteFile(file, "\n", strlen("\n"), &written, NULL);
323 left = size - lstrlen(name) - 1;
325 SetFilePointer(file, left, NULL, FILE_CURRENT);
326 SetEndOfFile(file);
328 CloseHandle(file);
331 static void create_test_files(void)
333 CreateDirectoryA("msitest", NULL);
334 create_file("msitest\\one.txt", 100);
335 CreateDirectoryA("msitest\\first", NULL);
336 create_file("msitest\\first\\two.txt", 100);
337 CreateDirectoryA("msitest\\second", NULL);
338 create_file("msitest\\second\\three.txt", 100);
339 CreateDirectoryA("msitest\\cabout",NULL);
340 create_file("msitest\\cabout\\four.txt", 100);
341 CreateDirectoryA("msitest\\cabout\\new",NULL);
342 create_file("msitest\\cabout\\new\\five.txt", 100);
343 create_file("msitest\\filename", 100);
344 create_file("msitest\\service.exe", 100);
347 static BOOL delete_pf(const CHAR *rel_path, BOOL is_file)
349 CHAR path[MAX_PATH];
351 lstrcpyA(path, PROG_FILES_DIR);
352 lstrcatA(path, "\\");
353 lstrcatA(path, rel_path);
355 if (is_file)
356 return DeleteFileA(path);
357 else
358 return RemoveDirectoryA(path);
361 static void delete_test_files(void)
363 DeleteFileA(msifile);
364 DeleteFileA("msitest\\cabout\\new\\five.txt");
365 DeleteFileA("msitest\\cabout\\four.txt");
366 DeleteFileA("msitest\\second\\three.txt");
367 DeleteFileA("msitest\\first\\two.txt");
368 DeleteFileA("msitest\\one.txt");
369 DeleteFileA("msitest\\service.exe");
370 DeleteFileA("msitest\\filename");
371 RemoveDirectoryA("msitest\\cabout\\new");
372 RemoveDirectoryA("msitest\\cabout");
373 RemoveDirectoryA("msitest\\second");
374 RemoveDirectoryA("msitest\\first");
375 RemoveDirectoryA("msitest");
378 static void check_service_is_installed(void)
380 SC_HANDLE scm, service;
381 BOOL res;
383 scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
384 ok(scm != NULL, "Failed to open the SC Manager\n");
386 service = OpenService(scm, "TestService", SC_MANAGER_ALL_ACCESS);
387 ok(service != NULL, "Failed to open TestService\n");
389 res = DeleteService(service);
390 ok(res, "Failed to delete TestService\n");
392 CloseServiceHandle(service);
393 CloseServiceHandle(scm);
397 * Automation helpers and tests
400 /* ok-like statement which takes two unicode strings or one unicode and one ANSI string as arguments */
401 static CHAR string1[MAX_PATH], string2[MAX_PATH];
403 #define ok_w2(format, szString1, szString2) \
405 if (lstrcmpW(szString1, szString2) != 0) \
407 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
408 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
409 ok(0, format, string1, string2); \
412 #define ok_aw(format, aString, wString) \
414 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
415 if (lstrcmpA(string1, aString) != 0) \
416 ok(0, format, string1, aString); \
418 #define ok_awplus(format, extra, aString, wString) \
420 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
421 if (lstrcmpA(string1, aString) != 0) \
422 ok(0, format, extra, string1, aString); \
424 /* exception checker */
425 static WCHAR szSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
427 #define ok_exception(hr, szDescription) \
428 if (hr == DISP_E_EXCEPTION) \
430 /* Compare wtype, source, and destination */ \
431 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
433 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
434 if (excepinfo.bstrSource) \
435 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, szSource); \
437 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
438 if (excepinfo.bstrDescription) \
439 ok_w2("Exception description was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrDescription, szDescription); \
441 SysFreeString(excepinfo.bstrSource); \
442 SysFreeString(excepinfo.bstrDescription); \
443 SysFreeString(excepinfo.bstrHelpFile); \
446 static DISPID get_dispid( IDispatch *disp, const char *name )
448 LPOLESTR str;
449 UINT len;
450 DISPID id = -1;
451 HRESULT r;
453 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
454 str = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
455 if (str)
457 len = MultiByteToWideChar(CP_ACP, 0, name, -1, str, len );
458 r = IDispatch_GetIDsOfNames( disp, &IID_NULL, &str, 1, 0, &id );
459 HeapFree(GetProcessHeap(), 0, str);
460 if (r != S_OK)
461 return -1;
464 return id;
467 static void test_dispid(void)
469 ok( get_dispid( pInstaller, "CreateRecord" ) == 1, "dispid wrong\n");
470 ok( get_dispid( pInstaller, "OpenPackage" ) == 2, "dispid wrong\n");
471 todo_wine ok( get_dispid( pInstaller, "OpenProduct" ) == 3, "dispid wrong\n");
472 ok( get_dispid( pInstaller, "OpenDatabase" ) == 4, "dispid wrong\n");
473 todo_wine ok( get_dispid( pInstaller, "SummaryInformation" ) == 5, "dispid wrong\n");
474 ok( get_dispid( pInstaller, "UILevel" ) == 6, "dispid wrong\n");
475 todo_wine ok( get_dispid( pInstaller, "EnableLog" ) == 7, "dispid wrong\n");
476 ok( get_dispid( pInstaller, "InstallProduct" ) == 8, "dispid wrong\n");
477 ok( get_dispid( pInstaller, "Version" ) == 9, "dispid wrong\n");
478 todo_wine {
479 ok( get_dispid( pInstaller, "LastErrorRecord" ) == 10, "dispid wrong\n");
481 ok( get_dispid( pInstaller, "RegistryValue" ) == 11, "dispid wrong\n");
482 todo_wine {
483 ok( get_dispid( pInstaller, "Environment" ) == 12, "dispid wrong\n");
484 ok( get_dispid( pInstaller, "FileAttributes" ) == 13, "dispid wrong\n");
486 ok( get_dispid( pInstaller, "FileSize" ) == 15, "dispid wrong\n");
487 ok( get_dispid( pInstaller, "FileVersion" ) == 16, "dispid wrong\n");
489 ok( get_dispid( pInstaller, "ProductState" ) == 17, "dispid wrong\n");
490 ok( get_dispid( pInstaller, "ProductInfo" ) == 18, "dispid wrong\n");
491 todo_wine {
492 ok( get_dispid( pInstaller, "ConfigureProduct" ) == 19, "dispid wrong\n");
493 ok( get_dispid( pInstaller, "ReinstallProduct" ) == 20 , "dispid wrong\n");
494 ok( get_dispid( pInstaller, "CollectUserInfo" ) == 21, "dispid wrong\n");
495 ok( get_dispid( pInstaller, "ApplyPatch" ) == 22, "dispid wrong\n");
496 ok( get_dispid( pInstaller, "FeatureParent" ) == 23, "dispid wrong\n");
497 ok( get_dispid( pInstaller, "FeatureState" ) == 24, "dispid wrong\n");
498 ok( get_dispid( pInstaller, "UseFeature" ) == 25, "dispid wrong\n");
499 ok( get_dispid( pInstaller, "FeatureUsageCount" ) == 26, "dispid wrong\n");
500 ok( get_dispid( pInstaller, "FeatureUsageDate" ) == 27, "dispid wrong\n");
501 ok( get_dispid( pInstaller, "ConfigureFeature" ) == 28, "dispid wrong\n");
502 ok( get_dispid( pInstaller, "ReinstallFeature" ) == 29, "dispid wrong\n");
503 ok( get_dispid( pInstaller, "ProvideComponent" ) == 30, "dispid wrong\n");
504 ok( get_dispid( pInstaller, "ComponentPath" ) == 31, "dispid wrong\n");
505 ok( get_dispid( pInstaller, "ProvideQualifiedComponent" ) == 32, "dispid wrong\n");
506 ok( get_dispid( pInstaller, "QualifierDescription" ) == 33, "dispid wrong\n");
507 ok( get_dispid( pInstaller, "ComponentQualifiers" ) == 34, "dispid wrong\n");
509 ok( get_dispid( pInstaller, "Products" ) == 35, "dispid wrong\n");
510 todo_wine {
511 ok( get_dispid( pInstaller, "Features" ) == 36, "dispid wrong\n");
512 ok( get_dispid( pInstaller, "Components" ) == 37, "dispid wrong\n");
513 ok( get_dispid( pInstaller, "ComponentClients" ) == 38, "dispid wrong\n");
514 ok( get_dispid( pInstaller, "Patches" ) == 39, "dispid wrong\n");
516 ok( get_dispid( pInstaller, "RelatedProducts" ) == 40, "dispid wrong\n");
517 todo_wine {
518 ok( get_dispid( pInstaller, "PatchInfo" ) == 41, "dispid wrong\n");
519 ok( get_dispid( pInstaller, "PatchTransforms" ) == 42, "dispid wrong\n");
520 ok( get_dispid( pInstaller, "AddSource" ) == 43, "dispid wrong\n");
521 ok( get_dispid( pInstaller, "ClearSourceList" ) == 44, "dispid wrong\n");
522 ok( get_dispid( pInstaller, "ForceSourceListResolution" ) == 45, "dispid wrong\n");
523 ok( get_dispid( pInstaller, "ShortcutTarget" ) == 46, "dispid wrong\n");
524 ok( get_dispid( pInstaller, "FileHash" ) == 47, "dispid wrong\n");
525 ok( get_dispid( pInstaller, "FileSignatureInfo" ) == 48, "dispid wrong\n");
526 ok( get_dispid( pInstaller, "RemovePatches" ) == 49, "dispid wrong\n");
528 ok( get_dispid( pInstaller, "ApplyMultiplePatches" ) == 51, "dispid wrong\n");
529 ok( get_dispid( pInstaller, "ProductsEx" ) == 52, "dispid wrong\n");
531 ok( get_dispid( pInstaller, "PatchesEx" ) == 55, "dispid wrong\n");
533 ok( get_dispid( pInstaller, "ExtractPatchXMLData" ) == 57, "dispid wrong\n");
536 /* MSDN claims the following functions exist but IDispatch->GetIDsOfNames disagrees */
537 if (0)
539 get_dispid( pInstaller, "ProductElevated" );
540 get_dispid( pInstaller, "ProductInfoFromScript" );
541 get_dispid( pInstaller, "ProvideAssembly" );
542 get_dispid( pInstaller, "CreateAdvertiseScript" );
543 get_dispid( pInstaller, "AdvertiseProduct" );
544 get_dispid( pInstaller, "PatchFiles" );
548 /* Test basic IDispatch functions */
549 static void test_dispatch(void)
551 static WCHAR szOpenPackage[] = { 'O','p','e','n','P','a','c','k','a','g','e',0 };
552 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};
553 static WCHAR szProductState[] = { 'P','r','o','d','u','c','t','S','t','a','t','e',0 };
554 HRESULT hr;
555 DISPID dispid;
556 OLECHAR *name;
557 VARIANT varresult;
558 VARIANTARG vararg[2];
559 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
561 /* Test getting ID of a function name that does not exist */
562 name = (WCHAR *)szMsifile;
563 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
564 ok(hr == DISP_E_UNKNOWNNAME, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
566 /* Test invoking this function */
567 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
568 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
570 /* Test getting ID of a function name that does exist */
571 name = (WCHAR *)szOpenPackage;
572 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
573 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
575 /* Test invoking this function (without parameters passed) */
576 if (0) /* All of these crash MSI on Windows XP */
578 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
579 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL);
580 VariantInit(&varresult);
581 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, &varresult, &excepinfo, NULL);
584 /* Try with NULL params */
585 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
586 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
588 /* Try one empty parameter */
589 dispparams.rgvarg = vararg;
590 dispparams.cArgs = 1;
591 VariantInit(&vararg[0]);
592 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
593 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
595 /* Try one parameter, function requires two */
596 VariantInit(&vararg[0]);
597 V_VT(&vararg[0]) = VT_BSTR;
598 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
599 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
600 VariantClear(&vararg[0]);
602 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
603 ok_exception(hr, szOpenPackageException);
605 /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
606 VariantInit(&vararg[0]);
607 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
608 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
610 VariantInit(&vararg[0]);
611 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
612 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
614 /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
615 name = (WCHAR *)szProductState;
616 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
617 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
619 dispparams.rgvarg = NULL;
620 dispparams.cArgs = 0;
621 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
622 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
624 dispparams.rgvarg = NULL;
625 dispparams.cArgs = 0;
626 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
627 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
630 /* invocation helper function */
631 static int _invoke_todo_vtResult = 0;
633 static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult)
635 OLECHAR *name = NULL;
636 DISPID dispid;
637 HRESULT hr;
638 UINT i;
639 UINT len;
641 memset(pVarResult, 0, sizeof(VARIANT));
642 VariantInit(pVarResult);
644 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 );
645 name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
646 if (!name) return E_FAIL;
647 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len );
648 hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
649 HeapFree(GetProcessHeap(), 0, name);
650 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
651 if (!hr == S_OK) return hr;
653 memset(&excepinfo, 0, sizeof(excepinfo));
654 hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL);
656 if (hr == S_OK)
658 if (_invoke_todo_vtResult) todo_wine
659 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
660 else
661 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
662 if (vtResult != VT_EMPTY)
664 hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult);
665 ok(hr == S_OK, "VariantChangeTypeEx returned 0x%08x\n", hr);
669 for (i=0; i<pDispParams->cArgs; i++)
670 VariantClear(&pDispParams->rgvarg[i]);
672 return hr;
675 /* Object_Property helper functions */
677 static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord)
679 VARIANT varresult;
680 VARIANTARG vararg[1];
681 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
682 HRESULT hr;
684 VariantInit(&vararg[0]);
685 V_VT(&vararg[0]) = VT_I4;
686 V_I4(&vararg[0]) = count;
688 hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
689 *pRecord = V_DISPATCH(&varresult);
690 return hr;
693 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
695 VARIANTARG vararg[3];
696 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
698 VariantInit(&vararg[2]);
699 V_VT(&vararg[2]) = VT_I4;
700 V_I4(&vararg[2]) = (int)hkey;
701 VariantInit(&vararg[1]);
702 V_VT(&vararg[1]) = VT_BSTR;
703 V_BSTR(&vararg[1]) = SysAllocString(szKey);
704 VariantInit(&vararg[0]);
705 VariantCopy(&vararg[0], &vValue);
706 VariantClear(&vValue);
708 return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect);
711 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
713 VARIANT varresult;
714 VARIANTARG vararg;
715 HRESULT hr;
717 VariantInit(&vararg);
718 V_VT(&vararg) = VT_EMPTY;
719 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL);
720 *pBool = V_BOOL(&varresult);
721 VariantClear(&varresult);
722 return hr;
725 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
727 VARIANT varresult;
728 VARIANTARG vararg;
729 HRESULT hr;
731 VariantInit(&vararg);
732 V_VT(&vararg) = VT_BSTR;
733 V_BSTR(&vararg) = SysAllocString(szValue);
735 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR);
736 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
737 VariantClear(&varresult);
738 return hr;
741 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
743 VARIANT varresult;
744 VARIANTARG vararg;
745 HRESULT hr;
747 VariantInit(&vararg);
748 V_VT(&vararg) = VT_I4;
749 V_I4(&vararg) = iValue;
751 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult);
752 if (vtResult == VT_BSTR) lstrcpyW(szString, V_BSTR(&varresult));
753 VariantClear(&varresult);
754 return hr;
757 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
759 VARIANT varresult;
760 VARIANTARG vararg[2];
761 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
762 HRESULT hr;
764 VariantInit(&vararg[1]);
765 V_VT(&vararg[1]) = VT_BSTR;
766 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
767 VariantInit(&vararg[0]);
768 V_VT(&vararg[0]) = VT_I4;
769 V_I4(&vararg[0]) = options;
771 hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
772 *pSession = V_DISPATCH(&varresult);
773 return hr;
776 static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase)
778 VARIANT varresult;
779 VARIANTARG vararg[2];
780 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
781 HRESULT hr;
783 VariantInit(&vararg[1]);
784 V_VT(&vararg[1]) = VT_BSTR;
785 V_BSTR(&vararg[1]) = SysAllocString(szDatabasePath);
786 VariantInit(&vararg[0]);
787 V_VT(&vararg[0]) = VT_I4;
788 V_I4(&vararg[0]) = openmode;
790 hr = invoke(pInstaller, "OpenDatabase", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
791 *pDatabase = V_DISPATCH(&varresult);
792 return hr;
795 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
797 VARIANT varresult;
798 VARIANTARG vararg[2];
799 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
801 VariantInit(&vararg[1]);
802 V_VT(&vararg[1]) = VT_BSTR;
803 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
804 VariantInit(&vararg[0]);
805 V_VT(&vararg[0]) = VT_BSTR;
806 V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues);
808 return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
811 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
813 VARIANT varresult;
814 VARIANTARG vararg[1];
815 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
816 HRESULT hr;
818 VariantInit(&vararg[0]);
819 V_VT(&vararg[0]) = VT_BSTR;
820 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
822 hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
823 *pInstallState = V_I4(&varresult);
824 VariantClear(&varresult);
825 return hr;
828 static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szString)
830 VARIANT varresult;
831 VARIANTARG vararg[2];
832 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
833 HRESULT hr;
835 VariantInit(&vararg[1]);
836 V_VT(&vararg[1]) = VT_BSTR;
837 V_BSTR(&vararg[1]) = SysAllocString(szProduct);
838 VariantInit(&vararg[0]);
839 V_VT(&vararg[0]) = VT_BSTR;
840 V_BSTR(&vararg[0]) = SysAllocString(szAttribute);
842 hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
843 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
844 VariantClear(&varresult);
845 return hr;
848 static HRESULT Installer_Products(IDispatch **pStringList)
850 VARIANT varresult;
851 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
852 HRESULT hr;
854 hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
855 *pStringList = V_DISPATCH(&varresult);
856 return hr;
859 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
861 VARIANT varresult;
862 VARIANTARG vararg[1];
863 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
864 HRESULT hr;
866 VariantInit(&vararg[0]);
867 V_VT(&vararg[0]) = VT_BSTR;
868 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
870 hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
871 *pStringList = V_DISPATCH(&varresult);
872 return hr;
875 static HRESULT Installer_VersionGet(LPWSTR szVersion)
877 VARIANT varresult;
878 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
879 HRESULT hr;
881 hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
882 if (V_BSTR(&varresult)) lstrcpyW(szVersion, V_BSTR(&varresult));
883 VariantClear(&varresult);
884 return hr;
887 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
889 VARIANT varresult;
890 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
891 HRESULT hr;
893 hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
894 *pInst = V_DISPATCH(&varresult);
895 return hr;
898 static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn)
900 VARIANT varresult;
901 VARIANTARG vararg[1];
902 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
903 HRESULT hr;
905 VariantInit(&vararg[0]);
906 V_VT(&vararg[0]) = VT_BSTR;
907 V_BSTR(&vararg[0]) = SysAllocString(szName);
909 hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
910 if (V_BSTR(&varresult)) lstrcpyW(szReturn, V_BSTR(&varresult));
911 VariantClear(&varresult);
912 return hr;
915 static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue)
917 VARIANT varresult;
918 VARIANTARG vararg[2];
919 DISPID dispid = DISPID_PROPERTYPUT;
920 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
922 VariantInit(&vararg[1]);
923 V_VT(&vararg[1]) = VT_BSTR;
924 V_BSTR(&vararg[1]) = SysAllocString(szName);
925 VariantInit(&vararg[0]);
926 V_VT(&vararg[0]) = VT_BSTR;
927 V_BSTR(&vararg[0]) = SysAllocString(szValue);
929 return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
932 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
934 VARIANT varresult;
935 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
936 HRESULT hr;
938 hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
939 *pLangId = V_I4(&varresult);
940 VariantClear(&varresult);
941 return hr;
944 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, BOOL *pMode)
946 VARIANT varresult;
947 VARIANTARG vararg[1];
948 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
949 HRESULT hr;
951 VariantInit(&vararg[0]);
952 V_VT(&vararg[0]) = VT_I4;
953 V_I4(&vararg[0]) = iFlag;
955 hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL);
956 *pMode = V_BOOL(&varresult);
957 VariantClear(&varresult);
958 return hr;
961 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, BOOL bMode)
963 VARIANT varresult;
964 VARIANTARG vararg[2];
965 DISPID dispid = DISPID_PROPERTYPUT;
966 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
968 VariantInit(&vararg[1]);
969 V_VT(&vararg[1]) = VT_I4;
970 V_I4(&vararg[1]) = iFlag;
971 VariantInit(&vararg[0]);
972 V_VT(&vararg[0]) = VT_BOOL;
973 V_BOOL(&vararg[0]) = bMode;
975 return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
978 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
980 VARIANT varresult;
981 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
982 HRESULT hr;
984 hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
985 *pDatabase = V_DISPATCH(&varresult);
986 return hr;
989 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn)
991 VARIANT varresult;
992 VARIANTARG vararg[1];
993 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
994 HRESULT hr;
996 VariantInit(&vararg[0]);
997 V_VT(&vararg[0]) = VT_BSTR;
998 V_BSTR(&vararg[0]) = SysAllocString(szAction);
1000 hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1001 *iReturn = V_I4(&varresult);
1002 VariantClear(&varresult);
1003 return hr;
1006 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
1008 VARIANT varresult;
1009 VARIANTARG vararg[1];
1010 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1011 HRESULT hr;
1013 VariantInit(&vararg[0]);
1014 V_VT(&vararg[0]) = VT_BSTR;
1015 V_BSTR(&vararg[0]) = SysAllocString(szCondition);
1017 hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1018 *iReturn = V_I4(&varresult);
1019 VariantClear(&varresult);
1020 return hr;
1023 static HRESULT Session_SetInstallLevel(IDispatch *pSession, long iInstallLevel)
1025 VARIANT varresult;
1026 VARIANTARG vararg[1];
1027 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1029 VariantInit(&vararg[0]);
1030 V_VT(&vararg[0]) = VT_I4;
1031 V_I4(&vararg[0]) = iInstallLevel;
1033 return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1036 static HRESULT Session_FeatureCurrentState(IDispatch *pSession, LPCWSTR szName, int *pState)
1038 VARIANT varresult;
1039 VARIANTARG vararg[1];
1040 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1041 HRESULT hr;
1043 VariantInit(&vararg[0]);
1044 V_VT(&vararg[0]) = VT_BSTR;
1045 V_BSTR(&vararg[0]) = SysAllocString(szName);
1047 hr = invoke(pSession, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1048 *pState = V_I4(&varresult);
1049 VariantClear(&varresult);
1050 return hr;
1053 static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState)
1055 VARIANT varresult;
1056 VARIANTARG vararg[1];
1057 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1058 HRESULT hr;
1060 VariantInit(&vararg[0]);
1061 V_VT(&vararg[0]) = VT_BSTR;
1062 V_BSTR(&vararg[0]) = SysAllocString(szName);
1064 hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1065 *pState = V_I4(&varresult);
1066 VariantClear(&varresult);
1067 return hr;
1070 static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState)
1072 VARIANT varresult;
1073 VARIANTARG vararg[2];
1074 DISPID dispid = DISPID_PROPERTYPUT;
1075 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1077 VariantInit(&vararg[1]);
1078 V_VT(&vararg[1]) = VT_BSTR;
1079 V_BSTR(&vararg[1]) = SysAllocString(szName);
1080 VariantInit(&vararg[0]);
1081 V_VT(&vararg[0]) = VT_I4;
1082 V_I4(&vararg[0]) = iState;
1084 return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1087 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
1089 VARIANT varresult;
1090 VARIANTARG vararg[1];
1091 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1092 HRESULT hr;
1094 VariantInit(&vararg[0]);
1095 V_VT(&vararg[0]) = VT_BSTR;
1096 V_BSTR(&vararg[0]) = SysAllocString(szSql);
1098 hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1099 *pView = V_DISPATCH(&varresult);
1100 return hr;
1103 static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo)
1105 VARIANT varresult;
1106 VARIANTARG vararg[1];
1107 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1108 HRESULT hr;
1110 VariantInit(&vararg[0]);
1111 V_VT(&vararg[0]) = VT_I4;
1112 V_I4(&vararg[0]) = iUpdateCount;
1114 hr = invoke(pDatabase, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1115 *pSummaryInfo = V_DISPATCH(&varresult);
1116 return hr;
1119 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
1121 VARIANT varresult;
1122 VARIANTARG vararg[1];
1123 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1125 VariantInit(&vararg[0]);
1126 V_VT(&vararg[0]) = VT_DISPATCH;
1127 V_DISPATCH(&vararg[0]) = pRecord;
1129 return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1132 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
1134 VARIANT varresult;
1135 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1136 HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1137 *ppRecord = V_DISPATCH(&varresult);
1138 return hr;
1141 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
1143 VARIANT varresult;
1144 VARIANTARG vararg[2];
1145 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1147 VariantInit(&vararg[1]);
1148 V_VT(&vararg[1]) = VT_I4;
1149 V_I4(&vararg[1]) = iMode;
1150 VariantInit(&vararg[0]);
1151 V_VT(&vararg[0]) = VT_DISPATCH;
1152 V_DISPATCH(&vararg[0]) = pRecord;
1153 if (pRecord)
1154 IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */
1156 return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1159 static HRESULT View_Close(IDispatch *pView)
1161 VARIANT varresult;
1162 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1163 return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1166 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
1168 VARIANT varresult;
1169 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1170 HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1171 *pFieldCount = V_I4(&varresult);
1172 VariantClear(&varresult);
1173 return hr;
1176 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString)
1178 VARIANT varresult;
1179 VARIANTARG vararg[1];
1180 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1181 HRESULT hr;
1183 VariantInit(&vararg[0]);
1184 V_VT(&vararg[0]) = VT_I4;
1185 V_I4(&vararg[0]) = iField;
1187 hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1188 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1189 VariantClear(&varresult);
1190 return hr;
1193 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
1195 VARIANT varresult;
1196 VARIANTARG vararg[2];
1197 DISPID dispid = DISPID_PROPERTYPUT;
1198 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1200 VariantInit(&vararg[1]);
1201 V_VT(&vararg[1]) = VT_I4;
1202 V_I4(&vararg[1]) = iField;
1203 VariantInit(&vararg[0]);
1204 V_VT(&vararg[0]) = VT_BSTR;
1205 V_BSTR(&vararg[0]) = SysAllocString(szString);
1207 return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1210 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
1212 VARIANT varresult;
1213 VARIANTARG vararg[1];
1214 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1215 HRESULT hr;
1217 VariantInit(&vararg[0]);
1218 V_VT(&vararg[0]) = VT_I4;
1219 V_I4(&vararg[0]) = iField;
1221 hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1222 *pValue = V_I4(&varresult);
1223 VariantClear(&varresult);
1224 return hr;
1227 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
1229 VARIANT varresult;
1230 VARIANTARG vararg[2];
1231 DISPID dispid = DISPID_PROPERTYPUT;
1232 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1234 VariantInit(&vararg[1]);
1235 V_VT(&vararg[1]) = VT_I4;
1236 V_I4(&vararg[1]) = iField;
1237 VariantInit(&vararg[0]);
1238 V_VT(&vararg[0]) = VT_I4;
1239 V_I4(&vararg[0]) = iValue;
1241 return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1244 static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT)
1246 VARIANT varresult;
1247 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1248 HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN);
1249 *ppEnumVARIANT = V_UNKNOWN(&varresult);
1250 return hr;
1253 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
1255 VARIANT varresult;
1256 VARIANTARG vararg[1];
1257 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1258 HRESULT hr;
1260 VariantInit(&vararg[0]);
1261 V_VT(&vararg[0]) = VT_I4;
1262 V_I4(&vararg[0]) = iIndex;
1264 hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1265 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1266 VariantClear(&varresult);
1267 return hr;
1270 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
1272 VARIANT varresult;
1273 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1274 HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1275 *pCount = V_I4(&varresult);
1276 VariantClear(&varresult);
1277 return hr;
1280 static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect)
1282 VARIANTARG vararg[1];
1283 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1285 VariantInit(&vararg[0]);
1286 V_VT(&vararg[0]) = VT_I4;
1287 V_I4(&vararg[0]) = pid;
1288 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYGET, &dispparams, pVarResult, vtExpect);
1291 static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant)
1293 VARIANT varresult;
1294 VARIANTARG vararg[2];
1295 DISPID dispid = DISPID_PROPERTYPUT;
1296 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1298 VariantInit(&vararg[1]);
1299 V_VT(&vararg[1]) = VT_I4;
1300 V_I4(&vararg[1]) = pid;
1301 VariantInit(&vararg[0]);
1302 VariantCopyInd(vararg, pVariant);
1304 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1307 static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount)
1309 VARIANT varresult;
1310 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1311 HRESULT hr;
1313 hr = invoke(pSummaryInfo, "PropertyCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1314 *pCount = V_I4(&varresult);
1315 VariantClear(&varresult);
1316 return hr;
1319 /* Test the various objects */
1321 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4
1323 static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly)
1325 static const WCHAR szPropertyException[] = { 'P','r','o','p','e','r','t','y',',','P','i','d',0 };
1326 static const WCHAR szTitle[] = { 'T','i','t','l','e',0 };
1327 VARIANT varresult, var;
1328 SYSTEMTIME st;
1329 HRESULT hr;
1330 int j;
1332 /* SummaryInfo::PropertyCount */
1333 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1334 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1335 ok(j == num_info, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1337 /* SummaryInfo::Property, get for properties we have set */
1338 for (j = 0; j < num_info; j++)
1340 const msi_summary_info *entry = &info[j];
1342 int vt = entry->datatype;
1343 if (vt == VT_LPSTR) vt = VT_BSTR;
1344 else if (vt == VT_FILETIME) vt = VT_DATE;
1345 else if (vt == VT_I2) vt = VT_I4;
1347 hr = SummaryInfo_PropertyGet(pSummaryInfo, entry->property, &varresult, vt);
1348 ok(hr == S_OK, "SummaryInfo_Property (pid %d) failed, hresult 0x%08x\n", entry->property, hr);
1349 if (V_VT(&varresult) != vt)
1350 skip("Skipping property tests due to type mismatch\n");
1351 else if (vt == VT_I4)
1352 ok(V_I4(&varresult) == entry->iValue, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %d\n",
1353 entry->property, entry->iValue, V_I4(&varresult));
1354 else if (vt == VT_DATE)
1356 FILETIME ft;
1357 DATE d;
1359 FileTimeToLocalFileTime(entry->pftValue, &ft);
1360 FileTimeToSystemTime(&ft, &st);
1361 SystemTimeToVariantTime(&st, &d);
1362 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));
1364 else if (vt == VT_BSTR)
1366 ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry->property, entry->szValue, V_BSTR(&varresult));
1368 else
1369 skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry->property, vt);
1371 VariantClear(&varresult);
1374 /* SummaryInfo::Property, get; invalid arguments */
1376 /* Invalid pids */
1377 hr = SummaryInfo_PropertyGet(pSummaryInfo, -1, &varresult, VT_EMPTY);
1378 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1379 ok_exception(hr, szPropertyException);
1381 hr = SummaryInfo_PropertyGet(pSummaryInfo, 1000, &varresult, VT_EMPTY);
1382 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1383 ok_exception(hr, szPropertyException);
1385 /* Unsupported pids */
1386 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_DICTIONARY, &varresult, VT_EMPTY);
1387 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1389 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY);
1390 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1392 /* Pids we have not set, one for each type */
1393 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_EMPTY);
1394 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1396 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY);
1397 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1399 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY);
1400 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1402 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY);
1403 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1405 if (!readonly)
1407 /* SummaryInfo::Property, put; one for each type */
1409 /* VT_I2 */
1410 VariantInit(&var);
1411 V_VT(&var) = VT_I2;
1412 V_I2(&var) = 1;
1413 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CODEPAGE, &var);
1414 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1416 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */);
1417 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1418 ok(V_I2(&var) == V_I2(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var), V_I2(&varresult));
1419 VariantClear(&varresult);
1420 VariantClear(&var);
1422 /* VT_BSTR */
1423 V_VT(&var) = VT_BSTR;
1424 V_BSTR(&var) = SysAllocString(szTitle);
1425 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_TITLE, &var);
1426 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1428 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var));
1429 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1430 ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var), V_BSTR(&varresult));
1431 VariantClear(&varresult);
1432 VariantClear(&var);
1434 /* VT_DATE */
1435 V_VT(&var) = VT_DATE;
1436 FileTimeToSystemTime(&systemtime, &st);
1437 SystemTimeToVariantTime(&st, &V_DATE(&var));
1438 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_LASTSAVE_DTM, &var);
1439 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1441 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var));
1442 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1443 /* FIXME: Off by one second */
1444 todo_wine ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1445 VariantClear(&varresult);
1446 VariantClear(&var);
1448 /* VT_I4 */
1449 V_VT(&var) = VT_I4;
1450 V_I4(&var) = 1000;
1451 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1452 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1454 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1455 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1456 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult));
1457 VariantClear(&varresult);
1458 VariantClear(&var);
1460 /* SummaryInfo::PropertyCount */
1461 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1462 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1463 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1467 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1469 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 };
1470 static WCHAR szThree[] = { 'T','h','r','e','e',0 };
1471 static WCHAR szTwo[] = { 'T','w','o',0 };
1472 static WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
1473 static WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 };
1474 IDispatch *pView = NULL, *pSummaryInfo = NULL;
1475 HRESULT hr;
1477 hr = Database_OpenView(pDatabase, szSql, &pView);
1478 ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr);
1479 if (hr == S_OK)
1481 IDispatch *pRecord = NULL;
1482 WCHAR szString[MAX_PATH];
1484 /* View::Execute */
1485 hr = View_Execute(pView, NULL);
1486 ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr);
1488 /* View::Fetch */
1489 hr = View_Fetch(pView, &pRecord);
1490 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1491 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1492 if (pRecord)
1494 /* Record::StringDataGet */
1495 memset(szString, 0, sizeof(szString));
1496 hr = Record_StringDataGet(pRecord, 1, szString);
1497 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1498 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1500 /* Record::StringDataPut with correct index */
1501 hr = Record_StringDataPut(pRecord, 1, szTwo);
1502 ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1504 /* Record::StringDataGet */
1505 memset(szString, 0, sizeof(szString));
1506 hr = Record_StringDataGet(pRecord, 1, szString);
1507 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1508 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1510 /* Record::StringDataPut with incorrect index */
1511 hr = Record_StringDataPut(pRecord, -1, szString);
1512 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1513 ok_exception(hr, szStringDataField);
1515 /* View::Modify with incorrect parameters */
1516 hr = View_Modify(pView, -5, NULL);
1517 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1518 ok_exception(hr, szModifyModeRecord);
1520 hr = View_Modify(pView, -5, pRecord);
1521 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1522 ok_exception(hr, szModifyModeRecord);
1524 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1525 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1526 ok_exception(hr, szModifyModeRecord);
1528 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1529 ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr);
1531 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1532 memset(szString, 0, sizeof(szString));
1533 hr = Record_StringDataGet(pRecord, 1, szString);
1534 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1535 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1537 IDispatch_Release(pRecord);
1540 /* View::Fetch */
1541 hr = View_Fetch(pView, &pRecord);
1542 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1543 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1544 if (pRecord)
1546 /* Record::StringDataGet */
1547 memset(szString, 0, sizeof(szString));
1548 hr = Record_StringDataGet(pRecord, 1, szString);
1549 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1550 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1552 IDispatch_Release(pRecord);
1555 /* View::Fetch */
1556 hr = View_Fetch(pView, &pRecord);
1557 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1558 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1559 if (pRecord)
1560 IDispatch_Release(pRecord);
1562 /* View::Close */
1563 hr = View_Close(pView);
1564 ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr);
1566 IDispatch_Release(pView);
1569 /* Database::SummaryInformation */
1570 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo);
1571 ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr);
1572 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1573 if (pSummaryInfo)
1575 test_SummaryInfo(pSummaryInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), readonly);
1576 IDispatch_Release(pSummaryInfo);
1580 static void test_Session(IDispatch *pSession)
1582 static WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
1583 static WCHAR szOne[] = { 'O','n','e',0 };
1584 static WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 };
1585 static WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 };
1586 static WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 };
1587 static WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 };
1588 static WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1589 static WCHAR szEmpty[] = { 0 };
1590 static WCHAR szEquals[] = { '=',0 };
1591 static WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
1592 WCHAR stringw[MAX_PATH];
1593 CHAR string[MAX_PATH];
1594 UINT len;
1595 BOOL bool;
1596 int myint;
1597 IDispatch *pDatabase = NULL, *pInst = NULL;
1598 HRESULT hr;
1600 /* Session::Installer */
1601 hr = Session_Installer(pSession, &pInst);
1602 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1603 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1604 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1606 /* Session::Property, get */
1607 memset(stringw, 0, sizeof(stringw));
1608 hr = Session_PropertyGet(pSession, szProductName, stringw);
1609 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1610 if (lstrcmpW(stringw, szMSITEST) != 0)
1612 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1613 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1614 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1617 /* Session::Property, put */
1618 hr = Session_PropertyPut(pSession, szProductName, szProductName);
1619 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1620 memset(stringw, 0, sizeof(stringw));
1621 hr = Session_PropertyGet(pSession, szProductName, stringw);
1622 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1623 if (lstrcmpW(stringw, szProductName) != 0)
1625 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1626 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1627 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1630 /* Try putting a property using empty property identifier */
1631 hr = Session_PropertyPut(pSession, szEmpty, szProductName);
1632 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1633 ok_exception(hr, szPropertyName);
1635 /* Try putting a property using illegal property identifier */
1636 hr = Session_PropertyPut(pSession, szEquals, szProductName);
1637 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1639 /* Session::Language, get */
1640 hr = Session_LanguageGet(pSession, &len);
1641 ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1642 /* Not sure how to check the language is correct */
1644 /* Session::Mode, get */
1645 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1646 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1647 todo_wine ok(!bool, "Reboot at end session mode is %d\n", bool);
1649 /* Session::Mode, put */
1650 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE);
1651 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1652 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1653 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1654 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1655 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE); /* set it again so we don't reboot */
1656 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1658 /* Session::Database, get */
1659 hr = Session_Database(pSession, &pDatabase);
1660 ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr);
1661 if (hr == S_OK)
1663 test_Database(pDatabase, TRUE);
1664 IDispatch_Release(pDatabase);
1667 /* Session::EvaluateCondition */
1668 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1669 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1670 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1672 hr = Session_EvaluateCondition(pSession, szEmpty, &myint);
1673 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1674 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1676 hr = Session_EvaluateCondition(pSession, szEquals, &myint);
1677 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1678 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1680 /* Session::DoAction(CostInitialize) must occur before the next statements */
1681 hr = Session_DoAction(pSession, szCostInitialize, &myint);
1682 ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr);
1683 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1685 /* Session::SetInstallLevel */
1686 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1687 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
1689 /* Session::FeatureCurrentState, get */
1690 hr = Session_FeatureCurrentState(pSession, szOne, &myint);
1691 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
1692 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1694 /* Session::EvaluateCondition */
1695 hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint);
1696 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1697 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1699 hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint);
1700 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1701 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1703 /* Session::FeatureRequestState, put */
1704 hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED);
1705 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
1706 hr = Session_FeatureRequestStateGet(pSession, szOne, &myint);
1707 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
1708 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
1710 /* Session::EvaluateCondition */
1711 hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint);
1712 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1713 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1715 hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint);
1716 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1717 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1720 /* delete key and all its subkeys */
1721 static DWORD delete_key( HKEY hkey )
1723 char name[MAX_PATH];
1724 DWORD ret;
1726 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
1728 HKEY tmp;
1729 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
1731 ret = delete_key( tmp );
1732 RegCloseKey( tmp );
1734 if (ret) break;
1736 if (ret != ERROR_NO_MORE_ITEMS) return ret;
1737 RegDeleteKeyA( hkey, "" );
1738 return 0;
1741 static void test_Installer_RegistryValue(void)
1743 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
1744 static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 };
1745 static const WCHAR szOne[] = { 'O','n','e',0 };
1746 static const WCHAR szTwo[] = { 'T','w','o',0 };
1747 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
1748 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1749 static const WCHAR szFour[] = { 'F','o','u','r',0 };
1750 static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 };
1751 static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 };
1752 static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 };
1753 static const WCHAR szSix[] = { 'S','i','x',0 };
1754 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1755 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
1756 static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
1757 static const WCHAR szBlank[] = { 0 };
1758 VARIANT varresult;
1759 VARIANTARG vararg;
1760 WCHAR szString[MAX_PATH];
1761 HKEY hkey, hkey_sub;
1762 HRESULT hr;
1763 BOOL bRet;
1765 /* Delete keys */
1766 if (!RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey )) delete_key( hkey );
1768 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
1769 hr = Installer_RegistryValueE(HKEY_CURRENT_USER, szKey, &bRet);
1770 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1771 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
1773 memset(szString, 0, sizeof(szString));
1774 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, NULL, szString);
1775 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1777 memset(szString, 0, sizeof(szString));
1778 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 0, szString, VT_BSTR);
1779 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1781 /* Create key */
1782 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
1784 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1785 "RegSetValueExW failed\n");
1786 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
1787 "RegSetValueExW failed\n");
1788 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
1789 "RegSetValueExW failed\n");
1790 ok(SetEnvironmentVariableA("MSITEST", "Four"), "SetEnvironmentVariableA failed %d\n", GetLastError());
1791 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
1792 "RegSetValueExW failed\n");
1793 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
1794 "RegSetValueExW failed\n");
1795 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
1796 "RegSetValueExW failed\n");
1797 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, (const BYTE *)NULL, 0),
1798 "RegSetValueExW failed\n");
1800 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1801 "RegSetValueExW failed\n");
1803 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
1805 /* Does our key exist? It should, and make sure we retrieve the correct default value */
1806 bRet = FALSE;
1807 hr = Installer_RegistryValueE(HKEY_CURRENT_USER, szKey, &bRet);
1808 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1809 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
1811 memset(szString, 0, sizeof(szString));
1812 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, NULL, szString);
1813 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1814 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1816 /* Ask for the value of a nonexistent key */
1817 memset(szString, 0, sizeof(szString));
1818 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szExpand, szString);
1819 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1821 /* Get values of keys */
1822 memset(szString, 0, sizeof(szString));
1823 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szOne, szString);
1824 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1825 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1827 VariantInit(&vararg);
1828 V_VT(&vararg) = VT_BSTR;
1829 V_BSTR(&vararg) = SysAllocString(szTwo);
1830 hr = Installer_RegistryValue(HKEY_CURRENT_USER, szKey, vararg, &varresult, VT_I4);
1831 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1832 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
1833 VariantClear(&varresult);
1835 memset(szString, 0, sizeof(szString));
1836 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szThree, szString);
1837 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1838 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
1840 memset(szString, 0, sizeof(szString));
1841 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szFour, szString);
1842 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1843 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
1845 memset(szString, 0, sizeof(szString));
1846 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szFive, szString);
1847 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1848 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFiveHi);
1850 memset(szString, 0, sizeof(szString));
1851 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szSix, szString);
1852 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1853 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_);
1855 VariantInit(&vararg);
1856 V_VT(&vararg) = VT_BSTR;
1857 V_BSTR(&vararg) = SysAllocString(szSeven);
1858 hr = Installer_RegistryValue(HKEY_CURRENT_USER, szKey, vararg, &varresult, VT_EMPTY);
1859 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1861 /* Get string class name for the key */
1862 memset(szString, 0, sizeof(szString));
1863 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 0, szString, VT_BSTR);
1864 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1865 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank);
1867 /* Get name of a value by positive number (RegEnumValue like), valid index */
1868 memset(szString, 0, sizeof(szString));
1869 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 2, szString, VT_BSTR);
1870 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1871 /* RegEnumValue order seems different on wine */
1872 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
1874 /* Get name of a value by positive number (RegEnumValue like), invalid index */
1875 memset(szString, 0, sizeof(szString));
1876 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 10, szString, VT_EMPTY);
1877 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1879 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
1880 memset(szString, 0, sizeof(szString));
1881 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, -1, szString, VT_BSTR);
1882 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1883 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
1885 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
1886 memset(szString, 0, sizeof(szString));
1887 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, -10, szString, VT_EMPTY);
1888 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1890 /* clean up */
1891 delete_key(hkey);
1894 static void test_Installer_Products(BOOL bProductInstalled)
1896 WCHAR szString[MAX_PATH];
1897 HRESULT hr;
1898 int idx;
1899 IUnknown *pUnk = NULL;
1900 IEnumVARIANT *pEnum = NULL;
1901 VARIANT var;
1902 ULONG celt;
1903 int iCount, iValue;
1904 IDispatch *pStringList = NULL;
1905 BOOL bProductFound = FALSE;
1907 /* Installer::Products */
1908 hr = Installer_Products(&pStringList);
1909 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
1910 if (hr == S_OK)
1912 /* StringList::_NewEnum */
1913 hr = StringList__NewEnum(pStringList, &pUnk);
1914 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
1915 if (hr == S_OK)
1917 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
1918 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
1920 if (!pEnum)
1921 skip("IEnumVARIANT tests\n");
1923 /* StringList::Count */
1924 hr = StringList_Count(pStringList, &iCount);
1925 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
1927 for (idx=0; idx<iCount; idx++)
1929 /* StringList::Item */
1930 memset(szString, 0, sizeof(szString));
1931 hr = StringList_Item(pStringList, idx, szString);
1932 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
1934 if (hr == S_OK)
1936 /* Installer::ProductState */
1937 hr = Installer_ProductState(szString, &iValue);
1938 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
1939 if (hr == S_OK)
1940 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
1942 /* Not found our product code yet? Check */
1943 if (!bProductFound && !lstrcmpW(szString, szProductCode))
1944 bProductFound = TRUE;
1946 /* IEnumVARIANT::Next */
1947 if (pEnum)
1949 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
1950 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
1951 ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
1952 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
1953 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
1954 VariantClear(&var);
1959 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
1960 bProductInstalled ? "be" : "not be",
1961 bProductFound ? "found" : "not found");
1963 if (pEnum)
1965 IEnumVARIANT *pEnum2 = NULL;
1967 if (0) /* Crashes on Windows XP */
1969 /* IEnumVARIANT::Clone, NULL pointer */
1970 hr = IEnumVARIANT_Clone(pEnum, NULL);
1973 /* IEnumVARIANT::Clone */
1974 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
1975 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
1976 if (hr == S_OK)
1978 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
1980 /* IEnumVARIANT::Next of the clone */
1981 if (iCount)
1983 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
1984 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
1985 ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
1986 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
1987 VariantClear(&var);
1989 else
1990 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
1992 IEnumVARIANT_Release(pEnum2);
1995 /* IEnumVARIANT::Skip should fail */
1996 hr = IEnumVARIANT_Skip(pEnum, 1);
1997 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
1999 /* IEnumVARIANT::Next, NULL variant pointer */
2000 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2001 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2002 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2004 /* IEnumVARIANT::Next, should not return any more items */
2005 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2006 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2007 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2008 VariantClear(&var);
2010 /* IEnumVARIANT::Reset */
2011 hr = IEnumVARIANT_Reset(pEnum);
2012 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2014 if (iCount)
2016 /* IEnumVARIANT::Skip to the last product */
2017 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2018 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2020 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2021 * NULL celt pointer. */
2022 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2023 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2024 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2025 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2026 VariantClear(&var);
2028 else
2029 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2032 /* StringList::Item using an invalid index */
2033 memset(szString, 0, sizeof(szString));
2034 hr = StringList_Item(pStringList, iCount, szString);
2035 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2037 if (pEnum) IEnumVARIANT_Release(pEnum);
2038 if (pUnk) IUnknown_Release(pUnk);
2039 IDispatch_Release(pStringList);
2043 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2044 * deleting the subkeys first) */
2045 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey)
2047 UINT ret;
2048 CHAR *string = NULL;
2049 HKEY hkey;
2050 DWORD dwSize;
2052 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2053 if (ret != ERROR_SUCCESS) return ret;
2054 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2055 if (ret != ERROR_SUCCESS) return ret;
2056 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2058 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2059 delete_registry_key(hkey, string);
2061 RegCloseKey(hkey);
2062 HeapFree(GetProcessHeap(), 0, string);
2063 RegDeleteKeyA(hkeyParent, subkey);
2064 return ERROR_SUCCESS;
2067 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2068 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, HKEY *phkey)
2070 UINT ret;
2071 CHAR *string = NULL;
2072 int idx = 0;
2073 HKEY hkey;
2074 DWORD dwSize;
2075 BOOL found = FALSE;
2077 *phkey = 0;
2079 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2080 if (ret != ERROR_SUCCESS) return ret;
2081 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2082 if (ret != ERROR_SUCCESS) return ret;
2083 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2085 while (!found &&
2086 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2088 if (!strcmp(string, findkey))
2090 *phkey = hkey;
2091 found = TRUE;
2093 else if (find_registry_key(hkey, string, findkey, phkey) == ERROR_SUCCESS) found = TRUE;
2096 if (*phkey != hkey) RegCloseKey(hkey);
2097 HeapFree(GetProcessHeap(), 0, string);
2098 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2101 static void test_Installer_InstallProduct(void)
2103 HRESULT hr;
2104 CHAR path[MAX_PATH];
2105 WCHAR szString[MAX_PATH];
2106 LONG res;
2107 HKEY hkey;
2108 DWORD num, size, type;
2109 int iValue, iCount;
2110 IDispatch *pStringList = NULL;
2112 create_test_files();
2114 /* Installer::InstallProduct */
2115 hr = Installer_InstallProduct(szMsifile, NULL);
2116 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2118 /* Installer::ProductState for our product code, which has been installed */
2119 hr = Installer_ProductState(szProductCode, &iValue);
2120 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2121 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2123 /* Installer::ProductInfo for our product code */
2125 /* NULL attribute */
2126 memset(szString, 0, sizeof(szString));
2127 hr = Installer_ProductInfo(szProductCode, NULL, szString);
2128 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2129 ok_exception(hr, szProductInfoException);
2131 /* Nonexistent attribute */
2132 memset(szString, 0, sizeof(szString));
2133 hr = Installer_ProductInfo(szProductCode, szMsifile, szString);
2134 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2135 ok_exception(hr, szProductInfoException);
2137 /* Package name */
2138 memset(szString, 0, sizeof(szString));
2139 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szString);
2140 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2141 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile);
2143 /* Product name */
2144 memset(szString, 0, sizeof(szString));
2145 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PRODUCTNAMEW, szString);
2146 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2147 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST);
2149 /* Installer::Products */
2150 test_Installer_Products(TRUE);
2152 /* Installer::RelatedProducts for our upgrade code */
2153 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2154 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2155 if (hr == S_OK)
2157 /* StringList::Count */
2158 hr = StringList_Count(pStringList, &iCount);
2159 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2160 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2162 /* StringList::Item */
2163 memset(szString, 0, sizeof(szString));
2164 hr = StringList_Item(pStringList, 0, szString);
2165 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2166 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
2168 IDispatch_Release(pStringList);
2171 /* Check & clean up installed files & registry keys */
2172 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2173 ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
2174 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2175 ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
2176 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2177 ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
2178 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2179 ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
2180 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2181 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2182 ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
2183 ok(delete_pf("msitest", FALSE), "File not installed\n");
2185 res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
2186 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2188 size = MAX_PATH;
2189 type = REG_SZ;
2190 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2191 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2192 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2194 size = MAX_PATH;
2195 type = REG_SZ;
2196 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2197 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2199 size = sizeof(num);
2200 type = REG_DWORD;
2201 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2202 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2203 ok(num == 314, "Expected 314, got %d\n", num);
2205 size = MAX_PATH;
2206 type = REG_SZ;
2207 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2208 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2209 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2211 RegCloseKey(hkey);
2213 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest");
2214 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2216 check_service_is_installed();
2218 /* Remove registry keys written by RegisterProduct standard action */
2219 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F1C3AF50-8B56-4A69-A00C-00773FE42F30}");
2220 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2222 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2223 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2225 res = find_registry_key(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "05FA3C1F65B896A40AC00077F34EF203", &hkey);
2226 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2227 if (res == ERROR_SUCCESS)
2229 res = delete_registry_key(hkey, "05FA3C1F65B896A40AC00077F34EF203");
2230 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2231 RegCloseKey(hkey);
2234 /* Remove registry keys written by PublishProduct standard action */
2235 res = RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2236 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2238 res = delete_registry_key(hkey, "Products\\05FA3C1F65B896A40AC00077F34EF203");
2239 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2241 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2242 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2244 RegCloseKey(hkey);
2246 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203");
2247 todo_wine ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_SUCCESS, got %d\n", res);
2249 /* Delete installation files we installed */
2250 delete_test_files();
2253 static void test_Installer(void)
2255 static WCHAR szBackslash[] = { '\\',0 };
2256 static WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
2257 static WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
2258 WCHAR szPath[MAX_PATH];
2259 HRESULT hr;
2260 UINT len;
2261 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL;
2262 int iValue, iCount;
2264 if (!pInstaller) return;
2266 /* Installer::CreateRecord */
2268 /* Test for error */
2269 hr = Installer_CreateRecord(-1, &pRecord);
2270 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2271 ok_exception(hr, szCreateRecordException);
2273 /* Test for success */
2274 hr = Installer_CreateRecord(1, &pRecord);
2275 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2276 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2277 if (pRecord)
2279 /* Record::FieldCountGet */
2280 hr = Record_FieldCountGet(pRecord, &iValue);
2281 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2282 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2284 /* Record::IntegerDataGet */
2285 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2286 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2287 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2289 /* Record::IntegerDataGet, bad index */
2290 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2291 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2292 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2294 /* Record::IntegerDataPut */
2295 hr = Record_IntegerDataPut(pRecord, 1, 100);
2296 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2298 /* Record::IntegerDataPut, bad index */
2299 hr = Record_IntegerDataPut(pRecord, 10, 100);
2300 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2301 ok_exception(hr, szIntegerDataException);
2303 /* Record::IntegerDataGet */
2304 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2305 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2306 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2308 IDispatch_Release(pRecord);
2311 /* Prepare package */
2312 create_database(msifile, tables, sizeof(tables) / sizeof(msi_table),
2313 summary_info, sizeof(summary_info) / sizeof(msi_summary_info));
2315 len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, CURR_DIR, -1, szPath, MAX_PATH);
2316 ok(len, "MultiByteToWideChar returned error %d\n", GetLastError());
2317 if (!len) return;
2319 lstrcatW(szPath, szBackslash);
2320 lstrcatW(szPath, szMsifile);
2322 /* Installer::OpenPackage */
2323 hr = Installer_OpenPackage(szPath, 0, &pSession);
2324 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2325 if (hr == S_OK)
2327 test_Session(pSession);
2328 IDispatch_Release(pSession);
2331 /* Installer::OpenDatabase */
2332 hr = Installer_OpenDatabase(szPath, (int)MSIDBOPEN_TRANSACT, &pDatabase);
2333 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2334 if (hr == S_OK)
2336 test_Database(pDatabase, FALSE);
2337 IDispatch_Release(pDatabase);
2340 /* Installer::RegistryValue */
2341 test_Installer_RegistryValue();
2343 /* Installer::ProductState for our product code, which should not be installed */
2344 hr = Installer_ProductState(szProductCode, &iValue);
2345 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2346 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2348 /* Installer::ProductInfo for our product code, which should not be installed */
2350 /* Package name */
2351 memset(szPath, 0, sizeof(szPath));
2352 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szPath);
2353 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2354 ok_exception(hr, szProductInfoException);
2356 /* NULL attribute and NULL product code */
2357 memset(szPath, 0, sizeof(szPath));
2358 hr = Installer_ProductInfo(NULL, NULL, szPath);
2359 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2360 ok_exception(hr, szProductInfoException);
2362 /* Installer::Products */
2363 test_Installer_Products(FALSE);
2365 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2366 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2367 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2368 if (hr == S_OK)
2370 /* StringList::Count */
2371 hr = StringList_Count(pStringList, &iCount);
2372 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2373 ok(!iCount, "Expected no related products but found %d\n", iCount);
2375 IDispatch_Release(pStringList);
2378 /* Installer::Version */
2379 memset(szPath, 0, sizeof(szPath));
2380 hr = Installer_VersionGet(szPath);
2381 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();
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);