push 97f44e0adb27fff75ba63d8fb97c65db9edfbe82
[wine/hacks.git] / dlls / msi / tests / automation.c
blob269d17c35026ed09066720c3af3e37425171a537
1 /*
2 * Copyright (C) 2007 Mike McCormack for CodeWeavers
3 * Copyright (C) 2007 Misha Koshelev
5 * A test program for Microsoft Installer OLE automation functionality.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
24 #include <stdio.h>
26 #include <windows.h>
27 #include <msiquery.h>
28 #include <msidefs.h>
29 #include <msi.h>
30 #include <fci.h>
32 #include "wine/test.h"
34 static const char *msifile = "winetest.msi";
35 static const WCHAR szMsifile[] = {'w','i','n','e','t','e','s','t','.','m','s','i',0};
36 static const WCHAR szMSITEST[] = { 'M','S','I','T','E','S','T',0 };
37 static const WCHAR szProductCode[] = { '{','F','1','C','3','A','F','5','0','-','8','B','5','6','-','4','A','6','9','-','A','0','0','C','-','0','0','7','7','3','F','E','4','2','F','3','0','}',0 };
38 static const WCHAR szUpgradeCode[] = { '{','C','E','0','6','7','E','8','D','-','2','E','1','A','-','4','3','6','7','-','B','7','3','4','-','4','E','B','2','B','D','A','D','6','5','6','5','}',0 };
39 static const WCHAR szProductInfoException[] = { 'P','r','o','d','u','c','t','I','n','f','o',',','P','r','o','d','u','c','t',',','A','t','t','r','i','b','u','t','e',0 };
40 static const WCHAR WINE_INSTALLPROPERTY_PACKAGENAMEW[] = {'P','a','c','k','a','g','e','N','a','m','e',0};
41 static const WCHAR WINE_INSTALLPROPERTY_PRODUCTNAMEW[] = {'P','r','o','d','u','c','t','N','a','m','e',0};
42 static FILETIME systemtime;
43 static CHAR CURR_DIR[MAX_PATH];
44 static EXCEPINFO excepinfo;
47 * OLE automation data
48 **/
49 static const WCHAR szProgId[] = { 'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r','.','I','n','s','t','a','l','l','e','r',0 };
50 static IDispatch *pInstaller;
52 /* msi database data */
54 static const CHAR component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
55 "s72\tS38\ts72\ti2\tS255\tS72\n"
56 "Component\tComponent\n"
57 "Five\t{8CC92E9D-14B2-4CA4-B2AA-B11D02078087}\tNEWDIR\t2\t\tfive.txt\n"
58 "Four\t{FD37B4EA-7209-45C0-8917-535F35A2F080}\tCABOUTDIR\t2\t\tfour.txt\n"
59 "One\t{783B242E-E185-4A56-AF86-C09815EC053C}\tMSITESTDIR\t2\t\tone.txt\n"
60 "Three\t{010B6ADD-B27D-4EDD-9B3D-34C4F7D61684}\tCHANGEDDIR\t2\t\tthree.txt\n"
61 "Two\t{BF03D1A6-20DA-4A65-82F3-6CAC995915CE}\tFIRSTDIR\t2\t\ttwo.txt\n"
62 "dangler\t{6091DF25-EF96-45F1-B8E9-A9B1420C7A3C}\tTARGETDIR\t4\t\tregdata\n"
63 "component\t\tMSITESTDIR\t0\t1\tfile\n"
64 "service_comp\t\tMSITESTDIR\t0\t1\tservice_file";
66 static const CHAR directory_dat[] = "Directory\tDirectory_Parent\tDefaultDir\n"
67 "s72\tS72\tl255\n"
68 "Directory\tDirectory\n"
69 "CABOUTDIR\tMSITESTDIR\tcabout\n"
70 "CHANGEDDIR\tMSITESTDIR\tchanged:second\n"
71 "FIRSTDIR\tMSITESTDIR\tfirst\n"
72 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
73 "NEWDIR\tCABOUTDIR\tnew\n"
74 "ProgramFilesFolder\tTARGETDIR\t.\n"
75 "TARGETDIR\t\tSourceDir";
77 static const CHAR feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
78 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
79 "Feature\tFeature\n"
80 "Five\t\tFive\tThe Five Feature\t5\t3\tNEWDIR\t0\n"
81 "Four\t\tFour\tThe Four Feature\t4\t3\tCABOUTDIR\t0\n"
82 "One\t\tOne\tThe One Feature\t1\t3\tMSITESTDIR\t0\n"
83 "Three\tOne\tThree\tThe Three Feature\t3\t3\tCHANGEDDIR\t0\n"
84 "Two\tOne\tTwo\tThe Two Feature\t2\t3\tFIRSTDIR\t0\n"
85 "feature\t\t\t\t2\t1\tTARGETDIR\t0\n"
86 "service_feature\t\t\t\t2\t1\tTARGETDIR\t0";
88 static const CHAR feature_comp_dat[] = "Feature_\tComponent_\n"
89 "s38\ts72\n"
90 "FeatureComponents\tFeature_\tComponent_\n"
91 "Five\tFive\n"
92 "Four\tFour\n"
93 "One\tOne\n"
94 "Three\tThree\n"
95 "Two\tTwo\n"
96 "feature\tcomponent\n"
97 "service_feature\tservice_comp\n";
99 static const CHAR file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
100 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
101 "File\tFile\n"
102 "five.txt\tFive\tfive.txt\t1000\t\t\t0\t5\n"
103 "four.txt\tFour\tfour.txt\t1000\t\t\t0\t4\n"
104 "one.txt\tOne\tone.txt\t1000\t\t\t0\t1\n"
105 "three.txt\tThree\tthree.txt\t1000\t\t\t0\t3\n"
106 "two.txt\tTwo\ttwo.txt\t1000\t\t\t0\t2\n"
107 "file\tcomponent\tfilename\t100\t\t\t8192\t1\n"
108 "service_file\tservice_comp\tservice.exe\t100\t\t\t8192\t1";
110 static const CHAR install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
111 "s72\tS255\tI2\n"
112 "InstallExecuteSequence\tAction\n"
113 "AllocateRegistrySpace\tNOT Installed\t1550\n"
114 "CostFinalize\t\t1000\n"
115 "CostInitialize\t\t800\n"
116 "FileCost\t\t900\n"
117 "InstallFiles\t\t4000\n"
118 "InstallServices\t\t5000\n"
119 "RegisterProduct\t\t6100\n"
120 "PublishProduct\t\t6400\n"
121 "InstallFinalize\t\t6600\n"
122 "InstallInitialize\t\t1500\n"
123 "InstallValidate\t\t1400\n"
124 "LaunchConditions\t\t100\n"
125 "WriteRegistryValues\tSourceDir And SOURCEDIR\t5000";
127 static const CHAR media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
128 "i2\ti4\tL64\tS255\tS32\tS72\n"
129 "Media\tDiskId\n"
130 "1\t5\t\t\tDISK1\t\n";
132 static const CHAR property_dat[] = "Property\tValue\n"
133 "s72\tl0\n"
134 "Property\tProperty\n"
135 "DefaultUIFont\tDlgFont8\n"
136 "HASUIRUN\t0\n"
137 "INSTALLLEVEL\t3\n"
138 "InstallMode\tTypical\n"
139 "Manufacturer\tWine\n"
140 "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n"
141 "ProductCode\t{F1C3AF50-8B56-4A69-A00C-00773FE42F30}\n"
142 "ProductID\tnone\n"
143 "ProductLanguage\t1033\n"
144 "ProductName\tMSITEST\n"
145 "ProductVersion\t1.1.1\n"
146 "PROMPTROLLBACKCOST\tP\n"
147 "Setup\tSetup\n"
148 "UpgradeCode\t{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}";
150 static const CHAR registry_dat[] = "Registry\tRoot\tKey\tName\tValue\tComponent_\n"
151 "s72\ti2\tl255\tL255\tL0\ts72\n"
152 "Registry\tRegistry\n"
153 "Apples\t2\tSOFTWARE\\Wine\\msitest\tName\timaname\tOne\n"
154 "Oranges\t2\tSOFTWARE\\Wine\\msitest\tnumber\t#314\tTwo\n"
155 "regdata\t2\tSOFTWARE\\Wine\\msitest\tblah\tbad\tdangler\n"
156 "OrderTest\t2\tSOFTWARE\\Wine\\msitest\tOrderTestName\tOrderTestValue\tcomponent";
158 static const CHAR service_install_dat[] = "ServiceInstall\tName\tDisplayName\tServiceType\tStartType\tErrorControl\t"
159 "LoadOrderGroup\tDependencies\tStartName\tPassword\tArguments\tComponent_\tDescription\n"
160 "s72\ts255\tL255\ti4\ti4\ti4\tS255\tS255\tS255\tS255\tS255\ts72\tL255\n"
161 "ServiceInstall\tServiceInstall\n"
162 "TestService\tTestService\tTestService\t2\t3\t0\t\t\tTestService\t\t\tservice_comp\t\t";
164 static const CHAR service_control_dat[] = "ServiceControl\tName\tEvent\tArguments\tWait\tComponent_\n"
165 "s72\tl255\ti2\tL255\tI2\ts72\n"
166 "ServiceControl\tServiceControl\n"
167 "ServiceControl\tTestService\t8\t\t0\tservice_comp";
169 typedef struct _msi_table
171 const CHAR *filename;
172 const CHAR *data;
173 int size;
174 } msi_table;
176 #define ADD_TABLE(x) {#x".idt", x##_dat, sizeof(x##_dat)}
178 static const msi_table tables[] =
180 ADD_TABLE(component),
181 ADD_TABLE(directory),
182 ADD_TABLE(feature),
183 ADD_TABLE(feature_comp),
184 ADD_TABLE(file),
185 ADD_TABLE(install_exec_seq),
186 ADD_TABLE(media),
187 ADD_TABLE(property),
188 ADD_TABLE(registry),
189 ADD_TABLE(service_install),
190 ADD_TABLE(service_control)
193 typedef struct _msi_summary_info
195 UINT property;
196 UINT datatype;
197 INT iValue;
198 FILETIME *pftValue;
199 const CHAR *szValue;
200 } msi_summary_info;
202 #define ADD_INFO_I2(property, iValue) {property, VT_I2, iValue, NULL, NULL}
203 #define ADD_INFO_I4(property, iValue) {property, VT_I4, iValue, NULL, NULL}
204 #define ADD_INFO_LPSTR(property, szValue) {property, VT_LPSTR, 0, NULL, szValue}
205 #define ADD_INFO_FILETIME(property, pftValue) {property, VT_FILETIME, 0, pftValue, NULL}
207 static const msi_summary_info summary_info[] =
209 ADD_INFO_LPSTR(PID_TEMPLATE, ";1033"),
210 ADD_INFO_LPSTR(PID_REVNUMBER, "{004757CA-5092-49c2-AD20-28E1CE0DF5F2}"),
211 ADD_INFO_I4(PID_PAGECOUNT, 100),
212 ADD_INFO_I4(PID_WORDCOUNT, 0),
213 ADD_INFO_FILETIME(PID_CREATE_DTM, &systemtime),
214 ADD_INFO_FILETIME(PID_LASTPRINTED, &systemtime)
218 * Database Helpers
221 static void write_file(const CHAR *filename, const char *data, int data_size)
223 DWORD size;
225 HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL,
226 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
228 WriteFile(hf, data, data_size, &size, NULL);
229 CloseHandle(hf);
232 static void write_msi_summary_info(MSIHANDLE db, const msi_summary_info *info, int num_info)
234 MSIHANDLE summary;
235 UINT r;
236 int j;
238 r = MsiGetSummaryInformationA(db, NULL, num_info, &summary);
239 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
241 /* import summary information into the stream */
242 for (j = 0; j < num_info; j++)
244 const msi_summary_info *entry = &info[j];
246 r = MsiSummaryInfoSetPropertyA(summary, entry->property, entry->datatype,
247 entry->iValue, entry->pftValue, entry->szValue);
248 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
251 /* write the summary changes back to the stream */
252 r = MsiSummaryInfoPersist(summary);
253 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
255 MsiCloseHandle(summary);
258 static void create_database(const CHAR *name, const msi_table *tables, int num_tables,
259 const msi_summary_info *info, int num_info)
261 MSIHANDLE db;
262 UINT r;
263 int j;
265 r = MsiOpenDatabaseA(name, MSIDBOPEN_CREATE, &db);
266 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
268 /* import the tables into the database */
269 for (j = 0; j < num_tables; j++)
271 const msi_table *table = &tables[j];
273 write_file(table->filename, table->data, (table->size - 1) * sizeof(char));
275 r = MsiDatabaseImportA(db, CURR_DIR, table->filename);
276 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
278 DeleteFileA(table->filename);
281 write_msi_summary_info(db, info, num_info);
283 r = MsiDatabaseCommit(db);
284 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
286 MsiCloseHandle(db);
290 * Installation helpers
293 static char PROG_FILES_DIR[MAX_PATH];
295 static BOOL get_program_files_dir(LPSTR buf)
297 HKEY hkey;
298 DWORD type = REG_EXPAND_SZ, size;
300 if (RegOpenKey(HKEY_LOCAL_MACHINE,
301 "Software\\Microsoft\\Windows\\CurrentVersion", &hkey))
302 return FALSE;
304 size = MAX_PATH;
305 if (RegQueryValueEx(hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size))
306 return FALSE;
308 RegCloseKey(hkey);
309 return TRUE;
312 static void create_file(const CHAR *name, DWORD size)
314 HANDLE file;
315 DWORD written, left;
317 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
318 ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
319 WriteFile(file, name, strlen(name), &written, NULL);
320 WriteFile(file, "\n", strlen("\n"), &written, NULL);
322 left = size - lstrlen(name) - 1;
324 SetFilePointer(file, left, NULL, FILE_CURRENT);
325 SetEndOfFile(file);
327 CloseHandle(file);
330 static void create_test_files(void)
332 CreateDirectoryA("msitest", NULL);
333 create_file("msitest\\one.txt", 100);
334 CreateDirectoryA("msitest\\first", NULL);
335 create_file("msitest\\first\\two.txt", 100);
336 CreateDirectoryA("msitest\\second", NULL);
337 create_file("msitest\\second\\three.txt", 100);
338 CreateDirectoryA("msitest\\cabout",NULL);
339 create_file("msitest\\cabout\\four.txt", 100);
340 CreateDirectoryA("msitest\\cabout\\new",NULL);
341 create_file("msitest\\cabout\\new\\five.txt", 100);
342 create_file("msitest\\filename", 100);
343 create_file("msitest\\service.exe", 100);
346 static BOOL delete_pf(const CHAR *rel_path, BOOL is_file)
348 CHAR path[MAX_PATH];
350 lstrcpyA(path, PROG_FILES_DIR);
351 lstrcatA(path, "\\");
352 lstrcatA(path, rel_path);
354 if (is_file)
355 return DeleteFileA(path);
356 else
357 return RemoveDirectoryA(path);
360 static void delete_test_files(void)
362 DeleteFileA(msifile);
363 DeleteFileA("msitest\\cabout\\new\\five.txt");
364 DeleteFileA("msitest\\cabout\\four.txt");
365 DeleteFileA("msitest\\second\\three.txt");
366 DeleteFileA("msitest\\first\\two.txt");
367 DeleteFileA("msitest\\one.txt");
368 DeleteFileA("msitest\\service.exe");
369 DeleteFileA("msitest\\filename");
370 RemoveDirectoryA("msitest\\cabout\\new");
371 RemoveDirectoryA("msitest\\cabout");
372 RemoveDirectoryA("msitest\\second");
373 RemoveDirectoryA("msitest\\first");
374 RemoveDirectoryA("msitest");
377 static void check_service_is_installed(void)
379 SC_HANDLE scm, service;
380 BOOL res;
382 scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
383 ok(scm != NULL, "Failed to open the SC Manager\n");
385 service = OpenService(scm, "TestService", SC_MANAGER_ALL_ACCESS);
386 ok(service != NULL, "Failed to open TestService\n");
388 res = DeleteService(service);
389 ok(res, "Failed to delete TestService\n");
391 CloseServiceHandle(service);
392 CloseServiceHandle(scm);
396 * Automation helpers and tests
399 /* ok-like statement which takes two unicode strings or one unicode and one ANSI string as arguments */
400 static CHAR string1[MAX_PATH], string2[MAX_PATH];
402 #define ok_w2(format, szString1, szString2) \
404 if (lstrcmpW(szString1, szString2) != 0) \
406 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
407 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
408 ok(0, format, string1, string2); \
411 #define ok_aw(format, aString, wString) \
413 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
414 if (lstrcmpA(string1, aString) != 0) \
415 ok(0, format, string1, aString); \
417 #define ok_awplus(format, extra, aString, wString) \
419 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
420 if (lstrcmpA(string1, aString) != 0) \
421 ok(0, format, extra, string1, aString); \
423 /* exception checker */
424 static WCHAR szSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
426 #define ok_exception(hr, szDescription) \
427 if (hr == DISP_E_EXCEPTION) \
429 /* Compare wtype, source, and destination */ \
430 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
432 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
433 if (excepinfo.bstrSource) \
434 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, szSource); \
436 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
437 if (excepinfo.bstrDescription) \
438 ok_w2("Exception description was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrDescription, szDescription); \
440 SysFreeString(excepinfo.bstrSource); \
441 SysFreeString(excepinfo.bstrDescription); \
442 SysFreeString(excepinfo.bstrHelpFile); \
445 static DISPID get_dispid( IDispatch *disp, const char *name )
447 LPOLESTR str;
448 UINT len;
449 DISPID id = -1;
450 HRESULT r;
452 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
453 str = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
454 if (str)
456 len = MultiByteToWideChar(CP_ACP, 0, name, -1, str, len );
457 r = IDispatch_GetIDsOfNames( disp, &IID_NULL, &str, 1, 0, &id );
458 HeapFree(GetProcessHeap(), 0, str);
459 if (r != S_OK)
460 return -1;
463 return id;
466 static void test_dispid(void)
468 ok( get_dispid( pInstaller, "CreateRecord" ) == 1, "dispid wrong\n");
469 ok( get_dispid( pInstaller, "OpenPackage" ) == 2, "dispid wrong\n");
470 todo_wine ok( get_dispid( pInstaller, "OpenProduct" ) == 3, "dispid wrong\n");
471 ok( get_dispid( pInstaller, "OpenDatabase" ) == 4, "dispid wrong\n");
472 todo_wine {
473 ok( get_dispid( pInstaller, "SummaryInformation" ) == 5, "dispid wrong\n");
474 ok( get_dispid( pInstaller, "UILevel" ) == 6, "dispid wrong\n");
475 ok( get_dispid( pInstaller, "EnableLog" ) == 7, "dispid wrong\n");
477 ok( get_dispid( pInstaller, "InstallProduct" ) == 8, "dispid wrong\n");
478 todo_wine {
479 ok( get_dispid( pInstaller, "Version" ) == 9, "dispid wrong\n");
480 ok( get_dispid( pInstaller, "LastErrorRecord" ) == 10, "dispid wrong\n");
482 ok( get_dispid( pInstaller, "RegistryValue" ) == 11, "dispid wrong\n");
483 todo_wine {
484 ok( get_dispid( pInstaller, "Environment" ) == 12, "dispid wrong\n");
485 ok( get_dispid( pInstaller, "FileAttributes" ) == 13, "dispid wrong\n");
487 ok( get_dispid( pInstaller, "FileSize" ) == 15, "dispid wrong\n");
488 ok( get_dispid( pInstaller, "FileVersion" ) == 16, "dispid wrong\n");
490 ok( get_dispid( pInstaller, "ProductState" ) == 17, "dispid wrong\n");
491 ok( get_dispid( pInstaller, "ProductInfo" ) == 18, "dispid wrong\n");
492 todo_wine {
493 ok( get_dispid( pInstaller, "ConfigureProduct" ) == 19, "dispid wrong\n");
494 ok( get_dispid( pInstaller, "ReinstallProduct" ) == 20 , "dispid wrong\n");
495 ok( get_dispid( pInstaller, "CollectUserInfo" ) == 21, "dispid wrong\n");
496 ok( get_dispid( pInstaller, "ApplyPatch" ) == 22, "dispid wrong\n");
497 ok( get_dispid( pInstaller, "FeatureParent" ) == 23, "dispid wrong\n");
498 ok( get_dispid( pInstaller, "FeatureState" ) == 24, "dispid wrong\n");
499 ok( get_dispid( pInstaller, "UseFeature" ) == 25, "dispid wrong\n");
500 ok( get_dispid( pInstaller, "FeatureUsageCount" ) == 26, "dispid wrong\n");
501 ok( get_dispid( pInstaller, "FeatureUsageDate" ) == 27, "dispid wrong\n");
502 ok( get_dispid( pInstaller, "ConfigureFeature" ) == 28, "dispid wrong\n");
503 ok( get_dispid( pInstaller, "ReinstallFeature" ) == 29, "dispid wrong\n");
504 ok( get_dispid( pInstaller, "ProvideComponent" ) == 30, "dispid wrong\n");
505 ok( get_dispid( pInstaller, "ComponentPath" ) == 31, "dispid wrong\n");
506 ok( get_dispid( pInstaller, "ProvideQualifiedComponent" ) == 32, "dispid wrong\n");
507 ok( get_dispid( pInstaller, "QualifierDescription" ) == 33, "dispid wrong\n");
508 ok( get_dispid( pInstaller, "ComponentQualifiers" ) == 34, "dispid wrong\n");
510 ok( get_dispid( pInstaller, "Products" ) == 35, "dispid wrong\n");
511 todo_wine {
512 ok( get_dispid( pInstaller, "Features" ) == 36, "dispid wrong\n");
513 ok( get_dispid( pInstaller, "Components" ) == 37, "dispid wrong\n");
514 ok( get_dispid( pInstaller, "ComponentClients" ) == 38, "dispid wrong\n");
515 ok( get_dispid( pInstaller, "Patches" ) == 39, "dispid wrong\n");
517 ok( get_dispid( pInstaller, "RelatedProducts" ) == 40, "dispid wrong\n");
518 todo_wine {
519 ok( get_dispid( pInstaller, "PatchInfo" ) == 41, "dispid wrong\n");
520 ok( get_dispid( pInstaller, "PatchTransforms" ) == 42, "dispid wrong\n");
521 ok( get_dispid( pInstaller, "AddSource" ) == 43, "dispid wrong\n");
522 ok( get_dispid( pInstaller, "ClearSourceList" ) == 44, "dispid wrong\n");
523 ok( get_dispid( pInstaller, "ForceSourceListResolution" ) == 45, "dispid wrong\n");
524 ok( get_dispid( pInstaller, "ShortcutTarget" ) == 46, "dispid wrong\n");
525 ok( get_dispid( pInstaller, "FileHash" ) == 47, "dispid wrong\n");
526 ok( get_dispid( pInstaller, "FileSignatureInfo" ) == 48, "dispid wrong\n");
527 ok( get_dispid( pInstaller, "RemovePatches" ) == 49, "dispid wrong\n");
529 ok( get_dispid( pInstaller, "ApplyMultiplePatches" ) == 51, "dispid wrong\n");
530 ok( get_dispid( pInstaller, "ProductsEx" ) == 52, "dispid wrong\n");
532 ok( get_dispid( pInstaller, "PatchesEx" ) == 55, "dispid wrong\n");
534 ok( get_dispid( pInstaller, "ExtractPatchXMLData" ) == 57, "dispid wrong\n");
537 /* MSDN claims the following functions exist but IDispatch->GetIDsOfNames disagrees */
538 if (0)
540 get_dispid( pInstaller, "ProductElevated" );
541 get_dispid( pInstaller, "ProductInfoFromScript" );
542 get_dispid( pInstaller, "ProvideAssembly" );
543 get_dispid( pInstaller, "CreateAdvertiseScript" );
544 get_dispid( pInstaller, "AdvertiseProduct" );
545 get_dispid( pInstaller, "PatchFiles" );
549 /* Test basic IDispatch functions */
550 static void test_dispatch(void)
552 static WCHAR szOpenPackage[] = { 'O','p','e','n','P','a','c','k','a','g','e',0 };
553 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};
554 static WCHAR szProductState[] = { 'P','r','o','d','u','c','t','S','t','a','t','e',0 };
555 HRESULT hr;
556 DISPID dispid;
557 OLECHAR *name;
558 VARIANT varresult;
559 VARIANTARG vararg[2];
560 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
562 /* Test getting ID of a function name that does not exist */
563 name = (WCHAR *)szMsifile;
564 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
565 ok(hr == DISP_E_UNKNOWNNAME, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
567 /* Test invoking this function */
568 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
569 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
571 /* Test getting ID of a function name that does exist */
572 name = (WCHAR *)szOpenPackage;
573 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
574 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
576 /* Test invoking this function (without parameters passed) */
577 if (0) /* All of these crash MSI on Windows XP */
579 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
580 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL);
581 VariantInit(&varresult);
582 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, &varresult, &excepinfo, NULL);
585 /* Try with NULL params */
586 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
587 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
589 /* Try one empty parameter */
590 dispparams.rgvarg = vararg;
591 dispparams.cArgs = 1;
592 VariantInit(&vararg[0]);
593 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
594 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
596 /* Try one parameter, function requires two */
597 VariantInit(&vararg[0]);
598 V_VT(&vararg[0]) = VT_BSTR;
599 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
600 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
601 VariantClear(&vararg[0]);
603 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
604 ok_exception(hr, szOpenPackageException);
606 /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
607 VariantInit(&vararg[0]);
608 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
609 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
611 VariantInit(&vararg[0]);
612 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
613 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
615 /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
616 name = (WCHAR *)szProductState;
617 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
618 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
620 dispparams.rgvarg = NULL;
621 dispparams.cArgs = 0;
622 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
623 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
625 dispparams.rgvarg = NULL;
626 dispparams.cArgs = 0;
627 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
628 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
631 /* invocation helper function */
632 static int _invoke_todo_vtResult = 0;
634 static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult)
636 OLECHAR *name = NULL;
637 DISPID dispid;
638 HRESULT hr;
639 UINT i;
640 UINT len;
642 memset(pVarResult, 0, sizeof(VARIANT));
643 VariantInit(pVarResult);
645 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 );
646 name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
647 if (!name) return E_FAIL;
648 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len );
649 hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
650 HeapFree(GetProcessHeap(), 0, name);
651 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
652 if (!hr == S_OK) return hr;
654 memset(&excepinfo, 0, sizeof(excepinfo));
655 hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL);
657 if (hr == S_OK)
659 if (_invoke_todo_vtResult) todo_wine
660 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
661 else
662 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
663 if (vtResult != VT_EMPTY)
665 hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult);
666 ok(hr == S_OK, "VariantChangeTypeEx returned 0x%08x\n", hr);
670 for (i=0; i<pDispParams->cArgs; i++)
671 VariantClear(&pDispParams->rgvarg[i]);
673 return hr;
676 /* Object_Property helper functions */
678 static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord)
680 VARIANT varresult;
681 VARIANTARG vararg[1];
682 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
683 HRESULT hr;
685 VariantInit(&vararg[0]);
686 V_VT(&vararg[0]) = VT_I4;
687 V_I4(&vararg[0]) = count;
689 hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
690 *pRecord = V_DISPATCH(&varresult);
691 return hr;
694 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
696 VARIANTARG vararg[3];
697 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
699 VariantInit(&vararg[2]);
700 V_VT(&vararg[2]) = VT_I4;
701 V_I4(&vararg[2]) = (int)hkey;
702 VariantInit(&vararg[1]);
703 V_VT(&vararg[1]) = VT_BSTR;
704 V_BSTR(&vararg[1]) = SysAllocString(szKey);
705 VariantInit(&vararg[0]);
706 VariantCopy(&vararg[0], &vValue);
707 VariantClear(&vValue);
709 return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect);
712 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
714 VARIANT varresult;
715 VARIANTARG vararg;
716 HRESULT hr;
718 VariantInit(&vararg);
719 V_VT(&vararg) = VT_EMPTY;
720 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL);
721 *pBool = V_BOOL(&varresult);
722 VariantClear(&varresult);
723 return hr;
726 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
728 VARIANT varresult;
729 VARIANTARG vararg;
730 HRESULT hr;
732 VariantInit(&vararg);
733 V_VT(&vararg) = VT_BSTR;
734 V_BSTR(&vararg) = SysAllocString(szValue);
736 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR);
737 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
738 VariantClear(&varresult);
739 return hr;
742 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
744 VARIANT varresult;
745 VARIANTARG vararg;
746 HRESULT hr;
748 VariantInit(&vararg);
749 V_VT(&vararg) = VT_I4;
750 V_I4(&vararg) = iValue;
752 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult);
753 if (vtResult == VT_BSTR) lstrcpyW(szString, V_BSTR(&varresult));
754 VariantClear(&varresult);
755 return hr;
758 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
760 VARIANT varresult;
761 VARIANTARG vararg[2];
762 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
763 HRESULT hr;
765 VariantInit(&vararg[1]);
766 V_VT(&vararg[1]) = VT_BSTR;
767 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
768 VariantInit(&vararg[0]);
769 V_VT(&vararg[0]) = VT_I4;
770 V_I4(&vararg[0]) = options;
772 hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
773 *pSession = V_DISPATCH(&varresult);
774 return hr;
777 static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase)
779 VARIANT varresult;
780 VARIANTARG vararg[2];
781 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
782 HRESULT hr;
784 VariantInit(&vararg[1]);
785 V_VT(&vararg[1]) = VT_BSTR;
786 V_BSTR(&vararg[1]) = SysAllocString(szDatabasePath);
787 VariantInit(&vararg[0]);
788 V_VT(&vararg[0]) = VT_I4;
789 V_I4(&vararg[0]) = openmode;
791 hr = invoke(pInstaller, "OpenDatabase", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
792 *pDatabase = V_DISPATCH(&varresult);
793 return hr;
796 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
798 VARIANT varresult;
799 VARIANTARG vararg[2];
800 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
802 VariantInit(&vararg[1]);
803 V_VT(&vararg[1]) = VT_BSTR;
804 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
805 VariantInit(&vararg[0]);
806 V_VT(&vararg[0]) = VT_BSTR;
807 V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues);
809 return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
812 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
814 VARIANT varresult;
815 VARIANTARG vararg[1];
816 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
817 HRESULT hr;
819 VariantInit(&vararg[0]);
820 V_VT(&vararg[0]) = VT_BSTR;
821 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
823 hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
824 *pInstallState = V_I4(&varresult);
825 VariantClear(&varresult);
826 return hr;
829 static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szString)
831 VARIANT varresult;
832 VARIANTARG vararg[2];
833 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
834 HRESULT hr;
836 VariantInit(&vararg[1]);
837 V_VT(&vararg[1]) = VT_BSTR;
838 V_BSTR(&vararg[1]) = SysAllocString(szProduct);
839 VariantInit(&vararg[0]);
840 V_VT(&vararg[0]) = VT_BSTR;
841 V_BSTR(&vararg[0]) = SysAllocString(szAttribute);
843 hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
844 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
845 VariantClear(&varresult);
846 return hr;
849 static HRESULT Installer_Products(IDispatch **pStringList)
851 VARIANT varresult;
852 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
853 HRESULT hr;
855 hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
856 *pStringList = V_DISPATCH(&varresult);
857 return hr;
860 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
862 VARIANT varresult;
863 VARIANTARG vararg[1];
864 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
865 HRESULT hr;
867 VariantInit(&vararg[0]);
868 V_VT(&vararg[0]) = VT_BSTR;
869 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
871 hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
872 *pStringList = V_DISPATCH(&varresult);
873 return hr;
876 static HRESULT Installer_VersionGet(LPWSTR szVersion)
878 VARIANT varresult;
879 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
880 HRESULT hr;
882 hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
883 if (V_BSTR(&varresult)) lstrcpyW(szVersion, V_BSTR(&varresult));
884 VariantClear(&varresult);
885 return hr;
888 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
890 VARIANT varresult;
891 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
892 HRESULT hr;
894 hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
895 *pInst = V_DISPATCH(&varresult);
896 return hr;
899 static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn)
901 VARIANT varresult;
902 VARIANTARG vararg[1];
903 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
904 HRESULT hr;
906 VariantInit(&vararg[0]);
907 V_VT(&vararg[0]) = VT_BSTR;
908 V_BSTR(&vararg[0]) = SysAllocString(szName);
910 hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
911 if (V_BSTR(&varresult)) lstrcpyW(szReturn, V_BSTR(&varresult));
912 VariantClear(&varresult);
913 return hr;
916 static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue)
918 VARIANT varresult;
919 VARIANTARG vararg[2];
920 DISPID dispid = DISPID_PROPERTYPUT;
921 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
923 VariantInit(&vararg[1]);
924 V_VT(&vararg[1]) = VT_BSTR;
925 V_BSTR(&vararg[1]) = SysAllocString(szName);
926 VariantInit(&vararg[0]);
927 V_VT(&vararg[0]) = VT_BSTR;
928 V_BSTR(&vararg[0]) = SysAllocString(szValue);
930 return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
933 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
935 VARIANT varresult;
936 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
937 HRESULT hr;
939 hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
940 *pLangId = V_I4(&varresult);
941 VariantClear(&varresult);
942 return hr;
945 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, BOOL *pMode)
947 VARIANT varresult;
948 VARIANTARG vararg[1];
949 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
950 HRESULT hr;
952 VariantInit(&vararg[0]);
953 V_VT(&vararg[0]) = VT_I4;
954 V_I4(&vararg[0]) = iFlag;
956 hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL);
957 *pMode = V_BOOL(&varresult);
958 VariantClear(&varresult);
959 return hr;
962 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, BOOL bMode)
964 VARIANT varresult;
965 VARIANTARG vararg[2];
966 DISPID dispid = DISPID_PROPERTYPUT;
967 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
969 VariantInit(&vararg[1]);
970 V_VT(&vararg[1]) = VT_I4;
971 V_I4(&vararg[1]) = iFlag;
972 VariantInit(&vararg[0]);
973 V_VT(&vararg[0]) = VT_BOOL;
974 V_BOOL(&vararg[0]) = bMode;
976 return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
979 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
981 VARIANT varresult;
982 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
983 HRESULT hr;
985 hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
986 *pDatabase = V_DISPATCH(&varresult);
987 return hr;
990 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn)
992 VARIANT varresult;
993 VARIANTARG vararg[1];
994 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
995 HRESULT hr;
997 VariantInit(&vararg[0]);
998 V_VT(&vararg[0]) = VT_BSTR;
999 V_BSTR(&vararg[0]) = SysAllocString(szAction);
1001 hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1002 *iReturn = V_I4(&varresult);
1003 VariantClear(&varresult);
1004 return hr;
1007 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
1009 VARIANT varresult;
1010 VARIANTARG vararg[1];
1011 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1012 HRESULT hr;
1014 VariantInit(&vararg[0]);
1015 V_VT(&vararg[0]) = VT_BSTR;
1016 V_BSTR(&vararg[0]) = SysAllocString(szCondition);
1018 hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1019 *iReturn = V_I4(&varresult);
1020 VariantClear(&varresult);
1021 return hr;
1024 static HRESULT Session_SetInstallLevel(IDispatch *pSession, long iInstallLevel)
1026 VARIANT varresult;
1027 VARIANTARG vararg[1];
1028 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1030 VariantInit(&vararg[0]);
1031 V_VT(&vararg[0]) = VT_I4;
1032 V_I4(&vararg[0]) = iInstallLevel;
1034 return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1037 static HRESULT Session_FeatureCurrentState(IDispatch *pSession, LPCWSTR szName, int *pState)
1039 VARIANT varresult;
1040 VARIANTARG vararg[1];
1041 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1042 HRESULT hr;
1044 VariantInit(&vararg[0]);
1045 V_VT(&vararg[0]) = VT_BSTR;
1046 V_BSTR(&vararg[0]) = SysAllocString(szName);
1048 hr = invoke(pSession, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1049 *pState = V_I4(&varresult);
1050 VariantClear(&varresult);
1051 return hr;
1054 static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState)
1056 VARIANT varresult;
1057 VARIANTARG vararg[1];
1058 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1059 HRESULT hr;
1061 VariantInit(&vararg[0]);
1062 V_VT(&vararg[0]) = VT_BSTR;
1063 V_BSTR(&vararg[0]) = SysAllocString(szName);
1065 hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1066 *pState = V_I4(&varresult);
1067 VariantClear(&varresult);
1068 return hr;
1071 static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState)
1073 VARIANT varresult;
1074 VARIANTARG vararg[2];
1075 DISPID dispid = DISPID_PROPERTYPUT;
1076 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1078 VariantInit(&vararg[1]);
1079 V_VT(&vararg[1]) = VT_BSTR;
1080 V_BSTR(&vararg[1]) = SysAllocString(szName);
1081 VariantInit(&vararg[0]);
1082 V_VT(&vararg[0]) = VT_I4;
1083 V_I4(&vararg[0]) = iState;
1085 return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1088 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
1090 VARIANT varresult;
1091 VARIANTARG vararg[1];
1092 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1093 HRESULT hr;
1095 VariantInit(&vararg[0]);
1096 V_VT(&vararg[0]) = VT_BSTR;
1097 V_BSTR(&vararg[0]) = SysAllocString(szSql);
1099 hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1100 *pView = V_DISPATCH(&varresult);
1101 return hr;
1104 static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo)
1106 VARIANT varresult;
1107 VARIANTARG vararg[1];
1108 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1109 HRESULT hr;
1111 VariantInit(&vararg[0]);
1112 V_VT(&vararg[0]) = VT_I4;
1113 V_I4(&vararg[0]) = iUpdateCount;
1115 hr = invoke(pDatabase, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1116 *pSummaryInfo = V_DISPATCH(&varresult);
1117 return hr;
1120 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
1122 VARIANT varresult;
1123 VARIANTARG vararg[1];
1124 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1126 VariantInit(&vararg[0]);
1127 V_VT(&vararg[0]) = VT_DISPATCH;
1128 V_DISPATCH(&vararg[0]) = pRecord;
1130 return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1133 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
1135 VARIANT varresult;
1136 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1137 HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1138 *ppRecord = V_DISPATCH(&varresult);
1139 return hr;
1142 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
1144 VARIANT varresult;
1145 VARIANTARG vararg[2];
1146 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1148 VariantInit(&vararg[1]);
1149 V_VT(&vararg[1]) = VT_I4;
1150 V_I4(&vararg[1]) = iMode;
1151 VariantInit(&vararg[0]);
1152 V_VT(&vararg[0]) = VT_DISPATCH;
1153 V_DISPATCH(&vararg[0]) = pRecord;
1154 if (pRecord)
1155 IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */
1157 return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1160 static HRESULT View_Close(IDispatch *pView)
1162 VARIANT varresult;
1163 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1164 return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1167 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
1169 VARIANT varresult;
1170 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1171 HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1172 *pFieldCount = V_I4(&varresult);
1173 VariantClear(&varresult);
1174 return hr;
1177 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString)
1179 VARIANT varresult;
1180 VARIANTARG vararg[1];
1181 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1182 HRESULT hr;
1184 VariantInit(&vararg[0]);
1185 V_VT(&vararg[0]) = VT_I4;
1186 V_I4(&vararg[0]) = iField;
1188 hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1189 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1190 VariantClear(&varresult);
1191 return hr;
1194 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
1196 VARIANT varresult;
1197 VARIANTARG vararg[2];
1198 DISPID dispid = DISPID_PROPERTYPUT;
1199 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1201 VariantInit(&vararg[1]);
1202 V_VT(&vararg[1]) = VT_I4;
1203 V_I4(&vararg[1]) = iField;
1204 VariantInit(&vararg[0]);
1205 V_VT(&vararg[0]) = VT_BSTR;
1206 V_BSTR(&vararg[0]) = SysAllocString(szString);
1208 return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1211 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
1213 VARIANT varresult;
1214 VARIANTARG vararg[1];
1215 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1216 HRESULT hr;
1218 VariantInit(&vararg[0]);
1219 V_VT(&vararg[0]) = VT_I4;
1220 V_I4(&vararg[0]) = iField;
1222 hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1223 *pValue = V_I4(&varresult);
1224 VariantClear(&varresult);
1225 return hr;
1228 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
1230 VARIANT varresult;
1231 VARIANTARG vararg[2];
1232 DISPID dispid = DISPID_PROPERTYPUT;
1233 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1235 VariantInit(&vararg[1]);
1236 V_VT(&vararg[1]) = VT_I4;
1237 V_I4(&vararg[1]) = iField;
1238 VariantInit(&vararg[0]);
1239 V_VT(&vararg[0]) = VT_I4;
1240 V_I4(&vararg[0]) = iValue;
1242 return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1245 static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT)
1247 VARIANT varresult;
1248 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1249 HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN);
1250 *ppEnumVARIANT = V_UNKNOWN(&varresult);
1251 return hr;
1254 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
1256 VARIANT varresult;
1257 VARIANTARG vararg[1];
1258 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1259 HRESULT hr;
1261 VariantInit(&vararg[0]);
1262 V_VT(&vararg[0]) = VT_I4;
1263 V_I4(&vararg[0]) = iIndex;
1265 hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1266 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1267 VariantClear(&varresult);
1268 return hr;
1271 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
1273 VARIANT varresult;
1274 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1275 HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1276 *pCount = V_I4(&varresult);
1277 VariantClear(&varresult);
1278 return hr;
1281 static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect)
1283 VARIANTARG vararg[1];
1284 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1286 VariantInit(&vararg[0]);
1287 V_VT(&vararg[0]) = VT_I4;
1288 V_I4(&vararg[0]) = pid;
1289 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYGET, &dispparams, pVarResult, vtExpect);
1292 static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant)
1294 VARIANT varresult;
1295 VARIANTARG vararg[2];
1296 DISPID dispid = DISPID_PROPERTYPUT;
1297 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1299 VariantInit(&vararg[1]);
1300 V_VT(&vararg[1]) = VT_I4;
1301 V_I4(&vararg[1]) = pid;
1302 VariantInit(&vararg[0]);
1303 VariantCopyInd(vararg, pVariant);
1305 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1308 static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount)
1310 VARIANT varresult;
1311 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1312 HRESULT hr;
1314 hr = invoke(pSummaryInfo, "PropertyCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1315 *pCount = V_I4(&varresult);
1316 VariantClear(&varresult);
1317 return hr;
1320 /* Test the various objects */
1322 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4
1324 static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly)
1326 static const WCHAR szPropertyException[] = { 'P','r','o','p','e','r','t','y',',','P','i','d',0 };
1327 static const WCHAR szTitle[] = { 'T','i','t','l','e',0 };
1328 VARIANT varresult, var;
1329 SYSTEMTIME st;
1330 HRESULT hr;
1331 int j;
1333 /* SummaryInfo::PropertyCount */
1334 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1335 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1336 ok(j == num_info, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1338 /* SummaryInfo::Property, get for properties we have set */
1339 for (j = 0; j < num_info; j++)
1341 const msi_summary_info *entry = &info[j];
1343 int vt = entry->datatype;
1344 if (vt == VT_LPSTR) vt = VT_BSTR;
1345 else if (vt == VT_FILETIME) vt = VT_DATE;
1346 else if (vt == VT_I2) vt = VT_I4;
1348 hr = SummaryInfo_PropertyGet(pSummaryInfo, entry->property, &varresult, vt);
1349 ok(hr == S_OK, "SummaryInfo_Property (pid %d) failed, hresult 0x%08x\n", entry->property, hr);
1350 if (V_VT(&varresult) != vt)
1351 skip("Skipping property tests due to type mismatch\n");
1352 else if (vt == VT_I4)
1353 ok(V_I4(&varresult) == entry->iValue, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %d\n",
1354 entry->property, entry->iValue, V_I4(&varresult));
1355 else if (vt == VT_DATE)
1357 FILETIME ft;
1358 DATE d;
1360 FileTimeToLocalFileTime(entry->pftValue, &ft);
1361 FileTimeToSystemTime(&ft, &st);
1362 SystemTimeToVariantTime(&st, &d);
1363 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));
1365 else if (vt == VT_BSTR)
1367 ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry->property, entry->szValue, V_BSTR(&varresult));
1369 else
1370 skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry->property, vt);
1372 VariantClear(&varresult);
1375 /* SummaryInfo::Property, get; invalid arguments */
1377 /* Invalid pids */
1378 hr = SummaryInfo_PropertyGet(pSummaryInfo, -1, &varresult, VT_EMPTY);
1379 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1380 ok_exception(hr, szPropertyException);
1382 hr = SummaryInfo_PropertyGet(pSummaryInfo, 1000, &varresult, VT_EMPTY);
1383 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1384 ok_exception(hr, szPropertyException);
1386 /* Unsupported pids */
1387 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_DICTIONARY, &varresult, VT_EMPTY);
1388 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1390 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY);
1391 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1393 /* Pids we have not set, one for each type */
1394 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_EMPTY);
1395 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1397 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY);
1398 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1400 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY);
1401 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1403 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY);
1404 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1406 if (!readonly)
1408 /* SummaryInfo::Property, put; one for each type */
1410 /* VT_I2 */
1411 VariantInit(&var);
1412 V_VT(&var) = VT_I2;
1413 V_I2(&var) = 1;
1414 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CODEPAGE, &var);
1415 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1417 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */);
1418 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1419 ok(V_I2(&var) == V_I2(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var), V_I2(&varresult));
1420 VariantClear(&varresult);
1421 VariantClear(&var);
1423 /* VT_BSTR */
1424 V_VT(&var) = VT_BSTR;
1425 V_BSTR(&var) = SysAllocString(szTitle);
1426 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_TITLE, &var);
1427 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1429 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var));
1430 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1431 ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var), V_BSTR(&varresult));
1432 VariantClear(&varresult);
1433 VariantClear(&var);
1435 /* VT_DATE */
1436 V_VT(&var) = VT_DATE;
1437 FileTimeToSystemTime(&systemtime, &st);
1438 SystemTimeToVariantTime(&st, &V_DATE(&var));
1439 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_LASTSAVE_DTM, &var);
1440 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1442 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var));
1443 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1444 /* FIXME: Off by one second */
1445 todo_wine ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1446 VariantClear(&varresult);
1447 VariantClear(&var);
1449 /* VT_I4 */
1450 V_VT(&var) = VT_I4;
1451 V_I4(&var) = 1000;
1452 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1453 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1455 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1456 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1457 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult));
1458 VariantClear(&varresult);
1459 VariantClear(&var);
1461 /* SummaryInfo::PropertyCount */
1462 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1463 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1464 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1468 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1470 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 };
1471 static WCHAR szThree[] = { 'T','h','r','e','e',0 };
1472 static WCHAR szTwo[] = { 'T','w','o',0 };
1473 static WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
1474 static WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 };
1475 IDispatch *pView = NULL, *pSummaryInfo = NULL;
1476 HRESULT hr;
1478 hr = Database_OpenView(pDatabase, szSql, &pView);
1479 ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr);
1480 if (hr == S_OK)
1482 IDispatch *pRecord = NULL;
1483 WCHAR szString[MAX_PATH];
1485 /* View::Execute */
1486 hr = View_Execute(pView, NULL);
1487 ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr);
1489 /* View::Fetch */
1490 hr = View_Fetch(pView, &pRecord);
1491 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1492 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1493 if (pRecord)
1495 /* Record::StringDataGet */
1496 memset(szString, 0, sizeof(szString));
1497 hr = Record_StringDataGet(pRecord, 1, szString);
1498 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1499 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1501 /* Record::StringDataPut with correct index */
1502 hr = Record_StringDataPut(pRecord, 1, szTwo);
1503 ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1505 /* Record::StringDataGet */
1506 memset(szString, 0, sizeof(szString));
1507 hr = Record_StringDataGet(pRecord, 1, szString);
1508 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1509 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1511 /* Record::StringDataPut with incorrect index */
1512 hr = Record_StringDataPut(pRecord, -1, szString);
1513 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1514 ok_exception(hr, szStringDataField);
1516 /* View::Modify with incorrect parameters */
1517 hr = View_Modify(pView, -5, NULL);
1518 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1519 ok_exception(hr, szModifyModeRecord);
1521 hr = View_Modify(pView, -5, pRecord);
1522 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1523 ok_exception(hr, szModifyModeRecord);
1525 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1526 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1527 ok_exception(hr, szModifyModeRecord);
1529 /* View::Modify with MSIMODIFY_REFRESH should undo our changes */
1530 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1531 /* Wine's MsiViewModify currently does not support MSIMODIFY_REFRESH */
1532 todo_wine ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr);
1534 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1535 memset(szString, 0, sizeof(szString));
1536 hr = Record_StringDataGet(pRecord, 1, szString);
1537 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1538 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1540 IDispatch_Release(pRecord);
1543 /* View::Fetch */
1544 hr = View_Fetch(pView, &pRecord);
1545 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1546 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1547 if (pRecord)
1549 /* Record::StringDataGet */
1550 memset(szString, 0, sizeof(szString));
1551 hr = Record_StringDataGet(pRecord, 1, szString);
1552 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1553 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1555 IDispatch_Release(pRecord);
1558 /* View::Fetch */
1559 hr = View_Fetch(pView, &pRecord);
1560 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1561 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1562 if (pRecord)
1563 IDispatch_Release(pRecord);
1565 /* View::Close */
1566 hr = View_Close(pView);
1567 ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr);
1569 IDispatch_Release(pView);
1572 /* Database::SummaryInformation */
1573 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo);
1574 ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr);
1575 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1576 if (pSummaryInfo)
1578 test_SummaryInfo(pSummaryInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), readonly);
1579 IDispatch_Release(pSummaryInfo);
1583 static void test_Session(IDispatch *pSession)
1585 static WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
1586 static WCHAR szOne[] = { 'O','n','e',0 };
1587 static WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 };
1588 static WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 };
1589 static WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 };
1590 static WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 };
1591 static WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1592 static WCHAR szEmpty[] = { 0 };
1593 static WCHAR szEquals[] = { '=',0 };
1594 static WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
1595 WCHAR stringw[MAX_PATH];
1596 CHAR string[MAX_PATH];
1597 UINT len;
1598 BOOL bool;
1599 int myint;
1600 IDispatch *pDatabase = NULL, *pInst = NULL;
1601 HRESULT hr;
1603 /* Session::Installer */
1604 hr = Session_Installer(pSession, &pInst);
1605 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1606 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1607 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1609 /* Session::Property, get */
1610 memset(stringw, 0, sizeof(stringw));
1611 hr = Session_PropertyGet(pSession, szProductName, stringw);
1612 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1613 if (lstrcmpW(stringw, szMSITEST) != 0)
1615 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1616 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1617 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1620 /* Session::Property, put */
1621 hr = Session_PropertyPut(pSession, szProductName, szProductName);
1622 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1623 memset(stringw, 0, sizeof(stringw));
1624 hr = Session_PropertyGet(pSession, szProductName, stringw);
1625 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1626 if (lstrcmpW(stringw, szProductName) != 0)
1628 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1629 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1630 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1633 /* Try putting a property using empty property identifier */
1634 hr = Session_PropertyPut(pSession, szEmpty, szProductName);
1635 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1636 ok_exception(hr, szPropertyName);
1638 /* Try putting a property using illegal property identifier */
1639 hr = Session_PropertyPut(pSession, szEquals, szProductName);
1640 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1642 /* Session::Language, get */
1643 hr = Session_LanguageGet(pSession, &len);
1644 ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1645 /* Not sure how to check the language is correct */
1647 /* Session::Mode, get */
1648 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1649 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1650 todo_wine ok(!bool, "Reboot at end session mode is %d\n", bool);
1652 /* Session::Mode, put */
1653 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE);
1654 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1655 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1656 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1657 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1658 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE); /* set it again so we don't reboot */
1659 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1661 /* Session::Database, get */
1662 hr = Session_Database(pSession, &pDatabase);
1663 ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr);
1664 if (hr == S_OK)
1666 test_Database(pDatabase, TRUE);
1667 IDispatch_Release(pDatabase);
1670 /* Session::EvaluateCondition */
1671 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1672 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1673 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1675 hr = Session_EvaluateCondition(pSession, szEmpty, &myint);
1676 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1677 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1679 hr = Session_EvaluateCondition(pSession, szEquals, &myint);
1680 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1681 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1683 /* Session::DoAction(CostInitialize) must occur before the next statements */
1684 hr = Session_DoAction(pSession, szCostInitialize, &myint);
1685 ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr);
1686 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1688 /* Session::SetInstallLevel */
1689 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1690 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
1692 /* Session::FeatureCurrentState, get */
1693 hr = Session_FeatureCurrentState(pSession, szOne, &myint);
1694 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
1695 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1697 /* Session::EvaluateCondition */
1698 hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint);
1699 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1700 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1702 hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint);
1703 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1704 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1706 /* Session::FeatureRequestState, put */
1707 hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED);
1708 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
1709 hr = Session_FeatureRequestStateGet(pSession, szOne, &myint);
1710 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
1711 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
1713 /* Session::EvaluateCondition */
1714 hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint);
1715 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1716 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1718 hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint);
1719 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1720 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1723 /* delete key and all its subkeys */
1724 static DWORD delete_key( HKEY hkey )
1726 char name[MAX_PATH];
1727 DWORD ret;
1729 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
1731 HKEY tmp;
1732 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
1734 ret = delete_key( tmp );
1735 RegCloseKey( tmp );
1737 if (ret) break;
1739 if (ret != ERROR_NO_MORE_ITEMS) return ret;
1740 RegDeleteKeyA( hkey, "" );
1741 return 0;
1744 static void test_Installer_RegistryValue(void)
1746 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
1747 static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 };
1748 static const WCHAR szOne[] = { 'O','n','e',0 };
1749 static const WCHAR szTwo[] = { 'T','w','o',0 };
1750 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
1751 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1752 static const WCHAR szFour[] = { 'F','o','u','r',0 };
1753 static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 };
1754 static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 };
1755 static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 };
1756 static const WCHAR szSix[] = { 'S','i','x',0 };
1757 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1758 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
1759 static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
1760 static const WCHAR szBlank[] = { 0 };
1761 VARIANT varresult;
1762 VARIANTARG vararg;
1763 WCHAR szString[MAX_PATH];
1764 HKEY hkey, hkey_sub;
1765 HRESULT hr;
1766 BOOL bRet;
1768 /* Delete keys */
1769 if (!RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey )) delete_key( hkey );
1771 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
1772 hr = Installer_RegistryValueE(HKEY_CURRENT_USER, szKey, &bRet);
1773 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1774 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
1776 memset(szString, 0, sizeof(szString));
1777 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, NULL, szString);
1778 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1780 memset(szString, 0, sizeof(szString));
1781 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 0, szString, VT_BSTR);
1782 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1784 /* Create key */
1785 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
1787 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1788 "RegSetValueExW failed\n");
1789 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
1790 "RegSetValueExW failed\n");
1791 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
1792 "RegSetValueExW failed\n");
1793 ok(SetEnvironmentVariableA("MSITEST", "Four"), "SetEnvironmentVariableA failed %d\n", GetLastError());
1794 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
1795 "RegSetValueExW failed\n");
1796 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
1797 "RegSetValueExW failed\n");
1798 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
1799 "RegSetValueExW failed\n");
1800 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, (const BYTE *)NULL, 0),
1801 "RegSetValueExW failed\n");
1803 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1804 "RegSetValueExW failed\n");
1806 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
1808 /* Does our key exist? It should, and make sure we retrieve the correct default value */
1809 bRet = FALSE;
1810 hr = Installer_RegistryValueE(HKEY_CURRENT_USER, szKey, &bRet);
1811 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1812 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
1814 memset(szString, 0, sizeof(szString));
1815 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, NULL, szString);
1816 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1817 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1819 /* Ask for the value of a nonexistent key */
1820 memset(szString, 0, sizeof(szString));
1821 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szExpand, szString);
1822 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1824 /* Get values of keys */
1825 memset(szString, 0, sizeof(szString));
1826 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szOne, szString);
1827 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1828 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1830 VariantInit(&vararg);
1831 V_VT(&vararg) = VT_BSTR;
1832 V_BSTR(&vararg) = SysAllocString(szTwo);
1833 hr = Installer_RegistryValue(HKEY_CURRENT_USER, szKey, vararg, &varresult, VT_I4);
1834 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1835 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
1836 VariantClear(&varresult);
1838 memset(szString, 0, sizeof(szString));
1839 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szThree, szString);
1840 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1841 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
1843 memset(szString, 0, sizeof(szString));
1844 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szFour, szString);
1845 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1846 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
1848 memset(szString, 0, sizeof(szString));
1849 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szFive, szString);
1850 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1851 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFiveHi);
1853 memset(szString, 0, sizeof(szString));
1854 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szSix, szString);
1855 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1856 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_);
1858 VariantInit(&vararg);
1859 V_VT(&vararg) = VT_BSTR;
1860 V_BSTR(&vararg) = SysAllocString(szSeven);
1861 hr = Installer_RegistryValue(HKEY_CURRENT_USER, szKey, vararg, &varresult, VT_EMPTY);
1862 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1864 /* Get string class name for the key */
1865 memset(szString, 0, sizeof(szString));
1866 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 0, szString, VT_BSTR);
1867 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1868 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank);
1870 /* Get name of a value by positive number (RegEnumValue like), valid index */
1871 memset(szString, 0, sizeof(szString));
1872 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 2, szString, VT_BSTR);
1873 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1874 /* RegEnumValue order seems different on wine */
1875 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
1877 /* Get name of a value by positive number (RegEnumValue like), invalid index */
1878 memset(szString, 0, sizeof(szString));
1879 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 10, szString, VT_EMPTY);
1880 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1882 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
1883 memset(szString, 0, sizeof(szString));
1884 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, -1, szString, VT_BSTR);
1885 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1886 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
1888 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
1889 memset(szString, 0, sizeof(szString));
1890 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, -10, szString, VT_EMPTY);
1891 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1893 /* clean up */
1894 delete_key(hkey);
1897 static void test_Installer_Products(BOOL bProductInstalled)
1899 WCHAR szString[MAX_PATH];
1900 HRESULT hr;
1901 int idx;
1902 IUnknown *pUnk = NULL;
1903 IEnumVARIANT *pEnum = NULL;
1904 VARIANT var;
1905 ULONG celt;
1906 int iCount, iValue;
1907 IDispatch *pStringList = NULL;
1908 BOOL bProductFound = FALSE;
1910 /* Installer::Products */
1911 hr = Installer_Products(&pStringList);
1912 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
1913 if (hr == S_OK)
1915 /* StringList::_NewEnum */
1916 hr = StringList__NewEnum(pStringList, &pUnk);
1917 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
1918 if (hr == S_OK)
1920 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
1921 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
1923 if (!pEnum)
1924 skip("IEnumVARIANT tests\n");
1926 /* StringList::Count */
1927 hr = StringList_Count(pStringList, &iCount);
1928 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
1930 for (idx=0; idx<iCount; idx++)
1932 /* StringList::Item */
1933 memset(szString, 0, sizeof(szString));
1934 hr = StringList_Item(pStringList, idx, szString);
1935 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
1937 if (hr == S_OK)
1939 /* Installer::ProductState */
1940 hr = Installer_ProductState(szString, &iValue);
1941 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
1942 if (hr == S_OK)
1943 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
1945 /* Not found our product code yet? Check */
1946 if (!bProductFound && !lstrcmpW(szString, szProductCode))
1947 bProductFound = TRUE;
1949 /* IEnumVARIANT::Next */
1950 if (pEnum)
1952 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
1953 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
1954 ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
1955 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
1956 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
1957 VariantClear(&var);
1962 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
1963 bProductInstalled ? "be" : "not be",
1964 bProductFound ? "found" : "not found");
1966 if (pEnum)
1968 IEnumVARIANT *pEnum2 = NULL;
1970 if (0) /* Crashes on Windows XP */
1972 /* IEnumVARIANT::Clone, NULL pointer */
1973 hr = IEnumVARIANT_Clone(pEnum, NULL);
1976 /* IEnumVARIANT::Clone */
1977 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
1978 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
1979 if (hr == S_OK)
1981 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
1983 /* IEnumVARIANT::Next of the clone */
1984 if (iCount)
1986 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
1987 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
1988 ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
1989 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
1990 VariantClear(&var);
1992 else
1993 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
1995 IEnumVARIANT_Release(pEnum2);
1998 /* IEnumVARIANT::Skip should fail */
1999 hr = IEnumVARIANT_Skip(pEnum, 1);
2000 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2002 /* IEnumVARIANT::Next, NULL variant pointer */
2003 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2004 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2005 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2007 /* IEnumVARIANT::Next, should not return any more items */
2008 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2009 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2010 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2011 VariantClear(&var);
2013 /* IEnumVARIANT::Reset */
2014 hr = IEnumVARIANT_Reset(pEnum);
2015 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2017 if (iCount)
2019 /* IEnumVARIANT::Skip to the last product */
2020 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2021 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2023 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2024 * NULL celt pointer. */
2025 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2026 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2027 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2028 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2029 VariantClear(&var);
2031 else
2032 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2035 /* StringList::Item using an invalid index */
2036 memset(szString, 0, sizeof(szString));
2037 hr = StringList_Item(pStringList, iCount, szString);
2038 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2040 if (pEnum) IEnumVARIANT_Release(pEnum);
2041 if (pUnk) IUnknown_Release(pUnk);
2042 IDispatch_Release(pStringList);
2046 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2047 * deleting the subkeys first) */
2048 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey)
2050 UINT ret;
2051 CHAR *string = NULL;
2052 HKEY hkey;
2053 DWORD dwSize;
2055 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2056 if (ret != ERROR_SUCCESS) return ret;
2057 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2058 if (ret != ERROR_SUCCESS) return ret;
2059 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2061 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2062 delete_registry_key(hkey, string);
2064 RegCloseKey(hkey);
2065 HeapFree(GetProcessHeap(), 0, string);
2066 RegDeleteKeyA(hkeyParent, subkey);
2067 return ERROR_SUCCESS;
2070 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2071 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, HKEY *phkey)
2073 UINT ret;
2074 CHAR *string = NULL;
2075 int idx = 0;
2076 HKEY hkey;
2077 DWORD dwSize;
2078 BOOL found = FALSE;
2080 *phkey = 0;
2082 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2083 if (ret != ERROR_SUCCESS) return ret;
2084 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2085 if (ret != ERROR_SUCCESS) return ret;
2086 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2088 while (!found &&
2089 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2091 if (!strcmp(string, findkey))
2093 *phkey = hkey;
2094 found = TRUE;
2096 else if (find_registry_key(hkey, string, findkey, phkey) == ERROR_SUCCESS) found = TRUE;
2099 if (*phkey != hkey) RegCloseKey(hkey);
2100 HeapFree(GetProcessHeap(), 0, string);
2101 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2104 static void test_Installer_InstallProduct(void)
2106 HRESULT hr;
2107 CHAR path[MAX_PATH];
2108 WCHAR szString[MAX_PATH];
2109 LONG res;
2110 HKEY hkey;
2111 DWORD num, size, type;
2112 int iValue, iCount;
2113 IDispatch *pStringList = NULL;
2115 create_test_files();
2117 /* Installer::InstallProduct */
2118 hr = Installer_InstallProduct(szMsifile, NULL);
2119 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2121 /* Installer::ProductState for our product code, which has been installed */
2122 hr = Installer_ProductState(szProductCode, &iValue);
2123 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2124 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2126 /* Installer::ProductInfo for our product code */
2128 /* NULL attribute */
2129 memset(szString, 0, sizeof(szString));
2130 hr = Installer_ProductInfo(szProductCode, NULL, szString);
2131 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2132 ok_exception(hr, szProductInfoException);
2134 /* Nonexistent attribute */
2135 memset(szString, 0, sizeof(szString));
2136 hr = Installer_ProductInfo(szProductCode, szMsifile, szString);
2137 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2138 ok_exception(hr, szProductInfoException);
2140 /* Package name */
2141 memset(szString, 0, sizeof(szString));
2142 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szString);
2143 todo_wine ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2144 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile);
2146 /* Product name */
2147 memset(szString, 0, sizeof(szString));
2148 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PRODUCTNAMEW, szString);
2149 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2150 ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST);
2152 /* Installer::Products */
2153 test_Installer_Products(TRUE);
2155 /* Installer::RelatedProducts for our upgrade code */
2156 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2157 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2158 if (hr == S_OK)
2160 /* StringList::Count */
2161 hr = StringList_Count(pStringList, &iCount);
2162 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2163 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2165 /* StringList::Item */
2166 memset(szString, 0, sizeof(szString));
2167 hr = StringList_Item(pStringList, 0, szString);
2168 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2169 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
2171 IDispatch_Release(pStringList);
2174 /* Check & clean up installed files & registry keys */
2175 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2176 ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
2177 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2178 ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
2179 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2180 ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
2181 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2182 ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
2183 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2184 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2185 ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
2186 ok(delete_pf("msitest", FALSE), "File not installed\n");
2188 res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
2189 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2191 size = MAX_PATH;
2192 type = REG_SZ;
2193 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2194 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2195 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2197 size = MAX_PATH;
2198 type = REG_SZ;
2199 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2200 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2202 size = sizeof(num);
2203 type = REG_DWORD;
2204 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2205 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2206 ok(num == 314, "Expected 314, got %d\n", num);
2208 size = MAX_PATH;
2209 type = REG_SZ;
2210 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2211 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2212 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2214 RegCloseKey(hkey);
2216 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest");
2217 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2219 check_service_is_installed();
2221 /* Remove registry keys written by RegisterProduct standard action */
2222 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F1C3AF50-8B56-4A69-A00C-00773FE42F30}");
2223 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2225 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2226 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2228 res = find_registry_key(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "05FA3C1F65B896A40AC00077F34EF203", &hkey);
2229 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2230 if (res == ERROR_SUCCESS)
2232 res = delete_registry_key(hkey, "05FA3C1F65B896A40AC00077F34EF203");
2233 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2234 RegCloseKey(hkey);
2237 /* Remove registry keys written by PublishProduct standard action */
2238 res = RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2239 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2241 res = delete_registry_key(hkey, "Products\\05FA3C1F65B896A40AC00077F34EF203");
2242 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2244 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2245 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2247 RegCloseKey(hkey);
2249 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203");
2250 todo_wine ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_SUCCESS, got %d\n", res);
2252 /* Delete installation files we installed */
2253 delete_test_files();
2256 static void test_Installer(void)
2258 static WCHAR szBackslash[] = { '\\',0 };
2259 static WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
2260 static WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
2261 WCHAR szPath[MAX_PATH];
2262 HRESULT hr;
2263 UINT len;
2264 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL;
2265 int iValue, iCount;
2267 if (!pInstaller) return;
2269 /* Installer::CreateRecord */
2271 /* Test for error */
2272 hr = Installer_CreateRecord(-1, &pRecord);
2273 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2274 ok_exception(hr, szCreateRecordException);
2276 /* Test for success */
2277 hr = Installer_CreateRecord(1, &pRecord);
2278 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2279 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2280 if (pRecord)
2282 /* Record::FieldCountGet */
2283 hr = Record_FieldCountGet(pRecord, &iValue);
2284 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2285 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2287 /* Record::IntegerDataGet */
2288 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2289 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2290 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2292 /* Record::IntegerDataGet, bad index */
2293 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2294 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2295 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2297 /* Record::IntegerDataPut */
2298 hr = Record_IntegerDataPut(pRecord, 1, 100);
2299 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2301 /* Record::IntegerDataPut, bad index */
2302 hr = Record_IntegerDataPut(pRecord, 10, 100);
2303 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2304 ok_exception(hr, szIntegerDataException);
2306 /* Record::IntegerDataGet */
2307 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2308 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2309 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2311 IDispatch_Release(pRecord);
2314 /* Prepare package */
2315 create_database(msifile, tables, sizeof(tables) / sizeof(msi_table),
2316 summary_info, sizeof(summary_info) / sizeof(msi_summary_info));
2318 len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, CURR_DIR, -1, szPath, MAX_PATH);
2319 ok(len, "MultiByteToWideChar returned error %d\n", GetLastError());
2320 if (!len) return;
2322 lstrcatW(szPath, szBackslash);
2323 lstrcatW(szPath, szMsifile);
2325 /* Installer::OpenPackage */
2326 hr = Installer_OpenPackage(szPath, 0, &pSession);
2327 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2328 if (hr == S_OK)
2330 test_Session(pSession);
2331 IDispatch_Release(pSession);
2334 /* Installer::OpenDatabase */
2335 hr = Installer_OpenDatabase(szPath, (int)MSIDBOPEN_TRANSACT, &pDatabase);
2336 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2337 if (hr == S_OK)
2339 test_Database(pDatabase, FALSE);
2340 IDispatch_Release(pDatabase);
2343 /* Installer::RegistryValue */
2344 test_Installer_RegistryValue();
2346 /* Installer::ProductState for our product code, which should not be installed */
2347 hr = Installer_ProductState(szProductCode, &iValue);
2348 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2349 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2351 /* Installer::ProductInfo for our product code, which should not be installed */
2353 /* Package name */
2354 memset(szPath, 0, sizeof(szPath));
2355 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szPath);
2356 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2357 ok_exception(hr, szProductInfoException);
2359 /* NULL attribute and NULL product code */
2360 memset(szPath, 0, sizeof(szPath));
2361 hr = Installer_ProductInfo(NULL, NULL, szPath);
2362 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2363 ok_exception(hr, szProductInfoException);
2365 /* Installer::Products */
2366 test_Installer_Products(FALSE);
2368 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2369 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2370 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2371 if (hr == S_OK)
2373 /* StringList::Count */
2374 hr = StringList_Count(pStringList, &iCount);
2375 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2376 ok(!iCount, "Expected no related products but found %d\n", iCount);
2378 IDispatch_Release(pStringList);
2381 /* Installer::Version */
2382 todo_wine {
2383 memset(szPath, 0, sizeof(szPath));
2384 hr = Installer_VersionGet(szPath);
2385 ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr);
2388 /* Installer::InstallProduct and other tests that depend on our product being installed */
2389 test_Installer_InstallProduct();
2392 START_TEST(automation)
2394 DWORD len;
2395 char temp_path[MAX_PATH], prev_path[MAX_PATH];
2396 HRESULT hr;
2397 CLSID clsid;
2398 IUnknown *pUnk;
2400 GetSystemTimeAsFileTime(&systemtime);
2402 GetCurrentDirectoryA(MAX_PATH, prev_path);
2403 GetTempPath(MAX_PATH, temp_path);
2404 SetCurrentDirectoryA(temp_path);
2406 lstrcpyA(CURR_DIR, temp_path);
2407 len = lstrlenA(CURR_DIR);
2409 if(len && (CURR_DIR[len - 1] == '\\'))
2410 CURR_DIR[len - 1] = 0;
2412 get_program_files_dir(PROG_FILES_DIR);
2414 hr = OleInitialize(NULL);
2415 ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr);
2416 hr = CLSIDFromProgID(szProgId, &clsid);
2417 ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr);
2418 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2419 ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr);
2421 if (pUnk)
2423 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2424 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2426 test_dispid();
2427 test_dispatch();
2428 test_Installer();
2430 IDispatch_Release(pInstaller);
2431 IUnknown_Release(pUnk);
2434 OleUninitialize();
2436 SetCurrentDirectoryA(prev_path);