richedit: Removed useless code.
[wine/wine-kai.git] / dlls / msi / tests / automation.c
blobf2e5c13abe461961e001d80afaf5b9362f0c00d3
1 /*
2 * Copyright (C) 2007 Mike McCormack for CodeWeavers
3 * Copyright (C) 2007 Misha Koshelev
5 * A test program for Microsoft Installer OLE automation functionality.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
24 #include <stdio.h>
26 #include <windows.h>
27 #include <msiquery.h>
28 #include <msidefs.h>
29 #include <msi.h>
30 #include <fci.h>
32 #include "wine/test.h"
34 static const char *msifile = "winetest.msi";
35 static const WCHAR szMsifile[] = {'w','i','n','e','t','e','s','t','.','m','s','i',0};
36 static const WCHAR szMSITEST[] = { 'M','S','I','T','E','S','T',0 };
37 static const WCHAR szProductCode[] = { '{','F','1','C','3','A','F','5','0','-','8','B','5','6','-','4','A','6','9','-','A','0','0','C','-','0','0','7','7','3','F','E','4','2','F','3','0','}',0 };
38 static const WCHAR szUpgradeCode[] = { '{','C','E','0','6','7','E','8','D','-','2','E','1','A','-','4','3','6','7','-','B','7','3','4','-','4','E','B','2','B','D','A','D','6','5','6','5','}',0 };
39 static const WCHAR szProductInfoException[] = { 'P','r','o','d','u','c','t','I','n','f','o',',','P','r','o','d','u','c','t',',','A','t','t','r','i','b','u','t','e',0 };
40 static const WCHAR WINE_INSTALLPROPERTY_PACKAGENAMEW[] = {'P','a','c','k','a','g','e','N','a','m','e',0};
41 static const WCHAR WINE_INSTALLPROPERTY_PRODUCTNAMEW[] = {'P','r','o','d','u','c','t','N','a','m','e',0};
42 static FILETIME systemtime;
43 static CHAR CURR_DIR[MAX_PATH];
44 static EXCEPINFO excepinfo;
47 * OLE automation data
48 **/
49 static const WCHAR szProgId[] = { 'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r','.','I','n','s','t','a','l','l','e','r',0 };
50 static IDispatch *pInstaller;
52 /* msi database data */
54 static const CHAR component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
55 "s72\tS38\ts72\ti2\tS255\tS72\n"
56 "Component\tComponent\n"
57 "Five\t{8CC92E9D-14B2-4CA4-B2AA-B11D02078087}\tNEWDIR\t2\t\tfive.txt\n"
58 "Four\t{FD37B4EA-7209-45C0-8917-535F35A2F080}\tCABOUTDIR\t2\t\tfour.txt\n"
59 "One\t{783B242E-E185-4A56-AF86-C09815EC053C}\tMSITESTDIR\t2\t\tone.txt\n"
60 "Three\t{010B6ADD-B27D-4EDD-9B3D-34C4F7D61684}\tCHANGEDDIR\t2\t\tthree.txt\n"
61 "Two\t{BF03D1A6-20DA-4A65-82F3-6CAC995915CE}\tFIRSTDIR\t2\t\ttwo.txt\n"
62 "dangler\t{6091DF25-EF96-45F1-B8E9-A9B1420C7A3C}\tTARGETDIR\t4\t\tregdata\n"
63 "component\t\tMSITESTDIR\t0\t1\tfile\n"
64 "service_comp\t\tMSITESTDIR\t0\t1\tservice_file";
66 static const CHAR directory_dat[] = "Directory\tDirectory_Parent\tDefaultDir\n"
67 "s72\tS72\tl255\n"
68 "Directory\tDirectory\n"
69 "CABOUTDIR\tMSITESTDIR\tcabout\n"
70 "CHANGEDDIR\tMSITESTDIR\tchanged:second\n"
71 "FIRSTDIR\tMSITESTDIR\tfirst\n"
72 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
73 "NEWDIR\tCABOUTDIR\tnew\n"
74 "ProgramFilesFolder\tTARGETDIR\t.\n"
75 "TARGETDIR\t\tSourceDir";
77 static const CHAR feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
78 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
79 "Feature\tFeature\n"
80 "Five\t\tFive\tThe Five Feature\t5\t3\tNEWDIR\t0\n"
81 "Four\t\tFour\tThe Four Feature\t4\t3\tCABOUTDIR\t0\n"
82 "One\t\tOne\tThe One Feature\t1\t3\tMSITESTDIR\t0\n"
83 "Three\tOne\tThree\tThe Three Feature\t3\t3\tCHANGEDDIR\t0\n"
84 "Two\tOne\tTwo\tThe Two Feature\t2\t3\tFIRSTDIR\t0\n"
85 "feature\t\t\t\t2\t1\tTARGETDIR\t0\n"
86 "service_feature\t\t\t\t2\t1\tTARGETDIR\t0";
88 static const CHAR feature_comp_dat[] = "Feature_\tComponent_\n"
89 "s38\ts72\n"
90 "FeatureComponents\tFeature_\tComponent_\n"
91 "Five\tFive\n"
92 "Four\tFour\n"
93 "One\tOne\n"
94 "Three\tThree\n"
95 "Two\tTwo\n"
96 "feature\tcomponent\n"
97 "service_feature\tservice_comp\n";
99 static const CHAR file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
100 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
101 "File\tFile\n"
102 "five.txt\tFive\tfive.txt\t1000\t\t\t0\t5\n"
103 "four.txt\tFour\tfour.txt\t1000\t\t\t0\t4\n"
104 "one.txt\tOne\tone.txt\t1000\t\t\t0\t1\n"
105 "three.txt\tThree\tthree.txt\t1000\t\t\t0\t3\n"
106 "two.txt\tTwo\ttwo.txt\t1000\t\t\t0\t2\n"
107 "file\tcomponent\tfilename\t100\t\t\t8192\t1\n"
108 "service_file\tservice_comp\tservice.exe\t100\t\t\t8192\t1";
110 static const CHAR install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
111 "s72\tS255\tI2\n"
112 "InstallExecuteSequence\tAction\n"
113 "AllocateRegistrySpace\tNOT Installed\t1550\n"
114 "CostFinalize\t\t1000\n"
115 "CostInitialize\t\t800\n"
116 "FileCost\t\t900\n"
117 "InstallFiles\t\t4000\n"
118 "InstallServices\t\t5000\n"
119 "RegisterProduct\t\t6100\n"
120 "PublishProduct\t\t6400\n"
121 "InstallFinalize\t\t6600\n"
122 "InstallInitialize\t\t1500\n"
123 "InstallValidate\t\t1400\n"
124 "LaunchConditions\t\t100\n"
125 "WriteRegistryValues\tSourceDir And SOURCEDIR\t5000";
127 static const CHAR media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
128 "i2\ti4\tL64\tS255\tS32\tS72\n"
129 "Media\tDiskId\n"
130 "1\t5\t\t\tDISK1\t\n";
132 static const CHAR property_dat[] = "Property\tValue\n"
133 "s72\tl0\n"
134 "Property\tProperty\n"
135 "DefaultUIFont\tDlgFont8\n"
136 "HASUIRUN\t0\n"
137 "INSTALLLEVEL\t3\n"
138 "InstallMode\tTypical\n"
139 "Manufacturer\tWine\n"
140 "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n"
141 "ProductCode\t{F1C3AF50-8B56-4A69-A00C-00773FE42F30}\n"
142 "ProductID\tnone\n"
143 "ProductLanguage\t1033\n"
144 "ProductName\tMSITEST\n"
145 "ProductVersion\t1.1.1\n"
146 "PROMPTROLLBACKCOST\tP\n"
147 "Setup\tSetup\n"
148 "UpgradeCode\t{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}";
150 static const CHAR registry_dat[] = "Registry\tRoot\tKey\tName\tValue\tComponent_\n"
151 "s72\ti2\tl255\tL255\tL0\ts72\n"
152 "Registry\tRegistry\n"
153 "Apples\t2\tSOFTWARE\\Wine\\msitest\tName\timaname\tOne\n"
154 "Oranges\t2\tSOFTWARE\\Wine\\msitest\tnumber\t#314\tTwo\n"
155 "regdata\t2\tSOFTWARE\\Wine\\msitest\tblah\tbad\tdangler\n"
156 "OrderTest\t2\tSOFTWARE\\Wine\\msitest\tOrderTestName\tOrderTestValue\tcomponent";
158 static const CHAR service_install_dat[] = "ServiceInstall\tName\tDisplayName\tServiceType\tStartType\tErrorControl\t"
159 "LoadOrderGroup\tDependencies\tStartName\tPassword\tArguments\tComponent_\tDescription\n"
160 "s72\ts255\tL255\ti4\ti4\ti4\tS255\tS255\tS255\tS255\tS255\ts72\tL255\n"
161 "ServiceInstall\tServiceInstall\n"
162 "TestService\tTestService\tTestService\t2\t3\t0\t\t\tTestService\t\t\tservice_comp\t\t";
164 static const CHAR service_control_dat[] = "ServiceControl\tName\tEvent\tArguments\tWait\tComponent_\n"
165 "s72\tl255\ti2\tL255\tI2\ts72\n"
166 "ServiceControl\tServiceControl\n"
167 "ServiceControl\tTestService\t8\t\t0\tservice_comp";
169 typedef struct _msi_table
171 const CHAR *filename;
172 const CHAR *data;
173 int size;
174 } msi_table;
176 #define ADD_TABLE(x) {#x".idt", x##_dat, sizeof(x##_dat)}
178 static const msi_table tables[] =
180 ADD_TABLE(component),
181 ADD_TABLE(directory),
182 ADD_TABLE(feature),
183 ADD_TABLE(feature_comp),
184 ADD_TABLE(file),
185 ADD_TABLE(install_exec_seq),
186 ADD_TABLE(media),
187 ADD_TABLE(property),
188 ADD_TABLE(registry),
189 ADD_TABLE(service_install),
190 ADD_TABLE(service_control)
193 typedef struct _msi_summary_info
195 UINT property;
196 UINT datatype;
197 INT iValue;
198 FILETIME *pftValue;
199 const CHAR *szValue;
200 } msi_summary_info;
202 #define ADD_INFO_I2(property, iValue) {property, VT_I2, iValue, NULL, NULL}
203 #define ADD_INFO_I4(property, iValue) {property, VT_I4, iValue, NULL, NULL}
204 #define ADD_INFO_LPSTR(property, szValue) {property, VT_LPSTR, 0, NULL, szValue}
205 #define ADD_INFO_FILETIME(property, pftValue) {property, VT_FILETIME, 0, pftValue, NULL}
207 static const msi_summary_info summary_info[] =
209 ADD_INFO_LPSTR(PID_TEMPLATE, ";1033"),
210 ADD_INFO_LPSTR(PID_REVNUMBER, "{004757CA-5092-49c2-AD20-28E1CE0DF5F2}"),
211 ADD_INFO_I4(PID_PAGECOUNT, 100),
212 ADD_INFO_I4(PID_WORDCOUNT, 0),
213 ADD_INFO_FILETIME(PID_CREATE_DTM, &systemtime),
214 ADD_INFO_FILETIME(PID_LASTPRINTED, &systemtime)
218 * Database Helpers
221 static void write_file(const CHAR *filename, const char *data, int data_size)
223 DWORD size;
225 HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL,
226 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
228 WriteFile(hf, data, data_size, &size, NULL);
229 CloseHandle(hf);
232 static void write_msi_summary_info(MSIHANDLE db, const msi_summary_info *info, int num_info)
234 MSIHANDLE summary;
235 UINT r;
236 int j;
238 r = MsiGetSummaryInformationA(db, NULL, num_info, &summary);
239 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
241 /* import summary information into the stream */
242 for (j = 0; j < num_info; j++)
244 const msi_summary_info *entry = &info[j];
246 r = MsiSummaryInfoSetPropertyA(summary, entry->property, entry->datatype,
247 entry->iValue, entry->pftValue, entry->szValue);
248 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
251 /* write the summary changes back to the stream */
252 r = MsiSummaryInfoPersist(summary);
253 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
255 MsiCloseHandle(summary);
258 static void create_database(const CHAR *name, const msi_table *tables, int num_tables,
259 const msi_summary_info *info, int num_info)
261 MSIHANDLE db;
262 UINT r;
263 int j;
265 r = MsiOpenDatabaseA(name, MSIDBOPEN_CREATE, &db);
266 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
268 /* import the tables into the database */
269 for (j = 0; j < num_tables; j++)
271 const msi_table *table = &tables[j];
273 write_file(table->filename, table->data, (table->size - 1) * sizeof(char));
275 r = MsiDatabaseImportA(db, CURR_DIR, table->filename);
276 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
278 DeleteFileA(table->filename);
281 write_msi_summary_info(db, info, num_info);
283 r = MsiDatabaseCommit(db);
284 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
286 MsiCloseHandle(db);
290 * Installation helpers
293 static char PROG_FILES_DIR[MAX_PATH];
295 static BOOL get_program_files_dir(LPSTR buf)
297 HKEY hkey;
298 DWORD type = REG_EXPAND_SZ, size;
300 if (RegOpenKey(HKEY_LOCAL_MACHINE,
301 "Software\\Microsoft\\Windows\\CurrentVersion", &hkey))
302 return FALSE;
304 size = MAX_PATH;
305 if (RegQueryValueEx(hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size))
306 return FALSE;
308 RegCloseKey(hkey);
309 return TRUE;
312 static void create_file(const CHAR *name, DWORD size)
314 HANDLE file;
315 DWORD written, left;
317 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
318 ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
319 WriteFile(file, name, strlen(name), &written, NULL);
320 WriteFile(file, "\n", strlen("\n"), &written, NULL);
322 left = size - lstrlen(name) - 1;
324 SetFilePointer(file, left, NULL, FILE_CURRENT);
325 SetEndOfFile(file);
327 CloseHandle(file);
330 static void create_test_files(void)
332 CreateDirectoryA("msitest", NULL);
333 create_file("msitest\\one.txt", 100);
334 CreateDirectoryA("msitest\\first", NULL);
335 create_file("msitest\\first\\two.txt", 100);
336 CreateDirectoryA("msitest\\second", NULL);
337 create_file("msitest\\second\\three.txt", 100);
338 CreateDirectoryA("msitest\\cabout",NULL);
339 create_file("msitest\\cabout\\four.txt", 100);
340 CreateDirectoryA("msitest\\cabout\\new",NULL);
341 create_file("msitest\\cabout\\new\\five.txt", 100);
342 create_file("msitest\\filename", 100);
343 create_file("msitest\\service.exe", 100);
346 static BOOL delete_pf(const CHAR *rel_path, BOOL is_file)
348 CHAR path[MAX_PATH];
350 lstrcpyA(path, PROG_FILES_DIR);
351 lstrcatA(path, "\\");
352 lstrcatA(path, rel_path);
354 if (is_file)
355 return DeleteFileA(path);
356 else
357 return RemoveDirectoryA(path);
360 static void delete_test_files(void)
362 DeleteFileA(msifile);
363 DeleteFileA("msitest\\cabout\\new\\five.txt");
364 DeleteFileA("msitest\\cabout\\four.txt");
365 DeleteFileA("msitest\\second\\three.txt");
366 DeleteFileA("msitest\\first\\two.txt");
367 DeleteFileA("msitest\\one.txt");
368 DeleteFileA("msitest\\service.exe");
369 DeleteFileA("msitest\\filename");
370 RemoveDirectoryA("msitest\\cabout\\new");
371 RemoveDirectoryA("msitest\\cabout");
372 RemoveDirectoryA("msitest\\second");
373 RemoveDirectoryA("msitest\\first");
374 RemoveDirectoryA("msitest");
377 static void check_service_is_installed(void)
379 SC_HANDLE scm, service;
380 BOOL res;
382 scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
383 ok(scm != NULL, "Failed to open the SC Manager\n");
385 service = OpenService(scm, "TestService", SC_MANAGER_ALL_ACCESS);
386 ok(service != NULL, "Failed to open TestService\n");
388 res = DeleteService(service);
389 ok(res, "Failed to delete TestService\n");
391 CloseServiceHandle(service);
392 CloseServiceHandle(scm);
396 * Automation helpers and tests
399 /* ok-like statement which takes two unicode strings or one unicode and one ANSI string as arguments */
400 static CHAR string1[MAX_PATH], string2[MAX_PATH];
402 #define ok_w2(format, szString1, szString2) \
404 if (lstrcmpW(szString1, szString2) != 0) \
406 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
407 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
408 ok(0, format, string1, string2); \
411 #define ok_aw(format, aString, wString) \
413 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
414 if (lstrcmpA(string1, aString) != 0) \
415 ok(0, format, string1, aString); \
417 #define ok_awplus(format, extra, aString, wString) \
419 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
420 if (lstrcmpA(string1, aString) != 0) \
421 ok(0, format, extra, string1, aString); \
423 /* exception checker */
424 static WCHAR szSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
426 #define ok_exception(hr, szDescription) \
427 if (hr == DISP_E_EXCEPTION) \
429 /* Compare wtype, source, and destination */ \
430 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
432 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
433 if (excepinfo.bstrSource) \
434 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, szSource); \
436 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
437 if (excepinfo.bstrDescription) \
438 ok_w2("Exception description was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrDescription, szDescription); \
440 SysFreeString(excepinfo.bstrSource); \
441 SysFreeString(excepinfo.bstrDescription); \
442 SysFreeString(excepinfo.bstrHelpFile); \
445 static DISPID get_dispid( IDispatch *disp, const char *name )
447 LPOLESTR str;
448 UINT len;
449 DISPID id = -1;
450 HRESULT r;
452 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
453 str = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
454 if (str)
456 len = MultiByteToWideChar(CP_ACP, 0, name, -1, str, len );
457 r = IDispatch_GetIDsOfNames( disp, &IID_NULL, &str, 1, 0, &id );
458 HeapFree(GetProcessHeap(), 0, str);
459 if (r != S_OK)
460 return -1;
463 return id;
466 static void test_dispid(void)
468 DISPID dispid;
470 dispid = get_dispid(pInstaller, "CreateRecord");
471 ok(dispid == 1, "Expected 1, got %d\n", dispid);
472 dispid = get_dispid(pInstaller, "OpenPackage");
473 ok(dispid == 2, "Expected 2, got %d\n", dispid);
474 dispid = get_dispid(pInstaller, "OpenDatabase");
475 ok(dispid == 4, "Expected 4, got %d\n", dispid);
476 dispid = get_dispid( pInstaller, "UILevel" );
477 ok(dispid == 6, "Expected 6, got %d\n", dispid);
478 dispid = get_dispid(pInstaller, "InstallProduct");
479 ok(dispid == 8, "Expected 8, got %d\n", dispid);
480 dispid = get_dispid(pInstaller, "Version");
481 ok(dispid == 9, "Expected 9, got %d\n", dispid);
482 dispid = get_dispid(pInstaller, "RegistryValue");
483 ok(dispid == 11, "Expected 11, got %d\n", dispid);
484 todo_wine
486 dispid = get_dispid(pInstaller, "OpenProduct");
487 ok(dispid == 3, "Expected 3, got %d\n", dispid);
488 dispid = get_dispid(pInstaller, "SummaryInformation");
489 ok(dispid == 5, "Expected 5, got %d\n", dispid);
490 dispid = get_dispid(pInstaller, "EnableLog");
491 ok(dispid == 7, "Expected 7, got %d\n", dispid);
492 dispid = get_dispid(pInstaller, "LastErrorRecord");
493 ok(dispid == 10, "Expected 10, got %d\n", dispid);
494 dispid = get_dispid(pInstaller, "Environment");
495 ok(dispid == 12, "Expected 12, got %d\n", dispid);
496 dispid = get_dispid(pInstaller, "FileAttributes");
497 ok(dispid == 13, "Expected 13, got %d\n", dispid);
498 dispid = get_dispid(pInstaller, "FileSize");
499 ok(dispid == 15, "Expected 15, got %d\n", dispid);
500 dispid = get_dispid(pInstaller, "FileVersion");
501 ok(dispid == 16, "Expected 16, got %d\n", dispid);
503 dispid = get_dispid(pInstaller, "ProductState");
504 ok(dispid == 17, "Expected 17, got %d\n", dispid);
505 dispid = get_dispid(pInstaller, "ProductInfo");
506 ok(dispid == 18, "Expected 18, got %d\n", dispid);
507 todo_wine
509 dispid = get_dispid(pInstaller, "ConfigureProduct");
510 ok(dispid == 19, "Expected 19, got %d\n", dispid);
511 dispid = get_dispid(pInstaller, "ReinstallProduct");
512 ok(dispid == 20 , "Expected 20, got %d\n", dispid);
513 dispid = get_dispid(pInstaller, "CollectUserInfo");
514 ok(dispid == 21, "Expected 21, got %d\n", dispid);
515 dispid = get_dispid(pInstaller, "ApplyPatch");
516 ok(dispid == 22, "Expected 22, got %d\n", dispid);
517 dispid = get_dispid(pInstaller, "FeatureParent");
518 ok(dispid == 23, "Expected 23, got %d\n", dispid);
519 dispid = get_dispid(pInstaller, "FeatureState");
520 ok(dispid == 24, "Expected 24, got %d\n", dispid);
521 dispid = get_dispid(pInstaller, "UseFeature");
522 ok(dispid == 25, "Expected 25, got %d\n", dispid);
523 dispid = get_dispid(pInstaller, "FeatureUsageCount");
524 ok(dispid == 26, "Expected 26, got %d\n", dispid);
525 dispid = get_dispid(pInstaller, "FeatureUsageDate");
526 ok(dispid == 27, "Expected 27, got %d\n", dispid);
527 dispid = get_dispid(pInstaller, "ConfigureFeature");
528 ok(dispid == 28, "Expected 28, got %d\n", dispid);
529 dispid = get_dispid(pInstaller, "ReinstallFeature");
530 ok(dispid == 29, "Expected 29, got %d\n", dispid);
531 dispid = get_dispid(pInstaller, "ProvideComponent");
532 ok(dispid == 30, "Expected 30, got %d\n", dispid);
533 dispid = get_dispid(pInstaller, "ComponentPath");
534 ok(dispid == 31, "Expected 31, got %d\n", dispid);
535 dispid = get_dispid(pInstaller, "ProvideQualifiedComponent");
536 ok(dispid == 32, "Expected 32, got %d\n", dispid);
537 dispid = get_dispid(pInstaller, "QualifierDescription");
538 ok(dispid == 33, "Expected 33, got %d\n", dispid);
539 dispid = get_dispid(pInstaller, "ComponentQualifiers");
540 ok(dispid == 34, "Expected 34, got %d\n", dispid);
542 dispid = get_dispid(pInstaller, "Products");
543 ok(dispid == 35, "Expected 35, got %d\n", dispid);
544 todo_wine
546 dispid = get_dispid(pInstaller, "Features");
547 ok(dispid == 36, "Expected 36, got %d\n", dispid);
548 dispid = get_dispid(pInstaller, "Components");
549 ok(dispid == 37, "Expected 37, got %d\n", dispid);
550 dispid = get_dispid(pInstaller, "ComponentClients");
551 ok(dispid == 38, "Expected 38, got %d\n", dispid);
552 dispid = get_dispid(pInstaller, "Patches");
553 ok(dispid == 39, "Expected 39, got %d\n", dispid);
555 dispid = get_dispid(pInstaller, "RelatedProducts");
556 ok(dispid == 40, "Expected 40, got %d\n", dispid);
557 dispid = get_dispid(pInstaller, "RemovePatches");
558 ok(dispid == 49 || dispid == -1, "Expected 49 or -1, got %d\n", dispid);
559 dispid = get_dispid(pInstaller, "ApplyMultiplePatches");
560 ok(dispid == 51 || dispid == -1, "Expected 51 or -1, got %d\n", dispid);
561 dispid = get_dispid(pInstaller, "ProductsEx");
562 ok(dispid == 52 || dispid == -1, "Expected 52 or -1, got %d\n", dispid);
563 dispid = get_dispid(pInstaller, "PatchesEx");
564 ok(dispid == 55 || dispid == -1, "Expected 55 or -1, got %d\n", dispid);
565 dispid = get_dispid(pInstaller, "ExtractPatchXMLData");
566 ok(dispid == 57 || dispid == -1, "Expected 57 or -1, got %d\n", dispid);
567 todo_wine
569 dispid = get_dispid(pInstaller, "PatchInfo");
570 ok(dispid == 41, "Expected 41, got %d\n", dispid);
571 dispid = get_dispid(pInstaller, "PatchTransforms");
572 ok(dispid == 42, "Expected 42, got %d\n", dispid);
573 dispid = get_dispid(pInstaller, "AddSource");
574 ok(dispid == 43, "Expected 43, got %d\n", dispid);
575 dispid = get_dispid(pInstaller, "ClearSourceList");
576 ok(dispid == 44, "Expected 44, got %d\n", dispid);
577 dispid = get_dispid(pInstaller, "ForceSourceListResolution");
578 ok(dispid == 45, "Expected 45, got %d\n", dispid);
579 dispid = get_dispid(pInstaller, "ShortcutTarget");
580 ok(dispid == 46, "Expected 46, got %d\n", dispid);
581 dispid = get_dispid(pInstaller, "FileHash");
582 ok(dispid == 47, "Expected 47, got %d\n", dispid);
583 dispid = get_dispid(pInstaller, "FileSignatureInfo");
584 ok(dispid == 48, "Expected 48, got %d\n", dispid);
587 /* MSDN claims the following functions exist but IDispatch->GetIDsOfNames disagrees */
588 dispid = get_dispid( pInstaller, "ProductElevated" );
589 ok(dispid == -1, "Expected -1, got %d\n", dispid);
590 dispid = get_dispid( pInstaller, "ProductInfoFromScript" );
591 ok(dispid == -1, "Expected -1, got %d\n", dispid);
592 dispid = get_dispid( pInstaller, "ProvideAssembly" );
593 ok(dispid == -1, "Expected -1, got %d\n", dispid);
594 dispid = get_dispid( pInstaller, "CreateAdvertiseScript" );
595 ok(dispid == -1, "Expected -1, got %d\n", dispid);
596 dispid = get_dispid( pInstaller, "AdvertiseProduct" );
597 ok(dispid == -1, "Expected -1, got %d\n", dispid);
598 dispid = get_dispid( pInstaller, "PatchFiles" );
599 ok(dispid == -1, "Expected -1, got %d\n", dispid);
602 /* Test basic IDispatch functions */
603 static void test_dispatch(void)
605 static WCHAR szOpenPackage[] = { 'O','p','e','n','P','a','c','k','a','g','e',0 };
606 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};
607 static WCHAR szProductState[] = { 'P','r','o','d','u','c','t','S','t','a','t','e',0 };
608 HRESULT hr;
609 DISPID dispid;
610 OLECHAR *name;
611 VARIANT varresult;
612 VARIANTARG vararg[2];
613 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
615 /* Test getting ID of a function name that does not exist */
616 name = (WCHAR *)szMsifile;
617 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
618 ok(hr == DISP_E_UNKNOWNNAME, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
620 /* Test invoking this function */
621 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
622 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
624 /* Test getting ID of a function name that does exist */
625 name = (WCHAR *)szOpenPackage;
626 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
627 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
629 /* Test invoking this function (without parameters passed) */
630 if (0) /* All of these crash MSI on Windows XP */
632 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
633 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL);
634 VariantInit(&varresult);
635 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, &varresult, &excepinfo, NULL);
638 /* Try with NULL params */
639 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
640 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
642 /* Try one empty parameter */
643 dispparams.rgvarg = vararg;
644 dispparams.cArgs = 1;
645 VariantInit(&vararg[0]);
646 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
647 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
649 /* Try one parameter, function requires two */
650 VariantInit(&vararg[0]);
651 V_VT(&vararg[0]) = VT_BSTR;
652 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
653 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
654 VariantClear(&vararg[0]);
656 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
657 ok_exception(hr, szOpenPackageException);
659 /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
660 VariantInit(&vararg[0]);
661 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
662 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
664 VariantInit(&vararg[0]);
665 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
666 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
668 /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
669 name = (WCHAR *)szProductState;
670 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
671 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
673 dispparams.rgvarg = NULL;
674 dispparams.cArgs = 0;
675 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
676 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
678 dispparams.rgvarg = NULL;
679 dispparams.cArgs = 0;
680 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
681 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
684 /* invocation helper function */
685 static int _invoke_todo_vtResult = 0;
687 static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult)
689 OLECHAR *name = NULL;
690 DISPID dispid;
691 HRESULT hr;
692 UINT i;
693 UINT len;
695 memset(pVarResult, 0, sizeof(VARIANT));
696 VariantInit(pVarResult);
698 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 );
699 name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
700 if (!name) return E_FAIL;
701 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len );
702 hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
703 HeapFree(GetProcessHeap(), 0, name);
704 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
705 if (!hr == S_OK) return hr;
707 memset(&excepinfo, 0, sizeof(excepinfo));
708 hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL);
710 if (hr == S_OK)
712 if (_invoke_todo_vtResult) todo_wine
713 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
714 else
715 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
716 if (vtResult != VT_EMPTY)
718 hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult);
719 ok(hr == S_OK, "VariantChangeTypeEx returned 0x%08x\n", hr);
723 for (i=0; i<pDispParams->cArgs; i++)
724 VariantClear(&pDispParams->rgvarg[i]);
726 return hr;
729 /* Object_Property helper functions */
731 static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord)
733 VARIANT varresult;
734 VARIANTARG vararg[1];
735 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
736 HRESULT hr;
738 VariantInit(&vararg[0]);
739 V_VT(&vararg[0]) = VT_I4;
740 V_I4(&vararg[0]) = count;
742 hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
743 *pRecord = V_DISPATCH(&varresult);
744 return hr;
747 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
749 VARIANTARG vararg[3];
750 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
752 VariantInit(&vararg[2]);
753 V_VT(&vararg[2]) = VT_I4;
754 V_I4(&vararg[2]) = (int)hkey;
755 VariantInit(&vararg[1]);
756 V_VT(&vararg[1]) = VT_BSTR;
757 V_BSTR(&vararg[1]) = SysAllocString(szKey);
758 VariantInit(&vararg[0]);
759 VariantCopy(&vararg[0], &vValue);
760 VariantClear(&vValue);
762 return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect);
765 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
767 VARIANT varresult;
768 VARIANTARG vararg;
769 HRESULT hr;
771 VariantInit(&vararg);
772 V_VT(&vararg) = VT_EMPTY;
773 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL);
774 *pBool = V_BOOL(&varresult);
775 VariantClear(&varresult);
776 return hr;
779 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
781 VARIANT varresult;
782 VARIANTARG vararg;
783 HRESULT hr;
785 VariantInit(&vararg);
786 V_VT(&vararg) = VT_BSTR;
787 V_BSTR(&vararg) = SysAllocString(szValue);
789 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR);
790 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
791 VariantClear(&varresult);
792 return hr;
795 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
797 VARIANT varresult;
798 VARIANTARG vararg;
799 HRESULT hr;
801 VariantInit(&vararg);
802 V_VT(&vararg) = VT_I4;
803 V_I4(&vararg) = iValue;
805 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult);
806 if (vtResult == VT_BSTR) lstrcpyW(szString, V_BSTR(&varresult));
807 VariantClear(&varresult);
808 return hr;
811 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
813 VARIANT varresult;
814 VARIANTARG vararg[2];
815 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
816 HRESULT hr;
818 VariantInit(&vararg[1]);
819 V_VT(&vararg[1]) = VT_BSTR;
820 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
821 VariantInit(&vararg[0]);
822 V_VT(&vararg[0]) = VT_I4;
823 V_I4(&vararg[0]) = options;
825 hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
826 *pSession = V_DISPATCH(&varresult);
827 return hr;
830 static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase)
832 VARIANT varresult;
833 VARIANTARG vararg[2];
834 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
835 HRESULT hr;
837 VariantInit(&vararg[1]);
838 V_VT(&vararg[1]) = VT_BSTR;
839 V_BSTR(&vararg[1]) = SysAllocString(szDatabasePath);
840 VariantInit(&vararg[0]);
841 V_VT(&vararg[0]) = VT_I4;
842 V_I4(&vararg[0]) = openmode;
844 hr = invoke(pInstaller, "OpenDatabase", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
845 *pDatabase = V_DISPATCH(&varresult);
846 return hr;
849 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
851 VARIANT varresult;
852 VARIANTARG vararg[2];
853 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
855 VariantInit(&vararg[1]);
856 V_VT(&vararg[1]) = VT_BSTR;
857 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
858 VariantInit(&vararg[0]);
859 V_VT(&vararg[0]) = VT_BSTR;
860 V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues);
862 return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
865 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
867 VARIANT varresult;
868 VARIANTARG vararg[1];
869 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
870 HRESULT hr;
872 VariantInit(&vararg[0]);
873 V_VT(&vararg[0]) = VT_BSTR;
874 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
876 hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
877 *pInstallState = V_I4(&varresult);
878 VariantClear(&varresult);
879 return hr;
882 static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szString)
884 VARIANT varresult;
885 VARIANTARG vararg[2];
886 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
887 HRESULT hr;
889 VariantInit(&vararg[1]);
890 V_VT(&vararg[1]) = VT_BSTR;
891 V_BSTR(&vararg[1]) = SysAllocString(szProduct);
892 VariantInit(&vararg[0]);
893 V_VT(&vararg[0]) = VT_BSTR;
894 V_BSTR(&vararg[0]) = SysAllocString(szAttribute);
896 hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
897 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
898 VariantClear(&varresult);
899 return hr;
902 static HRESULT Installer_Products(IDispatch **pStringList)
904 VARIANT varresult;
905 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
906 HRESULT hr;
908 hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
909 *pStringList = V_DISPATCH(&varresult);
910 return hr;
913 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
915 VARIANT varresult;
916 VARIANTARG vararg[1];
917 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
918 HRESULT hr;
920 VariantInit(&vararg[0]);
921 V_VT(&vararg[0]) = VT_BSTR;
922 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
924 hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
925 *pStringList = V_DISPATCH(&varresult);
926 return hr;
929 static HRESULT Installer_VersionGet(LPWSTR szVersion)
931 VARIANT varresult;
932 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
933 HRESULT hr;
935 hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
936 if (V_BSTR(&varresult)) lstrcpyW(szVersion, V_BSTR(&varresult));
937 VariantClear(&varresult);
938 return hr;
941 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
943 VARIANT varresult;
944 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
945 HRESULT hr;
947 hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
948 *pInst = V_DISPATCH(&varresult);
949 return hr;
952 static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn)
954 VARIANT varresult;
955 VARIANTARG vararg[1];
956 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
957 HRESULT hr;
959 VariantInit(&vararg[0]);
960 V_VT(&vararg[0]) = VT_BSTR;
961 V_BSTR(&vararg[0]) = SysAllocString(szName);
963 hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
964 if (V_BSTR(&varresult)) lstrcpyW(szReturn, V_BSTR(&varresult));
965 VariantClear(&varresult);
966 return hr;
969 static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue)
971 VARIANT varresult;
972 VARIANTARG vararg[2];
973 DISPID dispid = DISPID_PROPERTYPUT;
974 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
976 VariantInit(&vararg[1]);
977 V_VT(&vararg[1]) = VT_BSTR;
978 V_BSTR(&vararg[1]) = SysAllocString(szName);
979 VariantInit(&vararg[0]);
980 V_VT(&vararg[0]) = VT_BSTR;
981 V_BSTR(&vararg[0]) = SysAllocString(szValue);
983 return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
986 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
988 VARIANT varresult;
989 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
990 HRESULT hr;
992 hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
993 *pLangId = V_I4(&varresult);
994 VariantClear(&varresult);
995 return hr;
998 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, BOOL *pMode)
1000 VARIANT varresult;
1001 VARIANTARG vararg[1];
1002 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1003 HRESULT hr;
1005 VariantInit(&vararg[0]);
1006 V_VT(&vararg[0]) = VT_I4;
1007 V_I4(&vararg[0]) = iFlag;
1009 hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL);
1010 *pMode = V_BOOL(&varresult);
1011 VariantClear(&varresult);
1012 return hr;
1015 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, BOOL bMode)
1017 VARIANT varresult;
1018 VARIANTARG vararg[2];
1019 DISPID dispid = DISPID_PROPERTYPUT;
1020 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1022 VariantInit(&vararg[1]);
1023 V_VT(&vararg[1]) = VT_I4;
1024 V_I4(&vararg[1]) = iFlag;
1025 VariantInit(&vararg[0]);
1026 V_VT(&vararg[0]) = VT_BOOL;
1027 V_BOOL(&vararg[0]) = bMode;
1029 return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1032 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
1034 VARIANT varresult;
1035 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1036 HRESULT hr;
1038 hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1039 *pDatabase = V_DISPATCH(&varresult);
1040 return hr;
1043 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn)
1045 VARIANT varresult;
1046 VARIANTARG vararg[1];
1047 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1048 HRESULT hr;
1050 VariantInit(&vararg[0]);
1051 V_VT(&vararg[0]) = VT_BSTR;
1052 V_BSTR(&vararg[0]) = SysAllocString(szAction);
1054 hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1055 *iReturn = V_I4(&varresult);
1056 VariantClear(&varresult);
1057 return hr;
1060 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
1062 VARIANT varresult;
1063 VARIANTARG vararg[1];
1064 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1065 HRESULT hr;
1067 VariantInit(&vararg[0]);
1068 V_VT(&vararg[0]) = VT_BSTR;
1069 V_BSTR(&vararg[0]) = SysAllocString(szCondition);
1071 hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1072 *iReturn = V_I4(&varresult);
1073 VariantClear(&varresult);
1074 return hr;
1077 static HRESULT Session_SetInstallLevel(IDispatch *pSession, long iInstallLevel)
1079 VARIANT varresult;
1080 VARIANTARG vararg[1];
1081 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1083 VariantInit(&vararg[0]);
1084 V_VT(&vararg[0]) = VT_I4;
1085 V_I4(&vararg[0]) = iInstallLevel;
1087 return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1090 static HRESULT Session_FeatureCurrentState(IDispatch *pSession, LPCWSTR szName, int *pState)
1092 VARIANT varresult;
1093 VARIANTARG vararg[1];
1094 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1095 HRESULT hr;
1097 VariantInit(&vararg[0]);
1098 V_VT(&vararg[0]) = VT_BSTR;
1099 V_BSTR(&vararg[0]) = SysAllocString(szName);
1101 hr = invoke(pSession, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1102 *pState = V_I4(&varresult);
1103 VariantClear(&varresult);
1104 return hr;
1107 static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState)
1109 VARIANT varresult;
1110 VARIANTARG vararg[1];
1111 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1112 HRESULT hr;
1114 VariantInit(&vararg[0]);
1115 V_VT(&vararg[0]) = VT_BSTR;
1116 V_BSTR(&vararg[0]) = SysAllocString(szName);
1118 hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1119 *pState = V_I4(&varresult);
1120 VariantClear(&varresult);
1121 return hr;
1124 static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState)
1126 VARIANT varresult;
1127 VARIANTARG vararg[2];
1128 DISPID dispid = DISPID_PROPERTYPUT;
1129 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1131 VariantInit(&vararg[1]);
1132 V_VT(&vararg[1]) = VT_BSTR;
1133 V_BSTR(&vararg[1]) = SysAllocString(szName);
1134 VariantInit(&vararg[0]);
1135 V_VT(&vararg[0]) = VT_I4;
1136 V_I4(&vararg[0]) = iState;
1138 return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1141 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
1143 VARIANT varresult;
1144 VARIANTARG vararg[1];
1145 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1146 HRESULT hr;
1148 VariantInit(&vararg[0]);
1149 V_VT(&vararg[0]) = VT_BSTR;
1150 V_BSTR(&vararg[0]) = SysAllocString(szSql);
1152 hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1153 *pView = V_DISPATCH(&varresult);
1154 return hr;
1157 static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo)
1159 VARIANT varresult;
1160 VARIANTARG vararg[1];
1161 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1162 HRESULT hr;
1164 VariantInit(&vararg[0]);
1165 V_VT(&vararg[0]) = VT_I4;
1166 V_I4(&vararg[0]) = iUpdateCount;
1168 hr = invoke(pDatabase, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1169 *pSummaryInfo = V_DISPATCH(&varresult);
1170 return hr;
1173 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
1175 VARIANT varresult;
1176 VARIANTARG vararg[1];
1177 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1179 VariantInit(&vararg[0]);
1180 V_VT(&vararg[0]) = VT_DISPATCH;
1181 V_DISPATCH(&vararg[0]) = pRecord;
1183 return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1186 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
1188 VARIANT varresult;
1189 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1190 HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1191 *ppRecord = V_DISPATCH(&varresult);
1192 return hr;
1195 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
1197 VARIANT varresult;
1198 VARIANTARG vararg[2];
1199 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1201 VariantInit(&vararg[1]);
1202 V_VT(&vararg[1]) = VT_I4;
1203 V_I4(&vararg[1]) = iMode;
1204 VariantInit(&vararg[0]);
1205 V_VT(&vararg[0]) = VT_DISPATCH;
1206 V_DISPATCH(&vararg[0]) = pRecord;
1207 if (pRecord)
1208 IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */
1210 return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1213 static HRESULT View_Close(IDispatch *pView)
1215 VARIANT varresult;
1216 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1217 return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1220 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
1222 VARIANT varresult;
1223 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1224 HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1225 *pFieldCount = V_I4(&varresult);
1226 VariantClear(&varresult);
1227 return hr;
1230 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString)
1232 VARIANT varresult;
1233 VARIANTARG vararg[1];
1234 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1235 HRESULT hr;
1237 VariantInit(&vararg[0]);
1238 V_VT(&vararg[0]) = VT_I4;
1239 V_I4(&vararg[0]) = iField;
1241 hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1242 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1243 VariantClear(&varresult);
1244 return hr;
1247 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
1249 VARIANT varresult;
1250 VARIANTARG vararg[2];
1251 DISPID dispid = DISPID_PROPERTYPUT;
1252 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1254 VariantInit(&vararg[1]);
1255 V_VT(&vararg[1]) = VT_I4;
1256 V_I4(&vararg[1]) = iField;
1257 VariantInit(&vararg[0]);
1258 V_VT(&vararg[0]) = VT_BSTR;
1259 V_BSTR(&vararg[0]) = SysAllocString(szString);
1261 return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1264 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
1266 VARIANT varresult;
1267 VARIANTARG vararg[1];
1268 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1269 HRESULT hr;
1271 VariantInit(&vararg[0]);
1272 V_VT(&vararg[0]) = VT_I4;
1273 V_I4(&vararg[0]) = iField;
1275 hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1276 *pValue = V_I4(&varresult);
1277 VariantClear(&varresult);
1278 return hr;
1281 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
1283 VARIANT varresult;
1284 VARIANTARG vararg[2];
1285 DISPID dispid = DISPID_PROPERTYPUT;
1286 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1288 VariantInit(&vararg[1]);
1289 V_VT(&vararg[1]) = VT_I4;
1290 V_I4(&vararg[1]) = iField;
1291 VariantInit(&vararg[0]);
1292 V_VT(&vararg[0]) = VT_I4;
1293 V_I4(&vararg[0]) = iValue;
1295 return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1298 static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT)
1300 VARIANT varresult;
1301 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1302 HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN);
1303 *ppEnumVARIANT = V_UNKNOWN(&varresult);
1304 return hr;
1307 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
1309 VARIANT varresult;
1310 VARIANTARG vararg[1];
1311 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1312 HRESULT hr;
1314 VariantInit(&vararg[0]);
1315 V_VT(&vararg[0]) = VT_I4;
1316 V_I4(&vararg[0]) = iIndex;
1318 hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1319 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1320 VariantClear(&varresult);
1321 return hr;
1324 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
1326 VARIANT varresult;
1327 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1328 HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1329 *pCount = V_I4(&varresult);
1330 VariantClear(&varresult);
1331 return hr;
1334 static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect)
1336 VARIANTARG vararg[1];
1337 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1339 VariantInit(&vararg[0]);
1340 V_VT(&vararg[0]) = VT_I4;
1341 V_I4(&vararg[0]) = pid;
1342 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYGET, &dispparams, pVarResult, vtExpect);
1345 static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant)
1347 VARIANT varresult;
1348 VARIANTARG vararg[2];
1349 DISPID dispid = DISPID_PROPERTYPUT;
1350 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1352 VariantInit(&vararg[1]);
1353 V_VT(&vararg[1]) = VT_I4;
1354 V_I4(&vararg[1]) = pid;
1355 VariantInit(&vararg[0]);
1356 VariantCopyInd(vararg, pVariant);
1358 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1361 static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount)
1363 VARIANT varresult;
1364 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1365 HRESULT hr;
1367 hr = invoke(pSummaryInfo, "PropertyCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1368 *pCount = V_I4(&varresult);
1369 VariantClear(&varresult);
1370 return hr;
1373 /* Test the various objects */
1375 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4
1377 static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly)
1379 static const WCHAR szPropertyException[] = { 'P','r','o','p','e','r','t','y',',','P','i','d',0 };
1380 static const WCHAR szTitle[] = { 'T','i','t','l','e',0 };
1381 VARIANT varresult, var;
1382 SYSTEMTIME st;
1383 HRESULT hr;
1384 int j;
1386 /* SummaryInfo::PropertyCount */
1387 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1388 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1389 ok(j == num_info, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1391 /* SummaryInfo::Property, get for properties we have set */
1392 for (j = 0; j < num_info; j++)
1394 const msi_summary_info *entry = &info[j];
1396 int vt = entry->datatype;
1397 if (vt == VT_LPSTR) vt = VT_BSTR;
1398 else if (vt == VT_FILETIME) vt = VT_DATE;
1399 else if (vt == VT_I2) vt = VT_I4;
1401 hr = SummaryInfo_PropertyGet(pSummaryInfo, entry->property, &varresult, vt);
1402 ok(hr == S_OK, "SummaryInfo_Property (pid %d) failed, hresult 0x%08x\n", entry->property, hr);
1403 if (V_VT(&varresult) != vt)
1404 skip("Skipping property tests due to type mismatch\n");
1405 else if (vt == VT_I4)
1406 ok(V_I4(&varresult) == entry->iValue, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %d\n",
1407 entry->property, entry->iValue, V_I4(&varresult));
1408 else if (vt == VT_DATE)
1410 FILETIME ft;
1411 DATE d;
1413 FileTimeToLocalFileTime(entry->pftValue, &ft);
1414 FileTimeToSystemTime(&ft, &st);
1415 SystemTimeToVariantTime(&st, &d);
1416 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));
1418 else if (vt == VT_BSTR)
1420 ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry->property, entry->szValue, V_BSTR(&varresult));
1422 else
1423 skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry->property, vt);
1425 VariantClear(&varresult);
1428 /* SummaryInfo::Property, get; invalid arguments */
1430 /* Invalid pids */
1431 hr = SummaryInfo_PropertyGet(pSummaryInfo, -1, &varresult, VT_EMPTY);
1432 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1433 ok_exception(hr, szPropertyException);
1435 hr = SummaryInfo_PropertyGet(pSummaryInfo, 1000, &varresult, VT_EMPTY);
1436 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1437 ok_exception(hr, szPropertyException);
1439 /* Unsupported pids */
1440 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_DICTIONARY, &varresult, VT_EMPTY);
1441 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1443 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY);
1444 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1446 /* Pids we have not set, one for each type */
1447 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_EMPTY);
1448 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1450 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY);
1451 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1453 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY);
1454 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1456 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY);
1457 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1459 if (!readonly)
1461 /* SummaryInfo::Property, put; one for each type */
1463 /* VT_I2 */
1464 VariantInit(&var);
1465 V_VT(&var) = VT_I2;
1466 V_I2(&var) = 1;
1467 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CODEPAGE, &var);
1468 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1470 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */);
1471 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1472 ok(V_I2(&var) == V_I2(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var), V_I2(&varresult));
1473 VariantClear(&varresult);
1474 VariantClear(&var);
1476 /* VT_BSTR */
1477 V_VT(&var) = VT_BSTR;
1478 V_BSTR(&var) = SysAllocString(szTitle);
1479 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_TITLE, &var);
1480 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1482 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var));
1483 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1484 ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var), V_BSTR(&varresult));
1485 VariantClear(&varresult);
1486 VariantClear(&var);
1488 /* VT_DATE */
1489 V_VT(&var) = VT_DATE;
1490 FileTimeToSystemTime(&systemtime, &st);
1491 SystemTimeToVariantTime(&st, &V_DATE(&var));
1492 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_LASTSAVE_DTM, &var);
1493 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1495 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var));
1496 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1497 /* FIXME: Off by one second */
1498 todo_wine ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1499 VariantClear(&varresult);
1500 VariantClear(&var);
1502 /* VT_I4 */
1503 V_VT(&var) = VT_I4;
1504 V_I4(&var) = 1000;
1505 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1506 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1508 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1509 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1510 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult));
1511 VariantClear(&varresult);
1512 VariantClear(&var);
1514 /* SummaryInfo::PropertyCount */
1515 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1516 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1517 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1521 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1523 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 };
1524 static WCHAR szThree[] = { 'T','h','r','e','e',0 };
1525 static WCHAR szTwo[] = { 'T','w','o',0 };
1526 static WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
1527 static WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 };
1528 IDispatch *pView = NULL, *pSummaryInfo = NULL;
1529 HRESULT hr;
1531 hr = Database_OpenView(pDatabase, szSql, &pView);
1532 ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr);
1533 if (hr == S_OK)
1535 IDispatch *pRecord = NULL;
1536 WCHAR szString[MAX_PATH];
1538 /* View::Execute */
1539 hr = View_Execute(pView, NULL);
1540 ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr);
1542 /* View::Fetch */
1543 hr = View_Fetch(pView, &pRecord);
1544 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1545 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1546 if (pRecord)
1548 /* Record::StringDataGet */
1549 memset(szString, 0, sizeof(szString));
1550 hr = Record_StringDataGet(pRecord, 1, szString);
1551 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1552 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1554 /* Record::StringDataPut with correct index */
1555 hr = Record_StringDataPut(pRecord, 1, szTwo);
1556 ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1558 /* Record::StringDataGet */
1559 memset(szString, 0, sizeof(szString));
1560 hr = Record_StringDataGet(pRecord, 1, szString);
1561 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1562 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1564 /* Record::StringDataPut with incorrect index */
1565 hr = Record_StringDataPut(pRecord, -1, szString);
1566 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1567 ok_exception(hr, szStringDataField);
1569 /* View::Modify with incorrect parameters */
1570 hr = View_Modify(pView, -5, NULL);
1571 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1572 ok_exception(hr, szModifyModeRecord);
1574 hr = View_Modify(pView, -5, pRecord);
1575 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1576 ok_exception(hr, szModifyModeRecord);
1578 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1579 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1580 ok_exception(hr, szModifyModeRecord);
1582 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1583 ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr);
1585 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1586 memset(szString, 0, sizeof(szString));
1587 hr = Record_StringDataGet(pRecord, 1, szString);
1588 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1589 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1591 IDispatch_Release(pRecord);
1594 /* View::Fetch */
1595 hr = View_Fetch(pView, &pRecord);
1596 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1597 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1598 if (pRecord)
1600 /* Record::StringDataGet */
1601 memset(szString, 0, sizeof(szString));
1602 hr = Record_StringDataGet(pRecord, 1, szString);
1603 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1604 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1606 IDispatch_Release(pRecord);
1609 /* View::Fetch */
1610 hr = View_Fetch(pView, &pRecord);
1611 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1612 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1613 if (pRecord)
1614 IDispatch_Release(pRecord);
1616 /* View::Close */
1617 hr = View_Close(pView);
1618 ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr);
1620 IDispatch_Release(pView);
1623 /* Database::SummaryInformation */
1624 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo);
1625 ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr);
1626 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1627 if (pSummaryInfo)
1629 test_SummaryInfo(pSummaryInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), readonly);
1630 IDispatch_Release(pSummaryInfo);
1634 static void test_Session(IDispatch *pSession)
1636 static WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
1637 static WCHAR szOne[] = { 'O','n','e',0 };
1638 static WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 };
1639 static WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 };
1640 static WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 };
1641 static WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 };
1642 static WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1643 static WCHAR szEmpty[] = { 0 };
1644 static WCHAR szEquals[] = { '=',0 };
1645 static WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
1646 WCHAR stringw[MAX_PATH];
1647 CHAR string[MAX_PATH];
1648 UINT len;
1649 BOOL bool;
1650 int myint;
1651 IDispatch *pDatabase = NULL, *pInst = NULL;
1652 HRESULT hr;
1654 /* Session::Installer */
1655 hr = Session_Installer(pSession, &pInst);
1656 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1657 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1658 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1660 /* Session::Property, get */
1661 memset(stringw, 0, sizeof(stringw));
1662 hr = Session_PropertyGet(pSession, szProductName, stringw);
1663 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1664 if (lstrcmpW(stringw, szMSITEST) != 0)
1666 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1667 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1668 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1671 /* Session::Property, put */
1672 hr = Session_PropertyPut(pSession, szProductName, szProductName);
1673 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1674 memset(stringw, 0, sizeof(stringw));
1675 hr = Session_PropertyGet(pSession, szProductName, stringw);
1676 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1677 if (lstrcmpW(stringw, szProductName) != 0)
1679 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1680 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1681 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1684 /* Try putting a property using empty property identifier */
1685 hr = Session_PropertyPut(pSession, szEmpty, szProductName);
1686 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1687 ok_exception(hr, szPropertyName);
1689 /* Try putting a property using illegal property identifier */
1690 hr = Session_PropertyPut(pSession, szEquals, szProductName);
1691 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1693 /* Session::Language, get */
1694 hr = Session_LanguageGet(pSession, &len);
1695 ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1696 /* Not sure how to check the language is correct */
1698 /* Session::Mode, get */
1699 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1700 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1701 todo_wine ok(!bool, "Reboot at end session mode is %d\n", bool);
1703 /* Session::Mode, put */
1704 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE);
1705 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1706 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1707 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1708 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1709 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE); /* set it again so we don't reboot */
1710 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1712 /* Session::Database, get */
1713 hr = Session_Database(pSession, &pDatabase);
1714 ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr);
1715 if (hr == S_OK)
1717 test_Database(pDatabase, TRUE);
1718 IDispatch_Release(pDatabase);
1721 /* Session::EvaluateCondition */
1722 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1723 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1724 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1726 hr = Session_EvaluateCondition(pSession, szEmpty, &myint);
1727 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1728 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1730 hr = Session_EvaluateCondition(pSession, szEquals, &myint);
1731 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1732 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1734 /* Session::DoAction(CostInitialize) must occur before the next statements */
1735 hr = Session_DoAction(pSession, szCostInitialize, &myint);
1736 ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr);
1737 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1739 /* Session::SetInstallLevel */
1740 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1741 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
1743 /* Session::FeatureCurrentState, get */
1744 hr = Session_FeatureCurrentState(pSession, szOne, &myint);
1745 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
1746 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1748 /* Session::EvaluateCondition */
1749 hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint);
1750 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1751 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1753 hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint);
1754 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1755 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1757 /* Session::FeatureRequestState, put */
1758 hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED);
1759 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
1760 hr = Session_FeatureRequestStateGet(pSession, szOne, &myint);
1761 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
1762 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
1764 /* Session::EvaluateCondition */
1765 hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint);
1766 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1767 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1769 hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint);
1770 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1771 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1774 /* delete key and all its subkeys */
1775 static DWORD delete_key( HKEY hkey )
1777 char name[MAX_PATH];
1778 DWORD ret;
1780 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
1782 HKEY tmp;
1783 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
1785 ret = delete_key( tmp );
1786 RegCloseKey( tmp );
1788 if (ret) break;
1790 if (ret != ERROR_NO_MORE_ITEMS) return ret;
1791 RegDeleteKeyA( hkey, "" );
1792 return 0;
1795 static void test_Installer_RegistryValue(void)
1797 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
1798 static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 };
1799 static const WCHAR szOne[] = { 'O','n','e',0 };
1800 static const WCHAR szTwo[] = { 'T','w','o',0 };
1801 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
1802 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1803 static const WCHAR szFour[] = { 'F','o','u','r',0 };
1804 static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 };
1805 static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 };
1806 static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 };
1807 static const WCHAR szSix[] = { 'S','i','x',0 };
1808 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1809 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
1810 static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
1811 static const WCHAR szBlank[] = { 0 };
1812 VARIANT varresult;
1813 VARIANTARG vararg;
1814 WCHAR szString[MAX_PATH];
1815 HKEY hkey, hkey_sub;
1816 HKEY curr_user = (HKEY)1;
1817 HRESULT hr;
1818 BOOL bRet;
1820 /* Delete keys */
1821 if (!RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey )) delete_key( hkey );
1823 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
1824 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
1825 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1826 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
1828 memset(szString, 0, sizeof(szString));
1829 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
1830 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1832 memset(szString, 0, sizeof(szString));
1833 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
1834 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1836 /* Create key */
1837 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
1839 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1840 "RegSetValueExW failed\n");
1841 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
1842 "RegSetValueExW failed\n");
1843 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
1844 "RegSetValueExW failed\n");
1845 ok(SetEnvironmentVariableA("MSITEST", "Four"), "SetEnvironmentVariableA failed %d\n", GetLastError());
1846 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
1847 "RegSetValueExW failed\n");
1848 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
1849 "RegSetValueExW failed\n");
1850 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
1851 "RegSetValueExW failed\n");
1852 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, (const BYTE *)NULL, 0),
1853 "RegSetValueExW failed\n");
1855 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1856 "RegSetValueExW failed\n");
1858 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
1860 /* Does our key exist? It should, and make sure we retrieve the correct default value */
1861 bRet = FALSE;
1862 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
1863 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1864 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
1866 memset(szString, 0, sizeof(szString));
1867 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
1868 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1869 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1871 /* Ask for the value of a nonexistent key */
1872 memset(szString, 0, sizeof(szString));
1873 hr = Installer_RegistryValueW(curr_user, szKey, szExpand, szString);
1874 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1876 /* Get values of keys */
1877 memset(szString, 0, sizeof(szString));
1878 hr = Installer_RegistryValueW(curr_user, szKey, szOne, szString);
1879 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1880 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1882 VariantInit(&vararg);
1883 V_VT(&vararg) = VT_BSTR;
1884 V_BSTR(&vararg) = SysAllocString(szTwo);
1885 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_I4);
1886 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1887 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
1888 VariantClear(&varresult);
1890 memset(szString, 0, sizeof(szString));
1891 hr = Installer_RegistryValueW(curr_user, szKey, szThree, szString);
1892 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1893 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
1895 memset(szString, 0, sizeof(szString));
1896 hr = Installer_RegistryValueW(curr_user, szKey, szFour, szString);
1897 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1898 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
1900 memset(szString, 0, sizeof(szString));
1901 hr = Installer_RegistryValueW(curr_user, szKey, szFive, szString);
1902 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1903 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFiveHi);
1905 memset(szString, 0, sizeof(szString));
1906 hr = Installer_RegistryValueW(curr_user, szKey, szSix, szString);
1907 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1908 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_);
1910 VariantInit(&vararg);
1911 V_VT(&vararg) = VT_BSTR;
1912 V_BSTR(&vararg) = SysAllocString(szSeven);
1913 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_EMPTY);
1914 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1916 /* Get string class name for the key */
1917 memset(szString, 0, sizeof(szString));
1918 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
1919 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1920 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank);
1922 /* Get name of a value by positive number (RegEnumValue like), valid index */
1923 memset(szString, 0, sizeof(szString));
1924 hr = Installer_RegistryValueI(curr_user, szKey, 2, szString, VT_BSTR);
1925 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1926 /* RegEnumValue order seems different on wine */
1927 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
1929 /* Get name of a value by positive number (RegEnumValue like), invalid index */
1930 memset(szString, 0, sizeof(szString));
1931 hr = Installer_RegistryValueI(curr_user, szKey, 10, szString, VT_EMPTY);
1932 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1934 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
1935 memset(szString, 0, sizeof(szString));
1936 hr = Installer_RegistryValueI(curr_user, szKey, -1, szString, VT_BSTR);
1937 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1938 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
1940 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
1941 memset(szString, 0, sizeof(szString));
1942 hr = Installer_RegistryValueI(curr_user, szKey, -10, szString, VT_EMPTY);
1943 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1945 /* clean up */
1946 delete_key(hkey);
1949 static void test_Installer_Products(BOOL bProductInstalled)
1951 WCHAR szString[MAX_PATH];
1952 HRESULT hr;
1953 int idx;
1954 IUnknown *pUnk = NULL;
1955 IEnumVARIANT *pEnum = NULL;
1956 VARIANT var;
1957 ULONG celt;
1958 int iCount, iValue;
1959 IDispatch *pStringList = NULL;
1960 BOOL bProductFound = FALSE;
1962 /* Installer::Products */
1963 hr = Installer_Products(&pStringList);
1964 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
1965 if (hr == S_OK)
1967 /* StringList::_NewEnum */
1968 hr = StringList__NewEnum(pStringList, &pUnk);
1969 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
1970 if (hr == S_OK)
1972 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
1973 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
1975 if (!pEnum)
1976 skip("IEnumVARIANT tests\n");
1978 /* StringList::Count */
1979 hr = StringList_Count(pStringList, &iCount);
1980 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
1982 for (idx=0; idx<iCount; idx++)
1984 /* StringList::Item */
1985 memset(szString, 0, sizeof(szString));
1986 hr = StringList_Item(pStringList, idx, szString);
1987 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
1989 if (hr == S_OK)
1991 /* Installer::ProductState */
1992 hr = Installer_ProductState(szString, &iValue);
1993 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
1994 if (hr == S_OK)
1995 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
1997 /* Not found our product code yet? Check */
1998 if (!bProductFound && !lstrcmpW(szString, szProductCode))
1999 bProductFound = TRUE;
2001 /* IEnumVARIANT::Next */
2002 if (pEnum)
2004 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2005 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2006 ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
2007 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2008 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2009 VariantClear(&var);
2014 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
2015 bProductInstalled ? "be" : "not be",
2016 bProductFound ? "found" : "not found");
2018 if (pEnum)
2020 IEnumVARIANT *pEnum2 = NULL;
2022 if (0) /* Crashes on Windows XP */
2024 /* IEnumVARIANT::Clone, NULL pointer */
2025 hr = IEnumVARIANT_Clone(pEnum, NULL);
2028 /* IEnumVARIANT::Clone */
2029 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
2030 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
2031 if (hr == S_OK)
2033 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
2035 /* IEnumVARIANT::Next of the clone */
2036 if (iCount)
2038 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
2039 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2040 ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
2041 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2042 VariantClear(&var);
2044 else
2045 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
2047 IEnumVARIANT_Release(pEnum2);
2050 /* IEnumVARIANT::Skip should fail */
2051 hr = IEnumVARIANT_Skip(pEnum, 1);
2052 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2054 /* IEnumVARIANT::Next, NULL variant pointer */
2055 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2056 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2057 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2059 /* IEnumVARIANT::Next, should not return any more items */
2060 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2061 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2062 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2063 VariantClear(&var);
2065 /* IEnumVARIANT::Reset */
2066 hr = IEnumVARIANT_Reset(pEnum);
2067 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2069 if (iCount)
2071 /* IEnumVARIANT::Skip to the last product */
2072 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2073 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2075 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2076 * NULL celt pointer. */
2077 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2078 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2079 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2080 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2081 VariantClear(&var);
2083 else
2084 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2087 /* StringList::Item using an invalid index */
2088 memset(szString, 0, sizeof(szString));
2089 hr = StringList_Item(pStringList, iCount, szString);
2090 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2092 if (pEnum) IEnumVARIANT_Release(pEnum);
2093 if (pUnk) IUnknown_Release(pUnk);
2094 IDispatch_Release(pStringList);
2098 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2099 * deleting the subkeys first) */
2100 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey)
2102 UINT ret;
2103 CHAR *string = NULL;
2104 HKEY hkey;
2105 DWORD dwSize;
2107 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2108 if (ret != ERROR_SUCCESS) return ret;
2109 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2110 if (ret != ERROR_SUCCESS) return ret;
2111 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2113 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2114 delete_registry_key(hkey, string);
2116 RegCloseKey(hkey);
2117 HeapFree(GetProcessHeap(), 0, string);
2118 RegDeleteKeyA(hkeyParent, subkey);
2119 return ERROR_SUCCESS;
2122 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2123 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, HKEY *phkey)
2125 UINT ret;
2126 CHAR *string = NULL;
2127 int idx = 0;
2128 HKEY hkey;
2129 DWORD dwSize;
2130 BOOL found = FALSE;
2132 *phkey = 0;
2134 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2135 if (ret != ERROR_SUCCESS) return ret;
2136 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2137 if (ret != ERROR_SUCCESS) return ret;
2138 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2140 while (!found &&
2141 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2143 if (!strcmp(string, findkey))
2145 *phkey = hkey;
2146 found = TRUE;
2148 else if (find_registry_key(hkey, string, findkey, phkey) == ERROR_SUCCESS) found = TRUE;
2151 if (*phkey != hkey) RegCloseKey(hkey);
2152 HeapFree(GetProcessHeap(), 0, string);
2153 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2156 static void test_Installer_InstallProduct(void)
2158 HRESULT hr;
2159 CHAR path[MAX_PATH];
2160 WCHAR szString[MAX_PATH];
2161 LONG res;
2162 HKEY hkey;
2163 DWORD num, size, type;
2164 int iValue, iCount;
2165 IDispatch *pStringList = NULL;
2167 create_test_files();
2169 /* Installer::InstallProduct */
2170 hr = Installer_InstallProduct(szMsifile, NULL);
2171 if (hr == DISP_E_EXCEPTION)
2173 skip("Installer object not supported.\n");
2174 delete_test_files();
2175 return;
2177 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2179 /* Installer::ProductState for our product code, which has been installed */
2180 hr = Installer_ProductState(szProductCode, &iValue);
2181 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2182 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2184 /* Installer::ProductInfo for our product code */
2186 /* NULL attribute */
2187 memset(szString, 0, sizeof(szString));
2188 hr = Installer_ProductInfo(szProductCode, NULL, szString);
2189 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2190 ok_exception(hr, szProductInfoException);
2192 /* Nonexistent attribute */
2193 memset(szString, 0, sizeof(szString));
2194 hr = Installer_ProductInfo(szProductCode, szMsifile, szString);
2195 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2196 ok_exception(hr, szProductInfoException);
2198 /* Package name */
2199 memset(szString, 0, sizeof(szString));
2200 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szString);
2201 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2202 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile);
2204 /* Product name */
2205 memset(szString, 0, sizeof(szString));
2206 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PRODUCTNAMEW, szString);
2207 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2208 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST);
2210 /* Installer::Products */
2211 test_Installer_Products(TRUE);
2213 /* Installer::RelatedProducts for our upgrade code */
2214 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2215 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2216 if (hr == S_OK)
2218 /* StringList::Count */
2219 hr = StringList_Count(pStringList, &iCount);
2220 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2221 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2223 /* StringList::Item */
2224 memset(szString, 0, sizeof(szString));
2225 hr = StringList_Item(pStringList, 0, szString);
2226 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2227 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
2229 IDispatch_Release(pStringList);
2232 /* Check & clean up installed files & registry keys */
2233 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2234 ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
2235 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2236 ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
2237 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2238 ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
2239 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2240 ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
2241 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2242 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2243 ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
2244 ok(delete_pf("msitest", FALSE), "File not installed\n");
2246 res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
2247 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2249 size = MAX_PATH;
2250 type = REG_SZ;
2251 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2252 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2253 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2255 size = MAX_PATH;
2256 type = REG_SZ;
2257 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2258 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2260 size = sizeof(num);
2261 type = REG_DWORD;
2262 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2263 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2264 ok(num == 314, "Expected 314, got %d\n", num);
2266 size = MAX_PATH;
2267 type = REG_SZ;
2268 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2269 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2270 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2272 RegCloseKey(hkey);
2274 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest");
2275 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2277 check_service_is_installed();
2279 /* Remove registry keys written by RegisterProduct standard action */
2280 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F1C3AF50-8B56-4A69-A00C-00773FE42F30}");
2281 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2283 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2284 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2286 res = find_registry_key(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "05FA3C1F65B896A40AC00077F34EF203", &hkey);
2287 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2288 if (res == ERROR_SUCCESS)
2290 res = delete_registry_key(hkey, "05FA3C1F65B896A40AC00077F34EF203");
2291 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2292 RegCloseKey(hkey);
2295 /* Remove registry keys written by PublishProduct standard action */
2296 res = RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2297 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2299 res = delete_registry_key(hkey, "Products\\05FA3C1F65B896A40AC00077F34EF203");
2300 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2302 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2303 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2305 RegCloseKey(hkey);
2307 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203");
2308 todo_wine ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_SUCCESS, got %d\n", res);
2310 /* Delete installation files we installed */
2311 delete_test_files();
2314 static void test_Installer(void)
2316 static WCHAR szBackslash[] = { '\\',0 };
2317 static WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
2318 static WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
2319 WCHAR szPath[MAX_PATH];
2320 HRESULT hr;
2321 UINT len;
2322 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL;
2323 int iValue, iCount;
2325 if (!pInstaller) return;
2327 /* Installer::CreateRecord */
2329 /* Test for error */
2330 hr = Installer_CreateRecord(-1, &pRecord);
2331 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2332 ok_exception(hr, szCreateRecordException);
2334 /* Test for success */
2335 hr = Installer_CreateRecord(1, &pRecord);
2336 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2337 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2338 if (pRecord)
2340 /* Record::FieldCountGet */
2341 hr = Record_FieldCountGet(pRecord, &iValue);
2342 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2343 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2345 /* Record::IntegerDataGet */
2346 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2347 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2348 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2350 /* Record::IntegerDataGet, bad index */
2351 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2352 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2353 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2355 /* Record::IntegerDataPut */
2356 hr = Record_IntegerDataPut(pRecord, 1, 100);
2357 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2359 /* Record::IntegerDataPut, bad index */
2360 hr = Record_IntegerDataPut(pRecord, 10, 100);
2361 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2362 ok_exception(hr, szIntegerDataException);
2364 /* Record::IntegerDataGet */
2365 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2366 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2367 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2369 IDispatch_Release(pRecord);
2372 /* Prepare package */
2373 create_database(msifile, tables, sizeof(tables) / sizeof(msi_table),
2374 summary_info, sizeof(summary_info) / sizeof(msi_summary_info));
2376 len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, CURR_DIR, -1, szPath, MAX_PATH);
2377 ok(len, "MultiByteToWideChar returned error %d\n", GetLastError());
2378 if (!len) return;
2380 lstrcatW(szPath, szBackslash);
2381 lstrcatW(szPath, szMsifile);
2383 /* Installer::OpenPackage */
2384 hr = Installer_OpenPackage(szPath, 0, &pSession);
2385 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2386 if (hr == S_OK)
2388 test_Session(pSession);
2389 IDispatch_Release(pSession);
2392 /* Installer::OpenDatabase */
2393 hr = Installer_OpenDatabase(szPath, (int)MSIDBOPEN_TRANSACT, &pDatabase);
2394 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2395 if (hr == S_OK)
2397 test_Database(pDatabase, FALSE);
2398 IDispatch_Release(pDatabase);
2401 /* Installer::RegistryValue */
2402 test_Installer_RegistryValue();
2404 /* Installer::ProductState for our product code, which should not be installed */
2405 hr = Installer_ProductState(szProductCode, &iValue);
2406 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2407 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2409 /* Installer::ProductInfo for our product code, which should not be installed */
2411 /* Package name */
2412 memset(szPath, 0, sizeof(szPath));
2413 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szPath);
2414 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2415 ok_exception(hr, szProductInfoException);
2417 /* NULL attribute and NULL product code */
2418 memset(szPath, 0, sizeof(szPath));
2419 hr = Installer_ProductInfo(NULL, NULL, szPath);
2420 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2421 ok_exception(hr, szProductInfoException);
2423 /* Installer::Products */
2424 test_Installer_Products(FALSE);
2426 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2427 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2428 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2429 if (hr == S_OK)
2431 /* StringList::Count */
2432 hr = StringList_Count(pStringList, &iCount);
2433 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2434 ok(!iCount, "Expected no related products but found %d\n", iCount);
2436 IDispatch_Release(pStringList);
2439 /* Installer::Version */
2440 memset(szPath, 0, sizeof(szPath));
2441 hr = Installer_VersionGet(szPath);
2442 ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr);
2444 /* Installer::InstallProduct and other tests that depend on our product being installed */
2445 test_Installer_InstallProduct();
2448 START_TEST(automation)
2450 DWORD len;
2451 char temp_path[MAX_PATH], prev_path[MAX_PATH];
2452 HRESULT hr;
2453 CLSID clsid;
2454 IUnknown *pUnk;
2456 GetSystemTimeAsFileTime(&systemtime);
2458 GetCurrentDirectoryA(MAX_PATH, prev_path);
2459 GetTempPath(MAX_PATH, temp_path);
2460 SetCurrentDirectoryA(temp_path);
2462 lstrcpyA(CURR_DIR, temp_path);
2463 len = lstrlenA(CURR_DIR);
2465 if(len && (CURR_DIR[len - 1] == '\\'))
2466 CURR_DIR[len - 1] = 0;
2468 get_program_files_dir(PROG_FILES_DIR);
2470 hr = OleInitialize(NULL);
2471 ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr);
2472 hr = CLSIDFromProgID(szProgId, &clsid);
2473 ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr);
2474 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2475 ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr);
2477 if (pUnk)
2479 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2480 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2482 test_dispid();
2483 test_dispatch();
2484 test_Installer();
2486 IDispatch_Release(pInstaller);
2487 IUnknown_Release(pUnk);
2490 OleUninitialize();
2492 SetCurrentDirectoryA(prev_path);