Release 0.9.39.
[wine/gsoc-2012-control.git] / dlls / msi / tests / automation.c
blob7308671c16c35b7906629ecc9fe0439debe480cd
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 FILETIME systemtime;
41 static CHAR CURR_DIR[MAX_PATH];
42 static EXCEPINFO excepinfo;
45 * OLE automation data
46 **/
47 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 };
48 static IDispatch *pInstaller;
50 /* msi database data */
52 static const CHAR component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
53 "s72\tS38\ts72\ti2\tS255\tS72\n"
54 "Component\tComponent\n"
55 "Five\t{8CC92E9D-14B2-4CA4-B2AA-B11D02078087}\tNEWDIR\t2\t\tfive.txt\n"
56 "Four\t{FD37B4EA-7209-45C0-8917-535F35A2F080}\tCABOUTDIR\t2\t\tfour.txt\n"
57 "One\t{783B242E-E185-4A56-AF86-C09815EC053C}\tMSITESTDIR\t2\t\tone.txt\n"
58 "Three\t{010B6ADD-B27D-4EDD-9B3D-34C4F7D61684}\tCHANGEDDIR\t2\t\tthree.txt\n"
59 "Two\t{BF03D1A6-20DA-4A65-82F3-6CAC995915CE}\tFIRSTDIR\t2\t\ttwo.txt\n"
60 "dangler\t{6091DF25-EF96-45F1-B8E9-A9B1420C7A3C}\tTARGETDIR\t4\t\tregdata\n"
61 "component\t\tMSITESTDIR\t0\t1\tfile\n"
62 "service_comp\t\tMSITESTDIR\t0\t1\tservice_file";
64 static const CHAR directory_dat[] = "Directory\tDirectory_Parent\tDefaultDir\n"
65 "s72\tS72\tl255\n"
66 "Directory\tDirectory\n"
67 "CABOUTDIR\tMSITESTDIR\tcabout\n"
68 "CHANGEDDIR\tMSITESTDIR\tchanged:second\n"
69 "FIRSTDIR\tMSITESTDIR\tfirst\n"
70 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
71 "NEWDIR\tCABOUTDIR\tnew\n"
72 "ProgramFilesFolder\tTARGETDIR\t.\n"
73 "TARGETDIR\t\tSourceDir";
75 static const CHAR feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
76 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
77 "Feature\tFeature\n"
78 "Five\t\tFive\tThe Five Feature\t5\t3\tNEWDIR\t0\n"
79 "Four\t\tFour\tThe Four Feature\t4\t3\tCABOUTDIR\t0\n"
80 "One\t\tOne\tThe One Feature\t1\t3\tMSITESTDIR\t0\n"
81 "Three\tOne\tThree\tThe Three Feature\t3\t3\tCHANGEDDIR\t0\n"
82 "Two\tOne\tTwo\tThe Two Feature\t2\t3\tFIRSTDIR\t0\n"
83 "feature\t\t\t\t2\t1\tTARGETDIR\t0\n"
84 "service_feature\t\t\t\t2\t1\tTARGETDIR\t0";
86 static const CHAR feature_comp_dat[] = "Feature_\tComponent_\n"
87 "s38\ts72\n"
88 "FeatureComponents\tFeature_\tComponent_\n"
89 "Five\tFive\n"
90 "Four\tFour\n"
91 "One\tOne\n"
92 "Three\tThree\n"
93 "Two\tTwo\n"
94 "feature\tcomponent\n"
95 "service_feature\tservice_comp\n";
97 static const CHAR file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
98 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
99 "File\tFile\n"
100 "five.txt\tFive\tfive.txt\t1000\t\t\t0\t5\n"
101 "four.txt\tFour\tfour.txt\t1000\t\t\t0\t4\n"
102 "one.txt\tOne\tone.txt\t1000\t\t\t0\t1\n"
103 "three.txt\tThree\tthree.txt\t1000\t\t\t0\t3\n"
104 "two.txt\tTwo\ttwo.txt\t1000\t\t\t0\t2\n"
105 "file\tcomponent\tfilename\t100\t\t\t8192\t1\n"
106 "service_file\tservice_comp\tservice.exe\t100\t\t\t8192\t1";
108 static const CHAR install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
109 "s72\tS255\tI2\n"
110 "InstallExecuteSequence\tAction\n"
111 "AllocateRegistrySpace\tNOT Installed\t1550\n"
112 "CostFinalize\t\t1000\n"
113 "CostInitialize\t\t800\n"
114 "FileCost\t\t900\n"
115 "InstallFiles\t\t4000\n"
116 "InstallServices\t\t5000\n"
117 "RegisterProduct\t\t6100\n"
118 "PublishProduct\t\t6400\n"
119 "InstallFinalize\t\t6600\n"
120 "InstallInitialize\t\t1500\n"
121 "InstallValidate\t\t1400\n"
122 "LaunchConditions\t\t100\n"
123 "WriteRegistryValues\tSourceDir And SOURCEDIR\t5000";
125 static const CHAR media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
126 "i2\ti4\tL64\tS255\tS32\tS72\n"
127 "Media\tDiskId\n"
128 "1\t5\t\t\tDISK1\t\n";
130 static const CHAR property_dat[] = "Property\tValue\n"
131 "s72\tl0\n"
132 "Property\tProperty\n"
133 "DefaultUIFont\tDlgFont8\n"
134 "HASUIRUN\t0\n"
135 "INSTALLLEVEL\t3\n"
136 "InstallMode\tTypical\n"
137 "Manufacturer\tWine\n"
138 "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n"
139 "ProductCode\t{F1C3AF50-8B56-4A69-A00C-00773FE42F30}\n"
140 "ProductID\tnone\n"
141 "ProductLanguage\t1033\n"
142 "ProductName\tMSITEST\n"
143 "ProductVersion\t1.1.1\n"
144 "PROMPTROLLBACKCOST\tP\n"
145 "Setup\tSetup\n"
146 "UpgradeCode\t{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}";
148 static const CHAR registry_dat[] = "Registry\tRoot\tKey\tName\tValue\tComponent_\n"
149 "s72\ti2\tl255\tL255\tL0\ts72\n"
150 "Registry\tRegistry\n"
151 "Apples\t2\tSOFTWARE\\Wine\\msitest\tName\timaname\tOne\n"
152 "Oranges\t2\tSOFTWARE\\Wine\\msitest\tnumber\t#314\tTwo\n"
153 "regdata\t2\tSOFTWARE\\Wine\\msitest\tblah\tbad\tdangler\n"
154 "OrderTest\t2\tSOFTWARE\\Wine\\msitest\tOrderTestName\tOrderTestValue\tcomponent";
156 static const CHAR service_install_dat[] = "ServiceInstall\tName\tDisplayName\tServiceType\tStartType\tErrorControl\t"
157 "LoadOrderGroup\tDependencies\tStartName\tPassword\tArguments\tComponent_\tDescription\n"
158 "s72\ts255\tL255\ti4\ti4\ti4\tS255\tS255\tS255\tS255\tS255\ts72\tL255\n"
159 "ServiceInstall\tServiceInstall\n"
160 "TestService\tTestService\tTestService\t2\t3\t0\t\t\tTestService\t\t\tservice_comp\t\t";
162 static const CHAR service_control_dat[] = "ServiceControl\tName\tEvent\tArguments\tWait\tComponent_\n"
163 "s72\tl255\ti2\tL255\tI2\ts72\n"
164 "ServiceControl\tServiceControl\n"
165 "ServiceControl\tTestService\t8\t\t0\tservice_comp";
167 typedef struct _msi_table
169 const CHAR *filename;
170 const CHAR *data;
171 int size;
172 } msi_table;
174 #define ADD_TABLE(x) {#x".idt", x##_dat, sizeof(x##_dat)}
176 static const msi_table tables[] =
178 ADD_TABLE(component),
179 ADD_TABLE(directory),
180 ADD_TABLE(feature),
181 ADD_TABLE(feature_comp),
182 ADD_TABLE(file),
183 ADD_TABLE(install_exec_seq),
184 ADD_TABLE(media),
185 ADD_TABLE(property),
186 ADD_TABLE(registry),
187 ADD_TABLE(service_install),
188 ADD_TABLE(service_control)
191 typedef struct _msi_summary_info
193 UINT property;
194 UINT datatype;
195 INT iValue;
196 FILETIME *pftValue;
197 const CHAR *szValue;
198 } msi_summary_info;
200 #define ADD_INFO_I2(property, iValue) {property, VT_I2, iValue, NULL, NULL}
201 #define ADD_INFO_I4(property, iValue) {property, VT_I4, iValue, NULL, NULL}
202 #define ADD_INFO_LPSTR(property, szValue) {property, VT_LPSTR, 0, NULL, szValue}
203 #define ADD_INFO_FILETIME(property, pftValue) {property, VT_FILETIME, 0, pftValue, NULL}
205 static const msi_summary_info summary_info[] =
207 ADD_INFO_LPSTR(PID_TEMPLATE, ";1033"),
208 ADD_INFO_LPSTR(PID_REVNUMBER, "{004757CA-5092-49c2-AD20-28E1CE0DF5F2}"),
209 ADD_INFO_I4(PID_PAGECOUNT, 100),
210 ADD_INFO_I4(PID_WORDCOUNT, 0),
211 ADD_INFO_FILETIME(PID_CREATE_DTM, &systemtime),
212 ADD_INFO_FILETIME(PID_LASTPRINTED, &systemtime)
216 * Database Helpers
219 static void write_file(const CHAR *filename, const char *data, int data_size)
221 DWORD size;
223 HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL,
224 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
226 WriteFile(hf, data, data_size, &size, NULL);
227 CloseHandle(hf);
230 static void write_msi_summary_info(MSIHANDLE db, const msi_summary_info *info, int num_info)
232 MSIHANDLE summary;
233 UINT r;
234 int j;
236 r = MsiGetSummaryInformationA(db, NULL, num_info, &summary);
237 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
239 /* import summary information into the stream */
240 for (j = 0; j < num_info; j++)
242 const msi_summary_info *entry = &info[j];
244 r = MsiSummaryInfoSetPropertyA(summary, entry->property, entry->datatype,
245 entry->iValue, entry->pftValue, entry->szValue);
246 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
249 /* write the summary changes back to the stream */
250 r = MsiSummaryInfoPersist(summary);
251 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
253 MsiCloseHandle(summary);
256 static void create_database(const CHAR *name, const msi_table *tables, int num_tables,
257 const msi_summary_info *info, int num_info)
259 MSIHANDLE db;
260 UINT r;
261 int j;
263 r = MsiOpenDatabaseA(name, MSIDBOPEN_CREATE, &db);
264 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
266 /* import the tables into the database */
267 for (j = 0; j < num_tables; j++)
269 const msi_table *table = &tables[j];
271 write_file(table->filename, table->data, (table->size - 1) * sizeof(char));
273 r = MsiDatabaseImportA(db, CURR_DIR, table->filename);
274 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
276 DeleteFileA(table->filename);
279 write_msi_summary_info(db, info, num_info);
281 r = MsiDatabaseCommit(db);
282 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
284 MsiCloseHandle(db);
288 * Installation helpers
291 static char PROG_FILES_DIR[MAX_PATH];
293 static BOOL get_program_files_dir(LPSTR buf)
295 HKEY hkey;
296 DWORD type = REG_EXPAND_SZ, size;
298 if (RegOpenKey(HKEY_LOCAL_MACHINE,
299 "Software\\Microsoft\\Windows\\CurrentVersion", &hkey))
300 return FALSE;
302 size = MAX_PATH;
303 if (RegQueryValueEx(hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size))
304 return FALSE;
306 RegCloseKey(hkey);
307 return TRUE;
310 static void create_file(const CHAR *name, DWORD size)
312 HANDLE file;
313 DWORD written, left;
315 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
316 ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
317 WriteFile(file, name, strlen(name), &written, NULL);
318 WriteFile(file, "\n", strlen("\n"), &written, NULL);
320 left = size - lstrlen(name) - 1;
322 SetFilePointer(file, left, NULL, FILE_CURRENT);
323 SetEndOfFile(file);
325 CloseHandle(file);
328 static void create_test_files(void)
330 CreateDirectoryA("msitest", NULL);
331 create_file("msitest\\one.txt", 100);
332 CreateDirectoryA("msitest\\first", NULL);
333 create_file("msitest\\first\\two.txt", 100);
334 CreateDirectoryA("msitest\\second", NULL);
335 create_file("msitest\\second\\three.txt", 100);
336 CreateDirectoryA("msitest\\cabout",NULL);
337 create_file("msitest\\cabout\\four.txt", 100);
338 CreateDirectoryA("msitest\\cabout\\new",NULL);
339 create_file("msitest\\cabout\\new\\five.txt", 100);
340 create_file("msitest\\filename", 100);
341 create_file("msitest\\service.exe", 100);
344 static BOOL delete_pf(const CHAR *rel_path, BOOL is_file)
346 CHAR path[MAX_PATH];
348 lstrcpyA(path, PROG_FILES_DIR);
349 lstrcatA(path, "\\");
350 lstrcatA(path, rel_path);
352 if (is_file)
353 return DeleteFileA(path);
354 else
355 return RemoveDirectoryA(path);
358 static void delete_test_files(void)
360 DeleteFileA(msifile);
361 DeleteFileA("msitest\\cabout\\new\\five.txt");
362 DeleteFileA("msitest\\cabout\\four.txt");
363 DeleteFileA("msitest\\second\\three.txt");
364 DeleteFileA("msitest\\first\\two.txt");
365 DeleteFileA("msitest\\one.txt");
366 DeleteFileA("msitest\\service.exe");
367 DeleteFileA("msitest\\filename");
368 RemoveDirectoryA("msitest\\cabout\\new");
369 RemoveDirectoryA("msitest\\cabout");
370 RemoveDirectoryA("msitest\\second");
371 RemoveDirectoryA("msitest\\first");
372 RemoveDirectoryA("msitest");
375 static void check_service_is_installed(void)
377 SC_HANDLE scm, service;
378 BOOL res;
380 scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
381 ok(scm != NULL, "Failed to open the SC Manager\n");
383 service = OpenService(scm, "TestService", SC_MANAGER_ALL_ACCESS);
384 ok(service != NULL, "Failed to open TestService\n");
386 res = DeleteService(service);
387 ok(res, "Failed to delete TestService\n");
391 * Automation helpers and tests
394 /* ok-like statement which takes two unicode strings or one unicode and one ANSI string as arguments */
395 static CHAR string1[MAX_PATH], string2[MAX_PATH];
397 #define ok_w2(format, szString1, szString2) \
399 if (lstrcmpW(szString1, szString2) != 0) \
401 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
402 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
403 ok(0, format, string1, string2); \
406 #define ok_aw(format, aString, wString) \
408 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
409 if (lstrcmpA(string1, aString) != 0) \
410 ok(0, format, string1, aString); \
412 #define ok_awplus(format, extra, aString, wString) \
414 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
415 if (lstrcmpA(string1, aString) != 0) \
416 ok(0, format, extra, string1, aString); \
418 /* exception checker */
419 static WCHAR szSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
421 #define ok_exception(hr, szDescription) \
422 if (hr == DISP_E_EXCEPTION) \
424 /* Compare wtype, source, and destination */ \
425 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
427 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
428 if (excepinfo.bstrSource) \
429 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, szSource); \
431 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
432 if (excepinfo.bstrDescription) \
433 ok_w2("Exception description was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrDescription, szDescription); \
436 static DISPID get_dispid( IDispatch *disp, const char *name )
438 LPOLESTR str;
439 UINT len;
440 DISPID id = -1;
441 HRESULT r;
443 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
444 str = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
445 if (str)
447 len = MultiByteToWideChar(CP_ACP, 0, name, -1, str, len );
448 r = IDispatch_GetIDsOfNames( disp, &IID_NULL, &str, 1, 0, &id );
449 HeapFree(GetProcessHeap(), 0, str);
450 if (r != S_OK)
451 return -1;
454 return id;
457 static void test_dispid(void)
459 ok( get_dispid( pInstaller, "CreateRecord" ) == 1, "dispid wrong\n");
460 ok( get_dispid( pInstaller, "OpenPackage" ) == 2, "dispid wrong\n");
461 todo_wine ok( get_dispid( pInstaller, "OpenProduct" ) == 3, "dispid wrong\n");
462 ok( get_dispid( pInstaller, "OpenDatabase" ) == 4, "dispid wrong\n");
463 todo_wine {
464 ok( get_dispid( pInstaller, "SummaryInformation" ) == 5, "dispid wrong\n");
465 ok( get_dispid( pInstaller, "UILevel" ) == 6, "dispid wrong\n");
466 ok( get_dispid( pInstaller, "EnableLog" ) == 7, "dispid wrong\n");
468 ok( get_dispid( pInstaller, "InstallProduct" ) == 8, "dispid wrong\n");
469 todo_wine {
470 ok( get_dispid( pInstaller, "Version" ) == 9, "dispid wrong\n");
471 ok( get_dispid( pInstaller, "LastErrorRecord" ) == 10, "dispid wrong\n");
473 ok( get_dispid( pInstaller, "RegistryValue" ) == 11, "dispid wrong\n");
474 todo_wine {
475 ok( get_dispid( pInstaller, "Environment" ) == 12, "dispid wrong\n");
476 ok( get_dispid( pInstaller, "FileAttributes" ) == 13, "dispid wrong\n");
478 ok( get_dispid( pInstaller, "FileSize" ) == 15, "dispid wrong\n");
479 ok( get_dispid( pInstaller, "FileVersion" ) == 16, "dispid wrong\n");
481 ok( get_dispid( pInstaller, "ProductState" ) == 17, "dispid wrong\n");
482 ok( get_dispid( pInstaller, "ProductInfo" ) == 18, "dispid wrong\n");
483 todo_wine {
484 ok( get_dispid( pInstaller, "ConfigureProduct" ) == 19, "dispid wrong\n");
485 ok( get_dispid( pInstaller, "ReinstallProduct" ) == 20 , "dispid wrong\n");
486 ok( get_dispid( pInstaller, "CollectUserInfo" ) == 21, "dispid wrong\n");
487 ok( get_dispid( pInstaller, "ApplyPatch" ) == 22, "dispid wrong\n");
488 ok( get_dispid( pInstaller, "FeatureParent" ) == 23, "dispid wrong\n");
489 ok( get_dispid( pInstaller, "FeatureState" ) == 24, "dispid wrong\n");
490 ok( get_dispid( pInstaller, "UseFeature" ) == 25, "dispid wrong\n");
491 ok( get_dispid( pInstaller, "FeatureUsageCount" ) == 26, "dispid wrong\n");
492 ok( get_dispid( pInstaller, "FeatureUsageDate" ) == 27, "dispid wrong\n");
493 ok( get_dispid( pInstaller, "ConfigureFeature" ) == 28, "dispid wrong\n");
494 ok( get_dispid( pInstaller, "ReinstallFeature" ) == 29, "dispid wrong\n");
495 ok( get_dispid( pInstaller, "ProvideComponent" ) == 30, "dispid wrong\n");
496 ok( get_dispid( pInstaller, "ComponentPath" ) == 31, "dispid wrong\n");
497 ok( get_dispid( pInstaller, "ProvideQualifiedComponent" ) == 32, "dispid wrong\n");
498 ok( get_dispid( pInstaller, "QualifierDescription" ) == 33, "dispid wrong\n");
499 ok( get_dispid( pInstaller, "ComponentQualifiers" ) == 34, "dispid wrong\n");
501 ok( get_dispid( pInstaller, "Products" ) == 35, "dispid wrong\n");
502 todo_wine {
503 ok( get_dispid( pInstaller, "Features" ) == 36, "dispid wrong\n");
504 ok( get_dispid( pInstaller, "Components" ) == 37, "dispid wrong\n");
505 ok( get_dispid( pInstaller, "ComponentClients" ) == 38, "dispid wrong\n");
506 ok( get_dispid( pInstaller, "Patches" ) == 39, "dispid wrong\n");
508 ok( get_dispid( pInstaller, "RelatedProducts" ) == 40, "dispid wrong\n");
509 todo_wine {
510 ok( get_dispid( pInstaller, "PatchInfo" ) == 41, "dispid wrong\n");
511 ok( get_dispid( pInstaller, "PatchTransforms" ) == 42, "dispid wrong\n");
512 ok( get_dispid( pInstaller, "AddSource" ) == 43, "dispid wrong\n");
513 ok( get_dispid( pInstaller, "ClearSourceList" ) == 44, "dispid wrong\n");
514 ok( get_dispid( pInstaller, "ForceSourceListResolution" ) == 45, "dispid wrong\n");
515 ok( get_dispid( pInstaller, "ShortcutTarget" ) == 46, "dispid wrong\n");
516 ok( get_dispid( pInstaller, "FileHash" ) == 47, "dispid wrong\n");
517 ok( get_dispid( pInstaller, "FileSignatureInfo" ) == 48, "dispid wrong\n");
518 ok( get_dispid( pInstaller, "RemovePatches" ) == 49, "dispid wrong\n");
520 ok( get_dispid( pInstaller, "ApplyMultiplePatches" ) == 51, "dispid wrong\n");
521 ok( get_dispid( pInstaller, "ProductsEx" ) == 52, "dispid wrong\n");
523 ok( get_dispid( pInstaller, "PatchesEx" ) == 55, "dispid wrong\n");
525 ok( get_dispid( pInstaller, "ExtractPatchXMLData" ) == 57, "dispid wrong\n");
528 /* MSDN claims the following functions exist but IDispatch->GetIDsOfNames disagrees */
529 if (0)
531 get_dispid( pInstaller, "ProductElevated" );
532 get_dispid( pInstaller, "ProductInfoFromScript" );
533 get_dispid( pInstaller, "ProvideAssembly" );
534 get_dispid( pInstaller, "CreateAdvertiseScript" );
535 get_dispid( pInstaller, "AdvertiseProduct" );
536 get_dispid( pInstaller, "PatchFiles" );
540 /* Test basic IDispatch functions */
541 static void test_dispatch(void)
543 static WCHAR szOpenPackage[] = { 'O','p','e','n','P','a','c','k','a','g','e',0 };
544 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};
545 static WCHAR szProductState[] = { 'P','r','o','d','u','c','t','S','t','a','t','e',0 };
546 HRESULT hr;
547 DISPID dispid;
548 OLECHAR *name;
549 VARIANT varresult;
550 VARIANTARG vararg[2];
551 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
553 /* Test getting ID of a function name that does not exist */
554 name = (WCHAR *)szMsifile;
555 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
556 ok(hr == DISP_E_UNKNOWNNAME, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
558 /* Test invoking this function */
559 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
560 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
562 /* Test getting ID of a function name that does exist */
563 name = (WCHAR *)szOpenPackage;
564 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
565 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
567 /* Test invoking this function (without parameters passed) */
568 if (0) /* All of these crash MSI on Windows XP */
570 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
571 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL);
572 VariantInit(&varresult);
573 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, &varresult, &excepinfo, NULL);
576 /* Try with NULL params */
577 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
578 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
580 /* Try one empty parameter */
581 dispparams.rgvarg = vararg;
582 dispparams.cArgs = 1;
583 VariantInit(&vararg[0]);
584 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
585 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
587 /* Try one parameter, function requires two */
588 VariantInit(&vararg[0]);
589 V_VT(&vararg[0]) = VT_BSTR;
590 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
591 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
592 VariantClear(&vararg[0]);
594 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
595 ok_exception(hr, szOpenPackageException);
597 /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
598 VariantInit(&vararg[0]);
599 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
600 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
602 VariantInit(&vararg[0]);
603 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
604 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
606 /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
607 name = (WCHAR *)szProductState;
608 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
609 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
611 dispparams.rgvarg = NULL;
612 dispparams.cArgs = 0;
613 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
614 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
616 dispparams.rgvarg = NULL;
617 dispparams.cArgs = 0;
618 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
619 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
622 /* invocation helper function */
623 static int _invoke_todo_vtResult = 0;
625 static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult)
627 OLECHAR *name = NULL;
628 DISPID dispid;
629 HRESULT hr;
630 UINT i;
631 UINT len;
633 memset(pVarResult, 0, sizeof(VARIANT));
634 VariantInit(pVarResult);
636 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 );
637 name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
638 if (!name) return E_FAIL;
639 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len );
640 hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
641 HeapFree(GetProcessHeap(), 0, name);
642 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
643 if (!hr == S_OK) return hr;
645 memset(&excepinfo, 0, sizeof(excepinfo));
646 hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL);
648 if (hr == S_OK)
650 if (_invoke_todo_vtResult) todo_wine
651 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
652 else
653 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
654 if (vtResult != VT_EMPTY)
656 hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult);
657 ok(hr == S_OK, "VariantChangeTypeEx returned 0x%08x\n", hr);
661 for (i=0; i<pDispParams->cArgs; i++)
662 VariantClear(&pDispParams->rgvarg[i]);
664 return hr;
667 /* Object_Property helper functions */
669 static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord)
671 VARIANT varresult;
672 VARIANTARG vararg[1];
673 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
674 HRESULT hr;
676 VariantInit(&vararg[0]);
677 V_VT(&vararg[0]) = VT_I4;
678 V_I4(&vararg[0]) = count;
680 hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
681 *pRecord = V_DISPATCH(&varresult);
682 return hr;
685 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
687 VARIANTARG vararg[3];
688 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
690 VariantInit(&vararg[2]);
691 V_VT(&vararg[2]) = VT_I4;
692 V_I4(&vararg[2]) = (int)hkey;
693 VariantInit(&vararg[1]);
694 V_VT(&vararg[1]) = VT_BSTR;
695 V_BSTR(&vararg[1]) = SysAllocString(szKey);
696 VariantInit(&vararg[0]);
697 VariantCopy(&vararg[0], &vValue);
698 VariantClear(&vValue);
700 return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect);
703 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
705 VARIANT varresult;
706 VARIANTARG vararg;
707 HRESULT hr;
709 VariantInit(&vararg);
710 V_VT(&vararg) = VT_EMPTY;
711 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL);
712 *pBool = V_BOOL(&varresult);
713 VariantClear(&varresult);
714 return hr;
717 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
719 VARIANT varresult;
720 VARIANTARG vararg;
721 HRESULT hr;
723 VariantInit(&vararg);
724 V_VT(&vararg) = VT_BSTR;
725 V_BSTR(&vararg) = SysAllocString(szValue);
727 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR);
728 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
729 VariantClear(&varresult);
730 return hr;
733 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
735 VARIANT varresult;
736 VARIANTARG vararg;
737 HRESULT hr;
739 VariantInit(&vararg);
740 V_VT(&vararg) = VT_I4;
741 V_I4(&vararg) = iValue;
743 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult);
744 if (vtResult == VT_BSTR) lstrcpyW(szString, V_BSTR(&varresult));
745 VariantClear(&varresult);
746 return hr;
749 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
751 VARIANT varresult;
752 VARIANTARG vararg[2];
753 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
754 HRESULT hr;
756 VariantInit(&vararg[1]);
757 V_VT(&vararg[1]) = VT_BSTR;
758 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
759 VariantInit(&vararg[0]);
760 V_VT(&vararg[0]) = VT_I4;
761 V_I4(&vararg[0]) = options;
763 hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
764 *pSession = V_DISPATCH(&varresult);
765 return hr;
768 static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase)
770 VARIANT varresult;
771 VARIANTARG vararg[2];
772 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
773 HRESULT hr;
775 VariantInit(&vararg[1]);
776 V_VT(&vararg[1]) = VT_BSTR;
777 V_BSTR(&vararg[1]) = SysAllocString(szDatabasePath);
778 VariantInit(&vararg[0]);
779 V_VT(&vararg[0]) = VT_I4;
780 V_I4(&vararg[0]) = openmode;
782 hr = invoke(pInstaller, "OpenDatabase", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
783 *pDatabase = V_DISPATCH(&varresult);
784 return hr;
787 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
789 VARIANT varresult;
790 VARIANTARG vararg[2];
791 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
793 VariantInit(&vararg[1]);
794 V_VT(&vararg[1]) = VT_BSTR;
795 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
796 VariantInit(&vararg[0]);
797 V_VT(&vararg[0]) = VT_BSTR;
798 V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues);
800 return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
803 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
805 VARIANT varresult;
806 VARIANTARG vararg[1];
807 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
808 HRESULT hr;
810 VariantInit(&vararg[0]);
811 V_VT(&vararg[0]) = VT_BSTR;
812 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
814 hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
815 *pInstallState = V_I4(&varresult);
816 VariantClear(&varresult);
817 return hr;
820 static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szString)
822 VARIANT varresult;
823 VARIANTARG vararg[2];
824 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
825 HRESULT hr;
827 VariantInit(&vararg[1]);
828 V_VT(&vararg[1]) = VT_BSTR;
829 V_BSTR(&vararg[1]) = SysAllocString(szProduct);
830 VariantInit(&vararg[0]);
831 V_VT(&vararg[0]) = VT_BSTR;
832 V_BSTR(&vararg[0]) = SysAllocString(szAttribute);
834 hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
835 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
836 VariantClear(&varresult);
837 return hr;
840 static HRESULT Installer_Products(IDispatch **pStringList)
842 VARIANT varresult;
843 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
844 HRESULT hr;
846 hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
847 *pStringList = V_DISPATCH(&varresult);
848 return hr;
851 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
853 VARIANT varresult;
854 VARIANTARG vararg[1];
855 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
856 HRESULT hr;
858 VariantInit(&vararg[0]);
859 V_VT(&vararg[0]) = VT_BSTR;
860 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
862 hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
863 *pStringList = V_DISPATCH(&varresult);
864 return hr;
867 static HRESULT Installer_VersionGet(LPWSTR szVersion)
869 VARIANT varresult;
870 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
871 HRESULT hr;
873 hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
874 if (V_BSTR(&varresult)) lstrcpyW(szVersion, V_BSTR(&varresult));
875 VariantClear(&varresult);
876 return hr;
879 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
881 VARIANT varresult;
882 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
883 HRESULT hr;
885 hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
886 *pInst = V_DISPATCH(&varresult);
887 return hr;
890 static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn)
892 VARIANT varresult;
893 VARIANTARG vararg[1];
894 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
895 HRESULT hr;
897 VariantInit(&vararg[0]);
898 V_VT(&vararg[0]) = VT_BSTR;
899 V_BSTR(&vararg[0]) = SysAllocString(szName);
901 hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
902 if (V_BSTR(&varresult)) lstrcpyW(szReturn, V_BSTR(&varresult));
903 VariantClear(&varresult);
904 return hr;
907 static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue)
909 VARIANT varresult;
910 VARIANTARG vararg[2];
911 DISPID dispid = DISPID_PROPERTYPUT;
912 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
914 VariantInit(&vararg[1]);
915 V_VT(&vararg[1]) = VT_BSTR;
916 V_BSTR(&vararg[1]) = SysAllocString(szName);
917 VariantInit(&vararg[0]);
918 V_VT(&vararg[0]) = VT_BSTR;
919 V_BSTR(&vararg[0]) = SysAllocString(szValue);
921 return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
924 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
926 VARIANT varresult;
927 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
928 HRESULT hr;
930 hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
931 *pLangId = V_I4(&varresult);
932 VariantClear(&varresult);
933 return hr;
936 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, BOOL *pMode)
938 VARIANT varresult;
939 VARIANTARG vararg[1];
940 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
941 HRESULT hr;
943 VariantInit(&vararg[0]);
944 V_VT(&vararg[0]) = VT_I4;
945 V_I4(&vararg[0]) = iFlag;
947 hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL);
948 *pMode = V_BOOL(&varresult);
949 VariantClear(&varresult);
950 return hr;
953 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, BOOL bMode)
955 VARIANT varresult;
956 VARIANTARG vararg[2];
957 DISPID dispid = DISPID_PROPERTYPUT;
958 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
960 VariantInit(&vararg[1]);
961 V_VT(&vararg[1]) = VT_I4;
962 V_I4(&vararg[1]) = iFlag;
963 VariantInit(&vararg[0]);
964 V_VT(&vararg[0]) = VT_BOOL;
965 V_BOOL(&vararg[0]) = bMode;
967 return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
970 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
972 VARIANT varresult;
973 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
974 HRESULT hr;
976 hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
977 *pDatabase = V_DISPATCH(&varresult);
978 return hr;
981 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn)
983 VARIANT varresult;
984 VARIANTARG vararg[1];
985 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
986 HRESULT hr;
988 VariantInit(&vararg[0]);
989 V_VT(&vararg[0]) = VT_BSTR;
990 V_BSTR(&vararg[0]) = SysAllocString(szAction);
992 hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
993 *iReturn = V_I4(&varresult);
994 VariantClear(&varresult);
995 return hr;
998 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
1000 VARIANT varresult;
1001 VARIANTARG vararg[1];
1002 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1003 HRESULT hr;
1005 VariantInit(&vararg[0]);
1006 V_VT(&vararg[0]) = VT_BSTR;
1007 V_BSTR(&vararg[0]) = SysAllocString(szCondition);
1009 hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1010 *iReturn = V_I4(&varresult);
1011 VariantClear(&varresult);
1012 return hr;
1015 static HRESULT Session_SetInstallLevel(IDispatch *pSession, long iInstallLevel)
1017 VARIANT varresult;
1018 VARIANTARG vararg[1];
1019 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1021 VariantInit(&vararg[0]);
1022 V_VT(&vararg[0]) = VT_I4;
1023 V_I4(&vararg[0]) = iInstallLevel;
1025 return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1028 static HRESULT Session_FeatureCurrentState(IDispatch *pSession, LPCWSTR szName, int *pState)
1030 VARIANT varresult;
1031 VARIANTARG vararg[1];
1032 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1033 HRESULT hr;
1035 VariantInit(&vararg[0]);
1036 V_VT(&vararg[0]) = VT_BSTR;
1037 V_BSTR(&vararg[0]) = SysAllocString(szName);
1039 hr = invoke(pSession, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1040 *pState = V_I4(&varresult);
1041 VariantClear(&varresult);
1042 return hr;
1045 static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState)
1047 VARIANT varresult;
1048 VARIANTARG vararg[1];
1049 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1050 HRESULT hr;
1052 VariantInit(&vararg[0]);
1053 V_VT(&vararg[0]) = VT_BSTR;
1054 V_BSTR(&vararg[0]) = SysAllocString(szName);
1056 hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1057 *pState = V_I4(&varresult);
1058 VariantClear(&varresult);
1059 return hr;
1062 static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState)
1064 VARIANT varresult;
1065 VARIANTARG vararg[2];
1066 DISPID dispid = DISPID_PROPERTYPUT;
1067 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1069 VariantInit(&vararg[1]);
1070 V_VT(&vararg[1]) = VT_BSTR;
1071 V_BSTR(&vararg[1]) = SysAllocString(szName);
1072 VariantInit(&vararg[0]);
1073 V_VT(&vararg[0]) = VT_I4;
1074 V_I4(&vararg[0]) = iState;
1076 return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1079 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
1081 VARIANT varresult;
1082 VARIANTARG vararg[1];
1083 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1084 HRESULT hr;
1086 VariantInit(&vararg[0]);
1087 V_VT(&vararg[0]) = VT_BSTR;
1088 V_BSTR(&vararg[0]) = SysAllocString(szSql);
1090 hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1091 *pView = V_DISPATCH(&varresult);
1092 return hr;
1095 static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo)
1097 VARIANT varresult;
1098 VARIANTARG vararg[1];
1099 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1100 HRESULT hr;
1102 VariantInit(&vararg[0]);
1103 V_VT(&vararg[0]) = VT_I4;
1104 V_I4(&vararg[0]) = iUpdateCount;
1106 hr = invoke(pDatabase, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1107 *pSummaryInfo = V_DISPATCH(&varresult);
1108 return hr;
1111 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
1113 VARIANT varresult;
1114 VARIANTARG vararg[1];
1115 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1117 VariantInit(&vararg[0]);
1118 V_VT(&vararg[0]) = VT_DISPATCH;
1119 V_DISPATCH(&vararg[0]) = pRecord;
1121 return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1124 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
1126 VARIANT varresult;
1127 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1128 HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1129 *ppRecord = V_DISPATCH(&varresult);
1130 return hr;
1133 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
1135 VARIANT varresult;
1136 VARIANTARG vararg[2];
1137 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1139 VariantInit(&vararg[1]);
1140 V_VT(&vararg[1]) = VT_I4;
1141 V_I4(&vararg[1]) = iMode;
1142 VariantInit(&vararg[0]);
1143 V_VT(&vararg[0]) = VT_DISPATCH;
1144 V_DISPATCH(&vararg[0]) = pRecord;
1145 if (pRecord)
1146 IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */
1148 return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1151 static HRESULT View_Close(IDispatch *pView)
1153 VARIANT varresult;
1154 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1155 return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1158 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
1160 VARIANT varresult;
1161 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1162 HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1163 *pFieldCount = V_I4(&varresult);
1164 VariantClear(&varresult);
1165 return hr;
1168 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString)
1170 VARIANT varresult;
1171 VARIANTARG vararg[1];
1172 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1173 HRESULT hr;
1175 VariantInit(&vararg[0]);
1176 V_VT(&vararg[0]) = VT_I4;
1177 V_I4(&vararg[0]) = iField;
1179 hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1180 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1181 VariantClear(&varresult);
1182 return hr;
1185 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
1187 VARIANT varresult;
1188 VARIANTARG vararg[2];
1189 DISPID dispid = DISPID_PROPERTYPUT;
1190 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1192 VariantInit(&vararg[1]);
1193 V_VT(&vararg[1]) = VT_I4;
1194 V_I4(&vararg[1]) = iField;
1195 VariantInit(&vararg[0]);
1196 V_VT(&vararg[0]) = VT_BSTR;
1197 V_BSTR(&vararg[0]) = SysAllocString(szString);
1199 return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1202 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
1204 VARIANT varresult;
1205 VARIANTARG vararg[1];
1206 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1207 HRESULT hr;
1209 VariantInit(&vararg[0]);
1210 V_VT(&vararg[0]) = VT_I4;
1211 V_I4(&vararg[0]) = iField;
1213 hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1214 *pValue = V_I4(&varresult);
1215 VariantClear(&varresult);
1216 return hr;
1219 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
1221 VARIANT varresult;
1222 VARIANTARG vararg[2];
1223 DISPID dispid = DISPID_PROPERTYPUT;
1224 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1226 VariantInit(&vararg[1]);
1227 V_VT(&vararg[1]) = VT_I4;
1228 V_I4(&vararg[1]) = iField;
1229 VariantInit(&vararg[0]);
1230 V_VT(&vararg[0]) = VT_I4;
1231 V_I4(&vararg[0]) = iValue;
1233 return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1236 static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT)
1238 VARIANT varresult;
1239 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1240 HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN);
1241 *ppEnumVARIANT = V_UNKNOWN(&varresult);
1242 return hr;
1245 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
1247 VARIANT varresult;
1248 VARIANTARG vararg[1];
1249 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1250 HRESULT hr;
1252 VariantInit(&vararg[0]);
1253 V_VT(&vararg[0]) = VT_I4;
1254 V_I4(&vararg[0]) = iIndex;
1256 hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1257 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1258 VariantClear(&varresult);
1259 return hr;
1262 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
1264 VARIANT varresult;
1265 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1266 HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1267 *pCount = V_I4(&varresult);
1268 VariantClear(&varresult);
1269 return hr;
1272 static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect)
1274 VARIANTARG vararg[1];
1275 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1277 VariantInit(&vararg[0]);
1278 V_VT(&vararg[0]) = VT_I4;
1279 V_I4(&vararg[0]) = pid;
1280 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYGET, &dispparams, pVarResult, vtExpect);
1283 static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant)
1285 VARIANT varresult;
1286 VARIANTARG vararg[2];
1287 DISPID dispid = DISPID_PROPERTYPUT;
1288 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1290 VariantInit(&vararg[1]);
1291 V_VT(&vararg[1]) = VT_I4;
1292 V_I4(&vararg[1]) = pid;
1293 VariantInit(&vararg[0]);
1294 VariantCopyInd(vararg, pVariant);
1296 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1299 static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount)
1301 VARIANT varresult;
1302 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1303 HRESULT hr;
1305 hr = invoke(pSummaryInfo, "PropertyCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1306 *pCount = V_I4(&varresult);
1307 VariantClear(&varresult);
1308 return hr;
1311 /* Test the various objects */
1313 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4
1315 static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly)
1317 static const WCHAR szPropertyException[] = { 'P','r','o','p','e','r','t','y',',','P','i','d',0 };
1318 static const WCHAR szTitle[] = { 'T','i','t','l','e',0 };
1319 VARIANT varresult, var;
1320 SYSTEMTIME st;
1321 HRESULT hr;
1322 int j;
1324 /* SummaryInfo::PropertyCount */
1325 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1326 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1327 ok(j == num_info, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1329 /* SummaryInfo::Property, get for properties we have set */
1330 for (j = 0; j < num_info; j++)
1332 const msi_summary_info *entry = &info[j];
1334 int vt = entry->datatype;
1335 if (vt == VT_LPSTR) vt = VT_BSTR;
1336 else if (vt == VT_FILETIME) vt = VT_DATE;
1337 else if (vt == VT_I2) vt = VT_I4;
1339 hr = SummaryInfo_PropertyGet(pSummaryInfo, entry->property, &varresult, vt);
1340 ok(hr == S_OK, "SummaryInfo_Property (pid %d) failed, hresult 0x%08x\n", entry->property, hr);
1341 if (V_VT(&varresult) != vt)
1342 skip("Skipping property tests due to type mismatch\n");
1343 else if (vt == VT_I4)
1344 ok(V_I4(&varresult) == entry->iValue, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %d\n",
1345 entry->property, entry->iValue, V_I4(&varresult));
1346 else if (vt == VT_DATE)
1348 FILETIME ft;
1349 DATE d;
1351 FileTimeToLocalFileTime(entry->pftValue, &ft);
1352 FileTimeToSystemTime(&ft, &st);
1353 SystemTimeToVariantTime(&st, &d);
1354 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));
1356 else if (vt == VT_BSTR)
1358 ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry->property, entry->szValue, V_BSTR(&varresult));
1360 else
1361 skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry->property, vt);
1364 /* SummaryInfo::Property, get; invalid arguments */
1366 /* Invalid pids */
1367 hr = SummaryInfo_PropertyGet(pSummaryInfo, -1, &varresult, VT_EMPTY);
1368 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1369 ok_exception(hr, szPropertyException);
1371 hr = SummaryInfo_PropertyGet(pSummaryInfo, 1000, &varresult, VT_EMPTY);
1372 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1373 ok_exception(hr, szPropertyException);
1375 /* Unsupported pids */
1376 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_DICTIONARY, &varresult, VT_EMPTY);
1377 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1379 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY);
1380 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1382 /* Pids we have not set, one for each type */
1383 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_EMPTY);
1384 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1386 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY);
1387 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1389 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY);
1390 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1392 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY);
1393 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1395 if (!readonly)
1397 /* SummaryInfo::Property, put; one for each type */
1399 /* VT_I2 */
1400 VariantInit(&var);
1401 V_VT(&var) = VT_I2;
1402 V_I2(&var) = 1;
1403 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CODEPAGE, &var);
1404 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1406 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */);
1407 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1408 ok(V_I2(&var) == V_I2(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var), V_I2(&varresult));
1409 VariantClear(&varresult);
1410 VariantClear(&var);
1412 /* VT_BSTR */
1413 V_VT(&var) = VT_BSTR;
1414 V_BSTR(&var) = SysAllocString(szTitle);
1415 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_TITLE, &var);
1416 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1418 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var));
1419 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1420 ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var), V_BSTR(&varresult));
1421 VariantClear(&varresult);
1422 VariantClear(&var);
1424 /* VT_DATE */
1425 V_VT(&var) = VT_DATE;
1426 FileTimeToSystemTime(&systemtime, &st);
1427 SystemTimeToVariantTime(&st, &V_DATE(&var));
1428 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_LASTSAVE_DTM, &var);
1429 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1431 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var));
1432 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1433 /* FIXME: Off by one second */
1434 todo_wine ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1435 VariantClear(&varresult);
1436 VariantClear(&var);
1438 /* VT_I4 */
1439 V_VT(&var) = VT_I4;
1440 V_I4(&var) = 1000;
1441 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1442 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1444 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1445 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1446 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult));
1447 VariantClear(&varresult);
1448 VariantClear(&var);
1450 /* SummaryInfo::PropertyCount */
1451 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1452 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1453 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1457 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1459 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 };
1460 static WCHAR szThree[] = { 'T','h','r','e','e',0 };
1461 static WCHAR szTwo[] = { 'T','w','o',0 };
1462 static WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
1463 static WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 };
1464 IDispatch *pView = NULL, *pSummaryInfo = NULL;
1465 HRESULT hr;
1467 hr = Database_OpenView(pDatabase, szSql, &pView);
1468 ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr);
1469 if (hr == S_OK)
1471 IDispatch *pRecord = NULL;
1472 WCHAR szString[MAX_PATH];
1474 /* View::Execute */
1475 hr = View_Execute(pView, NULL);
1476 ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr);
1478 /* View::Fetch */
1479 hr = View_Fetch(pView, &pRecord);
1480 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1481 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1482 if (pRecord)
1484 /* Record::StringDataGet */
1485 memset(szString, 0, sizeof(szString));
1486 hr = Record_StringDataGet(pRecord, 1, szString);
1487 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1488 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1490 /* Record::StringDataPut with correct index */
1491 hr = Record_StringDataPut(pRecord, 1, szTwo);
1492 ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1494 /* Record::StringDataGet */
1495 memset(szString, 0, sizeof(szString));
1496 hr = Record_StringDataGet(pRecord, 1, szString);
1497 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1498 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1500 /* Record::StringDataPut with incorrect index */
1501 hr = Record_StringDataPut(pRecord, -1, szString);
1502 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1503 ok_exception(hr, szStringDataField);
1505 /* View::Modify with incorrect parameters */
1506 hr = View_Modify(pView, -5, NULL);
1507 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1508 ok_exception(hr, szModifyModeRecord);
1510 hr = View_Modify(pView, -5, pRecord);
1511 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1512 ok_exception(hr, szModifyModeRecord);
1514 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1515 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1516 ok_exception(hr, szModifyModeRecord);
1518 /* View::Modify with MSIMODIFY_REFRESH should undo our changes */
1519 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1520 /* Wine's MsiViewModify currently does not support MSIMODIFY_REFRESH */
1521 todo_wine ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr);
1523 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1524 memset(szString, 0, sizeof(szString));
1525 hr = Record_StringDataGet(pRecord, 1, szString);
1526 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1527 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1529 IDispatch_Release(pRecord);
1532 /* View::Fetch */
1533 hr = View_Fetch(pView, &pRecord);
1534 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1535 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1536 if (pRecord)
1538 /* Record::StringDataGet */
1539 memset(szString, 0, sizeof(szString));
1540 hr = Record_StringDataGet(pRecord, 1, szString);
1541 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1542 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1544 IDispatch_Release(pRecord);
1547 /* View::Fetch */
1548 hr = View_Fetch(pView, &pRecord);
1549 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1550 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1551 if (pRecord)
1552 IDispatch_Release(pRecord);
1554 /* View::Close */
1555 hr = View_Close(pView);
1556 ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr);
1558 IDispatch_Release(pView);
1561 /* Database::SummaryInformation */
1562 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo);
1563 ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr);
1564 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1565 if (pSummaryInfo)
1567 test_SummaryInfo(pSummaryInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), readonly);
1568 IDispatch_Release(pSummaryInfo);
1572 static void test_Session(IDispatch *pSession)
1574 static WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
1575 static WCHAR szOne[] = { 'O','n','e',0 };
1576 static WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 };
1577 static WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 };
1578 static WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 };
1579 static WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 };
1580 static WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1581 static WCHAR szEmpty[] = { 0 };
1582 static WCHAR szEquals[] = { '=',0 };
1583 static WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
1584 WCHAR stringw[MAX_PATH];
1585 CHAR string[MAX_PATH];
1586 UINT len;
1587 BOOL bool;
1588 int myint;
1589 IDispatch *pDatabase = NULL, *pInst = NULL;
1590 HRESULT hr;
1592 /* Session::Installer */
1593 hr = Session_Installer(pSession, &pInst);
1594 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1595 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1596 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1598 /* Session::Property, get */
1599 memset(stringw, 0, sizeof(stringw));
1600 hr = Session_PropertyGet(pSession, szProductName, stringw);
1601 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1602 if (lstrcmpW(stringw, szMSITEST) != 0)
1604 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1605 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1606 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1609 /* Session::Property, put */
1610 hr = Session_PropertyPut(pSession, szProductName, szProductName);
1611 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1612 memset(stringw, 0, sizeof(stringw));
1613 hr = Session_PropertyGet(pSession, szProductName, stringw);
1614 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1615 if (lstrcmpW(stringw, szProductName) != 0)
1617 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1618 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1619 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1622 /* Try putting a property using empty property identifier */
1623 hr = Session_PropertyPut(pSession, szEmpty, szProductName);
1624 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1625 ok_exception(hr, szPropertyName);
1627 /* Try putting a property using illegal property identifier */
1628 hr = Session_PropertyPut(pSession, szEquals, szProductName);
1629 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1631 /* Session::Language, get */
1632 hr = Session_LanguageGet(pSession, &len);
1633 ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1634 /* Not sure how to check the language is correct */
1636 /* Session::Mode, get */
1637 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1638 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1639 todo_wine ok(!bool, "Reboot at end session mode is %d\n", bool);
1641 /* Session::Mode, put */
1642 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE);
1643 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1644 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1645 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1646 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1647 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE); /* set it again so we don't reboot */
1648 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1650 /* Session::Database, get */
1651 hr = Session_Database(pSession, &pDatabase);
1652 ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr);
1653 if (hr == S_OK)
1655 test_Database(pDatabase, TRUE);
1656 IDispatch_Release(pDatabase);
1659 /* Session::EvaluateCondition */
1660 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1661 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1662 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1664 hr = Session_EvaluateCondition(pSession, szEmpty, &myint);
1665 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1666 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1668 hr = Session_EvaluateCondition(pSession, szEquals, &myint);
1669 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1670 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1672 /* Session::DoAction(CostInitialize) must occur before the next statements */
1673 hr = Session_DoAction(pSession, szCostInitialize, &myint);
1674 ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr);
1675 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1677 /* Session::SetInstallLevel */
1678 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1679 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
1681 /* Session::FeatureCurrentState, get */
1682 hr = Session_FeatureCurrentState(pSession, szOne, &myint);
1683 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
1684 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1686 /* Session::EvaluateCondition */
1687 hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint);
1688 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1689 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1691 hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint);
1692 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1693 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1695 /* Session::FeatureRequestState, put */
1696 hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED);
1697 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
1698 hr = Session_FeatureRequestStateGet(pSession, szOne, &myint);
1699 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
1700 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
1702 /* Session::EvaluateCondition */
1703 hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint);
1704 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1705 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1707 hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint);
1708 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1709 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1712 /* delete key and all its subkeys */
1713 static DWORD delete_key( HKEY hkey )
1715 char name[MAX_PATH];
1716 DWORD ret;
1718 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
1720 HKEY tmp;
1721 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
1723 ret = delete_key( tmp );
1724 RegCloseKey( tmp );
1726 if (ret) break;
1728 if (ret != ERROR_NO_MORE_ITEMS) return ret;
1729 RegDeleteKeyA( hkey, "" );
1730 return 0;
1733 static void test_Installer_RegistryValue(void)
1735 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
1736 static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 };
1737 static const WCHAR szOne[] = { 'O','n','e',0 };
1738 static const WCHAR szTwo[] = { 'T','w','o',0 };
1739 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
1740 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1741 static const WCHAR szFour[] = { 'F','o','u','r',0 };
1742 static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 };
1743 static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 };
1744 static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 };
1745 static const WCHAR szSix[] = { 'S','i','x',0 };
1746 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1747 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
1748 static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
1749 static const WCHAR szBlank[] = { 0 };
1750 VARIANT varresult;
1751 VARIANTARG vararg;
1752 WCHAR szString[MAX_PATH];
1753 HKEY hkey, hkey_sub;
1754 HRESULT hr;
1755 BOOL bRet;
1757 /* Delete keys */
1758 if (!RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey )) delete_key( hkey );
1760 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
1761 hr = Installer_RegistryValueE(HKEY_CURRENT_USER, szKey, &bRet);
1762 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1763 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
1765 memset(szString, 0, sizeof(szString));
1766 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, NULL, szString);
1767 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1769 memset(szString, 0, sizeof(szString));
1770 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 0, szString, VT_BSTR);
1771 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1773 /* Create key */
1774 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
1776 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1777 "RegSetValueExW failed\n");
1778 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
1779 "RegSetValueExW failed\n");
1780 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
1781 "RegSetValueExW failed\n");
1782 ok(SetEnvironmentVariableA("MSITEST", "Four"), "SetEnvironmentVariableA failed %d\n", GetLastError());
1783 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
1784 "RegSetValueExW failed\n");
1785 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
1786 "RegSetValueExW failed\n");
1787 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
1788 "RegSetValueExW failed\n");
1789 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, (const BYTE *)NULL, 0),
1790 "RegSetValueExW failed\n");
1792 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1793 "RegSetValueExW failed\n");
1795 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
1797 /* Does our key exist? It should, and make sure we retrieve the correct default value */
1798 bRet = FALSE;
1799 hr = Installer_RegistryValueE(HKEY_CURRENT_USER, szKey, &bRet);
1800 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1801 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
1803 memset(szString, 0, sizeof(szString));
1804 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, NULL, szString);
1805 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1806 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1808 /* Ask for the value of a nonexistent key */
1809 memset(szString, 0, sizeof(szString));
1810 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szExpand, szString);
1811 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1813 /* Get values of keys */
1814 memset(szString, 0, sizeof(szString));
1815 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szOne, szString);
1816 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1817 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1819 VariantInit(&vararg);
1820 V_VT(&vararg) = VT_BSTR;
1821 V_BSTR(&vararg) = SysAllocString(szTwo);
1822 hr = Installer_RegistryValue(HKEY_CURRENT_USER, szKey, vararg, &varresult, VT_I4);
1823 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1824 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
1825 VariantClear(&varresult);
1827 memset(szString, 0, sizeof(szString));
1828 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szThree, szString);
1829 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1830 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
1832 memset(szString, 0, sizeof(szString));
1833 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szFour, szString);
1834 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1835 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
1837 memset(szString, 0, sizeof(szString));
1838 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szFive, szString);
1839 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1840 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFiveHi);
1842 memset(szString, 0, sizeof(szString));
1843 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szSix, szString);
1844 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1845 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_);
1847 VariantInit(&vararg);
1848 V_VT(&vararg) = VT_BSTR;
1849 V_BSTR(&vararg) = SysAllocString(szSeven);
1850 hr = Installer_RegistryValue(HKEY_CURRENT_USER, szKey, vararg, &varresult, VT_EMPTY);
1851 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1853 /* Get string class name for the key */
1854 memset(szString, 0, sizeof(szString));
1855 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 0, szString, VT_BSTR);
1856 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1857 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank);
1859 /* Get name of a value by positive number (RegEnumValue like), valid index */
1860 memset(szString, 0, sizeof(szString));
1861 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 2, szString, VT_BSTR);
1862 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1863 /* RegEnumValue order seems different on wine */
1864 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
1866 /* Get name of a value by positive number (RegEnumValue like), invalid index */
1867 memset(szString, 0, sizeof(szString));
1868 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 10, szString, VT_EMPTY);
1869 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1871 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
1872 memset(szString, 0, sizeof(szString));
1873 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, -1, szString, VT_BSTR);
1874 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1875 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
1877 /* Get name of a subkey by negative 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 /* clean up */
1883 delete_key(hkey);
1886 static void test_Installer_Products(BOOL bProductInstalled)
1888 WCHAR szString[MAX_PATH];
1889 HRESULT hr;
1890 int idx;
1891 IUnknown *pUnk = NULL;
1892 IEnumVARIANT *pEnum = NULL;
1893 VARIANT var;
1894 ULONG celt;
1895 int iCount, iValue;
1896 IDispatch *pStringList = NULL;
1897 BOOL bProductFound = FALSE;
1899 /* Installer::Products */
1900 hr = Installer_Products(&pStringList);
1901 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
1902 if (hr == S_OK)
1904 /* StringList::_NewEnum */
1905 hr = StringList__NewEnum(pStringList, &pUnk);
1906 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
1907 if (hr == S_OK)
1909 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
1910 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
1912 if (!pEnum)
1913 skip("IEnumVARIANT tests\n");
1915 /* StringList::Count */
1916 hr = StringList_Count(pStringList, &iCount);
1917 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
1919 for (idx=0; idx<iCount; idx++)
1921 /* StringList::Item */
1922 memset(szString, 0, sizeof(szString));
1923 hr = StringList_Item(pStringList, idx, szString);
1924 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
1926 if (hr == S_OK)
1928 /* Installer::ProductState */
1929 hr = Installer_ProductState(szString, &iValue);
1930 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
1931 if (hr == S_OK)
1932 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
1934 /* Not found our product code yet? Check */
1935 if (!bProductFound && !lstrcmpW(szString, szProductCode))
1936 bProductFound = TRUE;
1938 /* IEnumVARIANT::Next */
1939 if (pEnum)
1941 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
1942 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
1943 ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
1944 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
1945 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
1946 VariantClear(&var);
1951 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
1952 bProductInstalled ? "be" : "not be",
1953 bProductFound ? "found" : "not found");
1955 if (pEnum)
1957 IEnumVARIANT *pEnum2 = NULL;
1959 if (0) /* Crashes on Windows XP */
1961 /* IEnumVARIANT::Clone, NULL pointer */
1962 hr = IEnumVARIANT_Clone(pEnum, NULL);
1965 /* IEnumVARIANT::Clone */
1966 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
1967 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
1968 if (hr == S_OK)
1970 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
1972 /* IEnumVARIANT::Next of the clone */
1973 if (iCount)
1975 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
1976 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
1977 ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
1978 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
1979 VariantClear(&var);
1981 else
1982 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
1984 IEnumVARIANT_Release(pEnum2);
1987 /* IEnumVARIANT::Skip should fail */
1988 hr = IEnumVARIANT_Skip(pEnum, 1);
1989 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
1991 /* IEnumVARIANT::Next, NULL variant pointer */
1992 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
1993 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
1994 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
1996 /* IEnumVARIANT::Next, should not return any more items */
1997 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
1998 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
1999 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2000 VariantClear(&var);
2002 /* IEnumVARIANT::Reset */
2003 hr = IEnumVARIANT_Reset(pEnum);
2004 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2006 if (iCount)
2008 /* IEnumVARIANT::Skip to the last product */
2009 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2010 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2012 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2013 * NULL celt pointer. */
2014 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2015 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2016 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2017 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2018 VariantClear(&var);
2020 else
2021 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2024 /* StringList::Item using an invalid index */
2025 memset(szString, 0, sizeof(szString));
2026 hr = StringList_Item(pStringList, iCount, szString);
2027 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2029 if (pEnum) IEnumVARIANT_Release(pEnum);
2030 if (pUnk) IUnknown_Release(pUnk);
2031 IDispatch_Release(pStringList);
2035 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2036 * deleting the subkeys first) */
2037 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey)
2039 UINT ret;
2040 CHAR *string = NULL;
2041 HKEY hkey;
2042 DWORD dwSize;
2044 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2045 if (ret != ERROR_SUCCESS) return ret;
2046 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2047 if (ret != ERROR_SUCCESS) return ret;
2048 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2050 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2051 delete_registry_key(hkey, string);
2053 RegCloseKey(hkey);
2054 HeapFree(GetProcessHeap(), 0, string);
2055 RegDeleteKeyA(hkeyParent, subkey);
2056 return ERROR_SUCCESS;
2059 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2060 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, HKEY *phkey)
2062 UINT ret;
2063 CHAR *string = NULL;
2064 int idx = 0;
2065 HKEY hkey;
2066 DWORD dwSize;
2067 BOOL found = FALSE;
2069 *phkey = 0;
2071 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2072 if (ret != ERROR_SUCCESS) return ret;
2073 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2074 if (ret != ERROR_SUCCESS) return ret;
2075 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2077 while (!found &&
2078 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2080 if (!strcmp(string, findkey))
2082 *phkey = hkey;
2083 found = TRUE;
2085 else if (find_registry_key(hkey, string, findkey, phkey) == ERROR_SUCCESS) found = TRUE;
2088 if (*phkey != hkey) RegCloseKey(hkey);
2089 HeapFree(GetProcessHeap(), 0, string);
2090 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2093 static void test_Installer_InstallProduct(LPCWSTR szPath)
2095 HRESULT hr;
2096 CHAR path[MAX_PATH];
2097 WCHAR szString[MAX_PATH];
2098 LONG res;
2099 HKEY hkey;
2100 DWORD num, size, type;
2101 int iValue, iCount;
2102 IDispatch *pStringList = NULL;
2104 create_test_files();
2106 /* Installer::InstallProduct */
2107 hr = Installer_InstallProduct(szMsifile, NULL);
2108 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2110 /* Installer::ProductState for our product code, which has been installed */
2111 hr = Installer_ProductState(szProductCode, &iValue);
2112 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2113 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2115 /* Installer::ProductInfo for our product code */
2117 /* NULL attribute */
2118 memset(szString, 0, sizeof(szString));
2119 hr = Installer_ProductInfo(szProductCode, NULL, szString);
2120 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2121 ok_exception(hr, szProductInfoException);
2123 /* Nonexistent attribute */
2124 memset(szString, 0, sizeof(szString));
2125 hr = Installer_ProductInfo(szProductCode, szMsifile, szString);
2126 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2127 ok_exception(hr, szProductInfoException);
2129 /* Package name */
2130 memset(szString, 0, sizeof(szString));
2131 hr = Installer_ProductInfo(szProductCode, INSTALLPROPERTY_PACKAGENAMEW, szString);
2132 todo_wine ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2133 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile);
2135 /* Product name */
2136 memset(szString, 0, sizeof(szString));
2137 hr = Installer_ProductInfo(szProductCode, INSTALLPROPERTY_PRODUCTNAMEW, szString);
2138 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2139 ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST);
2141 /* Installer::Products */
2142 test_Installer_Products(TRUE);
2144 /* Installer::RelatedProducts for our upgrade code */
2145 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2146 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2147 if (hr == S_OK)
2149 /* StringList::Count */
2150 hr = StringList_Count(pStringList, &iCount);
2151 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2152 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2154 /* StringList::Item */
2155 memset(szString, 0, sizeof(szString));
2156 hr = StringList_Item(pStringList, 0, szString);
2157 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2158 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
2160 IDispatch_Release(pStringList);
2163 /* Check & clean up installed files & registry keys */
2164 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2165 ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
2166 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2167 ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
2168 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2169 ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
2170 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2171 ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
2172 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2173 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2174 ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
2175 ok(delete_pf("msitest", FALSE), "File not installed\n");
2177 res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
2178 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2180 size = MAX_PATH;
2181 type = REG_SZ;
2182 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2183 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2184 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2186 size = MAX_PATH;
2187 type = REG_SZ;
2188 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2189 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2191 size = sizeof(num);
2192 type = REG_DWORD;
2193 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2194 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2195 ok(num == 314, "Expected 314, got %d\n", num);
2197 size = MAX_PATH;
2198 type = REG_SZ;
2199 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2200 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2201 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2203 RegCloseKey(hkey);
2205 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest");
2206 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2208 check_service_is_installed();
2210 /* Remove registry keys written by RegisterProduct standard action */
2211 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F1C3AF50-8B56-4A69-A00C-00773FE42F30}");
2212 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2214 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2215 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2217 res = find_registry_key(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "05FA3C1F65B896A40AC00077F34EF203", &hkey);
2218 todo_wine ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2219 if (res == ERROR_SUCCESS)
2221 res = delete_registry_key(hkey, "05FA3C1F65B896A40AC00077F34EF203");
2222 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2223 RegCloseKey(hkey);
2226 /* Remove registry keys written by PublishProduct standard action */
2227 res = RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2228 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2230 res = delete_registry_key(hkey, "Products\\05FA3C1F65B896A40AC00077F34EF203");
2231 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2233 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2234 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2236 RegCloseKey(hkey);
2238 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203");
2239 todo_wine ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_SUCCESS, got %d\n", res);
2241 /* Delete installation files we installed */
2242 delete_test_files();
2245 static void test_Installer(void)
2247 static WCHAR szBackslash[] = { '\\',0 };
2248 static WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
2249 static WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
2250 WCHAR szPath[MAX_PATH];
2251 HRESULT hr;
2252 UINT len;
2253 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL;
2254 int iValue, iCount;
2256 if (!pInstaller) return;
2258 /* Installer::CreateRecord */
2260 /* Test for error */
2261 hr = Installer_CreateRecord(-1, &pRecord);
2262 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2263 ok_exception(hr, szCreateRecordException);
2265 /* Test for success */
2266 hr = Installer_CreateRecord(1, &pRecord);
2267 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2268 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2269 if (pRecord)
2271 /* Record::FieldCountGet */
2272 hr = Record_FieldCountGet(pRecord, &iValue);
2273 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2274 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2276 /* Record::IntegerDataGet */
2277 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2278 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2279 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2281 /* Record::IntegerDataGet, bad index */
2282 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2283 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2284 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2286 /* Record::IntegerDataPut */
2287 hr = Record_IntegerDataPut(pRecord, 1, 100);
2288 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2290 /* Record::IntegerDataPut, bad index */
2291 hr = Record_IntegerDataPut(pRecord, 10, 100);
2292 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2293 ok_exception(hr, szIntegerDataException);
2295 /* Record::IntegerDataGet */
2296 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2297 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2298 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2300 IDispatch_Release(pRecord);
2303 /* Prepare package */
2304 create_database(msifile, tables, sizeof(tables) / sizeof(msi_table),
2305 summary_info, sizeof(summary_info) / sizeof(msi_summary_info));
2307 len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, CURR_DIR, -1, szPath, MAX_PATH);
2308 ok(len, "MultiByteToWideChar returned error %d\n", GetLastError());
2309 if (!len) return;
2311 lstrcatW(szPath, szBackslash);
2312 lstrcatW(szPath, szMsifile);
2314 /* Installer::OpenPackage */
2315 hr = Installer_OpenPackage(szPath, 0, &pSession);
2316 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2317 if (hr == S_OK)
2319 test_Session(pSession);
2320 IDispatch_Release(pSession);
2323 /* Installer::OpenDatabase */
2324 hr = Installer_OpenDatabase(szPath, (int)MSIDBOPEN_TRANSACT, &pDatabase);
2325 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2326 if (hr == S_OK)
2328 test_Database(pDatabase, FALSE);
2329 IDispatch_Release(pDatabase);
2332 /* Installer::RegistryValue */
2333 test_Installer_RegistryValue();
2335 /* Installer::ProductState for our product code, which should not be installed */
2336 hr = Installer_ProductState(szProductCode, &iValue);
2337 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2338 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2340 /* Installer::ProductInfo for our product code, which should not be installed */
2342 /* Package name */
2343 memset(szPath, 0, sizeof(szPath));
2344 hr = Installer_ProductInfo(szProductCode, INSTALLPROPERTY_PACKAGENAMEW, szPath);
2345 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2346 ok_exception(hr, szProductInfoException);
2348 /* NULL attribute and NULL product code */
2349 memset(szPath, 0, sizeof(szPath));
2350 hr = Installer_ProductInfo(NULL, NULL, szPath);
2351 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2352 ok_exception(hr, szProductInfoException);
2354 /* Installer::Products */
2355 test_Installer_Products(FALSE);
2357 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2358 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2359 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2360 if (hr == S_OK)
2362 /* StringList::Count */
2363 hr = StringList_Count(pStringList, &iCount);
2364 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2365 ok(!iCount, "Expected no related products but found %d\n", iCount);
2367 IDispatch_Release(pStringList);
2370 /* Installer::Version */
2371 todo_wine {
2372 memset(szPath, 0, sizeof(szPath));
2373 hr = Installer_VersionGet(szPath);
2374 ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr);
2377 /* Installer::InstallProduct and other tests that depend on our product being installed */
2378 test_Installer_InstallProduct(szPath);
2381 START_TEST(automation)
2383 DWORD len;
2384 char temp_path[MAX_PATH], prev_path[MAX_PATH];
2385 HRESULT hr;
2386 CLSID clsid;
2387 IUnknown *pUnk;
2389 GetSystemTimeAsFileTime(&systemtime);
2391 GetCurrentDirectoryA(MAX_PATH, prev_path);
2392 GetTempPath(MAX_PATH, temp_path);
2393 SetCurrentDirectoryA(temp_path);
2395 lstrcpyA(CURR_DIR, temp_path);
2396 len = lstrlenA(CURR_DIR);
2398 if(len && (CURR_DIR[len - 1] == '\\'))
2399 CURR_DIR[len - 1] = 0;
2401 get_program_files_dir(PROG_FILES_DIR);
2403 hr = OleInitialize(NULL);
2404 ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr);
2405 hr = CLSIDFromProgID(szProgId, &clsid);
2406 ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr);
2407 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2408 ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr);
2410 if (pUnk)
2412 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2413 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2415 test_dispid();
2416 test_dispatch();
2417 test_Installer();
2419 IDispatch_Release(pInstaller);
2420 IUnknown_Release(pUnk);
2423 OleUninitialize();
2425 SetCurrentDirectoryA(prev_path);