push 7f8c39dca3a5819e8ef115eebf7abed537de3a22
[wine/hacks.git] / dlls / msi / tests / automation.c
blob68b0f75c25c699ba9565d242b5852d7c504ed527
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 todo_wine
559 dispid = get_dispid(pInstaller, "PatchInfo");
560 ok(dispid == 41, "Expected 41, got %d\n", dispid);
561 dispid = get_dispid(pInstaller, "PatchTransforms");
562 ok(dispid == 42, "Expected 42, got %d\n", dispid);
563 dispid = get_dispid(pInstaller, "AddSource");
564 ok(dispid == 43, "Expected 43, got %d\n", dispid);
565 dispid = get_dispid(pInstaller, "ClearSourceList");
566 ok(dispid == 44, "Expected 44, got %d\n", dispid);
567 dispid = get_dispid(pInstaller, "ForceSourceListResolution");
568 ok(dispid == 45, "Expected 45, got %d\n", dispid);
569 dispid = get_dispid(pInstaller, "ShortcutTarget");
570 ok(dispid == 46, "Expected 46, got %d\n", dispid);
571 dispid = get_dispid(pInstaller, "FileHash");
572 ok(dispid == 47, "Expected 47, got %d\n", dispid);
573 dispid = get_dispid(pInstaller, "FileSignatureInfo");
574 ok(dispid == 48, "Expected 48, got %d\n", dispid);
576 dispid = get_dispid(pInstaller, "RemovePatches");
577 ok(dispid == 49 || dispid == -1, "Expected 49 or -1, got %d\n", dispid);
578 dispid = get_dispid(pInstaller, "ApplyMultiplePatches");
579 ok(dispid == 51 || dispid == -1, "Expected 51 or -1, got %d\n", dispid);
580 dispid = get_dispid(pInstaller, "ProductsEx");
581 ok(dispid == 52 || dispid == -1, "Expected 52 or -1, got %d\n", dispid);
582 dispid = get_dispid(pInstaller, "PatchesEx");
583 ok(dispid == 55 || dispid == -1, "Expected 55 or -1, got %d\n", dispid);
584 dispid = get_dispid(pInstaller, "ExtractPatchXMLData");
585 ok(dispid == 57 || dispid == -1, "Expected 57 or -1, got %d\n", dispid);
586 dispid = get_dispid( pInstaller, "ProductElevated" );
587 ok(dispid == 59 || dispid == -1, "Expected 59 or -1, got %d\n", dispid);
588 dispid = get_dispid( pInstaller, "ProvideAssembly" );
589 ok(dispid == 60 || dispid == -1, "Expected 60 or -1, got %d\n", dispid);
590 dispid = get_dispid( pInstaller, "ProductInfoFromScript" );
591 ok(dispid == 61 || dispid == -1, "Expected 61 or -1, got %d\n", dispid);
592 dispid = get_dispid( pInstaller, "AdvertiseProduct" );
593 ok(dispid == 62 || dispid == -1, "Expected 62 or -1, got %d\n", dispid);
594 dispid = get_dispid( pInstaller, "CreateAdvertiseScript" );
595 ok(dispid == 63 || dispid == -1, "Expected 63 or -1, got %d\n", dispid);
596 dispid = get_dispid( pInstaller, "PatchFiles" );
597 ok(dispid == 65 || dispid == -1, "Expected 65 or -1, got %d\n", dispid);
600 /* Test basic IDispatch functions */
601 static void test_dispatch(void)
603 static WCHAR szOpenPackage[] = { 'O','p','e','n','P','a','c','k','a','g','e',0 };
604 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};
605 static WCHAR szProductState[] = { 'P','r','o','d','u','c','t','S','t','a','t','e',0 };
606 HRESULT hr;
607 DISPID dispid;
608 OLECHAR *name;
609 VARIANT varresult;
610 VARIANTARG vararg[2];
611 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
613 /* Test getting ID of a function name that does not exist */
614 name = (WCHAR *)szMsifile;
615 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
616 ok(hr == DISP_E_UNKNOWNNAME, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
618 /* Test invoking this function */
619 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
620 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
622 /* Test getting ID of a function name that does exist */
623 name = (WCHAR *)szOpenPackage;
624 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
625 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
627 /* Test invoking this function (without parameters passed) */
628 if (0) /* All of these crash MSI on Windows XP */
630 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
631 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL);
632 VariantInit(&varresult);
633 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, &varresult, &excepinfo, NULL);
636 /* Try with NULL params */
637 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
638 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
640 /* Try one empty parameter */
641 dispparams.rgvarg = vararg;
642 dispparams.cArgs = 1;
643 VariantInit(&vararg[0]);
644 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
645 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
647 /* Try one parameter, function requires two */
648 VariantInit(&vararg[0]);
649 V_VT(&vararg[0]) = VT_BSTR;
650 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
651 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
652 VariantClear(&vararg[0]);
654 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
655 ok_exception(hr, szOpenPackageException);
657 /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
658 VariantInit(&vararg[0]);
659 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
660 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
662 VariantInit(&vararg[0]);
663 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
664 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
666 /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
667 name = (WCHAR *)szProductState;
668 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
669 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
671 dispparams.rgvarg = NULL;
672 dispparams.cArgs = 0;
673 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
674 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
676 dispparams.rgvarg = NULL;
677 dispparams.cArgs = 0;
678 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
679 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
682 /* invocation helper function */
683 static int _invoke_todo_vtResult = 0;
685 static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult)
687 OLECHAR *name = NULL;
688 DISPID dispid;
689 HRESULT hr;
690 UINT i;
691 UINT len;
693 memset(pVarResult, 0, sizeof(VARIANT));
694 VariantInit(pVarResult);
696 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 );
697 name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
698 if (!name) return E_FAIL;
699 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len );
700 hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
701 HeapFree(GetProcessHeap(), 0, name);
702 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
703 if (!hr == S_OK) return hr;
705 memset(&excepinfo, 0, sizeof(excepinfo));
706 hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL);
708 if (hr == S_OK)
710 if (_invoke_todo_vtResult) todo_wine
711 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
712 else
713 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
714 if (vtResult != VT_EMPTY)
716 hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult);
717 ok(hr == S_OK, "VariantChangeTypeEx returned 0x%08x\n", hr);
721 for (i=0; i<pDispParams->cArgs; i++)
722 VariantClear(&pDispParams->rgvarg[i]);
724 return hr;
727 /* Object_Property helper functions */
729 static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord)
731 VARIANT varresult;
732 VARIANTARG vararg[1];
733 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
734 HRESULT hr;
736 VariantInit(&vararg[0]);
737 V_VT(&vararg[0]) = VT_I4;
738 V_I4(&vararg[0]) = count;
740 hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
741 *pRecord = V_DISPATCH(&varresult);
742 return hr;
745 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
747 VARIANTARG vararg[3];
748 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
750 VariantInit(&vararg[2]);
751 V_VT(&vararg[2]) = VT_I4;
752 V_I4(&vararg[2]) = (int)hkey;
753 VariantInit(&vararg[1]);
754 V_VT(&vararg[1]) = VT_BSTR;
755 V_BSTR(&vararg[1]) = SysAllocString(szKey);
756 VariantInit(&vararg[0]);
757 VariantCopy(&vararg[0], &vValue);
758 VariantClear(&vValue);
760 return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect);
763 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
765 VARIANT varresult;
766 VARIANTARG vararg;
767 HRESULT hr;
769 VariantInit(&vararg);
770 V_VT(&vararg) = VT_EMPTY;
771 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL);
772 *pBool = V_BOOL(&varresult);
773 VariantClear(&varresult);
774 return hr;
777 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
779 VARIANT varresult;
780 VARIANTARG vararg;
781 HRESULT hr;
783 VariantInit(&vararg);
784 V_VT(&vararg) = VT_BSTR;
785 V_BSTR(&vararg) = SysAllocString(szValue);
787 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR);
788 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
789 VariantClear(&varresult);
790 return hr;
793 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
795 VARIANT varresult;
796 VARIANTARG vararg;
797 HRESULT hr;
799 VariantInit(&vararg);
800 V_VT(&vararg) = VT_I4;
801 V_I4(&vararg) = iValue;
803 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult);
804 if (vtResult == VT_BSTR) lstrcpyW(szString, V_BSTR(&varresult));
805 VariantClear(&varresult);
806 return hr;
809 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
811 VARIANT varresult;
812 VARIANTARG vararg[2];
813 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
814 HRESULT hr;
816 VariantInit(&vararg[1]);
817 V_VT(&vararg[1]) = VT_BSTR;
818 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
819 VariantInit(&vararg[0]);
820 V_VT(&vararg[0]) = VT_I4;
821 V_I4(&vararg[0]) = options;
823 hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
824 *pSession = V_DISPATCH(&varresult);
825 return hr;
828 static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase)
830 VARIANT varresult;
831 VARIANTARG vararg[2];
832 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
833 HRESULT hr;
835 VariantInit(&vararg[1]);
836 V_VT(&vararg[1]) = VT_BSTR;
837 V_BSTR(&vararg[1]) = SysAllocString(szDatabasePath);
838 VariantInit(&vararg[0]);
839 V_VT(&vararg[0]) = VT_I4;
840 V_I4(&vararg[0]) = openmode;
842 hr = invoke(pInstaller, "OpenDatabase", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
843 *pDatabase = V_DISPATCH(&varresult);
844 return hr;
847 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
849 VARIANT varresult;
850 VARIANTARG vararg[2];
851 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
853 VariantInit(&vararg[1]);
854 V_VT(&vararg[1]) = VT_BSTR;
855 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
856 VariantInit(&vararg[0]);
857 V_VT(&vararg[0]) = VT_BSTR;
858 V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues);
860 return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
863 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
865 VARIANT varresult;
866 VARIANTARG vararg[1];
867 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
868 HRESULT hr;
870 VariantInit(&vararg[0]);
871 V_VT(&vararg[0]) = VT_BSTR;
872 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
874 hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
875 *pInstallState = V_I4(&varresult);
876 VariantClear(&varresult);
877 return hr;
880 static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szString)
882 VARIANT varresult;
883 VARIANTARG vararg[2];
884 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
885 HRESULT hr;
887 VariantInit(&vararg[1]);
888 V_VT(&vararg[1]) = VT_BSTR;
889 V_BSTR(&vararg[1]) = SysAllocString(szProduct);
890 VariantInit(&vararg[0]);
891 V_VT(&vararg[0]) = VT_BSTR;
892 V_BSTR(&vararg[0]) = SysAllocString(szAttribute);
894 hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
895 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
896 VariantClear(&varresult);
897 return hr;
900 static HRESULT Installer_Products(IDispatch **pStringList)
902 VARIANT varresult;
903 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
904 HRESULT hr;
906 hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
907 *pStringList = V_DISPATCH(&varresult);
908 return hr;
911 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
913 VARIANT varresult;
914 VARIANTARG vararg[1];
915 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
916 HRESULT hr;
918 VariantInit(&vararg[0]);
919 V_VT(&vararg[0]) = VT_BSTR;
920 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
922 hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
923 *pStringList = V_DISPATCH(&varresult);
924 return hr;
927 static HRESULT Installer_VersionGet(LPWSTR szVersion)
929 VARIANT varresult;
930 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
931 HRESULT hr;
933 hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
934 if (V_BSTR(&varresult)) lstrcpyW(szVersion, V_BSTR(&varresult));
935 VariantClear(&varresult);
936 return hr;
939 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
941 VARIANT varresult;
942 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
943 HRESULT hr;
945 hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
946 *pInst = V_DISPATCH(&varresult);
947 return hr;
950 static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn)
952 VARIANT varresult;
953 VARIANTARG vararg[1];
954 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
955 HRESULT hr;
957 VariantInit(&vararg[0]);
958 V_VT(&vararg[0]) = VT_BSTR;
959 V_BSTR(&vararg[0]) = SysAllocString(szName);
961 hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
962 if (V_BSTR(&varresult)) lstrcpyW(szReturn, V_BSTR(&varresult));
963 VariantClear(&varresult);
964 return hr;
967 static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue)
969 VARIANT varresult;
970 VARIANTARG vararg[2];
971 DISPID dispid = DISPID_PROPERTYPUT;
972 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
974 VariantInit(&vararg[1]);
975 V_VT(&vararg[1]) = VT_BSTR;
976 V_BSTR(&vararg[1]) = SysAllocString(szName);
977 VariantInit(&vararg[0]);
978 V_VT(&vararg[0]) = VT_BSTR;
979 V_BSTR(&vararg[0]) = SysAllocString(szValue);
981 return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
984 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
986 VARIANT varresult;
987 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
988 HRESULT hr;
990 hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
991 *pLangId = V_I4(&varresult);
992 VariantClear(&varresult);
993 return hr;
996 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, BOOL *pMode)
998 VARIANT varresult;
999 VARIANTARG vararg[1];
1000 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1001 HRESULT hr;
1003 VariantInit(&vararg[0]);
1004 V_VT(&vararg[0]) = VT_I4;
1005 V_I4(&vararg[0]) = iFlag;
1007 hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL);
1008 *pMode = V_BOOL(&varresult);
1009 VariantClear(&varresult);
1010 return hr;
1013 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, BOOL bMode)
1015 VARIANT varresult;
1016 VARIANTARG vararg[2];
1017 DISPID dispid = DISPID_PROPERTYPUT;
1018 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1020 VariantInit(&vararg[1]);
1021 V_VT(&vararg[1]) = VT_I4;
1022 V_I4(&vararg[1]) = iFlag;
1023 VariantInit(&vararg[0]);
1024 V_VT(&vararg[0]) = VT_BOOL;
1025 V_BOOL(&vararg[0]) = bMode;
1027 return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1030 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
1032 VARIANT varresult;
1033 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1034 HRESULT hr;
1036 hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1037 *pDatabase = V_DISPATCH(&varresult);
1038 return hr;
1041 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn)
1043 VARIANT varresult;
1044 VARIANTARG vararg[1];
1045 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1046 HRESULT hr;
1048 VariantInit(&vararg[0]);
1049 V_VT(&vararg[0]) = VT_BSTR;
1050 V_BSTR(&vararg[0]) = SysAllocString(szAction);
1052 hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1053 *iReturn = V_I4(&varresult);
1054 VariantClear(&varresult);
1055 return hr;
1058 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
1060 VARIANT varresult;
1061 VARIANTARG vararg[1];
1062 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1063 HRESULT hr;
1065 VariantInit(&vararg[0]);
1066 V_VT(&vararg[0]) = VT_BSTR;
1067 V_BSTR(&vararg[0]) = SysAllocString(szCondition);
1069 hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1070 *iReturn = V_I4(&varresult);
1071 VariantClear(&varresult);
1072 return hr;
1075 static HRESULT Session_SetInstallLevel(IDispatch *pSession, long iInstallLevel)
1077 VARIANT varresult;
1078 VARIANTARG vararg[1];
1079 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1081 VariantInit(&vararg[0]);
1082 V_VT(&vararg[0]) = VT_I4;
1083 V_I4(&vararg[0]) = iInstallLevel;
1085 return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1088 static HRESULT Session_FeatureCurrentState(IDispatch *pSession, LPCWSTR szName, int *pState)
1090 VARIANT varresult;
1091 VARIANTARG vararg[1];
1092 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1093 HRESULT hr;
1095 VariantInit(&vararg[0]);
1096 V_VT(&vararg[0]) = VT_BSTR;
1097 V_BSTR(&vararg[0]) = SysAllocString(szName);
1099 hr = invoke(pSession, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1100 *pState = V_I4(&varresult);
1101 VariantClear(&varresult);
1102 return hr;
1105 static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState)
1107 VARIANT varresult;
1108 VARIANTARG vararg[1];
1109 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1110 HRESULT hr;
1112 VariantInit(&vararg[0]);
1113 V_VT(&vararg[0]) = VT_BSTR;
1114 V_BSTR(&vararg[0]) = SysAllocString(szName);
1116 hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1117 *pState = V_I4(&varresult);
1118 VariantClear(&varresult);
1119 return hr;
1122 static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState)
1124 VARIANT varresult;
1125 VARIANTARG vararg[2];
1126 DISPID dispid = DISPID_PROPERTYPUT;
1127 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1129 VariantInit(&vararg[1]);
1130 V_VT(&vararg[1]) = VT_BSTR;
1131 V_BSTR(&vararg[1]) = SysAllocString(szName);
1132 VariantInit(&vararg[0]);
1133 V_VT(&vararg[0]) = VT_I4;
1134 V_I4(&vararg[0]) = iState;
1136 return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1139 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
1141 VARIANT varresult;
1142 VARIANTARG vararg[1];
1143 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1144 HRESULT hr;
1146 VariantInit(&vararg[0]);
1147 V_VT(&vararg[0]) = VT_BSTR;
1148 V_BSTR(&vararg[0]) = SysAllocString(szSql);
1150 hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1151 *pView = V_DISPATCH(&varresult);
1152 return hr;
1155 static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo)
1157 VARIANT varresult;
1158 VARIANTARG vararg[1];
1159 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1160 HRESULT hr;
1162 VariantInit(&vararg[0]);
1163 V_VT(&vararg[0]) = VT_I4;
1164 V_I4(&vararg[0]) = iUpdateCount;
1166 hr = invoke(pDatabase, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1167 *pSummaryInfo = V_DISPATCH(&varresult);
1168 return hr;
1171 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
1173 VARIANT varresult;
1174 VARIANTARG vararg[1];
1175 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1177 VariantInit(&vararg[0]);
1178 V_VT(&vararg[0]) = VT_DISPATCH;
1179 V_DISPATCH(&vararg[0]) = pRecord;
1181 return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1184 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
1186 VARIANT varresult;
1187 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1188 HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1189 *ppRecord = V_DISPATCH(&varresult);
1190 return hr;
1193 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
1195 VARIANT varresult;
1196 VARIANTARG vararg[2];
1197 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1199 VariantInit(&vararg[1]);
1200 V_VT(&vararg[1]) = VT_I4;
1201 V_I4(&vararg[1]) = iMode;
1202 VariantInit(&vararg[0]);
1203 V_VT(&vararg[0]) = VT_DISPATCH;
1204 V_DISPATCH(&vararg[0]) = pRecord;
1205 if (pRecord)
1206 IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */
1208 return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1211 static HRESULT View_Close(IDispatch *pView)
1213 VARIANT varresult;
1214 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1215 return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1218 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
1220 VARIANT varresult;
1221 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1222 HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1223 *pFieldCount = V_I4(&varresult);
1224 VariantClear(&varresult);
1225 return hr;
1228 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString)
1230 VARIANT varresult;
1231 VARIANTARG vararg[1];
1232 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1233 HRESULT hr;
1235 VariantInit(&vararg[0]);
1236 V_VT(&vararg[0]) = VT_I4;
1237 V_I4(&vararg[0]) = iField;
1239 hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1240 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1241 VariantClear(&varresult);
1242 return hr;
1245 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
1247 VARIANT varresult;
1248 VARIANTARG vararg[2];
1249 DISPID dispid = DISPID_PROPERTYPUT;
1250 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1252 VariantInit(&vararg[1]);
1253 V_VT(&vararg[1]) = VT_I4;
1254 V_I4(&vararg[1]) = iField;
1255 VariantInit(&vararg[0]);
1256 V_VT(&vararg[0]) = VT_BSTR;
1257 V_BSTR(&vararg[0]) = SysAllocString(szString);
1259 return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1262 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
1264 VARIANT varresult;
1265 VARIANTARG vararg[1];
1266 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1267 HRESULT hr;
1269 VariantInit(&vararg[0]);
1270 V_VT(&vararg[0]) = VT_I4;
1271 V_I4(&vararg[0]) = iField;
1273 hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1274 *pValue = V_I4(&varresult);
1275 VariantClear(&varresult);
1276 return hr;
1279 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
1281 VARIANT varresult;
1282 VARIANTARG vararg[2];
1283 DISPID dispid = DISPID_PROPERTYPUT;
1284 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1286 VariantInit(&vararg[1]);
1287 V_VT(&vararg[1]) = VT_I4;
1288 V_I4(&vararg[1]) = iField;
1289 VariantInit(&vararg[0]);
1290 V_VT(&vararg[0]) = VT_I4;
1291 V_I4(&vararg[0]) = iValue;
1293 return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1296 static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT)
1298 VARIANT varresult;
1299 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1300 HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN);
1301 *ppEnumVARIANT = V_UNKNOWN(&varresult);
1302 return hr;
1305 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
1307 VARIANT varresult;
1308 VARIANTARG vararg[1];
1309 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1310 HRESULT hr;
1312 VariantInit(&vararg[0]);
1313 V_VT(&vararg[0]) = VT_I4;
1314 V_I4(&vararg[0]) = iIndex;
1316 hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1317 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1318 VariantClear(&varresult);
1319 return hr;
1322 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
1324 VARIANT varresult;
1325 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1326 HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1327 *pCount = V_I4(&varresult);
1328 VariantClear(&varresult);
1329 return hr;
1332 static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect)
1334 VARIANTARG vararg[1];
1335 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1337 VariantInit(&vararg[0]);
1338 V_VT(&vararg[0]) = VT_I4;
1339 V_I4(&vararg[0]) = pid;
1340 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYGET, &dispparams, pVarResult, vtExpect);
1343 static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant)
1345 VARIANT varresult;
1346 VARIANTARG vararg[2];
1347 DISPID dispid = DISPID_PROPERTYPUT;
1348 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1350 VariantInit(&vararg[1]);
1351 V_VT(&vararg[1]) = VT_I4;
1352 V_I4(&vararg[1]) = pid;
1353 VariantInit(&vararg[0]);
1354 VariantCopyInd(vararg, pVariant);
1356 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1359 static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount)
1361 VARIANT varresult;
1362 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1363 HRESULT hr;
1365 hr = invoke(pSummaryInfo, "PropertyCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1366 *pCount = V_I4(&varresult);
1367 VariantClear(&varresult);
1368 return hr;
1371 /* Test the various objects */
1373 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4
1375 static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly)
1377 static const WCHAR szPropertyException[] = { 'P','r','o','p','e','r','t','y',',','P','i','d',0 };
1378 static const WCHAR szTitle[] = { 'T','i','t','l','e',0 };
1379 VARIANT varresult, var;
1380 SYSTEMTIME st;
1381 HRESULT hr;
1382 int j;
1384 /* SummaryInfo::PropertyCount */
1385 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1386 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1387 ok(j == num_info, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1389 /* SummaryInfo::Property, get for properties we have set */
1390 for (j = 0; j < num_info; j++)
1392 const msi_summary_info *entry = &info[j];
1394 int vt = entry->datatype;
1395 if (vt == VT_LPSTR) vt = VT_BSTR;
1396 else if (vt == VT_FILETIME) vt = VT_DATE;
1397 else if (vt == VT_I2) vt = VT_I4;
1399 hr = SummaryInfo_PropertyGet(pSummaryInfo, entry->property, &varresult, vt);
1400 ok(hr == S_OK, "SummaryInfo_Property (pid %d) failed, hresult 0x%08x\n", entry->property, hr);
1401 if (V_VT(&varresult) != vt)
1402 skip("Skipping property tests due to type mismatch\n");
1403 else if (vt == VT_I4)
1404 ok(V_I4(&varresult) == entry->iValue, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %d\n",
1405 entry->property, entry->iValue, V_I4(&varresult));
1406 else if (vt == VT_DATE)
1408 FILETIME ft;
1409 DATE d;
1411 FileTimeToLocalFileTime(entry->pftValue, &ft);
1412 FileTimeToSystemTime(&ft, &st);
1413 SystemTimeToVariantTime(&st, &d);
1414 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));
1416 else if (vt == VT_BSTR)
1418 ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry->property, entry->szValue, V_BSTR(&varresult));
1420 else
1421 skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry->property, vt);
1423 VariantClear(&varresult);
1426 /* SummaryInfo::Property, get; invalid arguments */
1428 /* Invalid pids */
1429 hr = SummaryInfo_PropertyGet(pSummaryInfo, -1, &varresult, VT_EMPTY);
1430 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1431 ok_exception(hr, szPropertyException);
1433 hr = SummaryInfo_PropertyGet(pSummaryInfo, 1000, &varresult, VT_EMPTY);
1434 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1435 ok_exception(hr, szPropertyException);
1437 /* Unsupported pids */
1438 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_DICTIONARY, &varresult, VT_EMPTY);
1439 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1441 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY);
1442 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1444 /* Pids we have not set, one for each type */
1445 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_EMPTY);
1446 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1448 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY);
1449 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1451 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY);
1452 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1454 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY);
1455 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1457 if (!readonly)
1459 /* SummaryInfo::Property, put; one for each type */
1461 /* VT_I2 */
1462 VariantInit(&var);
1463 V_VT(&var) = VT_I2;
1464 V_I2(&var) = 1;
1465 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CODEPAGE, &var);
1466 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1468 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */);
1469 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1470 ok(V_I2(&var) == V_I2(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var), V_I2(&varresult));
1471 VariantClear(&varresult);
1472 VariantClear(&var);
1474 /* VT_BSTR */
1475 V_VT(&var) = VT_BSTR;
1476 V_BSTR(&var) = SysAllocString(szTitle);
1477 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_TITLE, &var);
1478 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1480 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var));
1481 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1482 ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var), V_BSTR(&varresult));
1483 VariantClear(&varresult);
1484 VariantClear(&var);
1486 /* VT_DATE */
1487 V_VT(&var) = VT_DATE;
1488 FileTimeToSystemTime(&systemtime, &st);
1489 SystemTimeToVariantTime(&st, &V_DATE(&var));
1490 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_LASTSAVE_DTM, &var);
1491 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1493 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var));
1494 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1495 /* FIXME: Off by one second */
1496 todo_wine ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1497 VariantClear(&varresult);
1498 VariantClear(&var);
1500 /* VT_I4 */
1501 V_VT(&var) = VT_I4;
1502 V_I4(&var) = 1000;
1503 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1504 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1506 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1507 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1508 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult));
1509 VariantClear(&varresult);
1510 VariantClear(&var);
1512 /* SummaryInfo::PropertyCount */
1513 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1514 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1515 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1519 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1521 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 };
1522 static WCHAR szThree[] = { 'T','h','r','e','e',0 };
1523 static WCHAR szTwo[] = { 'T','w','o',0 };
1524 static WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
1525 static WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 };
1526 IDispatch *pView = NULL, *pSummaryInfo = NULL;
1527 HRESULT hr;
1529 hr = Database_OpenView(pDatabase, szSql, &pView);
1530 ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr);
1531 if (hr == S_OK)
1533 IDispatch *pRecord = NULL;
1534 WCHAR szString[MAX_PATH];
1536 /* View::Execute */
1537 hr = View_Execute(pView, NULL);
1538 ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr);
1540 /* View::Fetch */
1541 hr = View_Fetch(pView, &pRecord);
1542 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1543 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1544 if (pRecord)
1546 /* Record::StringDataGet */
1547 memset(szString, 0, sizeof(szString));
1548 hr = Record_StringDataGet(pRecord, 1, szString);
1549 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1550 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1552 /* Record::StringDataPut with correct index */
1553 hr = Record_StringDataPut(pRecord, 1, szTwo);
1554 ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1556 /* Record::StringDataGet */
1557 memset(szString, 0, sizeof(szString));
1558 hr = Record_StringDataGet(pRecord, 1, szString);
1559 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1560 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1562 /* Record::StringDataPut with incorrect index */
1563 hr = Record_StringDataPut(pRecord, -1, szString);
1564 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1565 ok_exception(hr, szStringDataField);
1567 /* View::Modify with incorrect parameters */
1568 hr = View_Modify(pView, -5, NULL);
1569 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1570 ok_exception(hr, szModifyModeRecord);
1572 hr = View_Modify(pView, -5, pRecord);
1573 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1574 ok_exception(hr, szModifyModeRecord);
1576 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1577 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1578 ok_exception(hr, szModifyModeRecord);
1580 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1581 ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr);
1583 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1584 memset(szString, 0, sizeof(szString));
1585 hr = Record_StringDataGet(pRecord, 1, szString);
1586 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1587 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1589 IDispatch_Release(pRecord);
1592 /* View::Fetch */
1593 hr = View_Fetch(pView, &pRecord);
1594 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1595 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1596 if (pRecord)
1598 /* Record::StringDataGet */
1599 memset(szString, 0, sizeof(szString));
1600 hr = Record_StringDataGet(pRecord, 1, szString);
1601 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1602 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1604 IDispatch_Release(pRecord);
1607 /* View::Fetch */
1608 hr = View_Fetch(pView, &pRecord);
1609 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1610 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1611 if (pRecord)
1612 IDispatch_Release(pRecord);
1614 /* View::Close */
1615 hr = View_Close(pView);
1616 ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr);
1618 IDispatch_Release(pView);
1621 /* Database::SummaryInformation */
1622 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo);
1623 ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr);
1624 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1625 if (pSummaryInfo)
1627 test_SummaryInfo(pSummaryInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), readonly);
1628 IDispatch_Release(pSummaryInfo);
1632 static void test_Session(IDispatch *pSession)
1634 static WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
1635 static WCHAR szOne[] = { 'O','n','e',0 };
1636 static WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 };
1637 static WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 };
1638 static WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 };
1639 static WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 };
1640 static WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1641 static WCHAR szEmpty[] = { 0 };
1642 static WCHAR szEquals[] = { '=',0 };
1643 static WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
1644 WCHAR stringw[MAX_PATH];
1645 CHAR string[MAX_PATH];
1646 UINT len;
1647 BOOL bool;
1648 int myint;
1649 IDispatch *pDatabase = NULL, *pInst = NULL;
1650 HRESULT hr;
1652 /* Session::Installer */
1653 hr = Session_Installer(pSession, &pInst);
1654 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1655 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1656 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1658 /* Session::Property, get */
1659 memset(stringw, 0, sizeof(stringw));
1660 hr = Session_PropertyGet(pSession, szProductName, stringw);
1661 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1662 if (lstrcmpW(stringw, szMSITEST) != 0)
1664 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1665 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1666 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1669 /* Session::Property, put */
1670 hr = Session_PropertyPut(pSession, szProductName, szProductName);
1671 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1672 memset(stringw, 0, sizeof(stringw));
1673 hr = Session_PropertyGet(pSession, szProductName, stringw);
1674 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1675 if (lstrcmpW(stringw, szProductName) != 0)
1677 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1678 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1679 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1682 /* Try putting a property using empty property identifier */
1683 hr = Session_PropertyPut(pSession, szEmpty, szProductName);
1684 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1685 ok_exception(hr, szPropertyName);
1687 /* Try putting a property using illegal property identifier */
1688 hr = Session_PropertyPut(pSession, szEquals, szProductName);
1689 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1691 /* Session::Language, get */
1692 hr = Session_LanguageGet(pSession, &len);
1693 ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1694 /* Not sure how to check the language is correct */
1696 /* Session::Mode, get */
1697 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1698 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1699 todo_wine ok(!bool, "Reboot at end session mode is %d\n", bool);
1701 /* Session::Mode, put */
1702 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE);
1703 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1704 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1705 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1706 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1707 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE); /* set it again so we don't reboot */
1708 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1710 /* Session::Database, get */
1711 hr = Session_Database(pSession, &pDatabase);
1712 ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr);
1713 if (hr == S_OK)
1715 test_Database(pDatabase, TRUE);
1716 IDispatch_Release(pDatabase);
1719 /* Session::EvaluateCondition */
1720 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1721 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1722 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1724 hr = Session_EvaluateCondition(pSession, szEmpty, &myint);
1725 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1726 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1728 hr = Session_EvaluateCondition(pSession, szEquals, &myint);
1729 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1730 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1732 /* Session::DoAction(CostInitialize) must occur before the next statements */
1733 hr = Session_DoAction(pSession, szCostInitialize, &myint);
1734 ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr);
1735 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1737 /* Session::SetInstallLevel */
1738 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1739 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
1741 /* Session::FeatureCurrentState, get */
1742 hr = Session_FeatureCurrentState(pSession, szOne, &myint);
1743 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
1744 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1746 /* Session::EvaluateCondition */
1747 hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint);
1748 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1749 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1751 hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint);
1752 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1753 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1755 /* Session::FeatureRequestState, put */
1756 hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED);
1757 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
1758 hr = Session_FeatureRequestStateGet(pSession, szOne, &myint);
1759 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
1760 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
1762 /* Session::EvaluateCondition */
1763 hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint);
1764 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1765 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1767 hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint);
1768 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1769 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1772 /* delete key and all its subkeys */
1773 static DWORD delete_key( HKEY hkey )
1775 char name[MAX_PATH];
1776 DWORD ret;
1778 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
1780 HKEY tmp;
1781 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
1783 ret = delete_key( tmp );
1784 RegCloseKey( tmp );
1786 if (ret) break;
1788 if (ret != ERROR_NO_MORE_ITEMS) return ret;
1789 RegDeleteKeyA( hkey, "" );
1790 return 0;
1793 static void test_Installer_RegistryValue(void)
1795 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
1796 static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 };
1797 static const WCHAR szOne[] = { 'O','n','e',0 };
1798 static const WCHAR szTwo[] = { 'T','w','o',0 };
1799 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
1800 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1801 static const WCHAR szFour[] = { 'F','o','u','r',0 };
1802 static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 };
1803 static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 };
1804 static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 };
1805 static const WCHAR szSix[] = { 'S','i','x',0 };
1806 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1807 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
1808 static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
1809 static const WCHAR szBlank[] = { 0 };
1810 VARIANT varresult;
1811 VARIANTARG vararg;
1812 WCHAR szString[MAX_PATH];
1813 HKEY hkey, hkey_sub;
1814 HKEY curr_user = (HKEY)1;
1815 HRESULT hr;
1816 BOOL bRet;
1818 /* Delete keys */
1819 if (!RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey )) delete_key( hkey );
1821 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
1822 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
1823 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1824 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
1826 memset(szString, 0, sizeof(szString));
1827 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
1828 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1830 memset(szString, 0, sizeof(szString));
1831 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
1832 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1834 /* Create key */
1835 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
1837 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1838 "RegSetValueExW failed\n");
1839 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
1840 "RegSetValueExW failed\n");
1841 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
1842 "RegSetValueExW failed\n");
1843 ok(SetEnvironmentVariableA("MSITEST", "Four"), "SetEnvironmentVariableA failed %d\n", GetLastError());
1844 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
1845 "RegSetValueExW failed\n");
1846 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
1847 "RegSetValueExW failed\n");
1848 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
1849 "RegSetValueExW failed\n");
1850 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, (const BYTE *)NULL, 0),
1851 "RegSetValueExW failed\n");
1853 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1854 "RegSetValueExW failed\n");
1856 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
1858 /* Does our key exist? It should, and make sure we retrieve the correct default value */
1859 bRet = FALSE;
1860 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
1861 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1862 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
1864 memset(szString, 0, sizeof(szString));
1865 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
1866 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1867 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1869 /* Ask for the value of a nonexistent key */
1870 memset(szString, 0, sizeof(szString));
1871 hr = Installer_RegistryValueW(curr_user, szKey, szExpand, szString);
1872 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1874 /* Get values of keys */
1875 memset(szString, 0, sizeof(szString));
1876 hr = Installer_RegistryValueW(curr_user, szKey, szOne, szString);
1877 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1878 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1880 VariantInit(&vararg);
1881 V_VT(&vararg) = VT_BSTR;
1882 V_BSTR(&vararg) = SysAllocString(szTwo);
1883 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_I4);
1884 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1885 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
1886 VariantClear(&varresult);
1888 memset(szString, 0, sizeof(szString));
1889 hr = Installer_RegistryValueW(curr_user, szKey, szThree, szString);
1890 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1891 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
1893 memset(szString, 0, sizeof(szString));
1894 hr = Installer_RegistryValueW(curr_user, szKey, szFour, szString);
1895 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1896 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
1898 memset(szString, 0, sizeof(szString));
1899 hr = Installer_RegistryValueW(curr_user, szKey, szFive, szString);
1900 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1901 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFiveHi);
1903 memset(szString, 0, sizeof(szString));
1904 hr = Installer_RegistryValueW(curr_user, szKey, szSix, szString);
1905 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1906 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_);
1908 VariantInit(&vararg);
1909 V_VT(&vararg) = VT_BSTR;
1910 V_BSTR(&vararg) = SysAllocString(szSeven);
1911 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_EMPTY);
1912 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1914 /* Get string class name for the key */
1915 memset(szString, 0, sizeof(szString));
1916 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
1917 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1918 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank);
1920 /* Get name of a value by positive number (RegEnumValue like), valid index */
1921 memset(szString, 0, sizeof(szString));
1922 hr = Installer_RegistryValueI(curr_user, szKey, 2, szString, VT_BSTR);
1923 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1924 /* RegEnumValue order seems different on wine */
1925 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
1927 /* Get name of a value by positive number (RegEnumValue like), invalid index */
1928 memset(szString, 0, sizeof(szString));
1929 hr = Installer_RegistryValueI(curr_user, szKey, 10, szString, VT_EMPTY);
1930 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1932 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
1933 memset(szString, 0, sizeof(szString));
1934 hr = Installer_RegistryValueI(curr_user, szKey, -1, szString, VT_BSTR);
1935 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1936 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
1938 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
1939 memset(szString, 0, sizeof(szString));
1940 hr = Installer_RegistryValueI(curr_user, szKey, -10, szString, VT_EMPTY);
1941 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1943 /* clean up */
1944 delete_key(hkey);
1947 static void test_Installer_Products(BOOL bProductInstalled)
1949 WCHAR szString[MAX_PATH];
1950 HRESULT hr;
1951 int idx;
1952 IUnknown *pUnk = NULL;
1953 IEnumVARIANT *pEnum = NULL;
1954 VARIANT var;
1955 ULONG celt;
1956 int iCount, iValue;
1957 IDispatch *pStringList = NULL;
1958 BOOL bProductFound = FALSE;
1960 /* Installer::Products */
1961 hr = Installer_Products(&pStringList);
1962 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
1963 if (hr == S_OK)
1965 /* StringList::_NewEnum */
1966 hr = StringList__NewEnum(pStringList, &pUnk);
1967 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
1968 if (hr == S_OK)
1970 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
1971 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
1973 if (!pEnum)
1974 skip("IEnumVARIANT tests\n");
1976 /* StringList::Count */
1977 hr = StringList_Count(pStringList, &iCount);
1978 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
1980 for (idx=0; idx<iCount; idx++)
1982 /* StringList::Item */
1983 memset(szString, 0, sizeof(szString));
1984 hr = StringList_Item(pStringList, idx, szString);
1985 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
1987 if (hr == S_OK)
1989 /* Installer::ProductState */
1990 hr = Installer_ProductState(szString, &iValue);
1991 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
1992 if (hr == S_OK)
1993 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
1995 /* Not found our product code yet? Check */
1996 if (!bProductFound && !lstrcmpW(szString, szProductCode))
1997 bProductFound = TRUE;
1999 /* IEnumVARIANT::Next */
2000 if (pEnum)
2002 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2003 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2004 ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
2005 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2006 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2007 VariantClear(&var);
2012 if (bProductInstalled) todo_wine
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");
2019 if (pEnum)
2021 IEnumVARIANT *pEnum2 = NULL;
2023 if (0) /* Crashes on Windows XP */
2025 /* IEnumVARIANT::Clone, NULL pointer */
2026 hr = IEnumVARIANT_Clone(pEnum, NULL);
2029 /* IEnumVARIANT::Clone */
2030 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
2031 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
2032 if (hr == S_OK)
2034 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
2036 /* IEnumVARIANT::Next of the clone */
2037 if (iCount)
2039 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
2040 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2041 ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
2042 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2043 VariantClear(&var);
2045 else
2046 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
2048 IEnumVARIANT_Release(pEnum2);
2051 /* IEnumVARIANT::Skip should fail */
2052 hr = IEnumVARIANT_Skip(pEnum, 1);
2053 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2055 /* IEnumVARIANT::Next, NULL variant pointer */
2056 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2057 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2058 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2060 /* IEnumVARIANT::Next, should not return any more items */
2061 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2062 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2063 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2064 VariantClear(&var);
2066 /* IEnumVARIANT::Reset */
2067 hr = IEnumVARIANT_Reset(pEnum);
2068 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2070 if (iCount)
2072 /* IEnumVARIANT::Skip to the last product */
2073 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2074 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2076 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2077 * NULL celt pointer. */
2078 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2079 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2080 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2081 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2082 VariantClear(&var);
2084 else
2085 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2088 /* StringList::Item using an invalid index */
2089 memset(szString, 0, sizeof(szString));
2090 hr = StringList_Item(pStringList, iCount, szString);
2091 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2093 if (pEnum) IEnumVARIANT_Release(pEnum);
2094 if (pUnk) IUnknown_Release(pUnk);
2095 IDispatch_Release(pStringList);
2099 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2100 * deleting the subkeys first) */
2101 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey)
2103 UINT ret;
2104 CHAR *string = NULL;
2105 HKEY hkey;
2106 DWORD dwSize;
2108 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2109 if (ret != ERROR_SUCCESS) return ret;
2110 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2111 if (ret != ERROR_SUCCESS) return ret;
2112 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2114 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2115 delete_registry_key(hkey, string);
2117 RegCloseKey(hkey);
2118 HeapFree(GetProcessHeap(), 0, string);
2119 RegDeleteKeyA(hkeyParent, subkey);
2120 return ERROR_SUCCESS;
2123 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2124 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, HKEY *phkey)
2126 UINT ret;
2127 CHAR *string = NULL;
2128 int idx = 0;
2129 HKEY hkey;
2130 DWORD dwSize;
2131 BOOL found = FALSE;
2133 *phkey = 0;
2135 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2136 if (ret != ERROR_SUCCESS) return ret;
2137 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2138 if (ret != ERROR_SUCCESS) return ret;
2139 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2141 while (!found &&
2142 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2144 if (!strcmp(string, findkey))
2146 *phkey = hkey;
2147 found = TRUE;
2149 else if (find_registry_key(hkey, string, findkey, phkey) == ERROR_SUCCESS) found = TRUE;
2152 if (*phkey != hkey) RegCloseKey(hkey);
2153 HeapFree(GetProcessHeap(), 0, string);
2154 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2157 static void test_Installer_InstallProduct(void)
2159 HRESULT hr;
2160 CHAR path[MAX_PATH];
2161 WCHAR szString[MAX_PATH];
2162 LONG res;
2163 HKEY hkey;
2164 DWORD num, size, type;
2165 int iValue, iCount;
2166 IDispatch *pStringList = NULL;
2168 create_test_files();
2170 /* Installer::InstallProduct */
2171 hr = Installer_InstallProduct(szMsifile, NULL);
2172 if (hr == DISP_E_EXCEPTION)
2174 skip("Installer object not supported.\n");
2175 delete_test_files();
2176 return;
2178 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2180 /* Installer::ProductState for our product code, which has been installed */
2181 hr = Installer_ProductState(szProductCode, &iValue);
2182 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2183 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2185 /* Installer::ProductInfo for our product code */
2187 /* NULL attribute */
2188 memset(szString, 0, sizeof(szString));
2189 hr = Installer_ProductInfo(szProductCode, NULL, szString);
2190 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2191 ok_exception(hr, szProductInfoException);
2193 /* Nonexistent attribute */
2194 memset(szString, 0, sizeof(szString));
2195 hr = Installer_ProductInfo(szProductCode, szMsifile, szString);
2196 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2197 ok_exception(hr, szProductInfoException);
2199 /* Package name */
2200 memset(szString, 0, sizeof(szString));
2201 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szString);
2202 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2203 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile);
2205 /* Product name */
2206 memset(szString, 0, sizeof(szString));
2207 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PRODUCTNAMEW, szString);
2208 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2209 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST);
2211 /* Installer::Products */
2212 test_Installer_Products(TRUE);
2214 /* Installer::RelatedProducts for our upgrade code */
2215 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2216 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2217 if (hr == S_OK)
2219 /* StringList::Count */
2220 hr = StringList_Count(pStringList, &iCount);
2221 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2222 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2224 /* StringList::Item */
2225 memset(szString, 0, sizeof(szString));
2226 hr = StringList_Item(pStringList, 0, szString);
2227 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2228 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
2230 IDispatch_Release(pStringList);
2233 /* Check & clean up installed files & registry keys */
2234 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2235 ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
2236 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2237 ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
2238 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2239 ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
2240 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2241 ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
2242 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2243 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2244 ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
2245 ok(delete_pf("msitest", FALSE), "File not installed\n");
2247 res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
2248 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2250 size = MAX_PATH;
2251 type = REG_SZ;
2252 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2253 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2254 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2256 size = MAX_PATH;
2257 type = REG_SZ;
2258 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2259 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2261 size = sizeof(num);
2262 type = REG_DWORD;
2263 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2264 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2265 ok(num == 314, "Expected 314, got %d\n", num);
2267 size = MAX_PATH;
2268 type = REG_SZ;
2269 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2270 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2271 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2273 RegCloseKey(hkey);
2275 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest");
2276 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2278 check_service_is_installed();
2280 /* Remove registry keys written by RegisterProduct standard action */
2281 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F1C3AF50-8B56-4A69-A00C-00773FE42F30}");
2282 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2284 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2285 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2287 res = find_registry_key(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "05FA3C1F65B896A40AC00077F34EF203", &hkey);
2288 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2289 if (res == ERROR_SUCCESS)
2291 res = delete_registry_key(hkey, "05FA3C1F65B896A40AC00077F34EF203");
2292 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2293 RegCloseKey(hkey);
2296 /* Remove registry keys written by PublishProduct standard action */
2297 res = RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2298 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2300 res = delete_registry_key(hkey, "Products\\05FA3C1F65B896A40AC00077F34EF203");
2301 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2303 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2304 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2306 RegCloseKey(hkey);
2308 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203");
2309 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2311 /* Delete installation files we installed */
2312 delete_test_files();
2315 static void test_Installer(void)
2317 static WCHAR szBackslash[] = { '\\',0 };
2318 static WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
2319 static WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
2320 WCHAR szPath[MAX_PATH];
2321 HRESULT hr;
2322 UINT len;
2323 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL;
2324 int iValue, iCount;
2326 if (!pInstaller) return;
2328 /* Installer::CreateRecord */
2330 /* Test for error */
2331 hr = Installer_CreateRecord(-1, &pRecord);
2332 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2333 ok_exception(hr, szCreateRecordException);
2335 /* Test for success */
2336 hr = Installer_CreateRecord(1, &pRecord);
2337 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2338 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2339 if (pRecord)
2341 /* Record::FieldCountGet */
2342 hr = Record_FieldCountGet(pRecord, &iValue);
2343 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2344 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2346 /* Record::IntegerDataGet */
2347 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2348 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2349 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2351 /* Record::IntegerDataGet, bad index */
2352 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2353 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2354 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2356 /* Record::IntegerDataPut */
2357 hr = Record_IntegerDataPut(pRecord, 1, 100);
2358 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2360 /* Record::IntegerDataPut, bad index */
2361 hr = Record_IntegerDataPut(pRecord, 10, 100);
2362 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2363 ok_exception(hr, szIntegerDataException);
2365 /* Record::IntegerDataGet */
2366 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2367 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2368 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2370 IDispatch_Release(pRecord);
2373 /* Prepare package */
2374 create_database(msifile, tables, sizeof(tables) / sizeof(msi_table),
2375 summary_info, sizeof(summary_info) / sizeof(msi_summary_info));
2377 len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, CURR_DIR, -1, szPath, MAX_PATH);
2378 ok(len, "MultiByteToWideChar returned error %d\n", GetLastError());
2379 if (!len) return;
2381 lstrcatW(szPath, szBackslash);
2382 lstrcatW(szPath, szMsifile);
2384 /* Installer::OpenPackage */
2385 hr = Installer_OpenPackage(szPath, 0, &pSession);
2386 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2387 if (hr == S_OK)
2389 test_Session(pSession);
2390 IDispatch_Release(pSession);
2393 /* Installer::OpenDatabase */
2394 hr = Installer_OpenDatabase(szPath, (int)MSIDBOPEN_TRANSACT, &pDatabase);
2395 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2396 if (hr == S_OK)
2398 test_Database(pDatabase, FALSE);
2399 IDispatch_Release(pDatabase);
2402 /* Installer::RegistryValue */
2403 test_Installer_RegistryValue();
2405 /* Installer::ProductState for our product code, which should not be installed */
2406 hr = Installer_ProductState(szProductCode, &iValue);
2407 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2408 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2410 /* Installer::ProductInfo for our product code, which should not be installed */
2412 /* Package name */
2413 memset(szPath, 0, sizeof(szPath));
2414 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szPath);
2415 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2416 ok_exception(hr, szProductInfoException);
2418 /* NULL attribute and NULL product code */
2419 memset(szPath, 0, sizeof(szPath));
2420 hr = Installer_ProductInfo(NULL, NULL, szPath);
2421 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2422 ok_exception(hr, szProductInfoException);
2424 /* Installer::Products */
2425 test_Installer_Products(FALSE);
2427 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2428 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2429 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2430 if (hr == S_OK)
2432 /* StringList::Count */
2433 hr = StringList_Count(pStringList, &iCount);
2434 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2435 ok(!iCount, "Expected no related products but found %d\n", iCount);
2437 IDispatch_Release(pStringList);
2440 /* Installer::Version */
2441 memset(szPath, 0, sizeof(szPath));
2442 hr = Installer_VersionGet(szPath);
2443 ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr);
2445 /* Installer::InstallProduct and other tests that depend on our product being installed */
2446 test_Installer_InstallProduct();
2449 START_TEST(automation)
2451 DWORD len;
2452 char temp_path[MAX_PATH], prev_path[MAX_PATH];
2453 HRESULT hr;
2454 CLSID clsid;
2455 IUnknown *pUnk;
2457 GetSystemTimeAsFileTime(&systemtime);
2459 GetCurrentDirectoryA(MAX_PATH, prev_path);
2460 GetTempPath(MAX_PATH, temp_path);
2461 SetCurrentDirectoryA(temp_path);
2463 lstrcpyA(CURR_DIR, temp_path);
2464 len = lstrlenA(CURR_DIR);
2466 if(len && (CURR_DIR[len - 1] == '\\'))
2467 CURR_DIR[len - 1] = 0;
2469 get_program_files_dir(PROG_FILES_DIR);
2471 hr = OleInitialize(NULL);
2472 ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr);
2473 hr = CLSIDFromProgID(szProgId, &clsid);
2474 ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr);
2475 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2476 ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr);
2478 if (pUnk)
2480 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2481 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2483 test_dispid();
2484 test_dispatch();
2485 test_Installer();
2487 IDispatch_Release(pInstaller);
2488 IUnknown_Release(pUnk);
2491 OleUninitialize();
2493 SetCurrentDirectoryA(prev_path);