push 796d1f0023dad2c87fb209f8123a098fd8cc8a3e
[wine/hacks.git] / dlls / msi / tests / automation.c
blobb76aae1810afa1fca4d85a6ca0dc22ca664bfeab
1 /*
2 * Copyright (C) 2007 Mike McCormack for CodeWeavers
3 * Copyright (C) 2007 Misha Koshelev
5 * A test program for Microsoft Installer OLE automation functionality.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
24 #include <stdio.h>
26 #include <initguid.h>
27 #include <windows.h>
28 #include <msiquery.h>
29 #include <msidefs.h>
30 #include <msi.h>
31 #include <fci.h>
33 #include "wine/test.h"
35 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
37 static const char *msifile = "winetest.msi";
38 static const WCHAR szMsifile[] = {'w','i','n','e','t','e','s','t','.','m','s','i',0};
39 static const WCHAR szMSITEST[] = { 'M','S','I','T','E','S','T',0 };
40 static const WCHAR szProductCode[] = { '{','F','1','C','3','A','F','5','0','-','8','B','5','6','-','4','A','6','9','-','A','0','0','C','-','0','0','7','7','3','F','E','4','2','F','3','0','}',0 };
41 static const WCHAR szUpgradeCode[] = { '{','C','E','0','6','7','E','8','D','-','2','E','1','A','-','4','3','6','7','-','B','7','3','4','-','4','E','B','2','B','D','A','D','6','5','6','5','}',0 };
42 static const WCHAR szProductInfoException[] = { 'P','r','o','d','u','c','t','I','n','f','o',',','P','r','o','d','u','c','t',',','A','t','t','r','i','b','u','t','e',0 };
43 static const WCHAR WINE_INSTALLPROPERTY_PACKAGENAMEW[] = {'P','a','c','k','a','g','e','N','a','m','e',0};
44 static const WCHAR WINE_INSTALLPROPERTY_PRODUCTNAMEW[] = {'P','r','o','d','u','c','t','N','a','m','e',0};
45 static FILETIME systemtime;
46 static CHAR CURR_DIR[MAX_PATH];
47 static EXCEPINFO excepinfo;
50 * OLE automation data
51 **/
52 static const WCHAR szProgId[] = { 'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r','.','I','n','s','t','a','l','l','e','r',0 };
53 static IDispatch *pInstaller;
55 /* msi database data */
57 static const CHAR component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
58 "s72\tS38\ts72\ti2\tS255\tS72\n"
59 "Component\tComponent\n"
60 "Five\t{8CC92E9D-14B2-4CA4-B2AA-B11D02078087}\tNEWDIR\t2\t\tfive.txt\n"
61 "Four\t{FD37B4EA-7209-45C0-8917-535F35A2F080}\tCABOUTDIR\t2\t\tfour.txt\n"
62 "One\t{783B242E-E185-4A56-AF86-C09815EC053C}\tMSITESTDIR\t2\t\tone.txt\n"
63 "Three\t{010B6ADD-B27D-4EDD-9B3D-34C4F7D61684}\tCHANGEDDIR\t2\t\tthree.txt\n"
64 "Two\t{BF03D1A6-20DA-4A65-82F3-6CAC995915CE}\tFIRSTDIR\t2\t\ttwo.txt\n"
65 "dangler\t{6091DF25-EF96-45F1-B8E9-A9B1420C7A3C}\tTARGETDIR\t4\t\tregdata\n"
66 "component\t\tMSITESTDIR\t0\t1\tfile\n";
68 static const CHAR directory_dat[] = "Directory\tDirectory_Parent\tDefaultDir\n"
69 "s72\tS72\tl255\n"
70 "Directory\tDirectory\n"
71 "CABOUTDIR\tMSITESTDIR\tcabout\n"
72 "CHANGEDDIR\tMSITESTDIR\tchanged:second\n"
73 "FIRSTDIR\tMSITESTDIR\tfirst\n"
74 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
75 "NEWDIR\tCABOUTDIR\tnew\n"
76 "ProgramFilesFolder\tTARGETDIR\t.\n"
77 "TARGETDIR\t\tSourceDir";
79 static const CHAR feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
80 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
81 "Feature\tFeature\n"
82 "Five\t\tFive\tThe Five Feature\t5\t3\tNEWDIR\t0\n"
83 "Four\t\tFour\tThe Four Feature\t4\t3\tCABOUTDIR\t0\n"
84 "One\t\tOne\tThe One Feature\t1\t3\tMSITESTDIR\t0\n"
85 "Three\tOne\tThree\tThe Three Feature\t3\t3\tCHANGEDDIR\t0\n"
86 "Two\tOne\tTwo\tThe Two Feature\t2\t3\tFIRSTDIR\t0\n"
87 "feature\t\t\t\t2\t1\tTARGETDIR\t0\n";
89 static const CHAR feature_comp_dat[] = "Feature_\tComponent_\n"
90 "s38\ts72\n"
91 "FeatureComponents\tFeature_\tComponent_\n"
92 "Five\tFive\n"
93 "Four\tFour\n"
94 "One\tOne\n"
95 "Three\tThree\n"
96 "Two\tTwo\n"
97 "feature\tcomponent\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";
109 static const CHAR install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
110 "s72\tS255\tI2\n"
111 "InstallExecuteSequence\tAction\n"
112 "AllocateRegistrySpace\tNOT Installed\t1550\n"
113 "CostFinalize\t\t1000\n"
114 "CostInitialize\t\t800\n"
115 "FileCost\t\t900\n"
116 "InstallFiles\t\t4000\n"
117 "RegisterProduct\t\t6100\n"
118 "PublishProduct\t\t6400\n"
119 "InstallFinalize\t\t6600\n"
120 "InstallInitialize\t\t1500\n"
121 "InstallValidate\t\t1400\n"
122 "LaunchConditions\t\t100\n"
123 "WriteRegistryValues\tSourceDir And SOURCEDIR\t5000";
125 static const CHAR media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
126 "i2\ti4\tL64\tS255\tS32\tS72\n"
127 "Media\tDiskId\n"
128 "1\t5\t\t\tDISK1\t\n";
130 static const CHAR property_dat[] = "Property\tValue\n"
131 "s72\tl0\n"
132 "Property\tProperty\n"
133 "DefaultUIFont\tDlgFont8\n"
134 "HASUIRUN\t0\n"
135 "INSTALLLEVEL\t3\n"
136 "InstallMode\tTypical\n"
137 "Manufacturer\tWine\n"
138 "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n"
139 "ProductCode\t{F1C3AF50-8B56-4A69-A00C-00773FE42F30}\n"
140 "ProductID\tnone\n"
141 "ProductLanguage\t1033\n"
142 "ProductName\tMSITEST\n"
143 "ProductVersion\t1.1.1\n"
144 "PROMPTROLLBACKCOST\tP\n"
145 "Setup\tSetup\n"
146 "UpgradeCode\t{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}";
148 static const CHAR registry_dat[] = "Registry\tRoot\tKey\tName\tValue\tComponent_\n"
149 "s72\ti2\tl255\tL255\tL0\ts72\n"
150 "Registry\tRegistry\n"
151 "Apples\t2\tSOFTWARE\\Wine\\msitest\tName\timaname\tOne\n"
152 "Oranges\t2\tSOFTWARE\\Wine\\msitest\tnumber\t#314\tTwo\n"
153 "regdata\t2\tSOFTWARE\\Wine\\msitest\tblah\tbad\tdangler\n"
154 "OrderTest\t2\tSOFTWARE\\Wine\\msitest\tOrderTestName\tOrderTestValue\tcomponent";
156 typedef struct _msi_table
158 const CHAR *filename;
159 const CHAR *data;
160 int size;
161 } msi_table;
163 #define ADD_TABLE(x) {#x".idt", x##_dat, sizeof(x##_dat)}
165 static const msi_table tables[] =
167 ADD_TABLE(component),
168 ADD_TABLE(directory),
169 ADD_TABLE(feature),
170 ADD_TABLE(feature_comp),
171 ADD_TABLE(file),
172 ADD_TABLE(install_exec_seq),
173 ADD_TABLE(media),
174 ADD_TABLE(property),
175 ADD_TABLE(registry)
178 typedef struct _msi_summary_info
180 UINT property;
181 UINT datatype;
182 INT iValue;
183 FILETIME *pftValue;
184 const CHAR *szValue;
185 } msi_summary_info;
187 #define ADD_INFO_I2(property, iValue) {property, VT_I2, iValue, NULL, NULL}
188 #define ADD_INFO_I4(property, iValue) {property, VT_I4, iValue, NULL, NULL}
189 #define ADD_INFO_LPSTR(property, szValue) {property, VT_LPSTR, 0, NULL, szValue}
190 #define ADD_INFO_FILETIME(property, pftValue) {property, VT_FILETIME, 0, pftValue, NULL}
192 static const msi_summary_info summary_info[] =
194 ADD_INFO_LPSTR(PID_TEMPLATE, ";1033"),
195 ADD_INFO_LPSTR(PID_REVNUMBER, "{004757CA-5092-49c2-AD20-28E1CE0DF5F2}"),
196 ADD_INFO_I4(PID_PAGECOUNT, 100),
197 ADD_INFO_I4(PID_WORDCOUNT, 0),
198 ADD_INFO_FILETIME(PID_CREATE_DTM, &systemtime),
199 ADD_INFO_FILETIME(PID_LASTPRINTED, &systemtime)
203 * Database Helpers
206 static void write_file(const CHAR *filename, const char *data, int data_size)
208 DWORD size;
210 HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL,
211 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
213 WriteFile(hf, data, data_size, &size, NULL);
214 CloseHandle(hf);
217 static void write_msi_summary_info(MSIHANDLE db, const msi_summary_info *info, int num_info)
219 MSIHANDLE summary;
220 UINT r;
221 int j;
223 r = MsiGetSummaryInformationA(db, NULL, num_info, &summary);
224 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
226 /* import summary information into the stream */
227 for (j = 0; j < num_info; j++)
229 const msi_summary_info *entry = &info[j];
231 r = MsiSummaryInfoSetPropertyA(summary, entry->property, entry->datatype,
232 entry->iValue, entry->pftValue, entry->szValue);
233 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
236 /* write the summary changes back to the stream */
237 r = MsiSummaryInfoPersist(summary);
238 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
240 MsiCloseHandle(summary);
243 static void create_database(const CHAR *name, const msi_table *tables, int num_tables,
244 const msi_summary_info *info, int num_info)
246 MSIHANDLE db;
247 UINT r;
248 int j;
250 r = MsiOpenDatabaseA(name, MSIDBOPEN_CREATE, &db);
251 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
253 /* import the tables into the database */
254 for (j = 0; j < num_tables; j++)
256 const msi_table *table = &tables[j];
258 write_file(table->filename, table->data, (table->size - 1) * sizeof(char));
260 r = MsiDatabaseImportA(db, CURR_DIR, table->filename);
261 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
263 DeleteFileA(table->filename);
266 write_msi_summary_info(db, info, num_info);
268 r = MsiDatabaseCommit(db);
269 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
271 MsiCloseHandle(db);
275 * Installation helpers
278 static char PROG_FILES_DIR[MAX_PATH];
280 static BOOL get_program_files_dir(LPSTR buf)
282 HKEY hkey;
283 DWORD type = REG_EXPAND_SZ, size;
285 if (RegOpenKey(HKEY_LOCAL_MACHINE,
286 "Software\\Microsoft\\Windows\\CurrentVersion", &hkey))
287 return FALSE;
289 size = MAX_PATH;
290 if (RegQueryValueEx(hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size))
291 return FALSE;
293 RegCloseKey(hkey);
294 return TRUE;
297 static void create_file(const CHAR *name, DWORD size)
299 HANDLE file;
300 DWORD written, left;
302 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
303 ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
304 WriteFile(file, name, strlen(name), &written, NULL);
305 WriteFile(file, "\n", strlen("\n"), &written, NULL);
307 left = size - lstrlen(name) - 1;
309 SetFilePointer(file, left, NULL, FILE_CURRENT);
310 SetEndOfFile(file);
312 CloseHandle(file);
315 static void create_test_files(void)
317 CreateDirectoryA("msitest", NULL);
318 create_file("msitest\\one.txt", 100);
319 CreateDirectoryA("msitest\\first", NULL);
320 create_file("msitest\\first\\two.txt", 100);
321 CreateDirectoryA("msitest\\second", NULL);
322 create_file("msitest\\second\\three.txt", 100);
323 CreateDirectoryA("msitest\\cabout",NULL);
324 create_file("msitest\\cabout\\four.txt", 100);
325 CreateDirectoryA("msitest\\cabout\\new",NULL);
326 create_file("msitest\\cabout\\new\\five.txt", 100);
327 create_file("msitest\\filename", 100);
330 static BOOL delete_pf(const CHAR *rel_path, BOOL is_file)
332 CHAR path[MAX_PATH];
334 lstrcpyA(path, PROG_FILES_DIR);
335 lstrcatA(path, "\\");
336 lstrcatA(path, rel_path);
338 if (is_file)
339 return DeleteFileA(path);
340 else
341 return RemoveDirectoryA(path);
344 static void delete_test_files(void)
346 DeleteFileA(msifile);
347 DeleteFileA("msitest\\cabout\\new\\five.txt");
348 DeleteFileA("msitest\\cabout\\four.txt");
349 DeleteFileA("msitest\\second\\three.txt");
350 DeleteFileA("msitest\\first\\two.txt");
351 DeleteFileA("msitest\\one.txt");
352 DeleteFileA("msitest\\filename");
353 RemoveDirectoryA("msitest\\cabout\\new");
354 RemoveDirectoryA("msitest\\cabout");
355 RemoveDirectoryA("msitest\\second");
356 RemoveDirectoryA("msitest\\first");
357 RemoveDirectoryA("msitest");
361 * Automation helpers and tests
364 /* ok-like statement which takes two unicode strings or one unicode and one ANSI string as arguments */
365 static CHAR string1[MAX_PATH], string2[MAX_PATH];
367 #define ok_w2(format, szString1, szString2) \
369 if (lstrcmpW(szString1, szString2) != 0) \
371 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
372 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
373 ok(0, format, string1, string2); \
376 #define ok_w2n(format, szString1, szString2, len) \
378 if (memcmp(szString1, szString2, len * sizeof(WCHAR)) != 0) \
380 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
381 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
382 ok(0, format, string1, string2); \
385 #define ok_aw(format, aString, wString) \
387 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
388 if (lstrcmpA(string1, aString) != 0) \
389 ok(0, format, string1, aString); \
391 #define ok_awplus(format, extra, aString, wString) \
393 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
394 if (lstrcmpA(string1, aString) != 0) \
395 ok(0, format, extra, string1, aString); \
397 /* exception checker */
398 static WCHAR szSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
400 #define ok_exception(hr, szDescription) \
401 if (hr == DISP_E_EXCEPTION) \
403 /* Compare wtype, source, and destination */ \
404 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
406 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
407 if (excepinfo.bstrSource) \
408 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, szSource); \
410 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
411 if (excepinfo.bstrDescription) \
412 ok_w2("Exception description was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrDescription, szDescription); \
414 SysFreeString(excepinfo.bstrSource); \
415 SysFreeString(excepinfo.bstrDescription); \
416 SysFreeString(excepinfo.bstrHelpFile); \
419 static DISPID get_dispid( IDispatch *disp, const char *name )
421 LPOLESTR str;
422 UINT len;
423 DISPID id = -1;
424 HRESULT r;
426 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
427 str = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
428 if (str)
430 len = MultiByteToWideChar(CP_ACP, 0, name, -1, str, len );
431 r = IDispatch_GetIDsOfNames( disp, &IID_NULL, &str, 1, 0, &id );
432 HeapFree(GetProcessHeap(), 0, str);
433 if (r != S_OK)
434 return -1;
437 return id;
440 static void test_dispid(void)
442 DISPID dispid;
444 dispid = get_dispid(pInstaller, "CreateRecord");
445 ok(dispid == 1, "Expected 1, got %d\n", dispid);
446 dispid = get_dispid(pInstaller, "OpenPackage");
447 ok(dispid == 2, "Expected 2, got %d\n", dispid);
448 dispid = get_dispid(pInstaller, "OpenDatabase");
449 ok(dispid == 4, "Expected 4, got %d\n", dispid);
450 dispid = get_dispid( pInstaller, "UILevel" );
451 ok(dispid == 6, "Expected 6, got %d\n", dispid);
452 dispid = get_dispid(pInstaller, "InstallProduct");
453 ok(dispid == 8, "Expected 8, got %d\n", dispid);
454 dispid = get_dispid(pInstaller, "Version");
455 ok(dispid == 9, "Expected 9, got %d\n", dispid);
456 dispid = get_dispid(pInstaller, "RegistryValue");
457 ok(dispid == 11, "Expected 11, got %d\n", dispid);
458 todo_wine
460 dispid = get_dispid(pInstaller, "OpenProduct");
461 ok(dispid == 3, "Expected 3, got %d\n", dispid);
462 dispid = get_dispid(pInstaller, "SummaryInformation");
463 ok(dispid == 5, "Expected 5, got %d\n", dispid);
464 dispid = get_dispid(pInstaller, "EnableLog");
465 ok(dispid == 7, "Expected 7, got %d\n", dispid);
466 dispid = get_dispid(pInstaller, "LastErrorRecord");
467 ok(dispid == 10, "Expected 10, got %d\n", dispid);
468 dispid = get_dispid(pInstaller, "Environment");
469 ok(dispid == 12, "Expected 12, got %d\n", dispid);
470 dispid = get_dispid(pInstaller, "FileAttributes");
471 ok(dispid == 13, "Expected 13, got %d\n", dispid);
472 dispid = get_dispid(pInstaller, "FileSize");
473 ok(dispid == 15, "Expected 15, got %d\n", dispid);
474 dispid = get_dispid(pInstaller, "FileVersion");
475 ok(dispid == 16, "Expected 16, got %d\n", dispid);
477 dispid = get_dispid(pInstaller, "ProductState");
478 ok(dispid == 17, "Expected 17, got %d\n", dispid);
479 dispid = get_dispid(pInstaller, "ProductInfo");
480 ok(dispid == 18, "Expected 18, got %d\n", dispid);
481 todo_wine
483 dispid = get_dispid(pInstaller, "ConfigureProduct");
484 ok(dispid == 19, "Expected 19, got %d\n", dispid);
485 dispid = get_dispid(pInstaller, "ReinstallProduct");
486 ok(dispid == 20 , "Expected 20, got %d\n", dispid);
487 dispid = get_dispid(pInstaller, "CollectUserInfo");
488 ok(dispid == 21, "Expected 21, got %d\n", dispid);
489 dispid = get_dispid(pInstaller, "ApplyPatch");
490 ok(dispid == 22, "Expected 22, got %d\n", dispid);
491 dispid = get_dispid(pInstaller, "FeatureParent");
492 ok(dispid == 23, "Expected 23, got %d\n", dispid);
493 dispid = get_dispid(pInstaller, "FeatureState");
494 ok(dispid == 24, "Expected 24, got %d\n", dispid);
495 dispid = get_dispid(pInstaller, "UseFeature");
496 ok(dispid == 25, "Expected 25, got %d\n", dispid);
497 dispid = get_dispid(pInstaller, "FeatureUsageCount");
498 ok(dispid == 26, "Expected 26, got %d\n", dispid);
499 dispid = get_dispid(pInstaller, "FeatureUsageDate");
500 ok(dispid == 27, "Expected 27, got %d\n", dispid);
501 dispid = get_dispid(pInstaller, "ConfigureFeature");
502 ok(dispid == 28, "Expected 28, got %d\n", dispid);
503 dispid = get_dispid(pInstaller, "ReinstallFeature");
504 ok(dispid == 29, "Expected 29, got %d\n", dispid);
505 dispid = get_dispid(pInstaller, "ProvideComponent");
506 ok(dispid == 30, "Expected 30, got %d\n", dispid);
507 dispid = get_dispid(pInstaller, "ComponentPath");
508 ok(dispid == 31, "Expected 31, got %d\n", dispid);
509 dispid = get_dispid(pInstaller, "ProvideQualifiedComponent");
510 ok(dispid == 32, "Expected 32, got %d\n", dispid);
511 dispid = get_dispid(pInstaller, "QualifierDescription");
512 ok(dispid == 33, "Expected 33, got %d\n", dispid);
513 dispid = get_dispid(pInstaller, "ComponentQualifiers");
514 ok(dispid == 34, "Expected 34, got %d\n", dispid);
516 dispid = get_dispid(pInstaller, "Products");
517 ok(dispid == 35, "Expected 35, got %d\n", dispid);
518 todo_wine
520 dispid = get_dispid(pInstaller, "Features");
521 ok(dispid == 36, "Expected 36, got %d\n", dispid);
522 dispid = get_dispid(pInstaller, "Components");
523 ok(dispid == 37, "Expected 37, got %d\n", dispid);
524 dispid = get_dispid(pInstaller, "ComponentClients");
525 ok(dispid == 38, "Expected 38, got %d\n", dispid);
526 dispid = get_dispid(pInstaller, "Patches");
527 ok(dispid == 39, "Expected 39, got %d\n", dispid);
529 dispid = get_dispid(pInstaller, "RelatedProducts");
530 ok(dispid == 40, "Expected 40, got %d\n", dispid);
531 todo_wine
533 dispid = get_dispid(pInstaller, "PatchInfo");
534 ok(dispid == 41, "Expected 41, got %d\n", dispid);
535 dispid = get_dispid(pInstaller, "PatchTransforms");
536 ok(dispid == 42, "Expected 42, got %d\n", dispid);
537 dispid = get_dispid(pInstaller, "AddSource");
538 ok(dispid == 43, "Expected 43, got %d\n", dispid);
539 dispid = get_dispid(pInstaller, "ClearSourceList");
540 ok(dispid == 44, "Expected 44, got %d\n", dispid);
541 dispid = get_dispid(pInstaller, "ForceSourceListResolution");
542 ok(dispid == 45, "Expected 45, got %d\n", dispid);
543 dispid = get_dispid(pInstaller, "ShortcutTarget");
544 ok(dispid == 46, "Expected 46, got %d\n", dispid);
545 dispid = get_dispid(pInstaller, "FileHash");
546 ok(dispid == 47, "Expected 47, got %d\n", dispid);
547 dispid = get_dispid(pInstaller, "FileSignatureInfo");
548 ok(dispid == 48, "Expected 48, got %d\n", dispid);
550 dispid = get_dispid(pInstaller, "RemovePatches");
551 ok(dispid == 49 || dispid == -1, "Expected 49 or -1, got %d\n", dispid);
552 dispid = get_dispid(pInstaller, "ApplyMultiplePatches");
553 ok(dispid == 51 || dispid == -1, "Expected 51 or -1, got %d\n", dispid);
554 dispid = get_dispid(pInstaller, "ProductsEx");
555 ok(dispid == 52 || dispid == -1, "Expected 52 or -1, got %d\n", dispid);
556 dispid = get_dispid(pInstaller, "PatchesEx");
557 ok(dispid == 55 || dispid == -1, "Expected 55 or -1, got %d\n", dispid);
558 dispid = get_dispid(pInstaller, "ExtractPatchXMLData");
559 ok(dispid == 57 || dispid == -1, "Expected 57 or -1, got %d\n", dispid);
560 dispid = get_dispid( pInstaller, "ProductElevated" );
561 ok(dispid == 59 || dispid == -1, "Expected 59 or -1, got %d\n", dispid);
562 dispid = get_dispid( pInstaller, "ProvideAssembly" );
563 ok(dispid == 60 || dispid == -1, "Expected 60 or -1, got %d\n", dispid);
564 dispid = get_dispid( pInstaller, "ProductInfoFromScript" );
565 ok(dispid == 61 || dispid == -1, "Expected 61 or -1, got %d\n", dispid);
566 dispid = get_dispid( pInstaller, "AdvertiseProduct" );
567 ok(dispid == 62 || dispid == -1, "Expected 62 or -1, got %d\n", dispid);
568 dispid = get_dispid( pInstaller, "CreateAdvertiseScript" );
569 ok(dispid == 63 || dispid == -1, "Expected 63 or -1, got %d\n", dispid);
570 dispid = get_dispid( pInstaller, "PatchFiles" );
571 ok(dispid == 65 || dispid == -1, "Expected 65 or -1, got %d\n", dispid);
574 /* Test basic IDispatch functions */
575 static void test_dispatch(void)
577 static WCHAR szOpenPackage[] = { 'O','p','e','n','P','a','c','k','a','g','e',0 };
578 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};
579 static WCHAR szProductState[] = { 'P','r','o','d','u','c','t','S','t','a','t','e',0 };
580 HRESULT hr;
581 DISPID dispid;
582 OLECHAR *name;
583 VARIANT varresult;
584 VARIANTARG vararg[2];
585 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
587 /* Test getting ID of a function name that does not exist */
588 name = (WCHAR *)szMsifile;
589 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
590 ok(hr == DISP_E_UNKNOWNNAME, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
592 /* Test invoking this function */
593 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
594 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
596 /* Test getting ID of a function name that does exist */
597 name = (WCHAR *)szOpenPackage;
598 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
599 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
601 /* Test invoking this function (without parameters passed) */
602 if (0) /* All of these crash MSI on Windows XP */
604 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
605 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL);
606 VariantInit(&varresult);
607 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, &varresult, &excepinfo, NULL);
610 /* Try with NULL params */
611 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
612 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
614 /* Try one empty parameter */
615 dispparams.rgvarg = vararg;
616 dispparams.cArgs = 1;
617 VariantInit(&vararg[0]);
618 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
619 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
621 /* Try one parameter, function requires two */
622 VariantInit(&vararg[0]);
623 V_VT(&vararg[0]) = VT_BSTR;
624 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
625 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
626 VariantClear(&vararg[0]);
628 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
629 ok_exception(hr, szOpenPackageException);
631 /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
632 VariantInit(&vararg[0]);
633 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
634 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
636 VariantInit(&vararg[0]);
637 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
638 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
640 /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
641 name = (WCHAR *)szProductState;
642 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
643 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
645 dispparams.rgvarg = NULL;
646 dispparams.cArgs = 0;
647 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
648 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
650 dispparams.rgvarg = NULL;
651 dispparams.cArgs = 0;
652 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
653 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
656 /* invocation helper function */
657 static int _invoke_todo_vtResult = 0;
659 static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult)
661 OLECHAR *name = NULL;
662 DISPID dispid;
663 HRESULT hr;
664 UINT i;
665 UINT len;
667 memset(pVarResult, 0, sizeof(VARIANT));
668 VariantInit(pVarResult);
670 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 );
671 name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
672 if (!name) return E_FAIL;
673 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len );
674 hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
675 HeapFree(GetProcessHeap(), 0, name);
676 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
677 if (!hr == S_OK) return hr;
679 memset(&excepinfo, 0, sizeof(excepinfo));
680 hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL);
682 if (hr == S_OK)
684 if (_invoke_todo_vtResult) todo_wine
685 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
686 else
687 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
688 if (vtResult != VT_EMPTY)
690 hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult);
691 ok(hr == S_OK, "VariantChangeTypeEx returned 0x%08x\n", hr);
695 for (i=0; i<pDispParams->cArgs; i++)
696 VariantClear(&pDispParams->rgvarg[i]);
698 return hr;
701 /* Object_Property helper functions */
703 static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord)
705 VARIANT varresult;
706 VARIANTARG vararg[1];
707 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
708 HRESULT hr;
710 VariantInit(&vararg[0]);
711 V_VT(&vararg[0]) = VT_I4;
712 V_I4(&vararg[0]) = count;
714 hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
715 *pRecord = V_DISPATCH(&varresult);
716 return hr;
719 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
721 VARIANTARG vararg[3];
722 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
724 VariantInit(&vararg[2]);
725 V_VT(&vararg[2]) = VT_I4;
726 V_I4(&vararg[2]) = (int)hkey;
727 VariantInit(&vararg[1]);
728 V_VT(&vararg[1]) = VT_BSTR;
729 V_BSTR(&vararg[1]) = SysAllocString(szKey);
730 VariantInit(&vararg[0]);
731 VariantCopy(&vararg[0], &vValue);
732 VariantClear(&vValue);
734 return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect);
737 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
739 VARIANT varresult;
740 VARIANTARG vararg;
741 HRESULT hr;
743 VariantInit(&vararg);
744 V_VT(&vararg) = VT_EMPTY;
745 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL);
746 *pBool = V_BOOL(&varresult);
747 VariantClear(&varresult);
748 return hr;
751 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
753 VARIANT varresult;
754 VARIANTARG vararg;
755 HRESULT hr;
757 VariantInit(&vararg);
758 V_VT(&vararg) = VT_BSTR;
759 V_BSTR(&vararg) = SysAllocString(szValue);
761 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR);
762 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
763 VariantClear(&varresult);
764 return hr;
767 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
769 VARIANT varresult;
770 VARIANTARG vararg;
771 HRESULT hr;
773 VariantInit(&vararg);
774 V_VT(&vararg) = VT_I4;
775 V_I4(&vararg) = iValue;
777 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult);
778 if (SUCCEEDED(hr) && vtResult == VT_BSTR) lstrcpyW(szString, V_BSTR(&varresult));
779 VariantClear(&varresult);
780 return hr;
783 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
785 VARIANT varresult;
786 VARIANTARG vararg[2];
787 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
788 HRESULT hr;
790 VariantInit(&vararg[1]);
791 V_VT(&vararg[1]) = VT_BSTR;
792 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
793 VariantInit(&vararg[0]);
794 V_VT(&vararg[0]) = VT_I4;
795 V_I4(&vararg[0]) = options;
797 hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
798 *pSession = V_DISPATCH(&varresult);
799 return hr;
802 static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase)
804 VARIANT varresult;
805 VARIANTARG vararg[2];
806 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
807 HRESULT hr;
809 VariantInit(&vararg[1]);
810 V_VT(&vararg[1]) = VT_BSTR;
811 V_BSTR(&vararg[1]) = SysAllocString(szDatabasePath);
812 VariantInit(&vararg[0]);
813 V_VT(&vararg[0]) = VT_I4;
814 V_I4(&vararg[0]) = openmode;
816 hr = invoke(pInstaller, "OpenDatabase", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
817 *pDatabase = V_DISPATCH(&varresult);
818 return hr;
821 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
823 VARIANT varresult;
824 VARIANTARG vararg[2];
825 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
827 VariantInit(&vararg[1]);
828 V_VT(&vararg[1]) = VT_BSTR;
829 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
830 VariantInit(&vararg[0]);
831 V_VT(&vararg[0]) = VT_BSTR;
832 V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues);
834 return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
837 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
839 VARIANT varresult;
840 VARIANTARG vararg[1];
841 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
842 HRESULT hr;
844 VariantInit(&vararg[0]);
845 V_VT(&vararg[0]) = VT_BSTR;
846 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
848 hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
849 *pInstallState = V_I4(&varresult);
850 VariantClear(&varresult);
851 return hr;
854 static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szString)
856 VARIANT varresult;
857 VARIANTARG vararg[2];
858 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
859 HRESULT hr;
861 VariantInit(&vararg[1]);
862 V_VT(&vararg[1]) = VT_BSTR;
863 V_BSTR(&vararg[1]) = SysAllocString(szProduct);
864 VariantInit(&vararg[0]);
865 V_VT(&vararg[0]) = VT_BSTR;
866 V_BSTR(&vararg[0]) = SysAllocString(szAttribute);
868 hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
869 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
870 VariantClear(&varresult);
871 return hr;
874 static HRESULT Installer_Products(IDispatch **pStringList)
876 VARIANT varresult;
877 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
878 HRESULT hr;
880 hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
881 *pStringList = V_DISPATCH(&varresult);
882 return hr;
885 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
887 VARIANT varresult;
888 VARIANTARG vararg[1];
889 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
890 HRESULT hr;
892 VariantInit(&vararg[0]);
893 V_VT(&vararg[0]) = VT_BSTR;
894 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
896 hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
897 *pStringList = V_DISPATCH(&varresult);
898 return hr;
901 static HRESULT Installer_VersionGet(LPWSTR szVersion)
903 VARIANT varresult;
904 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
905 HRESULT hr;
907 hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
908 if (V_BSTR(&varresult)) lstrcpyW(szVersion, V_BSTR(&varresult));
909 VariantClear(&varresult);
910 return hr;
913 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
915 VARIANT varresult;
916 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
917 HRESULT hr;
919 hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
920 *pInst = V_DISPATCH(&varresult);
921 return hr;
924 static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn)
926 VARIANT varresult;
927 VARIANTARG vararg[1];
928 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
929 HRESULT hr;
931 VariantInit(&vararg[0]);
932 V_VT(&vararg[0]) = VT_BSTR;
933 V_BSTR(&vararg[0]) = SysAllocString(szName);
935 hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
936 if (V_BSTR(&varresult)) lstrcpyW(szReturn, V_BSTR(&varresult));
937 VariantClear(&varresult);
938 return hr;
941 static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue)
943 VARIANT varresult;
944 VARIANTARG vararg[2];
945 DISPID dispid = DISPID_PROPERTYPUT;
946 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
948 VariantInit(&vararg[1]);
949 V_VT(&vararg[1]) = VT_BSTR;
950 V_BSTR(&vararg[1]) = SysAllocString(szName);
951 VariantInit(&vararg[0]);
952 V_VT(&vararg[0]) = VT_BSTR;
953 V_BSTR(&vararg[0]) = SysAllocString(szValue);
955 return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
958 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
960 VARIANT varresult;
961 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
962 HRESULT hr;
964 hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
965 *pLangId = V_I4(&varresult);
966 VariantClear(&varresult);
967 return hr;
970 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, BOOL *pMode)
972 VARIANT varresult;
973 VARIANTARG vararg[1];
974 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
975 HRESULT hr;
977 VariantInit(&vararg[0]);
978 V_VT(&vararg[0]) = VT_I4;
979 V_I4(&vararg[0]) = iFlag;
981 hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL);
982 *pMode = V_BOOL(&varresult);
983 VariantClear(&varresult);
984 return hr;
987 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, BOOL bMode)
989 VARIANT varresult;
990 VARIANTARG vararg[2];
991 DISPID dispid = DISPID_PROPERTYPUT;
992 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
994 VariantInit(&vararg[1]);
995 V_VT(&vararg[1]) = VT_I4;
996 V_I4(&vararg[1]) = iFlag;
997 VariantInit(&vararg[0]);
998 V_VT(&vararg[0]) = VT_BOOL;
999 V_BOOL(&vararg[0]) = bMode;
1001 return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1004 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
1006 VARIANT varresult;
1007 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1008 HRESULT hr;
1010 hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1011 *pDatabase = V_DISPATCH(&varresult);
1012 return hr;
1015 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn)
1017 VARIANT varresult;
1018 VARIANTARG vararg[1];
1019 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1020 HRESULT hr;
1022 VariantInit(&vararg[0]);
1023 V_VT(&vararg[0]) = VT_BSTR;
1024 V_BSTR(&vararg[0]) = SysAllocString(szAction);
1026 hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1027 *iReturn = V_I4(&varresult);
1028 VariantClear(&varresult);
1029 return hr;
1032 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
1034 VARIANT varresult;
1035 VARIANTARG vararg[1];
1036 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1037 HRESULT hr;
1039 VariantInit(&vararg[0]);
1040 V_VT(&vararg[0]) = VT_BSTR;
1041 V_BSTR(&vararg[0]) = SysAllocString(szCondition);
1043 hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1044 *iReturn = V_I4(&varresult);
1045 VariantClear(&varresult);
1046 return hr;
1049 static HRESULT Session_Message(IDispatch *pSession, long kind, IDispatch *record, int *ret)
1051 VARIANT varresult;
1052 VARIANTARG vararg[2];
1053 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1054 HRESULT hr;
1056 VariantInit(&varresult);
1057 V_VT(vararg) = VT_DISPATCH;
1058 V_DISPATCH(vararg) = record;
1059 V_VT(vararg+1) = VT_I4;
1060 V_I4(vararg+1) = kind;
1062 hr = invoke(pSession, "Message", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1064 ok(V_VT(&varresult) == VT_I4, "V_VT(varresult) = %d\n", V_VT(&varresult));
1065 *ret = V_I4(&varresult);
1067 return hr;
1070 static HRESULT Session_SetInstallLevel(IDispatch *pSession, long iInstallLevel)
1072 VARIANT varresult;
1073 VARIANTARG vararg[1];
1074 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1076 VariantInit(&vararg[0]);
1077 V_VT(&vararg[0]) = VT_I4;
1078 V_I4(&vararg[0]) = iInstallLevel;
1080 return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1083 static HRESULT Session_FeatureCurrentState(IDispatch *pSession, LPCWSTR szName, int *pState)
1085 VARIANT varresult;
1086 VARIANTARG vararg[1];
1087 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1088 HRESULT hr;
1090 VariantInit(&vararg[0]);
1091 V_VT(&vararg[0]) = VT_BSTR;
1092 V_BSTR(&vararg[0]) = SysAllocString(szName);
1094 hr = invoke(pSession, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1095 *pState = V_I4(&varresult);
1096 VariantClear(&varresult);
1097 return hr;
1100 static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState)
1102 VARIANT varresult;
1103 VARIANTARG vararg[1];
1104 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1105 HRESULT hr;
1107 VariantInit(&vararg[0]);
1108 V_VT(&vararg[0]) = VT_BSTR;
1109 V_BSTR(&vararg[0]) = SysAllocString(szName);
1111 hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1112 *pState = V_I4(&varresult);
1113 VariantClear(&varresult);
1114 return hr;
1117 static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState)
1119 VARIANT varresult;
1120 VARIANTARG vararg[2];
1121 DISPID dispid = DISPID_PROPERTYPUT;
1122 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1124 VariantInit(&vararg[1]);
1125 V_VT(&vararg[1]) = VT_BSTR;
1126 V_BSTR(&vararg[1]) = SysAllocString(szName);
1127 VariantInit(&vararg[0]);
1128 V_VT(&vararg[0]) = VT_I4;
1129 V_I4(&vararg[0]) = iState;
1131 return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1134 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
1136 VARIANT varresult;
1137 VARIANTARG vararg[1];
1138 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1139 HRESULT hr;
1141 VariantInit(&vararg[0]);
1142 V_VT(&vararg[0]) = VT_BSTR;
1143 V_BSTR(&vararg[0]) = SysAllocString(szSql);
1145 hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1146 *pView = V_DISPATCH(&varresult);
1147 return hr;
1150 static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo)
1152 VARIANT varresult;
1153 VARIANTARG vararg[1];
1154 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1155 HRESULT hr;
1157 VariantInit(&vararg[0]);
1158 V_VT(&vararg[0]) = VT_I4;
1159 V_I4(&vararg[0]) = iUpdateCount;
1161 hr = invoke(pDatabase, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1162 *pSummaryInfo = V_DISPATCH(&varresult);
1163 return hr;
1166 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
1168 VARIANT varresult;
1169 VARIANTARG vararg[1];
1170 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1172 VariantInit(&vararg[0]);
1173 V_VT(&vararg[0]) = VT_DISPATCH;
1174 V_DISPATCH(&vararg[0]) = pRecord;
1176 return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1179 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
1181 VARIANT varresult;
1182 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1183 HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1184 *ppRecord = V_DISPATCH(&varresult);
1185 return hr;
1188 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
1190 VARIANT varresult;
1191 VARIANTARG vararg[2];
1192 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1194 VariantInit(&vararg[1]);
1195 V_VT(&vararg[1]) = VT_I4;
1196 V_I4(&vararg[1]) = iMode;
1197 VariantInit(&vararg[0]);
1198 V_VT(&vararg[0]) = VT_DISPATCH;
1199 V_DISPATCH(&vararg[0]) = pRecord;
1200 if (pRecord)
1201 IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */
1203 return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1206 static HRESULT View_Close(IDispatch *pView)
1208 VARIANT varresult;
1209 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1210 return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1213 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
1215 VARIANT varresult;
1216 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1217 HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1218 *pFieldCount = V_I4(&varresult);
1219 VariantClear(&varresult);
1220 return hr;
1223 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString)
1225 VARIANT varresult;
1226 VARIANTARG vararg[1];
1227 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1228 HRESULT hr;
1230 VariantInit(&vararg[0]);
1231 V_VT(&vararg[0]) = VT_I4;
1232 V_I4(&vararg[0]) = iField;
1234 hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1235 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1236 VariantClear(&varresult);
1237 return hr;
1240 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
1242 VARIANT varresult;
1243 VARIANTARG vararg[2];
1244 DISPID dispid = DISPID_PROPERTYPUT;
1245 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1247 VariantInit(&vararg[1]);
1248 V_VT(&vararg[1]) = VT_I4;
1249 V_I4(&vararg[1]) = iField;
1250 VariantInit(&vararg[0]);
1251 V_VT(&vararg[0]) = VT_BSTR;
1252 V_BSTR(&vararg[0]) = SysAllocString(szString);
1254 return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1257 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
1259 VARIANT varresult;
1260 VARIANTARG vararg[1];
1261 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1262 HRESULT hr;
1264 VariantInit(&vararg[0]);
1265 V_VT(&vararg[0]) = VT_I4;
1266 V_I4(&vararg[0]) = iField;
1268 hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1269 *pValue = V_I4(&varresult);
1270 VariantClear(&varresult);
1271 return hr;
1274 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
1276 VARIANT varresult;
1277 VARIANTARG vararg[2];
1278 DISPID dispid = DISPID_PROPERTYPUT;
1279 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1281 VariantInit(&vararg[1]);
1282 V_VT(&vararg[1]) = VT_I4;
1283 V_I4(&vararg[1]) = iField;
1284 VariantInit(&vararg[0]);
1285 V_VT(&vararg[0]) = VT_I4;
1286 V_I4(&vararg[0]) = iValue;
1288 return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1291 static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT)
1293 VARIANT varresult;
1294 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1295 HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN);
1296 *ppEnumVARIANT = V_UNKNOWN(&varresult);
1297 return hr;
1300 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
1302 VARIANT varresult;
1303 VARIANTARG vararg[1];
1304 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1305 HRESULT hr;
1307 VariantInit(&vararg[0]);
1308 V_VT(&vararg[0]) = VT_I4;
1309 V_I4(&vararg[0]) = iIndex;
1311 hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1312 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1313 VariantClear(&varresult);
1314 return hr;
1317 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
1319 VARIANT varresult;
1320 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1321 HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1322 *pCount = V_I4(&varresult);
1323 VariantClear(&varresult);
1324 return hr;
1327 static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect)
1329 VARIANTARG vararg[1];
1330 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1332 VariantInit(&vararg[0]);
1333 V_VT(&vararg[0]) = VT_I4;
1334 V_I4(&vararg[0]) = pid;
1335 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYGET, &dispparams, pVarResult, vtExpect);
1338 static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant)
1340 VARIANT varresult;
1341 VARIANTARG vararg[2];
1342 DISPID dispid = DISPID_PROPERTYPUT;
1343 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1345 VariantInit(&vararg[1]);
1346 V_VT(&vararg[1]) = VT_I4;
1347 V_I4(&vararg[1]) = pid;
1348 VariantInit(&vararg[0]);
1349 VariantCopyInd(vararg, pVariant);
1351 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1354 static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount)
1356 VARIANT varresult;
1357 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1358 HRESULT hr;
1360 hr = invoke(pSummaryInfo, "PropertyCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1361 *pCount = V_I4(&varresult);
1362 VariantClear(&varresult);
1363 return hr;
1366 /* Test the various objects */
1368 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4
1370 static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly)
1372 static const WCHAR szPropertyException[] = { 'P','r','o','p','e','r','t','y',',','P','i','d',0 };
1373 static const WCHAR szTitle[] = { 'T','i','t','l','e',0 };
1374 VARIANT varresult, var;
1375 SYSTEMTIME st;
1376 HRESULT hr;
1377 int j;
1379 /* SummaryInfo::PropertyCount */
1380 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1381 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1382 ok(j == num_info, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1384 /* SummaryInfo::Property, get for properties we have set */
1385 for (j = 0; j < num_info; j++)
1387 const msi_summary_info *entry = &info[j];
1389 int vt = entry->datatype;
1390 if (vt == VT_LPSTR) vt = VT_BSTR;
1391 else if (vt == VT_FILETIME) vt = VT_DATE;
1392 else if (vt == VT_I2) vt = VT_I4;
1394 hr = SummaryInfo_PropertyGet(pSummaryInfo, entry->property, &varresult, vt);
1395 ok(hr == S_OK, "SummaryInfo_Property (pid %d) failed, hresult 0x%08x\n", entry->property, hr);
1396 if (V_VT(&varresult) != vt)
1397 skip("Skipping property tests due to type mismatch\n");
1398 else if (vt == VT_I4)
1399 ok(V_I4(&varresult) == entry->iValue, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %d\n",
1400 entry->property, entry->iValue, V_I4(&varresult));
1401 else if (vt == VT_DATE)
1403 FILETIME ft;
1404 DATE d;
1406 FileTimeToLocalFileTime(entry->pftValue, &ft);
1407 FileTimeToSystemTime(&ft, &st);
1408 SystemTimeToVariantTime(&st, &d);
1409 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));
1411 else if (vt == VT_BSTR)
1413 ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry->property, entry->szValue, V_BSTR(&varresult));
1415 else
1416 skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry->property, vt);
1418 VariantClear(&varresult);
1421 /* SummaryInfo::Property, get; invalid arguments */
1423 /* Invalid pids */
1424 hr = SummaryInfo_PropertyGet(pSummaryInfo, -1, &varresult, VT_EMPTY);
1425 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1426 ok_exception(hr, szPropertyException);
1428 hr = SummaryInfo_PropertyGet(pSummaryInfo, 1000, &varresult, VT_EMPTY);
1429 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1430 ok_exception(hr, szPropertyException);
1432 /* Unsupported pids */
1433 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_DICTIONARY, &varresult, VT_EMPTY);
1434 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1436 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY);
1437 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1439 /* Pids we have not set, one for each type */
1440 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_EMPTY);
1441 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1443 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY);
1444 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1446 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY);
1447 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1449 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY);
1450 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1452 if (!readonly)
1454 /* SummaryInfo::Property, put; one for each type */
1456 /* VT_I2 */
1457 VariantInit(&var);
1458 V_VT(&var) = VT_I2;
1459 V_I2(&var) = 1;
1460 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CODEPAGE, &var);
1461 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1463 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */);
1464 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1465 ok(V_I2(&var) == V_I2(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var), V_I2(&varresult));
1466 VariantClear(&varresult);
1467 VariantClear(&var);
1469 /* VT_BSTR */
1470 V_VT(&var) = VT_BSTR;
1471 V_BSTR(&var) = SysAllocString(szTitle);
1472 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_TITLE, &var);
1473 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1475 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var));
1476 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1477 ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var), V_BSTR(&varresult));
1478 VariantClear(&varresult);
1479 VariantClear(&var);
1481 /* VT_DATE */
1482 V_VT(&var) = VT_DATE;
1483 FileTimeToSystemTime(&systemtime, &st);
1484 SystemTimeToVariantTime(&st, &V_DATE(&var));
1485 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_LASTSAVE_DTM, &var);
1486 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1488 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var));
1489 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1490 /* FIXME: Off by one second */
1491 todo_wine ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1492 VariantClear(&varresult);
1493 VariantClear(&var);
1495 /* VT_I4 */
1496 V_VT(&var) = VT_I4;
1497 V_I4(&var) = 1000;
1498 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1499 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1501 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1502 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1503 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult));
1504 VariantClear(&varresult);
1505 VariantClear(&var);
1507 /* SummaryInfo::PropertyCount */
1508 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1509 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1510 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1514 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1516 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 };
1517 static WCHAR szThree[] = { 'T','h','r','e','e',0 };
1518 static WCHAR szTwo[] = { 'T','w','o',0 };
1519 static WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
1520 static WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 };
1521 IDispatch *pView = NULL, *pSummaryInfo = NULL;
1522 HRESULT hr;
1524 hr = Database_OpenView(pDatabase, szSql, &pView);
1525 ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr);
1526 if (hr == S_OK)
1528 IDispatch *pRecord = NULL;
1529 WCHAR szString[MAX_PATH];
1531 /* View::Execute */
1532 hr = View_Execute(pView, NULL);
1533 ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr);
1535 /* View::Fetch */
1536 hr = View_Fetch(pView, &pRecord);
1537 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1538 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1539 if (pRecord)
1541 /* Record::StringDataGet */
1542 memset(szString, 0, sizeof(szString));
1543 hr = Record_StringDataGet(pRecord, 1, szString);
1544 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1545 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1547 /* Record::StringDataPut with correct index */
1548 hr = Record_StringDataPut(pRecord, 1, szTwo);
1549 ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1551 /* Record::StringDataGet */
1552 memset(szString, 0, sizeof(szString));
1553 hr = Record_StringDataGet(pRecord, 1, szString);
1554 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1555 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1557 /* Record::StringDataPut with incorrect index */
1558 hr = Record_StringDataPut(pRecord, -1, szString);
1559 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1560 ok_exception(hr, szStringDataField);
1562 /* View::Modify with incorrect parameters */
1563 hr = View_Modify(pView, -5, NULL);
1564 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1565 ok_exception(hr, szModifyModeRecord);
1567 hr = View_Modify(pView, -5, pRecord);
1568 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1569 ok_exception(hr, szModifyModeRecord);
1571 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1572 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1573 ok_exception(hr, szModifyModeRecord);
1575 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1576 ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr);
1578 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1579 memset(szString, 0, sizeof(szString));
1580 hr = Record_StringDataGet(pRecord, 1, szString);
1581 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1582 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1584 IDispatch_Release(pRecord);
1587 /* View::Fetch */
1588 hr = View_Fetch(pView, &pRecord);
1589 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1590 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1591 if (pRecord)
1593 /* Record::StringDataGet */
1594 memset(szString, 0, sizeof(szString));
1595 hr = Record_StringDataGet(pRecord, 1, szString);
1596 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1597 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1599 IDispatch_Release(pRecord);
1602 /* View::Fetch */
1603 hr = View_Fetch(pView, &pRecord);
1604 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1605 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1606 if (pRecord)
1607 IDispatch_Release(pRecord);
1609 /* View::Close */
1610 hr = View_Close(pView);
1611 ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr);
1613 IDispatch_Release(pView);
1616 /* Database::SummaryInformation */
1617 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo);
1618 ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr);
1619 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1620 if (pSummaryInfo)
1622 test_SummaryInfo(pSummaryInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), readonly);
1623 IDispatch_Release(pSummaryInfo);
1627 static void test_Session(IDispatch *pSession)
1629 static WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
1630 static WCHAR szOne[] = { 'O','n','e',0 };
1631 static WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 };
1632 static WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 };
1633 static WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 };
1634 static WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 };
1635 static WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1636 static WCHAR szEmpty[] = { 0 };
1637 static WCHAR szEquals[] = { '=',0 };
1638 static WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
1639 WCHAR stringw[MAX_PATH];
1640 CHAR string[MAX_PATH];
1641 UINT len;
1642 BOOL bool;
1643 int myint;
1644 IDispatch *pDatabase = NULL, *pInst = NULL, *record = NULL;
1645 HRESULT hr;
1647 /* Session::Installer */
1648 hr = Session_Installer(pSession, &pInst);
1649 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1650 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1651 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1653 /* Session::Property, get */
1654 memset(stringw, 0, sizeof(stringw));
1655 hr = Session_PropertyGet(pSession, szProductName, stringw);
1656 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1657 if (lstrcmpW(stringw, szMSITEST) != 0)
1659 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1660 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1661 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1664 /* Session::Property, put */
1665 hr = Session_PropertyPut(pSession, szProductName, szProductName);
1666 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1667 memset(stringw, 0, sizeof(stringw));
1668 hr = Session_PropertyGet(pSession, szProductName, stringw);
1669 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1670 if (lstrcmpW(stringw, szProductName) != 0)
1672 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1673 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1674 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1677 /* Try putting a property using empty property identifier */
1678 hr = Session_PropertyPut(pSession, szEmpty, szProductName);
1679 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1680 ok_exception(hr, szPropertyName);
1682 /* Try putting a property using illegal property identifier */
1683 hr = Session_PropertyPut(pSession, szEquals, szProductName);
1684 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1686 /* Session::Language, get */
1687 hr = Session_LanguageGet(pSession, &len);
1688 ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1689 /* Not sure how to check the language is correct */
1691 /* Session::Mode, get */
1692 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1693 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1694 todo_wine ok(!bool, "Reboot at end session mode is %d\n", bool);
1696 /* Session::Mode, put */
1697 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE);
1698 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1699 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1700 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1701 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1702 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE); /* set it again so we don't reboot */
1703 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1705 /* Session::Database, get */
1706 hr = Session_Database(pSession, &pDatabase);
1707 ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr);
1708 if (hr == S_OK)
1710 test_Database(pDatabase, TRUE);
1711 IDispatch_Release(pDatabase);
1714 /* Session::EvaluateCondition */
1715 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1716 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1717 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1719 hr = Session_EvaluateCondition(pSession, szEmpty, &myint);
1720 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1721 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1723 hr = Session_EvaluateCondition(pSession, szEquals, &myint);
1724 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1725 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1727 /* Session::DoAction(CostInitialize) must occur before the next statements */
1728 hr = Session_DoAction(pSession, szCostInitialize, &myint);
1729 ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr);
1730 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1732 /* Session::SetInstallLevel */
1733 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1734 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
1736 /* Session::FeatureCurrentState, get */
1737 hr = Session_FeatureCurrentState(pSession, szOne, &myint);
1738 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
1739 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1741 /* Session::Message */
1742 hr = Installer_CreateRecord(0, &record);
1743 ok(hr == S_OK, "Installer_CreateRecord failed: %08x\n", hr);
1744 hr = Session_Message(pSession, INSTALLMESSAGE_INFO, record, &myint);
1745 ok(hr == S_OK, "Session_Message failed: %08x\n", hr);
1746 ok(myint == 0, "Session_Message returned %x\n", myint);
1748 /* Session::EvaluateCondition */
1749 hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint);
1750 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1751 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1753 hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint);
1754 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1755 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1757 /* Session::FeatureRequestState, put */
1758 hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED);
1759 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
1760 hr = Session_FeatureRequestStateGet(pSession, szOne, &myint);
1761 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
1762 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
1764 /* Session::EvaluateCondition */
1765 hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint);
1766 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1767 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1769 hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint);
1770 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1771 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1774 /* delete key and all its subkeys */
1775 static DWORD delete_key( HKEY hkey )
1777 char name[MAX_PATH];
1778 DWORD ret;
1780 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
1782 HKEY tmp;
1783 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
1785 ret = delete_key( tmp );
1786 RegCloseKey( tmp );
1788 if (ret) break;
1790 if (ret != ERROR_NO_MORE_ITEMS) return ret;
1791 RegDeleteKeyA( hkey, "" );
1792 return 0;
1795 static void test_Installer_RegistryValue(void)
1797 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
1798 static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 };
1799 static const WCHAR szOne[] = { 'O','n','e',0 };
1800 static const WCHAR szTwo[] = { 'T','w','o',0 };
1801 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
1802 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1803 static const WCHAR szFour[] = { 'F','o','u','r',0 };
1804 static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 };
1805 static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 };
1806 static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 };
1807 static const WCHAR szSix[] = { 'S','i','x',0 };
1808 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1809 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
1810 static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
1811 static const WCHAR szBlank[] = { 0 };
1812 VARIANT varresult;
1813 VARIANTARG vararg;
1814 WCHAR szString[MAX_PATH];
1815 HKEY hkey, hkey_sub;
1816 HKEY curr_user = (HKEY)1;
1817 HRESULT hr;
1818 BOOL bRet;
1820 /* Delete keys */
1821 if (!RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey )) delete_key( hkey );
1823 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
1824 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
1825 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1826 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
1828 memset(szString, 0, sizeof(szString));
1829 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
1830 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1832 memset(szString, 0, sizeof(szString));
1833 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
1834 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1836 /* Create key */
1837 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
1839 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1840 "RegSetValueExW failed\n");
1841 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
1842 "RegSetValueExW failed\n");
1843 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
1844 "RegSetValueExW failed\n");
1845 ok(SetEnvironmentVariableA("MSITEST", "Four"), "SetEnvironmentVariableA failed %d\n", GetLastError());
1846 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
1847 "RegSetValueExW failed\n");
1848 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
1849 "RegSetValueExW failed\n");
1850 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
1851 "RegSetValueExW failed\n");
1852 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, (const BYTE *)NULL, 0),
1853 "RegSetValueExW failed\n");
1855 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1856 "RegSetValueExW failed\n");
1858 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
1860 /* Does our key exist? It should, and make sure we retrieve the correct default value */
1861 bRet = FALSE;
1862 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
1863 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1864 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
1866 memset(szString, 0, sizeof(szString));
1867 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
1868 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1869 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1871 /* Ask for the value of a nonexistent key */
1872 memset(szString, 0, sizeof(szString));
1873 hr = Installer_RegistryValueW(curr_user, szKey, szExpand, szString);
1874 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1876 /* Get values of keys */
1877 memset(szString, 0, sizeof(szString));
1878 hr = Installer_RegistryValueW(curr_user, szKey, szOne, szString);
1879 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1880 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1882 VariantInit(&vararg);
1883 V_VT(&vararg) = VT_BSTR;
1884 V_BSTR(&vararg) = SysAllocString(szTwo);
1885 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_I4);
1886 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1887 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
1888 VariantClear(&varresult);
1890 memset(szString, 0, sizeof(szString));
1891 hr = Installer_RegistryValueW(curr_user, szKey, szThree, szString);
1892 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1893 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
1895 memset(szString, 0, sizeof(szString));
1896 hr = Installer_RegistryValueW(curr_user, szKey, szFour, szString);
1897 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1898 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
1900 /* Vista does not NULL-terminate this case */
1901 memset(szString, 0, sizeof(szString));
1902 hr = Installer_RegistryValueW(curr_user, szKey, szFive, szString);
1903 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1904 ok_w2n("Registry value \"%s\" does not match expected \"%s\"\n",
1905 szString, szFiveHi, lstrlenW(szFiveHi));
1907 memset(szString, 0, sizeof(szString));
1908 hr = Installer_RegistryValueW(curr_user, szKey, szSix, szString);
1909 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1910 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_);
1912 VariantInit(&vararg);
1913 V_VT(&vararg) = VT_BSTR;
1914 V_BSTR(&vararg) = SysAllocString(szSeven);
1915 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_EMPTY);
1916 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1918 /* Get string class name for the key */
1919 memset(szString, 0, sizeof(szString));
1920 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
1921 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1922 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank);
1924 /* Get name of a value by positive number (RegEnumValue like), valid index */
1925 memset(szString, 0, sizeof(szString));
1926 hr = Installer_RegistryValueI(curr_user, szKey, 2, szString, VT_BSTR);
1927 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1928 /* RegEnumValue order seems different on wine */
1929 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
1931 /* Get name of a value by positive number (RegEnumValue like), invalid index */
1932 memset(szString, 0, sizeof(szString));
1933 hr = Installer_RegistryValueI(curr_user, szKey, 10, szString, VT_EMPTY);
1934 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1936 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
1937 memset(szString, 0, sizeof(szString));
1938 hr = Installer_RegistryValueI(curr_user, szKey, -1, szString, VT_BSTR);
1939 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1940 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
1942 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
1943 memset(szString, 0, sizeof(szString));
1944 hr = Installer_RegistryValueI(curr_user, szKey, -10, szString, VT_EMPTY);
1945 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1947 /* clean up */
1948 delete_key(hkey);
1951 static void test_Installer_Products(BOOL bProductInstalled)
1953 WCHAR szString[MAX_PATH];
1954 HRESULT hr;
1955 int idx;
1956 IUnknown *pUnk = NULL;
1957 IEnumVARIANT *pEnum = NULL;
1958 VARIANT var;
1959 ULONG celt;
1960 int iCount, iValue;
1961 IDispatch *pStringList = NULL;
1962 BOOL bProductFound = FALSE;
1964 /* Installer::Products */
1965 hr = Installer_Products(&pStringList);
1966 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
1967 if (hr == S_OK)
1969 /* StringList::_NewEnum */
1970 hr = StringList__NewEnum(pStringList, &pUnk);
1971 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
1972 if (hr == S_OK)
1974 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
1975 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
1977 if (!pEnum)
1978 skip("IEnumVARIANT tests\n");
1980 /* StringList::Count */
1981 hr = StringList_Count(pStringList, &iCount);
1982 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
1984 for (idx=0; idx<iCount; idx++)
1986 /* StringList::Item */
1987 memset(szString, 0, sizeof(szString));
1988 hr = StringList_Item(pStringList, idx, szString);
1989 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
1991 if (hr == S_OK)
1993 /* Installer::ProductState */
1994 hr = Installer_ProductState(szString, &iValue);
1995 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
1996 if (hr == S_OK)
1997 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
1999 /* Not found our product code yet? Check */
2000 if (!bProductFound && !lstrcmpW(szString, szProductCode))
2001 bProductFound = TRUE;
2003 /* IEnumVARIANT::Next */
2004 if (pEnum)
2006 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2007 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2008 ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
2009 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2010 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2011 VariantClear(&var);
2016 if (bProductInstalled) todo_wine
2018 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
2019 bProductInstalled ? "be" : "not be",
2020 bProductFound ? "found" : "not found");
2023 if (pEnum)
2025 IEnumVARIANT *pEnum2 = NULL;
2027 if (0) /* Crashes on Windows XP */
2029 /* IEnumVARIANT::Clone, NULL pointer */
2030 hr = IEnumVARIANT_Clone(pEnum, NULL);
2033 /* IEnumVARIANT::Clone */
2034 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
2035 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
2036 if (hr == S_OK)
2038 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
2040 /* IEnumVARIANT::Next of the clone */
2041 if (iCount)
2043 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
2044 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2045 ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
2046 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2047 VariantClear(&var);
2049 else
2050 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
2052 IEnumVARIANT_Release(pEnum2);
2055 /* IEnumVARIANT::Skip should fail */
2056 hr = IEnumVARIANT_Skip(pEnum, 1);
2057 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2059 /* IEnumVARIANT::Next, NULL variant pointer */
2060 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2061 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2062 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2064 /* IEnumVARIANT::Next, should not return any more items */
2065 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2066 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2067 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2068 VariantClear(&var);
2070 /* IEnumVARIANT::Reset */
2071 hr = IEnumVARIANT_Reset(pEnum);
2072 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2074 if (iCount)
2076 /* IEnumVARIANT::Skip to the last product */
2077 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2078 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2080 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2081 * NULL celt pointer. */
2082 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2083 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2084 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2085 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2086 VariantClear(&var);
2088 else
2089 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2092 /* StringList::Item using an invalid index */
2093 memset(szString, 0, sizeof(szString));
2094 hr = StringList_Item(pStringList, iCount, szString);
2095 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2097 if (pEnum) IEnumVARIANT_Release(pEnum);
2098 if (pUnk) IUnknown_Release(pUnk);
2099 IDispatch_Release(pStringList);
2103 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2104 * deleting the subkeys first) */
2105 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey)
2107 UINT ret;
2108 CHAR *string = NULL;
2109 HKEY hkey;
2110 DWORD dwSize;
2112 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2113 if (ret != ERROR_SUCCESS) return ret;
2114 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2115 if (ret != ERROR_SUCCESS) return ret;
2116 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2118 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2119 delete_registry_key(hkey, string);
2121 RegCloseKey(hkey);
2122 HeapFree(GetProcessHeap(), 0, string);
2123 RegDeleteKeyA(hkeyParent, subkey);
2124 return ERROR_SUCCESS;
2127 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2128 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, HKEY *phkey)
2130 UINT ret;
2131 CHAR *string = NULL;
2132 int idx = 0;
2133 HKEY hkey;
2134 DWORD dwSize;
2135 BOOL found = FALSE;
2137 *phkey = 0;
2139 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2140 if (ret != ERROR_SUCCESS) return ret;
2141 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2142 if (ret != ERROR_SUCCESS) return ret;
2143 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2145 while (!found &&
2146 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2148 if (!strcmp(string, findkey))
2150 *phkey = hkey;
2151 found = TRUE;
2153 else if (find_registry_key(hkey, string, findkey, phkey) == ERROR_SUCCESS) found = TRUE;
2156 if (*phkey != hkey) RegCloseKey(hkey);
2157 HeapFree(GetProcessHeap(), 0, string);
2158 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2161 static void test_Installer_InstallProduct(void)
2163 HRESULT hr;
2164 CHAR path[MAX_PATH];
2165 WCHAR szString[MAX_PATH];
2166 LONG res;
2167 HKEY hkey;
2168 DWORD num, size, type;
2169 int iValue, iCount;
2170 IDispatch *pStringList = NULL;
2172 create_test_files();
2174 /* Installer::InstallProduct */
2175 hr = Installer_InstallProduct(szMsifile, NULL);
2176 if (hr == DISP_E_EXCEPTION)
2178 skip("Installer object not supported.\n");
2179 delete_test_files();
2180 return;
2182 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2184 /* Installer::ProductState for our product code, which has been installed */
2185 hr = Installer_ProductState(szProductCode, &iValue);
2186 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2187 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2189 /* Installer::ProductInfo for our product code */
2191 /* NULL attribute */
2192 memset(szString, 0, sizeof(szString));
2193 hr = Installer_ProductInfo(szProductCode, NULL, szString);
2194 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2195 ok_exception(hr, szProductInfoException);
2197 /* Nonexistent attribute */
2198 memset(szString, 0, sizeof(szString));
2199 hr = Installer_ProductInfo(szProductCode, szMsifile, szString);
2200 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2201 ok_exception(hr, szProductInfoException);
2203 /* Package name */
2204 memset(szString, 0, sizeof(szString));
2205 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szString);
2206 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2207 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile);
2209 /* Product name */
2210 memset(szString, 0, sizeof(szString));
2211 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PRODUCTNAMEW, szString);
2212 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2213 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST);
2215 /* Installer::Products */
2216 test_Installer_Products(TRUE);
2218 /* Installer::RelatedProducts for our upgrade code */
2219 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2220 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2221 if (hr == S_OK)
2223 /* StringList::Count */
2224 hr = StringList_Count(pStringList, &iCount);
2225 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2226 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2228 /* StringList::Item */
2229 memset(szString, 0, sizeof(szString));
2230 hr = StringList_Item(pStringList, 0, szString);
2231 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2232 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
2234 IDispatch_Release(pStringList);
2237 /* Check & clean up installed files & registry keys */
2238 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2239 ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
2240 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2241 ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
2242 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2243 ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
2244 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2245 ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
2246 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2247 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2248 ok(delete_pf("msitest", FALSE), "File not installed\n");
2250 res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
2251 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2253 size = MAX_PATH;
2254 type = REG_SZ;
2255 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2256 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2257 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2259 size = MAX_PATH;
2260 type = REG_SZ;
2261 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2262 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2264 size = sizeof(num);
2265 type = REG_DWORD;
2266 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2267 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2268 ok(num == 314, "Expected 314, got %d\n", num);
2270 size = MAX_PATH;
2271 type = REG_SZ;
2272 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2273 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2274 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2276 RegCloseKey(hkey);
2278 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest");
2279 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2281 /* Remove registry keys written by RegisterProduct standard action */
2282 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F1C3AF50-8B56-4A69-A00C-00773FE42F30}");
2283 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2285 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2286 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2288 res = find_registry_key(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "05FA3C1F65B896A40AC00077F34EF203", &hkey);
2289 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2290 if (res == ERROR_SUCCESS)
2292 res = delete_registry_key(hkey, "05FA3C1F65B896A40AC00077F34EF203");
2293 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2294 RegCloseKey(hkey);
2297 /* Remove registry keys written by PublishProduct standard action */
2298 res = RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2299 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2301 res = delete_registry_key(hkey, "Products\\05FA3C1F65B896A40AC00077F34EF203");
2302 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2304 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2305 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2307 RegCloseKey(hkey);
2309 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203");
2310 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2312 /* Delete installation files we installed */
2313 delete_test_files();
2316 static void test_Installer(void)
2318 static WCHAR szBackslash[] = { '\\',0 };
2319 static WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
2320 static WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
2321 WCHAR szPath[MAX_PATH];
2322 HRESULT hr;
2323 UINT len;
2324 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL;
2325 int iValue, iCount;
2327 if (!pInstaller) return;
2329 /* Installer::CreateRecord */
2331 /* Test for error */
2332 hr = Installer_CreateRecord(-1, &pRecord);
2333 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2334 ok_exception(hr, szCreateRecordException);
2336 /* Test for success */
2337 hr = Installer_CreateRecord(1, &pRecord);
2338 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2339 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2340 if (pRecord)
2342 /* Record::FieldCountGet */
2343 hr = Record_FieldCountGet(pRecord, &iValue);
2344 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2345 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2347 /* Record::IntegerDataGet */
2348 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2349 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2350 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2352 /* Record::IntegerDataGet, bad index */
2353 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2354 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2355 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2357 /* Record::IntegerDataPut */
2358 hr = Record_IntegerDataPut(pRecord, 1, 100);
2359 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2361 /* Record::IntegerDataPut, bad index */
2362 hr = Record_IntegerDataPut(pRecord, 10, 100);
2363 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2364 ok_exception(hr, szIntegerDataException);
2366 /* Record::IntegerDataGet */
2367 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2368 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2369 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2371 IDispatch_Release(pRecord);
2374 /* Prepare package */
2375 create_database(msifile, tables, sizeof(tables) / sizeof(msi_table),
2376 summary_info, sizeof(summary_info) / sizeof(msi_summary_info));
2378 len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, CURR_DIR, -1, szPath, MAX_PATH);
2379 ok(len, "MultiByteToWideChar returned error %d\n", GetLastError());
2380 if (!len) return;
2382 lstrcatW(szPath, szBackslash);
2383 lstrcatW(szPath, szMsifile);
2385 /* Installer::OpenPackage */
2386 hr = Installer_OpenPackage(szPath, 0, &pSession);
2387 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2388 if (hr == S_OK)
2390 test_Session(pSession);
2391 IDispatch_Release(pSession);
2394 /* Installer::OpenDatabase */
2395 hr = Installer_OpenDatabase(szPath, (int)MSIDBOPEN_TRANSACT, &pDatabase);
2396 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2397 if (hr == S_OK)
2399 test_Database(pDatabase, FALSE);
2400 IDispatch_Release(pDatabase);
2403 /* Installer::RegistryValue */
2404 test_Installer_RegistryValue();
2406 /* Installer::ProductState for our product code, which should not be installed */
2407 hr = Installer_ProductState(szProductCode, &iValue);
2408 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2409 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2411 /* Installer::ProductInfo for our product code, which should not be installed */
2413 /* Package name */
2414 memset(szPath, 0, sizeof(szPath));
2415 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szPath);
2416 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2417 ok_exception(hr, szProductInfoException);
2419 /* NULL attribute and NULL product code */
2420 memset(szPath, 0, sizeof(szPath));
2421 hr = Installer_ProductInfo(NULL, NULL, szPath);
2422 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2423 ok_exception(hr, szProductInfoException);
2425 /* Installer::Products */
2426 test_Installer_Products(FALSE);
2428 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2429 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2430 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2431 if (hr == S_OK)
2433 /* StringList::Count */
2434 hr = StringList_Count(pStringList, &iCount);
2435 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2436 ok(!iCount, "Expected no related products but found %d\n", iCount);
2438 IDispatch_Release(pStringList);
2441 /* Installer::Version */
2442 memset(szPath, 0, sizeof(szPath));
2443 hr = Installer_VersionGet(szPath);
2444 ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr);
2446 /* Installer::InstallProduct and other tests that depend on our product being installed */
2447 test_Installer_InstallProduct();
2450 START_TEST(automation)
2452 DWORD len;
2453 char temp_path[MAX_PATH], prev_path[MAX_PATH];
2454 HRESULT hr;
2455 CLSID clsid;
2456 IUnknown *pUnk;
2458 GetSystemTimeAsFileTime(&systemtime);
2460 GetCurrentDirectoryA(MAX_PATH, prev_path);
2461 GetTempPath(MAX_PATH, temp_path);
2462 SetCurrentDirectoryA(temp_path);
2464 lstrcpyA(CURR_DIR, temp_path);
2465 len = lstrlenA(CURR_DIR);
2467 if(len && (CURR_DIR[len - 1] == '\\'))
2468 CURR_DIR[len - 1] = 0;
2470 get_program_files_dir(PROG_FILES_DIR);
2472 hr = OleInitialize(NULL);
2473 ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr);
2474 hr = CLSIDFromProgID(szProgId, &clsid);
2475 ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr);
2476 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2477 ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr);
2479 if (pUnk)
2481 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2482 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2484 test_dispid();
2485 test_dispatch();
2486 test_Installer();
2488 IDispatch_Release(pInstaller);
2489 IUnknown_Release(pUnk);
2492 OleUninitialize();
2494 SetCurrentDirectoryA(prev_path);