comctl32: Remove unused parameter from _read_bitmap().
[wine/wine-gecko.git] / dlls / msi / tests / automation.c
blob683de7a3178c82a482f47f70238d590823183cb0
1 /*
2 * Copyright (C) 2007 Mike McCormack for CodeWeavers
3 * Copyright (C) 2007 Misha Koshelev
5 * A test program for Microsoft Installer OLE automation functionality.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
24 #include <stdio.h>
26 #include <initguid.h>
27 #include <windows.h>
28 #include <msiquery.h>
29 #include <msidefs.h>
30 #include <msi.h>
31 #include <fci.h>
33 #include "wine/test.h"
35 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
37 static const char *msifile = "winetest.msi";
38 static const WCHAR szMsifile[] = {'w','i','n','e','t','e','s','t','.','m','s','i',0};
39 static const WCHAR szMSITEST[] = { 'M','S','I','T','E','S','T',0 };
40 static const WCHAR szProductCode[] = { '{','F','1','C','3','A','F','5','0','-','8','B','5','6','-','4','A','6','9','-','A','0','0','C','-','0','0','7','7','3','F','E','4','2','F','3','0','}',0 };
41 static const WCHAR szUpgradeCode[] = { '{','C','E','0','6','7','E','8','D','-','2','E','1','A','-','4','3','6','7','-','B','7','3','4','-','4','E','B','2','B','D','A','D','6','5','6','5','}',0 };
42 static const WCHAR szProductInfoException[] = { 'P','r','o','d','u','c','t','I','n','f','o',',','P','r','o','d','u','c','t',',','A','t','t','r','i','b','u','t','e',0 };
43 static const WCHAR WINE_INSTALLPROPERTY_PACKAGENAMEW[] = {'P','a','c','k','a','g','e','N','a','m','e',0};
44 static const WCHAR WINE_INSTALLPROPERTY_PRODUCTNAMEW[] = {'P','r','o','d','u','c','t','N','a','m','e',0};
45 static FILETIME systemtime;
46 static CHAR CURR_DIR[MAX_PATH];
47 static EXCEPINFO excepinfo;
50 * OLE automation data
51 **/
52 static const WCHAR szProgId[] = { 'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r','.','I','n','s','t','a','l','l','e','r',0 };
53 static IDispatch *pInstaller;
55 /* msi database data */
57 static const CHAR component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
58 "s72\tS38\ts72\ti2\tS255\tS72\n"
59 "Component\tComponent\n"
60 "Five\t{8CC92E9D-14B2-4CA4-B2AA-B11D02078087}\tNEWDIR\t2\t\tfive.txt\n"
61 "Four\t{FD37B4EA-7209-45C0-8917-535F35A2F080}\tCABOUTDIR\t2\t\tfour.txt\n"
62 "One\t{783B242E-E185-4A56-AF86-C09815EC053C}\tMSITESTDIR\t2\t\tone.txt\n"
63 "Three\t{010B6ADD-B27D-4EDD-9B3D-34C4F7D61684}\tCHANGEDDIR\t2\t\tthree.txt\n"
64 "Two\t{BF03D1A6-20DA-4A65-82F3-6CAC995915CE}\tFIRSTDIR\t2\t\ttwo.txt\n"
65 "dangler\t{6091DF25-EF96-45F1-B8E9-A9B1420C7A3C}\tTARGETDIR\t4\t\tregdata\n"
66 "component\t\tMSITESTDIR\t0\t1\tfile\n"
67 "service_comp\t\tMSITESTDIR\t0\t1\tservice_file";
69 static const CHAR directory_dat[] = "Directory\tDirectory_Parent\tDefaultDir\n"
70 "s72\tS72\tl255\n"
71 "Directory\tDirectory\n"
72 "CABOUTDIR\tMSITESTDIR\tcabout\n"
73 "CHANGEDDIR\tMSITESTDIR\tchanged:second\n"
74 "FIRSTDIR\tMSITESTDIR\tfirst\n"
75 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
76 "NEWDIR\tCABOUTDIR\tnew\n"
77 "ProgramFilesFolder\tTARGETDIR\t.\n"
78 "TARGETDIR\t\tSourceDir";
80 static const CHAR feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
81 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
82 "Feature\tFeature\n"
83 "Five\t\tFive\tThe Five Feature\t5\t3\tNEWDIR\t0\n"
84 "Four\t\tFour\tThe Four Feature\t4\t3\tCABOUTDIR\t0\n"
85 "One\t\tOne\tThe One Feature\t1\t3\tMSITESTDIR\t0\n"
86 "Three\tOne\tThree\tThe Three Feature\t3\t3\tCHANGEDDIR\t0\n"
87 "Two\tOne\tTwo\tThe Two Feature\t2\t3\tFIRSTDIR\t0\n"
88 "feature\t\t\t\t2\t1\tTARGETDIR\t0\n"
89 "service_feature\t\t\t\t2\t1\tTARGETDIR\t0";
91 static const CHAR feature_comp_dat[] = "Feature_\tComponent_\n"
92 "s38\ts72\n"
93 "FeatureComponents\tFeature_\tComponent_\n"
94 "Five\tFive\n"
95 "Four\tFour\n"
96 "One\tOne\n"
97 "Three\tThree\n"
98 "Two\tTwo\n"
99 "feature\tcomponent\n"
100 "service_feature\tservice_comp\n";
102 static const CHAR file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
103 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
104 "File\tFile\n"
105 "five.txt\tFive\tfive.txt\t1000\t\t\t0\t5\n"
106 "four.txt\tFour\tfour.txt\t1000\t\t\t0\t4\n"
107 "one.txt\tOne\tone.txt\t1000\t\t\t0\t1\n"
108 "three.txt\tThree\tthree.txt\t1000\t\t\t0\t3\n"
109 "two.txt\tTwo\ttwo.txt\t1000\t\t\t0\t2\n"
110 "file\tcomponent\tfilename\t100\t\t\t8192\t1\n"
111 "service_file\tservice_comp\tservice.exe\t100\t\t\t8192\t1";
113 static const CHAR install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
114 "s72\tS255\tI2\n"
115 "InstallExecuteSequence\tAction\n"
116 "AllocateRegistrySpace\tNOT Installed\t1550\n"
117 "CostFinalize\t\t1000\n"
118 "CostInitialize\t\t800\n"
119 "FileCost\t\t900\n"
120 "InstallFiles\t\t4000\n"
121 "InstallServices\t\t5000\n"
122 "RegisterProduct\t\t6100\n"
123 "PublishProduct\t\t6400\n"
124 "InstallFinalize\t\t6600\n"
125 "InstallInitialize\t\t1500\n"
126 "InstallValidate\t\t1400\n"
127 "LaunchConditions\t\t100\n"
128 "WriteRegistryValues\tSourceDir And SOURCEDIR\t5000";
130 static const CHAR media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
131 "i2\ti4\tL64\tS255\tS32\tS72\n"
132 "Media\tDiskId\n"
133 "1\t5\t\t\tDISK1\t\n";
135 static const CHAR property_dat[] = "Property\tValue\n"
136 "s72\tl0\n"
137 "Property\tProperty\n"
138 "DefaultUIFont\tDlgFont8\n"
139 "HASUIRUN\t0\n"
140 "INSTALLLEVEL\t3\n"
141 "InstallMode\tTypical\n"
142 "Manufacturer\tWine\n"
143 "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n"
144 "ProductCode\t{F1C3AF50-8B56-4A69-A00C-00773FE42F30}\n"
145 "ProductID\tnone\n"
146 "ProductLanguage\t1033\n"
147 "ProductName\tMSITEST\n"
148 "ProductVersion\t1.1.1\n"
149 "PROMPTROLLBACKCOST\tP\n"
150 "Setup\tSetup\n"
151 "UpgradeCode\t{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}";
153 static const CHAR registry_dat[] = "Registry\tRoot\tKey\tName\tValue\tComponent_\n"
154 "s72\ti2\tl255\tL255\tL0\ts72\n"
155 "Registry\tRegistry\n"
156 "Apples\t2\tSOFTWARE\\Wine\\msitest\tName\timaname\tOne\n"
157 "Oranges\t2\tSOFTWARE\\Wine\\msitest\tnumber\t#314\tTwo\n"
158 "regdata\t2\tSOFTWARE\\Wine\\msitest\tblah\tbad\tdangler\n"
159 "OrderTest\t2\tSOFTWARE\\Wine\\msitest\tOrderTestName\tOrderTestValue\tcomponent";
161 static const CHAR service_install_dat[] = "ServiceInstall\tName\tDisplayName\tServiceType\tStartType\tErrorControl\t"
162 "LoadOrderGroup\tDependencies\tStartName\tPassword\tArguments\tComponent_\tDescription\n"
163 "s72\ts255\tL255\ti4\ti4\ti4\tS255\tS255\tS255\tS255\tS255\ts72\tL255\n"
164 "ServiceInstall\tServiceInstall\n"
165 "TestService\tTestService\tTestService\t2\t3\t0\t\t\tTestService\t\t\tservice_comp\t\t";
167 static const CHAR service_control_dat[] = "ServiceControl\tName\tEvent\tArguments\tWait\tComponent_\n"
168 "s72\tl255\ti2\tL255\tI2\ts72\n"
169 "ServiceControl\tServiceControl\n"
170 "ServiceControl\tTestService\t8\t\t0\tservice_comp";
172 typedef struct _msi_table
174 const CHAR *filename;
175 const CHAR *data;
176 int size;
177 } msi_table;
179 #define ADD_TABLE(x) {#x".idt", x##_dat, sizeof(x##_dat)}
181 static const msi_table tables[] =
183 ADD_TABLE(component),
184 ADD_TABLE(directory),
185 ADD_TABLE(feature),
186 ADD_TABLE(feature_comp),
187 ADD_TABLE(file),
188 ADD_TABLE(install_exec_seq),
189 ADD_TABLE(media),
190 ADD_TABLE(property),
191 ADD_TABLE(registry),
192 ADD_TABLE(service_install),
193 ADD_TABLE(service_control)
196 typedef struct _msi_summary_info
198 UINT property;
199 UINT datatype;
200 INT iValue;
201 FILETIME *pftValue;
202 const CHAR *szValue;
203 } msi_summary_info;
205 #define ADD_INFO_I2(property, iValue) {property, VT_I2, iValue, NULL, NULL}
206 #define ADD_INFO_I4(property, iValue) {property, VT_I4, iValue, NULL, NULL}
207 #define ADD_INFO_LPSTR(property, szValue) {property, VT_LPSTR, 0, NULL, szValue}
208 #define ADD_INFO_FILETIME(property, pftValue) {property, VT_FILETIME, 0, pftValue, NULL}
210 static const msi_summary_info summary_info[] =
212 ADD_INFO_LPSTR(PID_TEMPLATE, ";1033"),
213 ADD_INFO_LPSTR(PID_REVNUMBER, "{004757CA-5092-49c2-AD20-28E1CE0DF5F2}"),
214 ADD_INFO_I4(PID_PAGECOUNT, 100),
215 ADD_INFO_I4(PID_WORDCOUNT, 0),
216 ADD_INFO_FILETIME(PID_CREATE_DTM, &systemtime),
217 ADD_INFO_FILETIME(PID_LASTPRINTED, &systemtime)
221 * Database Helpers
224 static void write_file(const CHAR *filename, const char *data, int data_size)
226 DWORD size;
228 HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL,
229 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
231 WriteFile(hf, data, data_size, &size, NULL);
232 CloseHandle(hf);
235 static void write_msi_summary_info(MSIHANDLE db, const msi_summary_info *info, int num_info)
237 MSIHANDLE summary;
238 UINT r;
239 int j;
241 r = MsiGetSummaryInformationA(db, NULL, num_info, &summary);
242 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
244 /* import summary information into the stream */
245 for (j = 0; j < num_info; j++)
247 const msi_summary_info *entry = &info[j];
249 r = MsiSummaryInfoSetPropertyA(summary, entry->property, entry->datatype,
250 entry->iValue, entry->pftValue, entry->szValue);
251 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
254 /* write the summary changes back to the stream */
255 r = MsiSummaryInfoPersist(summary);
256 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
258 MsiCloseHandle(summary);
261 static void create_database(const CHAR *name, const msi_table *tables, int num_tables,
262 const msi_summary_info *info, int num_info)
264 MSIHANDLE db;
265 UINT r;
266 int j;
268 r = MsiOpenDatabaseA(name, MSIDBOPEN_CREATE, &db);
269 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
271 /* import the tables into the database */
272 for (j = 0; j < num_tables; j++)
274 const msi_table *table = &tables[j];
276 write_file(table->filename, table->data, (table->size - 1) * sizeof(char));
278 r = MsiDatabaseImportA(db, CURR_DIR, table->filename);
279 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
281 DeleteFileA(table->filename);
284 write_msi_summary_info(db, info, num_info);
286 r = MsiDatabaseCommit(db);
287 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
289 MsiCloseHandle(db);
293 * Installation helpers
296 static char PROG_FILES_DIR[MAX_PATH];
298 static BOOL get_program_files_dir(LPSTR buf)
300 HKEY hkey;
301 DWORD type = REG_EXPAND_SZ, size;
303 if (RegOpenKey(HKEY_LOCAL_MACHINE,
304 "Software\\Microsoft\\Windows\\CurrentVersion", &hkey))
305 return FALSE;
307 size = MAX_PATH;
308 if (RegQueryValueEx(hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size))
309 return FALSE;
311 RegCloseKey(hkey);
312 return TRUE;
315 static void create_file(const CHAR *name, DWORD size)
317 HANDLE file;
318 DWORD written, left;
320 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
321 ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
322 WriteFile(file, name, strlen(name), &written, NULL);
323 WriteFile(file, "\n", strlen("\n"), &written, NULL);
325 left = size - lstrlen(name) - 1;
327 SetFilePointer(file, left, NULL, FILE_CURRENT);
328 SetEndOfFile(file);
330 CloseHandle(file);
333 static void create_test_files(void)
335 CreateDirectoryA("msitest", NULL);
336 create_file("msitest\\one.txt", 100);
337 CreateDirectoryA("msitest\\first", NULL);
338 create_file("msitest\\first\\two.txt", 100);
339 CreateDirectoryA("msitest\\second", NULL);
340 create_file("msitest\\second\\three.txt", 100);
341 CreateDirectoryA("msitest\\cabout",NULL);
342 create_file("msitest\\cabout\\four.txt", 100);
343 CreateDirectoryA("msitest\\cabout\\new",NULL);
344 create_file("msitest\\cabout\\new\\five.txt", 100);
345 create_file("msitest\\filename", 100);
346 create_file("msitest\\service.exe", 100);
349 static BOOL delete_pf(const CHAR *rel_path, BOOL is_file)
351 CHAR path[MAX_PATH];
353 lstrcpyA(path, PROG_FILES_DIR);
354 lstrcatA(path, "\\");
355 lstrcatA(path, rel_path);
357 if (is_file)
358 return DeleteFileA(path);
359 else
360 return RemoveDirectoryA(path);
363 static void delete_test_files(void)
365 DeleteFileA(msifile);
366 DeleteFileA("msitest\\cabout\\new\\five.txt");
367 DeleteFileA("msitest\\cabout\\four.txt");
368 DeleteFileA("msitest\\second\\three.txt");
369 DeleteFileA("msitest\\first\\two.txt");
370 DeleteFileA("msitest\\one.txt");
371 DeleteFileA("msitest\\service.exe");
372 DeleteFileA("msitest\\filename");
373 RemoveDirectoryA("msitest\\cabout\\new");
374 RemoveDirectoryA("msitest\\cabout");
375 RemoveDirectoryA("msitest\\second");
376 RemoveDirectoryA("msitest\\first");
377 RemoveDirectoryA("msitest");
380 static void check_service_is_installed(void)
382 SC_HANDLE scm, service;
383 BOOL res;
385 scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
386 ok(scm != NULL, "Failed to open the SC Manager\n");
388 service = OpenService(scm, "TestService", SC_MANAGER_ALL_ACCESS);
389 ok(service != NULL, "Failed to open TestService\n");
391 res = DeleteService(service);
392 ok(res, "Failed to delete TestService\n");
394 CloseServiceHandle(service);
395 CloseServiceHandle(scm);
399 * Automation helpers and tests
402 /* ok-like statement which takes two unicode strings or one unicode and one ANSI string as arguments */
403 static CHAR string1[MAX_PATH], string2[MAX_PATH];
405 #define ok_w2(format, szString1, szString2) \
407 if (lstrcmpW(szString1, szString2) != 0) \
409 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
410 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
411 ok(0, format, string1, string2); \
414 #define ok_aw(format, aString, wString) \
416 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
417 if (lstrcmpA(string1, aString) != 0) \
418 ok(0, format, string1, aString); \
420 #define ok_awplus(format, extra, aString, wString) \
422 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
423 if (lstrcmpA(string1, aString) != 0) \
424 ok(0, format, extra, string1, aString); \
426 /* exception checker */
427 static WCHAR szSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
429 #define ok_exception(hr, szDescription) \
430 if (hr == DISP_E_EXCEPTION) \
432 /* Compare wtype, source, and destination */ \
433 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
435 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
436 if (excepinfo.bstrSource) \
437 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, szSource); \
439 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
440 if (excepinfo.bstrDescription) \
441 ok_w2("Exception description was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrDescription, szDescription); \
443 SysFreeString(excepinfo.bstrSource); \
444 SysFreeString(excepinfo.bstrDescription); \
445 SysFreeString(excepinfo.bstrHelpFile); \
448 static DISPID get_dispid( IDispatch *disp, const char *name )
450 LPOLESTR str;
451 UINT len;
452 DISPID id = -1;
453 HRESULT r;
455 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
456 str = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
457 if (str)
459 len = MultiByteToWideChar(CP_ACP, 0, name, -1, str, len );
460 r = IDispatch_GetIDsOfNames( disp, &IID_NULL, &str, 1, 0, &id );
461 HeapFree(GetProcessHeap(), 0, str);
462 if (r != S_OK)
463 return -1;
466 return id;
469 static void test_dispid(void)
471 DISPID dispid;
473 dispid = get_dispid(pInstaller, "CreateRecord");
474 ok(dispid == 1, "Expected 1, got %d\n", dispid);
475 dispid = get_dispid(pInstaller, "OpenPackage");
476 ok(dispid == 2, "Expected 2, got %d\n", dispid);
477 dispid = get_dispid(pInstaller, "OpenDatabase");
478 ok(dispid == 4, "Expected 4, got %d\n", dispid);
479 dispid = get_dispid( pInstaller, "UILevel" );
480 ok(dispid == 6, "Expected 6, got %d\n", dispid);
481 dispid = get_dispid(pInstaller, "InstallProduct");
482 ok(dispid == 8, "Expected 8, got %d\n", dispid);
483 dispid = get_dispid(pInstaller, "Version");
484 ok(dispid == 9, "Expected 9, got %d\n", dispid);
485 dispid = get_dispid(pInstaller, "RegistryValue");
486 ok(dispid == 11, "Expected 11, got %d\n", dispid);
487 todo_wine
489 dispid = get_dispid(pInstaller, "OpenProduct");
490 ok(dispid == 3, "Expected 3, got %d\n", dispid);
491 dispid = get_dispid(pInstaller, "SummaryInformation");
492 ok(dispid == 5, "Expected 5, got %d\n", dispid);
493 dispid = get_dispid(pInstaller, "EnableLog");
494 ok(dispid == 7, "Expected 7, got %d\n", dispid);
495 dispid = get_dispid(pInstaller, "LastErrorRecord");
496 ok(dispid == 10, "Expected 10, got %d\n", dispid);
497 dispid = get_dispid(pInstaller, "Environment");
498 ok(dispid == 12, "Expected 12, got %d\n", dispid);
499 dispid = get_dispid(pInstaller, "FileAttributes");
500 ok(dispid == 13, "Expected 13, got %d\n", dispid);
501 dispid = get_dispid(pInstaller, "FileSize");
502 ok(dispid == 15, "Expected 15, got %d\n", dispid);
503 dispid = get_dispid(pInstaller, "FileVersion");
504 ok(dispid == 16, "Expected 16, got %d\n", dispid);
506 dispid = get_dispid(pInstaller, "ProductState");
507 ok(dispid == 17, "Expected 17, got %d\n", dispid);
508 dispid = get_dispid(pInstaller, "ProductInfo");
509 ok(dispid == 18, "Expected 18, got %d\n", dispid);
510 todo_wine
512 dispid = get_dispid(pInstaller, "ConfigureProduct");
513 ok(dispid == 19, "Expected 19, got %d\n", dispid);
514 dispid = get_dispid(pInstaller, "ReinstallProduct");
515 ok(dispid == 20 , "Expected 20, got %d\n", dispid);
516 dispid = get_dispid(pInstaller, "CollectUserInfo");
517 ok(dispid == 21, "Expected 21, got %d\n", dispid);
518 dispid = get_dispid(pInstaller, "ApplyPatch");
519 ok(dispid == 22, "Expected 22, got %d\n", dispid);
520 dispid = get_dispid(pInstaller, "FeatureParent");
521 ok(dispid == 23, "Expected 23, got %d\n", dispid);
522 dispid = get_dispid(pInstaller, "FeatureState");
523 ok(dispid == 24, "Expected 24, got %d\n", dispid);
524 dispid = get_dispid(pInstaller, "UseFeature");
525 ok(dispid == 25, "Expected 25, got %d\n", dispid);
526 dispid = get_dispid(pInstaller, "FeatureUsageCount");
527 ok(dispid == 26, "Expected 26, got %d\n", dispid);
528 dispid = get_dispid(pInstaller, "FeatureUsageDate");
529 ok(dispid == 27, "Expected 27, got %d\n", dispid);
530 dispid = get_dispid(pInstaller, "ConfigureFeature");
531 ok(dispid == 28, "Expected 28, got %d\n", dispid);
532 dispid = get_dispid(pInstaller, "ReinstallFeature");
533 ok(dispid == 29, "Expected 29, got %d\n", dispid);
534 dispid = get_dispid(pInstaller, "ProvideComponent");
535 ok(dispid == 30, "Expected 30, got %d\n", dispid);
536 dispid = get_dispid(pInstaller, "ComponentPath");
537 ok(dispid == 31, "Expected 31, got %d\n", dispid);
538 dispid = get_dispid(pInstaller, "ProvideQualifiedComponent");
539 ok(dispid == 32, "Expected 32, got %d\n", dispid);
540 dispid = get_dispid(pInstaller, "QualifierDescription");
541 ok(dispid == 33, "Expected 33, got %d\n", dispid);
542 dispid = get_dispid(pInstaller, "ComponentQualifiers");
543 ok(dispid == 34, "Expected 34, got %d\n", dispid);
545 dispid = get_dispid(pInstaller, "Products");
546 ok(dispid == 35, "Expected 35, got %d\n", dispid);
547 todo_wine
549 dispid = get_dispid(pInstaller, "Features");
550 ok(dispid == 36, "Expected 36, got %d\n", dispid);
551 dispid = get_dispid(pInstaller, "Components");
552 ok(dispid == 37, "Expected 37, got %d\n", dispid);
553 dispid = get_dispid(pInstaller, "ComponentClients");
554 ok(dispid == 38, "Expected 38, got %d\n", dispid);
555 dispid = get_dispid(pInstaller, "Patches");
556 ok(dispid == 39, "Expected 39, got %d\n", dispid);
558 dispid = get_dispid(pInstaller, "RelatedProducts");
559 ok(dispid == 40, "Expected 40, got %d\n", dispid);
560 todo_wine
562 dispid = get_dispid(pInstaller, "PatchInfo");
563 ok(dispid == 41, "Expected 41, got %d\n", dispid);
564 dispid = get_dispid(pInstaller, "PatchTransforms");
565 ok(dispid == 42, "Expected 42, got %d\n", dispid);
566 dispid = get_dispid(pInstaller, "AddSource");
567 ok(dispid == 43, "Expected 43, got %d\n", dispid);
568 dispid = get_dispid(pInstaller, "ClearSourceList");
569 ok(dispid == 44, "Expected 44, got %d\n", dispid);
570 dispid = get_dispid(pInstaller, "ForceSourceListResolution");
571 ok(dispid == 45, "Expected 45, got %d\n", dispid);
572 dispid = get_dispid(pInstaller, "ShortcutTarget");
573 ok(dispid == 46, "Expected 46, got %d\n", dispid);
574 dispid = get_dispid(pInstaller, "FileHash");
575 ok(dispid == 47, "Expected 47, got %d\n", dispid);
576 dispid = get_dispid(pInstaller, "FileSignatureInfo");
577 ok(dispid == 48, "Expected 48, got %d\n", dispid);
579 dispid = get_dispid(pInstaller, "RemovePatches");
580 ok(dispid == 49 || dispid == -1, "Expected 49 or -1, got %d\n", dispid);
581 dispid = get_dispid(pInstaller, "ApplyMultiplePatches");
582 ok(dispid == 51 || dispid == -1, "Expected 51 or -1, got %d\n", dispid);
583 dispid = get_dispid(pInstaller, "ProductsEx");
584 ok(dispid == 52 || dispid == -1, "Expected 52 or -1, got %d\n", dispid);
585 dispid = get_dispid(pInstaller, "PatchesEx");
586 ok(dispid == 55 || dispid == -1, "Expected 55 or -1, got %d\n", dispid);
587 dispid = get_dispid(pInstaller, "ExtractPatchXMLData");
588 ok(dispid == 57 || dispid == -1, "Expected 57 or -1, got %d\n", dispid);
589 dispid = get_dispid( pInstaller, "ProductElevated" );
590 ok(dispid == 59 || dispid == -1, "Expected 59 or -1, got %d\n", dispid);
591 dispid = get_dispid( pInstaller, "ProvideAssembly" );
592 ok(dispid == 60 || dispid == -1, "Expected 60 or -1, got %d\n", dispid);
593 dispid = get_dispid( pInstaller, "ProductInfoFromScript" );
594 ok(dispid == 61 || dispid == -1, "Expected 61 or -1, got %d\n", dispid);
595 dispid = get_dispid( pInstaller, "AdvertiseProduct" );
596 ok(dispid == 62 || dispid == -1, "Expected 62 or -1, got %d\n", dispid);
597 dispid = get_dispid( pInstaller, "CreateAdvertiseScript" );
598 ok(dispid == 63 || dispid == -1, "Expected 63 or -1, got %d\n", dispid);
599 dispid = get_dispid( pInstaller, "PatchFiles" );
600 ok(dispid == 65 || dispid == -1, "Expected 65 or -1, got %d\n", dispid);
603 /* Test basic IDispatch functions */
604 static void test_dispatch(void)
606 static WCHAR szOpenPackage[] = { 'O','p','e','n','P','a','c','k','a','g','e',0 };
607 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};
608 static WCHAR szProductState[] = { 'P','r','o','d','u','c','t','S','t','a','t','e',0 };
609 HRESULT hr;
610 DISPID dispid;
611 OLECHAR *name;
612 VARIANT varresult;
613 VARIANTARG vararg[2];
614 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
616 /* Test getting ID of a function name that does not exist */
617 name = (WCHAR *)szMsifile;
618 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
619 ok(hr == DISP_E_UNKNOWNNAME, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
621 /* Test invoking this function */
622 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
623 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
625 /* Test getting ID of a function name that does exist */
626 name = (WCHAR *)szOpenPackage;
627 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
628 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
630 /* Test invoking this function (without parameters passed) */
631 if (0) /* All of these crash MSI on Windows XP */
633 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
634 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL);
635 VariantInit(&varresult);
636 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, &varresult, &excepinfo, NULL);
639 /* Try with NULL params */
640 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
641 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
643 /* Try one empty parameter */
644 dispparams.rgvarg = vararg;
645 dispparams.cArgs = 1;
646 VariantInit(&vararg[0]);
647 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
648 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
650 /* Try one parameter, function requires two */
651 VariantInit(&vararg[0]);
652 V_VT(&vararg[0]) = VT_BSTR;
653 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
654 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
655 VariantClear(&vararg[0]);
657 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
658 ok_exception(hr, szOpenPackageException);
660 /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
661 VariantInit(&vararg[0]);
662 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
663 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
665 VariantInit(&vararg[0]);
666 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
667 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
669 /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
670 name = (WCHAR *)szProductState;
671 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
672 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
674 dispparams.rgvarg = NULL;
675 dispparams.cArgs = 0;
676 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
677 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
679 dispparams.rgvarg = NULL;
680 dispparams.cArgs = 0;
681 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
682 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
685 /* invocation helper function */
686 static int _invoke_todo_vtResult = 0;
688 static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult)
690 OLECHAR *name = NULL;
691 DISPID dispid;
692 HRESULT hr;
693 UINT i;
694 UINT len;
696 memset(pVarResult, 0, sizeof(VARIANT));
697 VariantInit(pVarResult);
699 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 );
700 name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
701 if (!name) return E_FAIL;
702 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len );
703 hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
704 HeapFree(GetProcessHeap(), 0, name);
705 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
706 if (!hr == S_OK) return hr;
708 memset(&excepinfo, 0, sizeof(excepinfo));
709 hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL);
711 if (hr == S_OK)
713 if (_invoke_todo_vtResult) todo_wine
714 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
715 else
716 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
717 if (vtResult != VT_EMPTY)
719 hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult);
720 ok(hr == S_OK, "VariantChangeTypeEx returned 0x%08x\n", hr);
724 for (i=0; i<pDispParams->cArgs; i++)
725 VariantClear(&pDispParams->rgvarg[i]);
727 return hr;
730 /* Object_Property helper functions */
732 static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord)
734 VARIANT varresult;
735 VARIANTARG vararg[1];
736 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
737 HRESULT hr;
739 VariantInit(&vararg[0]);
740 V_VT(&vararg[0]) = VT_I4;
741 V_I4(&vararg[0]) = count;
743 hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
744 *pRecord = V_DISPATCH(&varresult);
745 return hr;
748 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
750 VARIANTARG vararg[3];
751 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
753 VariantInit(&vararg[2]);
754 V_VT(&vararg[2]) = VT_I4;
755 V_I4(&vararg[2]) = (int)hkey;
756 VariantInit(&vararg[1]);
757 V_VT(&vararg[1]) = VT_BSTR;
758 V_BSTR(&vararg[1]) = SysAllocString(szKey);
759 VariantInit(&vararg[0]);
760 VariantCopy(&vararg[0], &vValue);
761 VariantClear(&vValue);
763 return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect);
766 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
768 VARIANT varresult;
769 VARIANTARG vararg;
770 HRESULT hr;
772 VariantInit(&vararg);
773 V_VT(&vararg) = VT_EMPTY;
774 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL);
775 *pBool = V_BOOL(&varresult);
776 VariantClear(&varresult);
777 return hr;
780 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
782 VARIANT varresult;
783 VARIANTARG vararg;
784 HRESULT hr;
786 VariantInit(&vararg);
787 V_VT(&vararg) = VT_BSTR;
788 V_BSTR(&vararg) = SysAllocString(szValue);
790 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR);
791 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
792 VariantClear(&varresult);
793 return hr;
796 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
798 VARIANT varresult;
799 VARIANTARG vararg;
800 HRESULT hr;
802 VariantInit(&vararg);
803 V_VT(&vararg) = VT_I4;
804 V_I4(&vararg) = iValue;
806 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult);
807 if (SUCCEEDED(hr) && vtResult == VT_BSTR) lstrcpyW(szString, V_BSTR(&varresult));
808 VariantClear(&varresult);
809 return hr;
812 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
814 VARIANT varresult;
815 VARIANTARG vararg[2];
816 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
817 HRESULT hr;
819 VariantInit(&vararg[1]);
820 V_VT(&vararg[1]) = VT_BSTR;
821 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
822 VariantInit(&vararg[0]);
823 V_VT(&vararg[0]) = VT_I4;
824 V_I4(&vararg[0]) = options;
826 hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
827 *pSession = V_DISPATCH(&varresult);
828 return hr;
831 static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase)
833 VARIANT varresult;
834 VARIANTARG vararg[2];
835 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
836 HRESULT hr;
838 VariantInit(&vararg[1]);
839 V_VT(&vararg[1]) = VT_BSTR;
840 V_BSTR(&vararg[1]) = SysAllocString(szDatabasePath);
841 VariantInit(&vararg[0]);
842 V_VT(&vararg[0]) = VT_I4;
843 V_I4(&vararg[0]) = openmode;
845 hr = invoke(pInstaller, "OpenDatabase", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
846 *pDatabase = V_DISPATCH(&varresult);
847 return hr;
850 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
852 VARIANT varresult;
853 VARIANTARG vararg[2];
854 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
856 VariantInit(&vararg[1]);
857 V_VT(&vararg[1]) = VT_BSTR;
858 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
859 VariantInit(&vararg[0]);
860 V_VT(&vararg[0]) = VT_BSTR;
861 V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues);
863 return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
866 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
868 VARIANT varresult;
869 VARIANTARG vararg[1];
870 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
871 HRESULT hr;
873 VariantInit(&vararg[0]);
874 V_VT(&vararg[0]) = VT_BSTR;
875 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
877 hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
878 *pInstallState = V_I4(&varresult);
879 VariantClear(&varresult);
880 return hr;
883 static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szString)
885 VARIANT varresult;
886 VARIANTARG vararg[2];
887 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
888 HRESULT hr;
890 VariantInit(&vararg[1]);
891 V_VT(&vararg[1]) = VT_BSTR;
892 V_BSTR(&vararg[1]) = SysAllocString(szProduct);
893 VariantInit(&vararg[0]);
894 V_VT(&vararg[0]) = VT_BSTR;
895 V_BSTR(&vararg[0]) = SysAllocString(szAttribute);
897 hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
898 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
899 VariantClear(&varresult);
900 return hr;
903 static HRESULT Installer_Products(IDispatch **pStringList)
905 VARIANT varresult;
906 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
907 HRESULT hr;
909 hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
910 *pStringList = V_DISPATCH(&varresult);
911 return hr;
914 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
916 VARIANT varresult;
917 VARIANTARG vararg[1];
918 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
919 HRESULT hr;
921 VariantInit(&vararg[0]);
922 V_VT(&vararg[0]) = VT_BSTR;
923 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
925 hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
926 *pStringList = V_DISPATCH(&varresult);
927 return hr;
930 static HRESULT Installer_VersionGet(LPWSTR szVersion)
932 VARIANT varresult;
933 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
934 HRESULT hr;
936 hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
937 if (V_BSTR(&varresult)) lstrcpyW(szVersion, V_BSTR(&varresult));
938 VariantClear(&varresult);
939 return hr;
942 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
944 VARIANT varresult;
945 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
946 HRESULT hr;
948 hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
949 *pInst = V_DISPATCH(&varresult);
950 return hr;
953 static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn)
955 VARIANT varresult;
956 VARIANTARG vararg[1];
957 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
958 HRESULT hr;
960 VariantInit(&vararg[0]);
961 V_VT(&vararg[0]) = VT_BSTR;
962 V_BSTR(&vararg[0]) = SysAllocString(szName);
964 hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
965 if (V_BSTR(&varresult)) lstrcpyW(szReturn, V_BSTR(&varresult));
966 VariantClear(&varresult);
967 return hr;
970 static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue)
972 VARIANT varresult;
973 VARIANTARG vararg[2];
974 DISPID dispid = DISPID_PROPERTYPUT;
975 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
977 VariantInit(&vararg[1]);
978 V_VT(&vararg[1]) = VT_BSTR;
979 V_BSTR(&vararg[1]) = SysAllocString(szName);
980 VariantInit(&vararg[0]);
981 V_VT(&vararg[0]) = VT_BSTR;
982 V_BSTR(&vararg[0]) = SysAllocString(szValue);
984 return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
987 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
989 VARIANT varresult;
990 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
991 HRESULT hr;
993 hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
994 *pLangId = V_I4(&varresult);
995 VariantClear(&varresult);
996 return hr;
999 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, BOOL *pMode)
1001 VARIANT varresult;
1002 VARIANTARG vararg[1];
1003 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1004 HRESULT hr;
1006 VariantInit(&vararg[0]);
1007 V_VT(&vararg[0]) = VT_I4;
1008 V_I4(&vararg[0]) = iFlag;
1010 hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL);
1011 *pMode = V_BOOL(&varresult);
1012 VariantClear(&varresult);
1013 return hr;
1016 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, BOOL bMode)
1018 VARIANT varresult;
1019 VARIANTARG vararg[2];
1020 DISPID dispid = DISPID_PROPERTYPUT;
1021 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1023 VariantInit(&vararg[1]);
1024 V_VT(&vararg[1]) = VT_I4;
1025 V_I4(&vararg[1]) = iFlag;
1026 VariantInit(&vararg[0]);
1027 V_VT(&vararg[0]) = VT_BOOL;
1028 V_BOOL(&vararg[0]) = bMode;
1030 return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1033 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
1035 VARIANT varresult;
1036 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1037 HRESULT hr;
1039 hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1040 *pDatabase = V_DISPATCH(&varresult);
1041 return hr;
1044 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn)
1046 VARIANT varresult;
1047 VARIANTARG vararg[1];
1048 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1049 HRESULT hr;
1051 VariantInit(&vararg[0]);
1052 V_VT(&vararg[0]) = VT_BSTR;
1053 V_BSTR(&vararg[0]) = SysAllocString(szAction);
1055 hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1056 *iReturn = V_I4(&varresult);
1057 VariantClear(&varresult);
1058 return hr;
1061 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
1063 VARIANT varresult;
1064 VARIANTARG vararg[1];
1065 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1066 HRESULT hr;
1068 VariantInit(&vararg[0]);
1069 V_VT(&vararg[0]) = VT_BSTR;
1070 V_BSTR(&vararg[0]) = SysAllocString(szCondition);
1072 hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1073 *iReturn = V_I4(&varresult);
1074 VariantClear(&varresult);
1075 return hr;
1078 static HRESULT Session_Message(IDispatch *pSession, long kind, IDispatch *record, int *ret)
1080 VARIANT varresult;
1081 VARIANTARG vararg[2];
1082 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1083 HRESULT hr;
1085 VariantInit(&varresult);
1086 V_VT(vararg) = VT_DISPATCH;
1087 V_DISPATCH(vararg) = record;
1088 V_VT(vararg+1) = VT_I4;
1089 V_I4(vararg+1) = kind;
1091 hr = invoke(pSession, "Message", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1093 ok(V_VT(&varresult) == VT_I4, "V_VT(varresult) = %d\n", V_VT(&varresult));
1094 *ret = V_I4(&varresult);
1096 return hr;
1099 static HRESULT Session_SetInstallLevel(IDispatch *pSession, long iInstallLevel)
1101 VARIANT varresult;
1102 VARIANTARG vararg[1];
1103 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1105 VariantInit(&vararg[0]);
1106 V_VT(&vararg[0]) = VT_I4;
1107 V_I4(&vararg[0]) = iInstallLevel;
1109 return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1112 static HRESULT Session_FeatureCurrentState(IDispatch *pSession, LPCWSTR szName, int *pState)
1114 VARIANT varresult;
1115 VARIANTARG vararg[1];
1116 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1117 HRESULT hr;
1119 VariantInit(&vararg[0]);
1120 V_VT(&vararg[0]) = VT_BSTR;
1121 V_BSTR(&vararg[0]) = SysAllocString(szName);
1123 hr = invoke(pSession, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1124 *pState = V_I4(&varresult);
1125 VariantClear(&varresult);
1126 return hr;
1129 static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState)
1131 VARIANT varresult;
1132 VARIANTARG vararg[1];
1133 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1134 HRESULT hr;
1136 VariantInit(&vararg[0]);
1137 V_VT(&vararg[0]) = VT_BSTR;
1138 V_BSTR(&vararg[0]) = SysAllocString(szName);
1140 hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1141 *pState = V_I4(&varresult);
1142 VariantClear(&varresult);
1143 return hr;
1146 static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState)
1148 VARIANT varresult;
1149 VARIANTARG vararg[2];
1150 DISPID dispid = DISPID_PROPERTYPUT;
1151 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1153 VariantInit(&vararg[1]);
1154 V_VT(&vararg[1]) = VT_BSTR;
1155 V_BSTR(&vararg[1]) = SysAllocString(szName);
1156 VariantInit(&vararg[0]);
1157 V_VT(&vararg[0]) = VT_I4;
1158 V_I4(&vararg[0]) = iState;
1160 return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1163 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
1165 VARIANT varresult;
1166 VARIANTARG vararg[1];
1167 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1168 HRESULT hr;
1170 VariantInit(&vararg[0]);
1171 V_VT(&vararg[0]) = VT_BSTR;
1172 V_BSTR(&vararg[0]) = SysAllocString(szSql);
1174 hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1175 *pView = V_DISPATCH(&varresult);
1176 return hr;
1179 static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo)
1181 VARIANT varresult;
1182 VARIANTARG vararg[1];
1183 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1184 HRESULT hr;
1186 VariantInit(&vararg[0]);
1187 V_VT(&vararg[0]) = VT_I4;
1188 V_I4(&vararg[0]) = iUpdateCount;
1190 hr = invoke(pDatabase, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1191 *pSummaryInfo = V_DISPATCH(&varresult);
1192 return hr;
1195 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
1197 VARIANT varresult;
1198 VARIANTARG vararg[1];
1199 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1201 VariantInit(&vararg[0]);
1202 V_VT(&vararg[0]) = VT_DISPATCH;
1203 V_DISPATCH(&vararg[0]) = pRecord;
1205 return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1208 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
1210 VARIANT varresult;
1211 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1212 HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1213 *ppRecord = V_DISPATCH(&varresult);
1214 return hr;
1217 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
1219 VARIANT varresult;
1220 VARIANTARG vararg[2];
1221 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1223 VariantInit(&vararg[1]);
1224 V_VT(&vararg[1]) = VT_I4;
1225 V_I4(&vararg[1]) = iMode;
1226 VariantInit(&vararg[0]);
1227 V_VT(&vararg[0]) = VT_DISPATCH;
1228 V_DISPATCH(&vararg[0]) = pRecord;
1229 if (pRecord)
1230 IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */
1232 return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1235 static HRESULT View_Close(IDispatch *pView)
1237 VARIANT varresult;
1238 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1239 return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1242 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
1244 VARIANT varresult;
1245 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1246 HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1247 *pFieldCount = V_I4(&varresult);
1248 VariantClear(&varresult);
1249 return hr;
1252 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString)
1254 VARIANT varresult;
1255 VARIANTARG vararg[1];
1256 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1257 HRESULT hr;
1259 VariantInit(&vararg[0]);
1260 V_VT(&vararg[0]) = VT_I4;
1261 V_I4(&vararg[0]) = iField;
1263 hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1264 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1265 VariantClear(&varresult);
1266 return hr;
1269 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
1271 VARIANT varresult;
1272 VARIANTARG vararg[2];
1273 DISPID dispid = DISPID_PROPERTYPUT;
1274 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1276 VariantInit(&vararg[1]);
1277 V_VT(&vararg[1]) = VT_I4;
1278 V_I4(&vararg[1]) = iField;
1279 VariantInit(&vararg[0]);
1280 V_VT(&vararg[0]) = VT_BSTR;
1281 V_BSTR(&vararg[0]) = SysAllocString(szString);
1283 return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1286 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
1288 VARIANT varresult;
1289 VARIANTARG vararg[1];
1290 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1291 HRESULT hr;
1293 VariantInit(&vararg[0]);
1294 V_VT(&vararg[0]) = VT_I4;
1295 V_I4(&vararg[0]) = iField;
1297 hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1298 *pValue = V_I4(&varresult);
1299 VariantClear(&varresult);
1300 return hr;
1303 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
1305 VARIANT varresult;
1306 VARIANTARG vararg[2];
1307 DISPID dispid = DISPID_PROPERTYPUT;
1308 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1310 VariantInit(&vararg[1]);
1311 V_VT(&vararg[1]) = VT_I4;
1312 V_I4(&vararg[1]) = iField;
1313 VariantInit(&vararg[0]);
1314 V_VT(&vararg[0]) = VT_I4;
1315 V_I4(&vararg[0]) = iValue;
1317 return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1320 static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT)
1322 VARIANT varresult;
1323 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1324 HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN);
1325 *ppEnumVARIANT = V_UNKNOWN(&varresult);
1326 return hr;
1329 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
1331 VARIANT varresult;
1332 VARIANTARG vararg[1];
1333 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1334 HRESULT hr;
1336 VariantInit(&vararg[0]);
1337 V_VT(&vararg[0]) = VT_I4;
1338 V_I4(&vararg[0]) = iIndex;
1340 hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1341 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1342 VariantClear(&varresult);
1343 return hr;
1346 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
1348 VARIANT varresult;
1349 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1350 HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1351 *pCount = V_I4(&varresult);
1352 VariantClear(&varresult);
1353 return hr;
1356 static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect)
1358 VARIANTARG vararg[1];
1359 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1361 VariantInit(&vararg[0]);
1362 V_VT(&vararg[0]) = VT_I4;
1363 V_I4(&vararg[0]) = pid;
1364 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYGET, &dispparams, pVarResult, vtExpect);
1367 static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant)
1369 VARIANT varresult;
1370 VARIANTARG vararg[2];
1371 DISPID dispid = DISPID_PROPERTYPUT;
1372 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1374 VariantInit(&vararg[1]);
1375 V_VT(&vararg[1]) = VT_I4;
1376 V_I4(&vararg[1]) = pid;
1377 VariantInit(&vararg[0]);
1378 VariantCopyInd(vararg, pVariant);
1380 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1383 static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount)
1385 VARIANT varresult;
1386 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1387 HRESULT hr;
1389 hr = invoke(pSummaryInfo, "PropertyCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1390 *pCount = V_I4(&varresult);
1391 VariantClear(&varresult);
1392 return hr;
1395 /* Test the various objects */
1397 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4
1399 static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly)
1401 static const WCHAR szPropertyException[] = { 'P','r','o','p','e','r','t','y',',','P','i','d',0 };
1402 static const WCHAR szTitle[] = { 'T','i','t','l','e',0 };
1403 VARIANT varresult, var;
1404 SYSTEMTIME st;
1405 HRESULT hr;
1406 int j;
1408 /* SummaryInfo::PropertyCount */
1409 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1410 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1411 ok(j == num_info, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1413 /* SummaryInfo::Property, get for properties we have set */
1414 for (j = 0; j < num_info; j++)
1416 const msi_summary_info *entry = &info[j];
1418 int vt = entry->datatype;
1419 if (vt == VT_LPSTR) vt = VT_BSTR;
1420 else if (vt == VT_FILETIME) vt = VT_DATE;
1421 else if (vt == VT_I2) vt = VT_I4;
1423 hr = SummaryInfo_PropertyGet(pSummaryInfo, entry->property, &varresult, vt);
1424 ok(hr == S_OK, "SummaryInfo_Property (pid %d) failed, hresult 0x%08x\n", entry->property, hr);
1425 if (V_VT(&varresult) != vt)
1426 skip("Skipping property tests due to type mismatch\n");
1427 else if (vt == VT_I4)
1428 ok(V_I4(&varresult) == entry->iValue, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %d\n",
1429 entry->property, entry->iValue, V_I4(&varresult));
1430 else if (vt == VT_DATE)
1432 FILETIME ft;
1433 DATE d;
1435 FileTimeToLocalFileTime(entry->pftValue, &ft);
1436 FileTimeToSystemTime(&ft, &st);
1437 SystemTimeToVariantTime(&st, &d);
1438 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));
1440 else if (vt == VT_BSTR)
1442 ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry->property, entry->szValue, V_BSTR(&varresult));
1444 else
1445 skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry->property, vt);
1447 VariantClear(&varresult);
1450 /* SummaryInfo::Property, get; invalid arguments */
1452 /* Invalid pids */
1453 hr = SummaryInfo_PropertyGet(pSummaryInfo, -1, &varresult, VT_EMPTY);
1454 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1455 ok_exception(hr, szPropertyException);
1457 hr = SummaryInfo_PropertyGet(pSummaryInfo, 1000, &varresult, VT_EMPTY);
1458 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1459 ok_exception(hr, szPropertyException);
1461 /* Unsupported pids */
1462 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_DICTIONARY, &varresult, VT_EMPTY);
1463 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1465 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY);
1466 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1468 /* Pids we have not set, one for each type */
1469 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_EMPTY);
1470 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1472 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY);
1473 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1475 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY);
1476 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1478 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY);
1479 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1481 if (!readonly)
1483 /* SummaryInfo::Property, put; one for each type */
1485 /* VT_I2 */
1486 VariantInit(&var);
1487 V_VT(&var) = VT_I2;
1488 V_I2(&var) = 1;
1489 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CODEPAGE, &var);
1490 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1492 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */);
1493 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1494 ok(V_I2(&var) == V_I2(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var), V_I2(&varresult));
1495 VariantClear(&varresult);
1496 VariantClear(&var);
1498 /* VT_BSTR */
1499 V_VT(&var) = VT_BSTR;
1500 V_BSTR(&var) = SysAllocString(szTitle);
1501 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_TITLE, &var);
1502 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1504 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var));
1505 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1506 ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var), V_BSTR(&varresult));
1507 VariantClear(&varresult);
1508 VariantClear(&var);
1510 /* VT_DATE */
1511 V_VT(&var) = VT_DATE;
1512 FileTimeToSystemTime(&systemtime, &st);
1513 SystemTimeToVariantTime(&st, &V_DATE(&var));
1514 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_LASTSAVE_DTM, &var);
1515 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1517 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var));
1518 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1519 /* FIXME: Off by one second */
1520 todo_wine ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1521 VariantClear(&varresult);
1522 VariantClear(&var);
1524 /* VT_I4 */
1525 V_VT(&var) = VT_I4;
1526 V_I4(&var) = 1000;
1527 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1528 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1530 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1531 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1532 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult));
1533 VariantClear(&varresult);
1534 VariantClear(&var);
1536 /* SummaryInfo::PropertyCount */
1537 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1538 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1539 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1543 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1545 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 };
1546 static WCHAR szThree[] = { 'T','h','r','e','e',0 };
1547 static WCHAR szTwo[] = { 'T','w','o',0 };
1548 static WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
1549 static WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 };
1550 IDispatch *pView = NULL, *pSummaryInfo = NULL;
1551 HRESULT hr;
1553 hr = Database_OpenView(pDatabase, szSql, &pView);
1554 ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr);
1555 if (hr == S_OK)
1557 IDispatch *pRecord = NULL;
1558 WCHAR szString[MAX_PATH];
1560 /* View::Execute */
1561 hr = View_Execute(pView, NULL);
1562 ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr);
1564 /* View::Fetch */
1565 hr = View_Fetch(pView, &pRecord);
1566 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1567 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1568 if (pRecord)
1570 /* Record::StringDataGet */
1571 memset(szString, 0, sizeof(szString));
1572 hr = Record_StringDataGet(pRecord, 1, szString);
1573 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1574 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1576 /* Record::StringDataPut with correct index */
1577 hr = Record_StringDataPut(pRecord, 1, szTwo);
1578 ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1580 /* Record::StringDataGet */
1581 memset(szString, 0, sizeof(szString));
1582 hr = Record_StringDataGet(pRecord, 1, szString);
1583 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1584 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1586 /* Record::StringDataPut with incorrect index */
1587 hr = Record_StringDataPut(pRecord, -1, szString);
1588 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1589 ok_exception(hr, szStringDataField);
1591 /* View::Modify with incorrect parameters */
1592 hr = View_Modify(pView, -5, NULL);
1593 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1594 ok_exception(hr, szModifyModeRecord);
1596 hr = View_Modify(pView, -5, pRecord);
1597 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1598 ok_exception(hr, szModifyModeRecord);
1600 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1601 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1602 ok_exception(hr, szModifyModeRecord);
1604 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1605 ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr);
1607 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1608 memset(szString, 0, sizeof(szString));
1609 hr = Record_StringDataGet(pRecord, 1, szString);
1610 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1611 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1613 IDispatch_Release(pRecord);
1616 /* View::Fetch */
1617 hr = View_Fetch(pView, &pRecord);
1618 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1619 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1620 if (pRecord)
1622 /* Record::StringDataGet */
1623 memset(szString, 0, sizeof(szString));
1624 hr = Record_StringDataGet(pRecord, 1, szString);
1625 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1626 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1628 IDispatch_Release(pRecord);
1631 /* View::Fetch */
1632 hr = View_Fetch(pView, &pRecord);
1633 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1634 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1635 if (pRecord)
1636 IDispatch_Release(pRecord);
1638 /* View::Close */
1639 hr = View_Close(pView);
1640 ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr);
1642 IDispatch_Release(pView);
1645 /* Database::SummaryInformation */
1646 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo);
1647 ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr);
1648 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1649 if (pSummaryInfo)
1651 test_SummaryInfo(pSummaryInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), readonly);
1652 IDispatch_Release(pSummaryInfo);
1656 static void test_Session(IDispatch *pSession)
1658 static WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
1659 static WCHAR szOne[] = { 'O','n','e',0 };
1660 static WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 };
1661 static WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 };
1662 static WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 };
1663 static WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 };
1664 static WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1665 static WCHAR szEmpty[] = { 0 };
1666 static WCHAR szEquals[] = { '=',0 };
1667 static WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
1668 WCHAR stringw[MAX_PATH];
1669 CHAR string[MAX_PATH];
1670 UINT len;
1671 BOOL bool;
1672 int myint;
1673 IDispatch *pDatabase = NULL, *pInst = NULL, *record = NULL;
1674 HRESULT hr;
1676 /* Session::Installer */
1677 hr = Session_Installer(pSession, &pInst);
1678 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1679 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1680 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1682 /* Session::Property, get */
1683 memset(stringw, 0, sizeof(stringw));
1684 hr = Session_PropertyGet(pSession, szProductName, stringw);
1685 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1686 if (lstrcmpW(stringw, szMSITEST) != 0)
1688 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1689 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1690 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1693 /* Session::Property, put */
1694 hr = Session_PropertyPut(pSession, szProductName, szProductName);
1695 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1696 memset(stringw, 0, sizeof(stringw));
1697 hr = Session_PropertyGet(pSession, szProductName, stringw);
1698 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1699 if (lstrcmpW(stringw, szProductName) != 0)
1701 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1702 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1703 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1706 /* Try putting a property using empty property identifier */
1707 hr = Session_PropertyPut(pSession, szEmpty, szProductName);
1708 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1709 ok_exception(hr, szPropertyName);
1711 /* Try putting a property using illegal property identifier */
1712 hr = Session_PropertyPut(pSession, szEquals, szProductName);
1713 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1715 /* Session::Language, get */
1716 hr = Session_LanguageGet(pSession, &len);
1717 ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1718 /* Not sure how to check the language is correct */
1720 /* Session::Mode, get */
1721 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1722 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1723 todo_wine ok(!bool, "Reboot at end session mode is %d\n", bool);
1725 /* Session::Mode, put */
1726 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE);
1727 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1728 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1729 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1730 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1731 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE); /* set it again so we don't reboot */
1732 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1734 /* Session::Database, get */
1735 hr = Session_Database(pSession, &pDatabase);
1736 ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr);
1737 if (hr == S_OK)
1739 test_Database(pDatabase, TRUE);
1740 IDispatch_Release(pDatabase);
1743 /* Session::EvaluateCondition */
1744 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1745 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1746 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1748 hr = Session_EvaluateCondition(pSession, szEmpty, &myint);
1749 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1750 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1752 hr = Session_EvaluateCondition(pSession, szEquals, &myint);
1753 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1754 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1756 /* Session::DoAction(CostInitialize) must occur before the next statements */
1757 hr = Session_DoAction(pSession, szCostInitialize, &myint);
1758 ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr);
1759 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1761 /* Session::SetInstallLevel */
1762 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1763 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
1765 /* Session::FeatureCurrentState, get */
1766 hr = Session_FeatureCurrentState(pSession, szOne, &myint);
1767 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
1768 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1770 /* Session::Message */
1771 hr = Installer_CreateRecord(0, &record);
1772 ok(hr == S_OK, "Installer_CreateRecord failed: %08x\n", hr);
1773 hr = Session_Message(pSession, INSTALLMESSAGE_INFO, record, &myint);
1774 ok(hr == S_OK, "Session_Message failed: %08x\n", hr);
1775 ok(myint == 0, "Session_Message returned %x\n", myint);
1777 /* Session::EvaluateCondition */
1778 hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint);
1779 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1780 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1782 hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint);
1783 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1784 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1786 /* Session::FeatureRequestState, put */
1787 hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED);
1788 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
1789 hr = Session_FeatureRequestStateGet(pSession, szOne, &myint);
1790 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
1791 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
1793 /* Session::EvaluateCondition */
1794 hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint);
1795 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1796 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1798 hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint);
1799 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1800 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1803 /* delete key and all its subkeys */
1804 static DWORD delete_key( HKEY hkey )
1806 char name[MAX_PATH];
1807 DWORD ret;
1809 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
1811 HKEY tmp;
1812 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
1814 ret = delete_key( tmp );
1815 RegCloseKey( tmp );
1817 if (ret) break;
1819 if (ret != ERROR_NO_MORE_ITEMS) return ret;
1820 RegDeleteKeyA( hkey, "" );
1821 return 0;
1824 static void test_Installer_RegistryValue(void)
1826 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
1827 static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 };
1828 static const WCHAR szOne[] = { 'O','n','e',0 };
1829 static const WCHAR szTwo[] = { 'T','w','o',0 };
1830 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
1831 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1832 static const WCHAR szFour[] = { 'F','o','u','r',0 };
1833 static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 };
1834 static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 };
1835 static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 };
1836 static const WCHAR szSix[] = { 'S','i','x',0 };
1837 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1838 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
1839 static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
1840 static const WCHAR szBlank[] = { 0 };
1841 VARIANT varresult;
1842 VARIANTARG vararg;
1843 WCHAR szString[MAX_PATH];
1844 HKEY hkey, hkey_sub;
1845 HKEY curr_user = (HKEY)1;
1846 HRESULT hr;
1847 BOOL bRet;
1849 /* Delete keys */
1850 if (!RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey )) delete_key( hkey );
1852 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
1853 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
1854 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1855 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
1857 memset(szString, 0, sizeof(szString));
1858 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
1859 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1861 memset(szString, 0, sizeof(szString));
1862 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
1863 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1865 /* Create key */
1866 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
1868 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1869 "RegSetValueExW failed\n");
1870 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
1871 "RegSetValueExW failed\n");
1872 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
1873 "RegSetValueExW failed\n");
1874 ok(SetEnvironmentVariableA("MSITEST", "Four"), "SetEnvironmentVariableA failed %d\n", GetLastError());
1875 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
1876 "RegSetValueExW failed\n");
1877 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
1878 "RegSetValueExW failed\n");
1879 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
1880 "RegSetValueExW failed\n");
1881 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, (const BYTE *)NULL, 0),
1882 "RegSetValueExW failed\n");
1884 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1885 "RegSetValueExW failed\n");
1887 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
1889 /* Does our key exist? It should, and make sure we retrieve the correct default value */
1890 bRet = FALSE;
1891 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
1892 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1893 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
1895 memset(szString, 0, sizeof(szString));
1896 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
1897 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1898 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1900 /* Ask for the value of a nonexistent key */
1901 memset(szString, 0, sizeof(szString));
1902 hr = Installer_RegistryValueW(curr_user, szKey, szExpand, szString);
1903 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1905 /* Get values of keys */
1906 memset(szString, 0, sizeof(szString));
1907 hr = Installer_RegistryValueW(curr_user, szKey, szOne, szString);
1908 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1909 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1911 VariantInit(&vararg);
1912 V_VT(&vararg) = VT_BSTR;
1913 V_BSTR(&vararg) = SysAllocString(szTwo);
1914 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_I4);
1915 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1916 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
1917 VariantClear(&varresult);
1919 memset(szString, 0, sizeof(szString));
1920 hr = Installer_RegistryValueW(curr_user, szKey, szThree, szString);
1921 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1922 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
1924 memset(szString, 0, sizeof(szString));
1925 hr = Installer_RegistryValueW(curr_user, szKey, szFour, szString);
1926 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1927 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
1929 memset(szString, 0, sizeof(szString));
1930 hr = Installer_RegistryValueW(curr_user, szKey, szFive, szString);
1931 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1932 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFiveHi);
1934 memset(szString, 0, sizeof(szString));
1935 hr = Installer_RegistryValueW(curr_user, szKey, szSix, szString);
1936 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1937 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_);
1939 VariantInit(&vararg);
1940 V_VT(&vararg) = VT_BSTR;
1941 V_BSTR(&vararg) = SysAllocString(szSeven);
1942 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_EMPTY);
1943 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1945 /* Get string class name for the key */
1946 memset(szString, 0, sizeof(szString));
1947 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
1948 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1949 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank);
1951 /* Get name of a value by positive number (RegEnumValue like), valid index */
1952 memset(szString, 0, sizeof(szString));
1953 hr = Installer_RegistryValueI(curr_user, szKey, 2, szString, VT_BSTR);
1954 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1955 /* RegEnumValue order seems different on wine */
1956 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
1958 /* Get name of a value by positive number (RegEnumValue like), invalid index */
1959 memset(szString, 0, sizeof(szString));
1960 hr = Installer_RegistryValueI(curr_user, szKey, 10, szString, VT_EMPTY);
1961 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1963 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
1964 memset(szString, 0, sizeof(szString));
1965 hr = Installer_RegistryValueI(curr_user, szKey, -1, szString, VT_BSTR);
1966 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1967 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
1969 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
1970 memset(szString, 0, sizeof(szString));
1971 hr = Installer_RegistryValueI(curr_user, szKey, -10, szString, VT_EMPTY);
1972 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1974 /* clean up */
1975 delete_key(hkey);
1978 static void test_Installer_Products(BOOL bProductInstalled)
1980 WCHAR szString[MAX_PATH];
1981 HRESULT hr;
1982 int idx;
1983 IUnknown *pUnk = NULL;
1984 IEnumVARIANT *pEnum = NULL;
1985 VARIANT var;
1986 ULONG celt;
1987 int iCount, iValue;
1988 IDispatch *pStringList = NULL;
1989 BOOL bProductFound = FALSE;
1991 /* Installer::Products */
1992 hr = Installer_Products(&pStringList);
1993 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
1994 if (hr == S_OK)
1996 /* StringList::_NewEnum */
1997 hr = StringList__NewEnum(pStringList, &pUnk);
1998 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
1999 if (hr == S_OK)
2001 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
2002 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2004 if (!pEnum)
2005 skip("IEnumVARIANT tests\n");
2007 /* StringList::Count */
2008 hr = StringList_Count(pStringList, &iCount);
2009 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2011 for (idx=0; idx<iCount; idx++)
2013 /* StringList::Item */
2014 memset(szString, 0, sizeof(szString));
2015 hr = StringList_Item(pStringList, idx, szString);
2016 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2018 if (hr == S_OK)
2020 /* Installer::ProductState */
2021 hr = Installer_ProductState(szString, &iValue);
2022 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2023 if (hr == S_OK)
2024 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
2026 /* Not found our product code yet? Check */
2027 if (!bProductFound && !lstrcmpW(szString, szProductCode))
2028 bProductFound = TRUE;
2030 /* IEnumVARIANT::Next */
2031 if (pEnum)
2033 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2034 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2035 ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
2036 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2037 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2038 VariantClear(&var);
2043 if (bProductInstalled) todo_wine
2045 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
2046 bProductInstalled ? "be" : "not be",
2047 bProductFound ? "found" : "not found");
2050 if (pEnum)
2052 IEnumVARIANT *pEnum2 = NULL;
2054 if (0) /* Crashes on Windows XP */
2056 /* IEnumVARIANT::Clone, NULL pointer */
2057 hr = IEnumVARIANT_Clone(pEnum, NULL);
2060 /* IEnumVARIANT::Clone */
2061 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
2062 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
2063 if (hr == S_OK)
2065 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
2067 /* IEnumVARIANT::Next of the clone */
2068 if (iCount)
2070 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
2071 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2072 ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
2073 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2074 VariantClear(&var);
2076 else
2077 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
2079 IEnumVARIANT_Release(pEnum2);
2082 /* IEnumVARIANT::Skip should fail */
2083 hr = IEnumVARIANT_Skip(pEnum, 1);
2084 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2086 /* IEnumVARIANT::Next, NULL variant pointer */
2087 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2088 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2089 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2091 /* IEnumVARIANT::Next, should not return any more items */
2092 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2093 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2094 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2095 VariantClear(&var);
2097 /* IEnumVARIANT::Reset */
2098 hr = IEnumVARIANT_Reset(pEnum);
2099 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2101 if (iCount)
2103 /* IEnumVARIANT::Skip to the last product */
2104 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2105 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2107 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2108 * NULL celt pointer. */
2109 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2110 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2111 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2112 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2113 VariantClear(&var);
2115 else
2116 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2119 /* StringList::Item using an invalid index */
2120 memset(szString, 0, sizeof(szString));
2121 hr = StringList_Item(pStringList, iCount, szString);
2122 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2124 if (pEnum) IEnumVARIANT_Release(pEnum);
2125 if (pUnk) IUnknown_Release(pUnk);
2126 IDispatch_Release(pStringList);
2130 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2131 * deleting the subkeys first) */
2132 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey)
2134 UINT ret;
2135 CHAR *string = NULL;
2136 HKEY hkey;
2137 DWORD dwSize;
2139 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2140 if (ret != ERROR_SUCCESS) return ret;
2141 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2142 if (ret != ERROR_SUCCESS) return ret;
2143 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2145 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2146 delete_registry_key(hkey, string);
2148 RegCloseKey(hkey);
2149 HeapFree(GetProcessHeap(), 0, string);
2150 RegDeleteKeyA(hkeyParent, subkey);
2151 return ERROR_SUCCESS;
2154 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2155 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, HKEY *phkey)
2157 UINT ret;
2158 CHAR *string = NULL;
2159 int idx = 0;
2160 HKEY hkey;
2161 DWORD dwSize;
2162 BOOL found = FALSE;
2164 *phkey = 0;
2166 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2167 if (ret != ERROR_SUCCESS) return ret;
2168 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2169 if (ret != ERROR_SUCCESS) return ret;
2170 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2172 while (!found &&
2173 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2175 if (!strcmp(string, findkey))
2177 *phkey = hkey;
2178 found = TRUE;
2180 else if (find_registry_key(hkey, string, findkey, phkey) == ERROR_SUCCESS) found = TRUE;
2183 if (*phkey != hkey) RegCloseKey(hkey);
2184 HeapFree(GetProcessHeap(), 0, string);
2185 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2188 static void test_Installer_InstallProduct(void)
2190 HRESULT hr;
2191 CHAR path[MAX_PATH];
2192 WCHAR szString[MAX_PATH];
2193 LONG res;
2194 HKEY hkey;
2195 DWORD num, size, type;
2196 int iValue, iCount;
2197 IDispatch *pStringList = NULL;
2199 create_test_files();
2201 /* Installer::InstallProduct */
2202 hr = Installer_InstallProduct(szMsifile, NULL);
2203 if (hr == DISP_E_EXCEPTION)
2205 skip("Installer object not supported.\n");
2206 delete_test_files();
2207 return;
2209 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2211 /* Installer::ProductState for our product code, which has been installed */
2212 hr = Installer_ProductState(szProductCode, &iValue);
2213 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2214 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2216 /* Installer::ProductInfo for our product code */
2218 /* NULL attribute */
2219 memset(szString, 0, sizeof(szString));
2220 hr = Installer_ProductInfo(szProductCode, NULL, szString);
2221 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2222 ok_exception(hr, szProductInfoException);
2224 /* Nonexistent attribute */
2225 memset(szString, 0, sizeof(szString));
2226 hr = Installer_ProductInfo(szProductCode, szMsifile, szString);
2227 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2228 ok_exception(hr, szProductInfoException);
2230 /* Package name */
2231 memset(szString, 0, sizeof(szString));
2232 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szString);
2233 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2234 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile);
2236 /* Product name */
2237 memset(szString, 0, sizeof(szString));
2238 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PRODUCTNAMEW, szString);
2239 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2240 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST);
2242 /* Installer::Products */
2243 test_Installer_Products(TRUE);
2245 /* Installer::RelatedProducts for our upgrade code */
2246 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2247 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2248 if (hr == S_OK)
2250 /* StringList::Count */
2251 hr = StringList_Count(pStringList, &iCount);
2252 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2253 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2255 /* StringList::Item */
2256 memset(szString, 0, sizeof(szString));
2257 hr = StringList_Item(pStringList, 0, szString);
2258 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2259 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
2261 IDispatch_Release(pStringList);
2264 /* Check & clean up installed files & registry keys */
2265 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2266 ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
2267 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2268 ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
2269 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2270 ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
2271 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2272 ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
2273 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2274 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2275 ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
2276 ok(delete_pf("msitest", FALSE), "File not installed\n");
2278 res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
2279 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2281 size = MAX_PATH;
2282 type = REG_SZ;
2283 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2284 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2285 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2287 size = MAX_PATH;
2288 type = REG_SZ;
2289 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2290 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2292 size = sizeof(num);
2293 type = REG_DWORD;
2294 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2295 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2296 ok(num == 314, "Expected 314, got %d\n", num);
2298 size = MAX_PATH;
2299 type = REG_SZ;
2300 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2301 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2302 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2304 RegCloseKey(hkey);
2306 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest");
2307 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2309 check_service_is_installed();
2311 /* Remove registry keys written by RegisterProduct standard action */
2312 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F1C3AF50-8B56-4A69-A00C-00773FE42F30}");
2313 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2315 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2316 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2318 res = find_registry_key(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "05FA3C1F65B896A40AC00077F34EF203", &hkey);
2319 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2320 if (res == ERROR_SUCCESS)
2322 res = delete_registry_key(hkey, "05FA3C1F65B896A40AC00077F34EF203");
2323 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2324 RegCloseKey(hkey);
2327 /* Remove registry keys written by PublishProduct standard action */
2328 res = RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2329 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2331 res = delete_registry_key(hkey, "Products\\05FA3C1F65B896A40AC00077F34EF203");
2332 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2334 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2335 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2337 RegCloseKey(hkey);
2339 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203");
2340 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2342 /* Delete installation files we installed */
2343 delete_test_files();
2346 static void test_Installer(void)
2348 static WCHAR szBackslash[] = { '\\',0 };
2349 static WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
2350 static WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
2351 WCHAR szPath[MAX_PATH];
2352 HRESULT hr;
2353 UINT len;
2354 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL;
2355 int iValue, iCount;
2357 if (!pInstaller) return;
2359 /* Installer::CreateRecord */
2361 /* Test for error */
2362 hr = Installer_CreateRecord(-1, &pRecord);
2363 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2364 ok_exception(hr, szCreateRecordException);
2366 /* Test for success */
2367 hr = Installer_CreateRecord(1, &pRecord);
2368 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2369 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2370 if (pRecord)
2372 /* Record::FieldCountGet */
2373 hr = Record_FieldCountGet(pRecord, &iValue);
2374 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2375 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2377 /* Record::IntegerDataGet */
2378 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2379 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2380 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2382 /* Record::IntegerDataGet, bad index */
2383 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2384 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2385 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2387 /* Record::IntegerDataPut */
2388 hr = Record_IntegerDataPut(pRecord, 1, 100);
2389 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2391 /* Record::IntegerDataPut, bad index */
2392 hr = Record_IntegerDataPut(pRecord, 10, 100);
2393 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2394 ok_exception(hr, szIntegerDataException);
2396 /* Record::IntegerDataGet */
2397 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2398 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2399 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2401 IDispatch_Release(pRecord);
2404 /* Prepare package */
2405 create_database(msifile, tables, sizeof(tables) / sizeof(msi_table),
2406 summary_info, sizeof(summary_info) / sizeof(msi_summary_info));
2408 len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, CURR_DIR, -1, szPath, MAX_PATH);
2409 ok(len, "MultiByteToWideChar returned error %d\n", GetLastError());
2410 if (!len) return;
2412 lstrcatW(szPath, szBackslash);
2413 lstrcatW(szPath, szMsifile);
2415 /* Installer::OpenPackage */
2416 hr = Installer_OpenPackage(szPath, 0, &pSession);
2417 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2418 if (hr == S_OK)
2420 test_Session(pSession);
2421 IDispatch_Release(pSession);
2424 /* Installer::OpenDatabase */
2425 hr = Installer_OpenDatabase(szPath, (int)MSIDBOPEN_TRANSACT, &pDatabase);
2426 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2427 if (hr == S_OK)
2429 test_Database(pDatabase, FALSE);
2430 IDispatch_Release(pDatabase);
2433 /* Installer::RegistryValue */
2434 test_Installer_RegistryValue();
2436 /* Installer::ProductState for our product code, which should not be installed */
2437 hr = Installer_ProductState(szProductCode, &iValue);
2438 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2439 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2441 /* Installer::ProductInfo for our product code, which should not be installed */
2443 /* Package name */
2444 memset(szPath, 0, sizeof(szPath));
2445 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szPath);
2446 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2447 ok_exception(hr, szProductInfoException);
2449 /* NULL attribute and NULL product code */
2450 memset(szPath, 0, sizeof(szPath));
2451 hr = Installer_ProductInfo(NULL, NULL, szPath);
2452 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2453 ok_exception(hr, szProductInfoException);
2455 /* Installer::Products */
2456 test_Installer_Products(FALSE);
2458 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2459 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2460 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2461 if (hr == S_OK)
2463 /* StringList::Count */
2464 hr = StringList_Count(pStringList, &iCount);
2465 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2466 ok(!iCount, "Expected no related products but found %d\n", iCount);
2468 IDispatch_Release(pStringList);
2471 /* Installer::Version */
2472 memset(szPath, 0, sizeof(szPath));
2473 hr = Installer_VersionGet(szPath);
2474 ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr);
2476 /* Installer::InstallProduct and other tests that depend on our product being installed */
2477 test_Installer_InstallProduct();
2480 START_TEST(automation)
2482 DWORD len;
2483 char temp_path[MAX_PATH], prev_path[MAX_PATH];
2484 HRESULT hr;
2485 CLSID clsid;
2486 IUnknown *pUnk;
2488 GetSystemTimeAsFileTime(&systemtime);
2490 GetCurrentDirectoryA(MAX_PATH, prev_path);
2491 GetTempPath(MAX_PATH, temp_path);
2492 SetCurrentDirectoryA(temp_path);
2494 lstrcpyA(CURR_DIR, temp_path);
2495 len = lstrlenA(CURR_DIR);
2497 if(len && (CURR_DIR[len - 1] == '\\'))
2498 CURR_DIR[len - 1] = 0;
2500 get_program_files_dir(PROG_FILES_DIR);
2502 hr = OleInitialize(NULL);
2503 ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr);
2504 hr = CLSIDFromProgID(szProgId, &clsid);
2505 ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr);
2506 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2507 ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr);
2509 if (pUnk)
2511 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2512 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2514 test_dispid();
2515 test_dispatch();
2516 test_Installer();
2518 IDispatch_Release(pInstaller);
2519 IUnknown_Release(pUnk);
2522 OleUninitialize();
2524 SetCurrentDirectoryA(prev_path);