push 738d605ff53d3691640a21cc20e5d55aef342d7c
[wine/hacks.git] / dlls / msi / tests / automation.c
blob35b660b7795ed1aa1ff1e830b886d779f3d79c93
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-automation.msi";
38 static const WCHAR szMsifile[] = {'w','i','n','e','t','e','s','t','-','a','u','t','o','m','a','t','i','o','n','.','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);
274 static BOOL create_package(LPWSTR path)
276 DWORD len;
278 /* Prepare package */
279 create_database(msifile, tables,
280 sizeof(tables) / sizeof(msi_table), summary_info,
281 sizeof(summary_info) / sizeof(msi_summary_info));
283 len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
284 CURR_DIR, -1, path, MAX_PATH);
285 ok(len, "MultiByteToWideChar returned error %d\n", GetLastError());
286 if (!len)
287 return FALSE;
289 /* lstrcatW does not work on win95 */
290 path[len - 1] = '\\';
291 memcpy(&path[len], szMsifile, sizeof(szMsifile));
292 return TRUE;
296 * Installation helpers
299 static char PROG_FILES_DIR[MAX_PATH];
301 static BOOL get_program_files_dir(LPSTR buf)
303 HKEY hkey;
304 DWORD type = REG_EXPAND_SZ, size;
306 if (RegOpenKey(HKEY_LOCAL_MACHINE,
307 "Software\\Microsoft\\Windows\\CurrentVersion", &hkey))
308 return FALSE;
310 size = MAX_PATH;
311 if (RegQueryValueEx(hkey, "ProgramFilesDir (x86)", 0, &type, (LPBYTE)buf, &size) &&
312 RegQueryValueEx(hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size))
313 return FALSE;
315 RegCloseKey(hkey);
316 return TRUE;
319 static void create_file(const CHAR *name, DWORD size)
321 HANDLE file;
322 DWORD written, left;
324 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
325 ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
326 WriteFile(file, name, strlen(name), &written, NULL);
327 WriteFile(file, "\n", strlen("\n"), &written, NULL);
329 left = size - lstrlen(name) - 1;
331 SetFilePointer(file, left, NULL, FILE_CURRENT);
332 SetEndOfFile(file);
334 CloseHandle(file);
337 static void create_test_files(void)
339 CreateDirectoryA("msitest", NULL);
340 create_file("msitest\\one.txt", 100);
341 CreateDirectoryA("msitest\\first", NULL);
342 create_file("msitest\\first\\two.txt", 100);
343 CreateDirectoryA("msitest\\second", NULL);
344 create_file("msitest\\second\\three.txt", 100);
345 CreateDirectoryA("msitest\\cabout",NULL);
346 create_file("msitest\\cabout\\four.txt", 100);
347 CreateDirectoryA("msitest\\cabout\\new",NULL);
348 create_file("msitest\\cabout\\new\\five.txt", 100);
349 create_file("msitest\\filename", 100);
352 static BOOL delete_pf(const CHAR *rel_path, BOOL is_file)
354 CHAR path[MAX_PATH];
356 lstrcpyA(path, PROG_FILES_DIR);
357 lstrcatA(path, "\\");
358 lstrcatA(path, rel_path);
360 if (is_file)
361 return DeleteFileA(path);
362 else
363 return RemoveDirectoryA(path);
366 static void delete_test_files(void)
368 DeleteFileA(msifile);
369 DeleteFileA("msitest\\cabout\\new\\five.txt");
370 DeleteFileA("msitest\\cabout\\four.txt");
371 DeleteFileA("msitest\\second\\three.txt");
372 DeleteFileA("msitest\\first\\two.txt");
373 DeleteFileA("msitest\\one.txt");
374 DeleteFileA("msitest\\filename");
375 RemoveDirectoryA("msitest\\cabout\\new");
376 RemoveDirectoryA("msitest\\cabout");
377 RemoveDirectoryA("msitest\\second");
378 RemoveDirectoryA("msitest\\first");
379 RemoveDirectoryA("msitest");
383 * Automation helpers and tests
386 /* ok-like statement which takes two unicode strings or one unicode and one ANSI string as arguments */
387 static CHAR string1[MAX_PATH], string2[MAX_PATH];
389 /* lstrcmpW is not supported on Win9x */
390 static int strcmp_ww(const WCHAR* str1, const WCHAR* str2)
392 CHAR str1A[MAX_PATH], str2A[MAX_PATH];
394 WideCharToMultiByte(CP_ACP, 0, str1, -1, str1A, MAX_PATH, NULL, NULL);
395 WideCharToMultiByte(CP_ACP, 0, str2, -1, str2A, MAX_PATH, NULL, NULL);
397 return lstrcmpA(str1A, str2A);
400 #define ok_w2(format, szString1, szString2) \
402 do { \
403 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
404 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
405 if (lstrcmpA(string1, string2) != 0) \
406 ok(0, format, string1, string2); \
407 } while(0);
409 #define ok_w2n(format, szString1, szString2, len) \
411 if (memcmp(szString1, szString2, len * sizeof(WCHAR)) != 0) \
413 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
414 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
415 ok(0, format, string1, string2); \
418 #define ok_aw(format, aString, wString) \
420 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
421 if (lstrcmpA(string1, aString) != 0) \
422 ok(0, format, string1, aString); \
424 #define ok_awplus(format, extra, aString, wString) \
426 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
427 if (lstrcmpA(string1, aString) != 0) \
428 ok(0, format, extra, string1, aString); \
430 /* exception checker */
431 static WCHAR szSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
433 #define ok_exception(hr, szDescription) \
434 if (hr == DISP_E_EXCEPTION) \
436 /* Compare wtype, source, and destination */ \
437 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
439 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
440 if (excepinfo.bstrSource) \
441 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, szSource); \
443 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
444 if (excepinfo.bstrDescription) \
445 ok_w2("Exception description was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrDescription, szDescription); \
447 SysFreeString(excepinfo.bstrSource); \
448 SysFreeString(excepinfo.bstrDescription); \
449 SysFreeString(excepinfo.bstrHelpFile); \
452 static DISPID get_dispid( IDispatch *disp, const char *name )
454 LPOLESTR str;
455 UINT len;
456 DISPID id = -1;
457 HRESULT r;
459 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
460 str = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
461 if (str)
463 len = MultiByteToWideChar(CP_ACP, 0, name, -1, str, len );
464 r = IDispatch_GetIDsOfNames( disp, &IID_NULL, &str, 1, 0, &id );
465 HeapFree(GetProcessHeap(), 0, str);
466 if (r != S_OK)
467 return -1;
470 return id;
473 static void test_dispid(void)
475 DISPID dispid;
477 dispid = get_dispid(pInstaller, "CreateRecord");
478 ok(dispid == 1, "Expected 1, got %d\n", dispid);
479 dispid = get_dispid(pInstaller, "OpenPackage");
480 ok(dispid == 2, "Expected 2, got %d\n", dispid);
481 dispid = get_dispid(pInstaller, "OpenProduct");
482 ok(dispid == 3, "Expected 3, got %d\n", dispid);
483 dispid = get_dispid(pInstaller, "OpenDatabase");
484 ok(dispid == 4, "Expected 4, got %d\n", dispid);
485 dispid = get_dispid(pInstaller, "SummaryInformation");
486 ok(dispid == 5, "Expected 5, got %d\n", dispid);
487 dispid = get_dispid( pInstaller, "UILevel" );
488 ok(dispid == 6, "Expected 6, got %d\n", dispid);
489 dispid = get_dispid(pInstaller, "EnableLog");
490 ok(dispid == 7, "Expected 7, got %d\n", dispid);
491 dispid = get_dispid(pInstaller, "InstallProduct");
492 ok(dispid == 8, "Expected 8, got %d\n", dispid);
493 dispid = get_dispid(pInstaller, "Version");
494 ok(dispid == 9, "Expected 9, got %d\n", dispid);
495 dispid = get_dispid(pInstaller, "LastErrorRecord");
496 ok(dispid == 10, "Expected 10, got %d\n", dispid);
497 dispid = get_dispid(pInstaller, "RegistryValue");
498 ok(dispid == 11, "Expected 11, got %d\n", dispid);
499 dispid = get_dispid(pInstaller, "Environment");
500 ok(dispid == 12, "Expected 12, got %d\n", dispid);
501 dispid = get_dispid(pInstaller, "FileAttributes");
502 ok(dispid == 13, "Expected 13, got %d\n", dispid);
503 dispid = get_dispid(pInstaller, "FileSize");
504 ok(dispid == 15, "Expected 15, got %d\n", dispid);
505 dispid = get_dispid(pInstaller, "FileVersion");
506 ok(dispid == 16, "Expected 16, got %d\n", dispid);
507 dispid = get_dispid(pInstaller, "ProductState");
508 ok(dispid == 17, "Expected 17, got %d\n", dispid);
509 dispid = get_dispid(pInstaller, "ProductInfo");
510 ok(dispid == 18, "Expected 18, got %d\n", dispid);
511 todo_wine
513 dispid = get_dispid(pInstaller, "ConfigureProduct");
514 ok(dispid == 19, "Expected 19, got %d\n", dispid);
515 dispid = get_dispid(pInstaller, "ReinstallProduct");
516 ok(dispid == 20 , "Expected 20, got %d\n", dispid);
517 dispid = get_dispid(pInstaller, "CollectUserInfo");
518 ok(dispid == 21, "Expected 21, got %d\n", dispid);
519 dispid = get_dispid(pInstaller, "ApplyPatch");
520 ok(dispid == 22, "Expected 22, got %d\n", dispid);
521 dispid = get_dispid(pInstaller, "FeatureParent");
522 ok(dispid == 23, "Expected 23, got %d\n", dispid);
523 dispid = get_dispid(pInstaller, "FeatureState");
524 ok(dispid == 24, "Expected 24, got %d\n", dispid);
525 dispid = get_dispid(pInstaller, "UseFeature");
526 ok(dispid == 25, "Expected 25, got %d\n", dispid);
527 dispid = get_dispid(pInstaller, "FeatureUsageCount");
528 ok(dispid == 26, "Expected 26, got %d\n", dispid);
529 dispid = get_dispid(pInstaller, "FeatureUsageDate");
530 ok(dispid == 27, "Expected 27, got %d\n", dispid);
531 dispid = get_dispid(pInstaller, "ConfigureFeature");
532 ok(dispid == 28, "Expected 28, got %d\n", dispid);
533 dispid = get_dispid(pInstaller, "ReinstallFeature");
534 ok(dispid == 29, "Expected 29, got %d\n", dispid);
535 dispid = get_dispid(pInstaller, "ProvideComponent");
536 ok(dispid == 30, "Expected 30, got %d\n", dispid);
537 dispid = get_dispid(pInstaller, "ComponentPath");
538 ok(dispid == 31, "Expected 31, got %d\n", dispid);
539 dispid = get_dispid(pInstaller, "ProvideQualifiedComponent");
540 ok(dispid == 32, "Expected 32, got %d\n", dispid);
541 dispid = get_dispid(pInstaller, "QualifierDescription");
542 ok(dispid == 33, "Expected 33, got %d\n", dispid);
543 dispid = get_dispid(pInstaller, "ComponentQualifiers");
544 ok(dispid == 34, "Expected 34, got %d\n", dispid);
546 dispid = get_dispid(pInstaller, "Products");
547 ok(dispid == 35, "Expected 35, got %d\n", dispid);
548 todo_wine
550 dispid = get_dispid(pInstaller, "Features");
551 ok(dispid == 36, "Expected 36, got %d\n", dispid);
552 dispid = get_dispid(pInstaller, "Components");
553 ok(dispid == 37, "Expected 37, got %d\n", dispid);
554 dispid = get_dispid(pInstaller, "ComponentClients");
555 ok(dispid == 38, "Expected 38, got %d\n", dispid);
556 dispid = get_dispid(pInstaller, "Patches");
557 ok(dispid == 39, "Expected 39, got %d\n", dispid);
559 dispid = get_dispid(pInstaller, "RelatedProducts");
560 ok(dispid == 40, "Expected 40, got %d\n", dispid);
561 todo_wine
563 dispid = get_dispid(pInstaller, "PatchInfo");
564 ok(dispid == 41, "Expected 41, got %d\n", dispid);
565 dispid = get_dispid(pInstaller, "PatchTransforms");
566 ok(dispid == 42, "Expected 42, got %d\n", dispid);
567 dispid = get_dispid(pInstaller, "AddSource");
568 ok(dispid == 43, "Expected 43, got %d\n", dispid);
569 dispid = get_dispid(pInstaller, "ClearSourceList");
570 ok(dispid == 44, "Expected 44, got %d\n", dispid);
571 dispid = get_dispid(pInstaller, "ForceSourceListResolution");
572 ok(dispid == 45, "Expected 45, got %d\n", dispid);
573 dispid = get_dispid(pInstaller, "ShortcutTarget");
574 ok(dispid == 46, "Expected 46, got %d\n", dispid);
575 dispid = get_dispid(pInstaller, "FileHash");
576 ok(dispid == 47, "Expected 47, got %d\n", dispid);
577 dispid = get_dispid(pInstaller, "FileSignatureInfo");
578 ok(dispid == 48, "Expected 48, got %d\n", dispid);
580 dispid = get_dispid(pInstaller, "RemovePatches");
581 ok(dispid == 49 || dispid == -1, "Expected 49 or -1, got %d\n", dispid);
582 dispid = get_dispid(pInstaller, "ApplyMultiplePatches");
583 ok(dispid == 51 || dispid == -1, "Expected 51 or -1, got %d\n", dispid);
584 dispid = get_dispid(pInstaller, "ProductsEx");
585 ok(dispid == 52 || dispid == -1, "Expected 52 or -1, got %d\n", dispid);
586 dispid = get_dispid(pInstaller, "PatchesEx");
587 ok(dispid == 55 || dispid == -1, "Expected 55 or -1, got %d\n", dispid);
588 dispid = get_dispid(pInstaller, "ExtractPatchXMLData");
589 ok(dispid == 57 || dispid == -1, "Expected 57 or -1, got %d\n", dispid);
590 dispid = get_dispid( pInstaller, "ProductElevated" );
591 ok(dispid == 59 || dispid == -1, "Expected 59 or -1, got %d\n", dispid);
592 dispid = get_dispid( pInstaller, "ProvideAssembly" );
593 ok(dispid == 60 || dispid == -1, "Expected 60 or -1, got %d\n", dispid);
594 dispid = get_dispid( pInstaller, "ProductInfoFromScript" );
595 ok(dispid == 61 || dispid == -1, "Expected 61 or -1, got %d\n", dispid);
596 dispid = get_dispid( pInstaller, "AdvertiseProduct" );
597 ok(dispid == 62 || dispid == -1, "Expected 62 or -1, got %d\n", dispid);
598 dispid = get_dispid( pInstaller, "CreateAdvertiseScript" );
599 ok(dispid == 63 || dispid == -1, "Expected 63 or -1, got %d\n", dispid);
600 dispid = get_dispid( pInstaller, "PatchFiles" );
601 ok(dispid == 65 || dispid == -1, "Expected 65 or -1, got %d\n", dispid);
604 /* Test basic IDispatch functions */
605 static void test_dispatch(void)
607 static WCHAR szOpenPackage[] = { 'O','p','e','n','P','a','c','k','a','g','e',0 };
608 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};
609 static WCHAR szProductState[] = { 'P','r','o','d','u','c','t','S','t','a','t','e',0 };
610 HRESULT hr;
611 DISPID dispid;
612 OLECHAR *name;
613 VARIANT varresult;
614 VARIANTARG vararg[3];
615 WCHAR path[MAX_PATH];
616 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
618 /* Test getting ID of a function name that does not exist */
619 name = (WCHAR *)szMsifile;
620 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
621 ok(hr == DISP_E_UNKNOWNNAME, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
623 /* Test invoking this function */
624 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
625 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
627 /* Test getting ID of a function name that does exist */
628 name = szOpenPackage;
629 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
630 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
632 /* Test invoking this function (without parameters passed) */
633 if (0) /* All of these crash MSI on Windows XP */
635 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
636 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL);
637 VariantInit(&varresult);
638 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, &varresult, &excepinfo, NULL);
641 /* Try with NULL params */
642 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
643 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
645 /* Try one empty parameter */
646 dispparams.rgvarg = vararg;
647 dispparams.cArgs = 1;
648 VariantInit(&vararg[0]);
649 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
650 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
652 /* Try two empty parameters */
653 dispparams.cArgs = 2;
654 VariantInit(&vararg[0]);
655 VariantInit(&vararg[1]);
656 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
657 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
659 /* Try one parameter, the required BSTR. Second parameter is optional.
660 * NOTE: The specified package does not exist, which is why the call fails.
662 dispparams.cArgs = 1;
663 VariantInit(&vararg[0]);
664 V_VT(&vararg[0]) = VT_BSTR;
665 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
666 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
667 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
668 ok_exception(hr, szOpenPackageException);
669 VariantClear(&vararg[0]);
671 /* Provide the required BSTR and an empty second parameter.
672 * NOTE: The specified package does not exist, which is why the call fails.
674 dispparams.cArgs = 2;
675 VariantInit(&vararg[1]);
676 V_VT(&vararg[1]) = VT_BSTR;
677 V_BSTR(&vararg[1]) = SysAllocString(szMsifile);
678 VariantInit(&vararg[0]);
679 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
680 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
681 ok_exception(hr, szOpenPackageException);
682 VariantClear(&vararg[1]);
684 /* Provide the required BSTR and two empty parameters.
685 * NOTE: The specified package does not exist, which is why the call fails.
687 dispparams.cArgs = 3;
688 VariantInit(&vararg[2]);
689 V_VT(&vararg[2]) = VT_BSTR;
690 V_BSTR(&vararg[2]) = SysAllocString(szMsifile);
691 VariantInit(&vararg[1]);
692 VariantInit(&vararg[0]);
693 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
694 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
695 ok_exception(hr, szOpenPackageException);
696 VariantClear(&vararg[2]);
698 /* Provide the required BSTR and a second parameter with the wrong type. */
699 dispparams.cArgs = 2;
700 VariantInit(&vararg[1]);
701 V_VT(&vararg[1]) = VT_BSTR;
702 V_BSTR(&vararg[1]) = SysAllocString(szMsifile);
703 VariantInit(&vararg[0]);
704 V_VT(&vararg[0]) = VT_BSTR;
705 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
706 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
707 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
708 VariantClear(&vararg[0]);
709 VariantClear(&vararg[1]);
711 /* Create a proper installer package. */
712 create_package(path);
714 /* Try one parameter, the required BSTR. Second parameter is optional.
715 * Proper installer package exists. Path to the package is relative.
717 dispparams.cArgs = 1;
718 VariantInit(&vararg[0]);
719 V_VT(&vararg[0]) = VT_BSTR;
720 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
721 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
722 todo_wine ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
723 ok_exception(hr, szOpenPackageException);
724 VariantClear(&vararg[0]);
725 if (hr != DISP_E_EXCEPTION)
726 VariantClear(&varresult);
728 /* Try one parameter, the required BSTR. Second parameter is optional.
729 * Proper installer package exists. Path to the package is absolute.
731 dispparams.cArgs = 1;
732 VariantInit(&vararg[0]);
733 V_VT(&vararg[0]) = VT_BSTR;
734 V_BSTR(&vararg[0]) = SysAllocString(path);
735 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
736 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
737 VariantClear(&vararg[0]);
738 VariantClear(&varresult);
740 /* Provide the required BSTR and an empty second parameter. Proper
741 * installation package exists.
743 dispparams.cArgs = 2;
744 VariantInit(&vararg[1]);
745 V_VT(&vararg[1]) = VT_BSTR;
746 V_BSTR(&vararg[1]) = SysAllocString(path);
747 VariantInit(&vararg[0]);
748 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
749 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
750 VariantClear(&vararg[1]);
751 VariantClear(&varresult);
753 /* Provide the required BSTR and two empty parameters. Proper
754 * installation package exists.
756 dispparams.cArgs = 3;
757 VariantInit(&vararg[2]);
758 V_VT(&vararg[2]) = VT_BSTR;
759 V_BSTR(&vararg[2]) = SysAllocString(path);
760 VariantInit(&vararg[1]);
761 VariantInit(&vararg[0]);
762 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
763 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
764 VariantClear(&vararg[2]);
765 VariantClear(&varresult);
767 /* Provide the required BSTR and a second parameter with the wrong type. */
768 dispparams.cArgs = 2;
769 VariantInit(&vararg[1]);
770 V_VT(&vararg[1]) = VT_BSTR;
771 V_BSTR(&vararg[1]) = SysAllocString(path);
772 VariantInit(&vararg[0]);
773 V_VT(&vararg[0]) = VT_BSTR;
774 V_BSTR(&vararg[0]) = SysAllocString(path);
775 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
776 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
777 VariantClear(&vararg[0]);
778 VariantClear(&vararg[1]);
780 /* Provide the required BSTR and a second parameter that can be coerced to
781 * VT_I4.
783 dispparams.cArgs = 2;
784 VariantInit(&vararg[1]);
785 V_VT(&vararg[1]) = VT_BSTR;
786 V_BSTR(&vararg[1]) = SysAllocString(path);
787 VariantInit(&vararg[0]);
788 V_VT(&vararg[0]) = VT_I2;
789 V_BSTR(&vararg[0]) = 0;
790 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
791 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
792 VariantClear(&vararg[1]);
793 VariantClear(&varresult);
795 DeleteFileW(path);
797 /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
798 VariantInit(&vararg[0]);
799 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
800 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
802 VariantInit(&vararg[0]);
803 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
804 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
806 /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
807 name = szProductState;
808 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
809 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
811 dispparams.rgvarg = NULL;
812 dispparams.cArgs = 0;
813 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
814 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
816 dispparams.rgvarg = NULL;
817 dispparams.cArgs = 0;
818 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
819 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
822 /* invocation helper function */
823 static int _invoke_todo_vtResult = 0;
825 static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult)
827 OLECHAR *name = NULL;
828 DISPID dispid;
829 HRESULT hr;
830 UINT i;
831 UINT len;
833 memset(pVarResult, 0, sizeof(VARIANT));
834 VariantInit(pVarResult);
836 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 );
837 name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
838 if (!name) return E_FAIL;
839 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len );
840 hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
841 HeapFree(GetProcessHeap(), 0, name);
842 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
843 if (!hr == S_OK) return hr;
845 memset(&excepinfo, 0, sizeof(excepinfo));
846 hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL);
848 if (hr == S_OK)
850 if (_invoke_todo_vtResult) todo_wine
851 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
852 else
853 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
854 if (vtResult != VT_EMPTY)
856 hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult);
857 ok(hr == S_OK, "VariantChangeTypeEx returned 0x%08x\n", hr);
861 for (i=0; i<pDispParams->cArgs; i++)
862 VariantClear(&pDispParams->rgvarg[i]);
864 return hr;
867 /* Object_Property helper functions */
869 static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord)
871 VARIANT varresult;
872 VARIANTARG vararg[1];
873 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
874 HRESULT hr;
876 VariantInit(&vararg[0]);
877 V_VT(&vararg[0]) = VT_I4;
878 V_I4(&vararg[0]) = count;
880 hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
881 *pRecord = V_DISPATCH(&varresult);
882 return hr;
885 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
887 VARIANTARG vararg[3];
888 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
890 VariantInit(&vararg[2]);
891 V_VT(&vararg[2]) = VT_I4;
892 V_I4(&vararg[2]) = (INT_PTR)hkey;
893 VariantInit(&vararg[1]);
894 V_VT(&vararg[1]) = VT_BSTR;
895 V_BSTR(&vararg[1]) = SysAllocString(szKey);
896 VariantInit(&vararg[0]);
897 VariantCopy(&vararg[0], &vValue);
898 VariantClear(&vValue);
900 return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect);
903 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
905 VARIANT varresult;
906 VARIANTARG vararg;
907 HRESULT hr;
909 VariantInit(&vararg);
910 V_VT(&vararg) = VT_EMPTY;
911 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL);
912 *pBool = V_BOOL(&varresult);
913 VariantClear(&varresult);
914 return hr;
917 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
919 VARIANT varresult;
920 VARIANTARG vararg;
921 HRESULT hr;
923 VariantInit(&vararg);
924 V_VT(&vararg) = VT_BSTR;
925 V_BSTR(&vararg) = SysAllocString(szValue);
927 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR);
928 if (V_BSTR(&varresult))
929 /* lstrcpyW is not implemented on Win95 (lstrlenW is though) */
930 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
931 VariantClear(&varresult);
932 return hr;
935 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
937 VARIANT varresult;
938 VARIANTARG vararg;
939 HRESULT hr;
941 VariantInit(&vararg);
942 V_VT(&vararg) = VT_I4;
943 V_I4(&vararg) = iValue;
945 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult);
946 if (SUCCEEDED(hr) && vtResult == VT_BSTR)
947 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
948 VariantClear(&varresult);
949 return hr;
952 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
954 VARIANT varresult;
955 VARIANTARG vararg[2];
956 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
957 HRESULT hr;
959 VariantInit(&vararg[1]);
960 V_VT(&vararg[1]) = VT_BSTR;
961 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
962 VariantInit(&vararg[0]);
963 V_VT(&vararg[0]) = VT_I4;
964 V_I4(&vararg[0]) = options;
966 hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
967 *pSession = V_DISPATCH(&varresult);
968 return hr;
971 static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase)
973 VARIANT varresult;
974 VARIANTARG vararg[2];
975 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
976 HRESULT hr;
978 VariantInit(&vararg[1]);
979 V_VT(&vararg[1]) = VT_BSTR;
980 V_BSTR(&vararg[1]) = SysAllocString(szDatabasePath);
981 VariantInit(&vararg[0]);
982 V_VT(&vararg[0]) = VT_I4;
983 V_I4(&vararg[0]) = openmode;
985 hr = invoke(pInstaller, "OpenDatabase", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
986 *pDatabase = V_DISPATCH(&varresult);
987 return hr;
990 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
992 VARIANT varresult;
993 VARIANTARG vararg[2];
994 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
996 VariantInit(&vararg[1]);
997 V_VT(&vararg[1]) = VT_BSTR;
998 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
999 VariantInit(&vararg[0]);
1000 V_VT(&vararg[0]) = VT_BSTR;
1001 V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues);
1003 return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1006 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
1008 VARIANT varresult;
1009 VARIANTARG vararg[1];
1010 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1011 HRESULT hr;
1013 VariantInit(&vararg[0]);
1014 V_VT(&vararg[0]) = VT_BSTR;
1015 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
1017 hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1018 *pInstallState = V_I4(&varresult);
1019 VariantClear(&varresult);
1020 return hr;
1023 static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szString)
1025 VARIANT varresult;
1026 VARIANTARG vararg[2];
1027 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1028 HRESULT hr;
1030 VariantInit(&vararg[1]);
1031 V_VT(&vararg[1]) = VT_BSTR;
1032 V_BSTR(&vararg[1]) = SysAllocString(szProduct);
1033 VariantInit(&vararg[0]);
1034 V_VT(&vararg[0]) = VT_BSTR;
1035 V_BSTR(&vararg[0]) = SysAllocString(szAttribute);
1037 hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1038 if (V_BSTR(&varresult))
1039 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
1040 VariantClear(&varresult);
1041 return hr;
1044 static HRESULT Installer_Products(IDispatch **pStringList)
1046 VARIANT varresult;
1047 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1048 HRESULT hr;
1050 hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1051 *pStringList = V_DISPATCH(&varresult);
1052 return hr;
1055 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
1057 VARIANT varresult;
1058 VARIANTARG vararg[1];
1059 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1060 HRESULT hr;
1062 VariantInit(&vararg[0]);
1063 V_VT(&vararg[0]) = VT_BSTR;
1064 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
1066 hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1067 *pStringList = V_DISPATCH(&varresult);
1068 return hr;
1071 static HRESULT Installer_VersionGet(LPWSTR szVersion)
1073 VARIANT varresult;
1074 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1075 HRESULT hr;
1077 hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1078 if (V_BSTR(&varresult))
1079 memcpy(szVersion, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
1080 VariantClear(&varresult);
1081 return hr;
1084 static HRESULT Installer_UILevelPut(int level)
1086 VARIANT varresult;
1087 VARIANTARG vararg;
1088 DISPID dispid = DISPID_PROPERTYPUT;
1089 DISPPARAMS dispparams = {&vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1091 VariantInit(&vararg);
1092 V_VT(&vararg) = VT_I4;
1093 V_I4(&vararg) = level;
1095 return invoke(pInstaller, "UILevel", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1098 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
1100 VARIANT varresult;
1101 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1102 HRESULT hr;
1104 hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1105 *pInst = V_DISPATCH(&varresult);
1106 return hr;
1109 static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn)
1111 VARIANT varresult;
1112 VARIANTARG vararg[1];
1113 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1114 HRESULT hr;
1116 VariantInit(&vararg[0]);
1117 V_VT(&vararg[0]) = VT_BSTR;
1118 V_BSTR(&vararg[0]) = SysAllocString(szName);
1120 hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1121 if (V_BSTR(&varresult))
1122 memcpy(szReturn, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
1123 VariantClear(&varresult);
1124 return hr;
1127 static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue)
1129 VARIANT varresult;
1130 VARIANTARG vararg[2];
1131 DISPID dispid = DISPID_PROPERTYPUT;
1132 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1134 VariantInit(&vararg[1]);
1135 V_VT(&vararg[1]) = VT_BSTR;
1136 V_BSTR(&vararg[1]) = SysAllocString(szName);
1137 VariantInit(&vararg[0]);
1138 V_VT(&vararg[0]) = VT_BSTR;
1139 V_BSTR(&vararg[0]) = SysAllocString(szValue);
1141 return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1144 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
1146 VARIANT varresult;
1147 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1148 HRESULT hr;
1150 hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1151 *pLangId = V_I4(&varresult);
1152 VariantClear(&varresult);
1153 return hr;
1156 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, BOOL *pMode)
1158 VARIANT varresult;
1159 VARIANTARG vararg[1];
1160 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1161 HRESULT hr;
1163 VariantInit(&vararg[0]);
1164 V_VT(&vararg[0]) = VT_I4;
1165 V_I4(&vararg[0]) = iFlag;
1167 hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL);
1168 *pMode = V_BOOL(&varresult);
1169 VariantClear(&varresult);
1170 return hr;
1173 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, BOOL bMode)
1175 VARIANT varresult;
1176 VARIANTARG vararg[2];
1177 DISPID dispid = DISPID_PROPERTYPUT;
1178 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1180 VariantInit(&vararg[1]);
1181 V_VT(&vararg[1]) = VT_I4;
1182 V_I4(&vararg[1]) = iFlag;
1183 VariantInit(&vararg[0]);
1184 V_VT(&vararg[0]) = VT_BOOL;
1185 V_BOOL(&vararg[0]) = bMode;
1187 return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1190 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
1192 VARIANT varresult;
1193 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1194 HRESULT hr;
1196 hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1197 *pDatabase = V_DISPATCH(&varresult);
1198 return hr;
1201 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn)
1203 VARIANT varresult;
1204 VARIANTARG vararg[1];
1205 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1206 HRESULT hr;
1208 VariantInit(&vararg[0]);
1209 V_VT(&vararg[0]) = VT_BSTR;
1210 V_BSTR(&vararg[0]) = SysAllocString(szAction);
1212 hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1213 *iReturn = V_I4(&varresult);
1214 VariantClear(&varresult);
1215 return hr;
1218 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
1220 VARIANT varresult;
1221 VARIANTARG vararg[1];
1222 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1223 HRESULT hr;
1225 VariantInit(&vararg[0]);
1226 V_VT(&vararg[0]) = VT_BSTR;
1227 V_BSTR(&vararg[0]) = SysAllocString(szCondition);
1229 hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1230 *iReturn = V_I4(&varresult);
1231 VariantClear(&varresult);
1232 return hr;
1235 static HRESULT Session_Message(IDispatch *pSession, LONG kind, IDispatch *record, int *ret)
1237 VARIANT varresult;
1238 VARIANTARG vararg[2];
1239 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1240 HRESULT hr;
1242 VariantInit(&varresult);
1243 V_VT(vararg) = VT_DISPATCH;
1244 V_DISPATCH(vararg) = record;
1245 V_VT(vararg+1) = VT_I4;
1246 V_I4(vararg+1) = kind;
1248 hr = invoke(pSession, "Message", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1250 ok(V_VT(&varresult) == VT_I4, "V_VT(varresult) = %d\n", V_VT(&varresult));
1251 *ret = V_I4(&varresult);
1253 return hr;
1256 static HRESULT Session_SetInstallLevel(IDispatch *pSession, LONG iInstallLevel)
1258 VARIANT varresult;
1259 VARIANTARG vararg[1];
1260 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1262 VariantInit(&vararg[0]);
1263 V_VT(&vararg[0]) = VT_I4;
1264 V_I4(&vararg[0]) = iInstallLevel;
1266 return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1269 static HRESULT Session_FeatureCurrentState(IDispatch *pSession, LPCWSTR szName, int *pState)
1271 VARIANT varresult;
1272 VARIANTARG vararg[1];
1273 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1274 HRESULT hr;
1276 VariantInit(&vararg[0]);
1277 V_VT(&vararg[0]) = VT_BSTR;
1278 V_BSTR(&vararg[0]) = SysAllocString(szName);
1280 hr = invoke(pSession, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1281 *pState = V_I4(&varresult);
1282 VariantClear(&varresult);
1283 return hr;
1286 static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState)
1288 VARIANT varresult;
1289 VARIANTARG vararg[1];
1290 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1291 HRESULT hr;
1293 VariantInit(&vararg[0]);
1294 V_VT(&vararg[0]) = VT_BSTR;
1295 V_BSTR(&vararg[0]) = SysAllocString(szName);
1297 hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1298 *pState = V_I4(&varresult);
1299 VariantClear(&varresult);
1300 return hr;
1303 static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState)
1305 VARIANT varresult;
1306 VARIANTARG vararg[2];
1307 DISPID dispid = DISPID_PROPERTYPUT;
1308 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1310 VariantInit(&vararg[1]);
1311 V_VT(&vararg[1]) = VT_BSTR;
1312 V_BSTR(&vararg[1]) = SysAllocString(szName);
1313 VariantInit(&vararg[0]);
1314 V_VT(&vararg[0]) = VT_I4;
1315 V_I4(&vararg[0]) = iState;
1317 return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1320 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
1322 VARIANT varresult;
1323 VARIANTARG vararg[1];
1324 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1325 HRESULT hr;
1327 VariantInit(&vararg[0]);
1328 V_VT(&vararg[0]) = VT_BSTR;
1329 V_BSTR(&vararg[0]) = SysAllocString(szSql);
1331 hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1332 *pView = V_DISPATCH(&varresult);
1333 return hr;
1336 static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo)
1338 VARIANT varresult;
1339 VARIANTARG vararg[1];
1340 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1341 HRESULT hr;
1343 VariantInit(&vararg[0]);
1344 V_VT(&vararg[0]) = VT_I4;
1345 V_I4(&vararg[0]) = iUpdateCount;
1347 hr = invoke(pDatabase, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1348 *pSummaryInfo = V_DISPATCH(&varresult);
1349 return hr;
1352 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
1354 VARIANT varresult;
1355 VARIANTARG vararg[1];
1356 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1358 VariantInit(&vararg[0]);
1359 V_VT(&vararg[0]) = VT_DISPATCH;
1360 V_DISPATCH(&vararg[0]) = pRecord;
1362 return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1365 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
1367 VARIANT varresult;
1368 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1369 HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1370 *ppRecord = V_DISPATCH(&varresult);
1371 return hr;
1374 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
1376 VARIANT varresult;
1377 VARIANTARG vararg[2];
1378 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1380 VariantInit(&vararg[1]);
1381 V_VT(&vararg[1]) = VT_I4;
1382 V_I4(&vararg[1]) = iMode;
1383 VariantInit(&vararg[0]);
1384 V_VT(&vararg[0]) = VT_DISPATCH;
1385 V_DISPATCH(&vararg[0]) = pRecord;
1386 if (pRecord)
1387 IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */
1389 return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1392 static HRESULT View_Close(IDispatch *pView)
1394 VARIANT varresult;
1395 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1396 return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1399 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
1401 VARIANT varresult;
1402 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1403 HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1404 *pFieldCount = V_I4(&varresult);
1405 VariantClear(&varresult);
1406 return hr;
1409 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString)
1411 VARIANT varresult;
1412 VARIANTARG vararg[1];
1413 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1414 HRESULT hr;
1416 VariantInit(&vararg[0]);
1417 V_VT(&vararg[0]) = VT_I4;
1418 V_I4(&vararg[0]) = iField;
1420 hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1421 if (V_BSTR(&varresult))
1422 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
1423 VariantClear(&varresult);
1424 return hr;
1427 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
1429 VARIANT varresult;
1430 VARIANTARG vararg[2];
1431 DISPID dispid = DISPID_PROPERTYPUT;
1432 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1434 VariantInit(&vararg[1]);
1435 V_VT(&vararg[1]) = VT_I4;
1436 V_I4(&vararg[1]) = iField;
1437 VariantInit(&vararg[0]);
1438 V_VT(&vararg[0]) = VT_BSTR;
1439 V_BSTR(&vararg[0]) = SysAllocString(szString);
1441 return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1444 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
1446 VARIANT varresult;
1447 VARIANTARG vararg[1];
1448 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1449 HRESULT hr;
1451 VariantInit(&vararg[0]);
1452 V_VT(&vararg[0]) = VT_I4;
1453 V_I4(&vararg[0]) = iField;
1455 hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1456 *pValue = V_I4(&varresult);
1457 VariantClear(&varresult);
1458 return hr;
1461 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
1463 VARIANT varresult;
1464 VARIANTARG vararg[2];
1465 DISPID dispid = DISPID_PROPERTYPUT;
1466 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1468 VariantInit(&vararg[1]);
1469 V_VT(&vararg[1]) = VT_I4;
1470 V_I4(&vararg[1]) = iField;
1471 VariantInit(&vararg[0]);
1472 V_VT(&vararg[0]) = VT_I4;
1473 V_I4(&vararg[0]) = iValue;
1475 return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1478 static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT)
1480 VARIANT varresult;
1481 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1482 HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN);
1483 *ppEnumVARIANT = V_UNKNOWN(&varresult);
1484 return hr;
1487 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
1489 VARIANT varresult;
1490 VARIANTARG vararg[1];
1491 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1492 HRESULT hr;
1494 VariantInit(&vararg[0]);
1495 V_VT(&vararg[0]) = VT_I4;
1496 V_I4(&vararg[0]) = iIndex;
1498 hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1499 if (V_BSTR(&varresult))
1500 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
1501 VariantClear(&varresult);
1502 return hr;
1505 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
1507 VARIANT varresult;
1508 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1509 HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1510 *pCount = V_I4(&varresult);
1511 VariantClear(&varresult);
1512 return hr;
1515 static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect)
1517 VARIANTARG vararg[1];
1518 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1520 VariantInit(&vararg[0]);
1521 V_VT(&vararg[0]) = VT_I4;
1522 V_I4(&vararg[0]) = pid;
1523 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYGET, &dispparams, pVarResult, vtExpect);
1526 static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant)
1528 VARIANT varresult;
1529 VARIANTARG vararg[2];
1530 DISPID dispid = DISPID_PROPERTYPUT;
1531 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1533 VariantInit(&vararg[1]);
1534 V_VT(&vararg[1]) = VT_I4;
1535 V_I4(&vararg[1]) = pid;
1536 VariantInit(&vararg[0]);
1537 VariantCopyInd(vararg, pVariant);
1539 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1542 static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount)
1544 VARIANT varresult;
1545 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1546 HRESULT hr;
1548 hr = invoke(pSummaryInfo, "PropertyCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1549 *pCount = V_I4(&varresult);
1550 VariantClear(&varresult);
1551 return hr;
1554 /* Test the various objects */
1556 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4
1558 static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly)
1560 static const WCHAR szPropertyException[] = { 'P','r','o','p','e','r','t','y',',','P','i','d',0 };
1561 static const WCHAR szTitle[] = { 'T','i','t','l','e',0 };
1562 VARIANT varresult, var;
1563 SYSTEMTIME st;
1564 HRESULT hr;
1565 int j;
1567 /* SummaryInfo::PropertyCount */
1568 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1569 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1570 ok(j == num_info, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1572 /* SummaryInfo::Property, get for properties we have set */
1573 for (j = 0; j < num_info; j++)
1575 const msi_summary_info *entry = &info[j];
1577 int vt = entry->datatype;
1578 if (vt == VT_LPSTR) vt = VT_BSTR;
1579 else if (vt == VT_FILETIME) vt = VT_DATE;
1580 else if (vt == VT_I2) vt = VT_I4;
1582 hr = SummaryInfo_PropertyGet(pSummaryInfo, entry->property, &varresult, vt);
1583 ok(hr == S_OK, "SummaryInfo_Property (pid %d) failed, hresult 0x%08x\n", entry->property, hr);
1584 if (V_VT(&varresult) != vt)
1585 skip("Skipping property tests due to type mismatch\n");
1586 else if (vt == VT_I4)
1587 ok(V_I4(&varresult) == entry->iValue, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %d\n",
1588 entry->property, entry->iValue, V_I4(&varresult));
1589 else if (vt == VT_DATE)
1591 FILETIME ft;
1592 DATE d;
1594 FileTimeToLocalFileTime(entry->pftValue, &ft);
1595 FileTimeToSystemTime(&ft, &st);
1596 SystemTimeToVariantTime(&st, &d);
1597 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));
1599 else if (vt == VT_BSTR)
1601 ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry->property, entry->szValue, V_BSTR(&varresult));
1603 else
1604 skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry->property, vt);
1606 VariantClear(&varresult);
1609 /* SummaryInfo::Property, get; invalid arguments */
1611 /* Invalid pids */
1612 hr = SummaryInfo_PropertyGet(pSummaryInfo, -1, &varresult, VT_EMPTY);
1613 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1614 ok_exception(hr, szPropertyException);
1616 hr = SummaryInfo_PropertyGet(pSummaryInfo, 1000, &varresult, VT_EMPTY);
1617 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1618 ok_exception(hr, szPropertyException);
1620 /* Unsupported pids */
1621 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_DICTIONARY, &varresult, VT_EMPTY);
1622 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1624 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY);
1625 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1627 /* Pids we have not set, one for each type */
1628 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_EMPTY);
1629 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1631 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY);
1632 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1634 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY);
1635 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1637 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY);
1638 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1640 if (!readonly)
1642 /* SummaryInfo::Property, put; one for each type */
1644 /* VT_I2 */
1645 VariantInit(&var);
1646 V_VT(&var) = VT_I2;
1647 V_I2(&var) = 1;
1648 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CODEPAGE, &var);
1649 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1651 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */);
1652 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1653 ok(V_I2(&var) == V_I2(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var), V_I2(&varresult));
1654 VariantClear(&varresult);
1655 VariantClear(&var);
1657 /* VT_BSTR */
1658 V_VT(&var) = VT_BSTR;
1659 V_BSTR(&var) = SysAllocString(szTitle);
1660 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_TITLE, &var);
1661 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1663 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var));
1664 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1665 ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var), V_BSTR(&varresult));
1666 VariantClear(&varresult);
1667 VariantClear(&var);
1669 /* VT_DATE */
1670 V_VT(&var) = VT_DATE;
1671 FileTimeToSystemTime(&systemtime, &st);
1672 SystemTimeToVariantTime(&st, &V_DATE(&var));
1673 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_LASTSAVE_DTM, &var);
1674 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1676 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var));
1677 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1678 ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1679 VariantClear(&varresult);
1680 VariantClear(&var);
1682 /* VT_I4 */
1683 V_VT(&var) = VT_I4;
1684 V_I4(&var) = 1000;
1685 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1686 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1688 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1689 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1690 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult));
1691 VariantClear(&varresult);
1692 VariantClear(&var);
1694 /* SummaryInfo::PropertyCount */
1695 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1696 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1697 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1701 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1703 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 };
1704 static WCHAR szThree[] = { 'T','h','r','e','e',0 };
1705 static WCHAR szTwo[] = { 'T','w','o',0 };
1706 static WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
1707 static WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 };
1708 IDispatch *pView = NULL, *pSummaryInfo = NULL;
1709 HRESULT hr;
1711 hr = Database_OpenView(pDatabase, szSql, &pView);
1712 ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr);
1713 if (hr == S_OK)
1715 IDispatch *pRecord = NULL;
1716 WCHAR szString[MAX_PATH];
1718 /* View::Execute */
1719 hr = View_Execute(pView, NULL);
1720 ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr);
1722 /* View::Fetch */
1723 hr = View_Fetch(pView, &pRecord);
1724 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1725 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1726 if (pRecord)
1728 /* Record::StringDataGet */
1729 memset(szString, 0, sizeof(szString));
1730 hr = Record_StringDataGet(pRecord, 1, szString);
1731 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1732 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1734 /* Record::StringDataPut with correct index */
1735 hr = Record_StringDataPut(pRecord, 1, szTwo);
1736 ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1738 /* Record::StringDataGet */
1739 memset(szString, 0, sizeof(szString));
1740 hr = Record_StringDataGet(pRecord, 1, szString);
1741 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1742 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1744 /* Record::StringDataPut with incorrect index */
1745 hr = Record_StringDataPut(pRecord, -1, szString);
1746 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1747 ok_exception(hr, szStringDataField);
1749 /* View::Modify with incorrect parameters */
1750 hr = View_Modify(pView, -5, NULL);
1751 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1752 ok_exception(hr, szModifyModeRecord);
1754 hr = View_Modify(pView, -5, pRecord);
1755 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1756 ok_exception(hr, szModifyModeRecord);
1758 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1759 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1760 ok_exception(hr, szModifyModeRecord);
1762 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1763 ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr);
1765 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1766 memset(szString, 0, sizeof(szString));
1767 hr = Record_StringDataGet(pRecord, 1, szString);
1768 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1769 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1771 IDispatch_Release(pRecord);
1774 /* View::Fetch */
1775 hr = View_Fetch(pView, &pRecord);
1776 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1777 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1778 if (pRecord)
1780 /* Record::StringDataGet */
1781 memset(szString, 0, sizeof(szString));
1782 hr = Record_StringDataGet(pRecord, 1, szString);
1783 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1784 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1786 IDispatch_Release(pRecord);
1789 /* View::Fetch */
1790 hr = View_Fetch(pView, &pRecord);
1791 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1792 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1793 if (pRecord)
1794 IDispatch_Release(pRecord);
1796 /* View::Close */
1797 hr = View_Close(pView);
1798 ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr);
1800 IDispatch_Release(pView);
1803 /* Database::SummaryInformation */
1804 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo);
1805 ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr);
1806 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1807 if (pSummaryInfo)
1809 test_SummaryInfo(pSummaryInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), readonly);
1810 IDispatch_Release(pSummaryInfo);
1814 static void test_Session(IDispatch *pSession)
1816 static WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
1817 static WCHAR szOne[] = { 'O','n','e',0 };
1818 static WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 };
1819 static WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 };
1820 static WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 };
1821 static WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 };
1822 static WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1823 static WCHAR szEmpty[] = { 0 };
1824 static WCHAR szEquals[] = { '=',0 };
1825 static WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
1826 static WCHAR szModeFlag[] = { 'M','o','d','e',',','F','l','a','g',0 };
1827 WCHAR stringw[MAX_PATH];
1828 CHAR string[MAX_PATH];
1829 UINT len;
1830 BOOL bool;
1831 int myint;
1832 IDispatch *pDatabase = NULL, *pInst = NULL, *record = NULL;
1833 ULONG refs_before, refs_after;
1834 HRESULT hr;
1836 /* Session::Installer */
1837 hr = Session_Installer(pSession, &pInst);
1838 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1839 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1840 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1841 refs_before = IDispatch_AddRef(pInst);
1843 hr = Session_Installer(pSession, &pInst);
1844 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1845 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1846 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1847 refs_after = IDispatch_Release(pInst);
1848 ok(refs_before == refs_after, "got %u and %u\n", refs_before, refs_after);
1850 /* Session::Property, get */
1851 memset(stringw, 0, sizeof(stringw));
1852 hr = Session_PropertyGet(pSession, szProductName, stringw);
1853 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1854 if (strcmp_ww(stringw, szMSITEST) != 0)
1856 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1857 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1858 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1861 /* Session::Property, put */
1862 hr = Session_PropertyPut(pSession, szProductName, szProductName);
1863 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1864 memset(stringw, 0, sizeof(stringw));
1865 hr = Session_PropertyGet(pSession, szProductName, stringw);
1866 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1867 if (strcmp_ww(stringw, szProductName) != 0)
1869 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1870 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1871 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1874 /* Try putting a property using empty property identifier */
1875 hr = Session_PropertyPut(pSession, szEmpty, szProductName);
1876 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1877 ok_exception(hr, szPropertyName);
1879 /* Try putting a property using illegal property identifier */
1880 hr = Session_PropertyPut(pSession, szEquals, szProductName);
1881 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1883 /* Session::Language, get */
1884 hr = Session_LanguageGet(pSession, &len);
1885 ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1886 /* Not sure how to check the language is correct */
1888 /* Session::Mode, get */
1889 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1890 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1891 ok(!bool, "Reboot at end session mode is %d\n", bool);
1893 hr = Session_ModeGet(pSession, MSIRUNMODE_MAINTENANCE, &bool);
1894 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1895 ok(!bool, "Maintenance mode is %d\n", bool);
1897 /* Session::Mode, put */
1898 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE);
1899 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1900 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1901 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1902 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1903 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE); /* set it again so we don't reboot */
1904 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1906 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, TRUE);
1907 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1908 if (hr == DISP_E_EXCEPTION) ok_exception(hr, szModeFlag);
1910 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTNOW, &bool);
1911 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1912 ok(bool, "Reboot now mode is %d, expected 1\n", bool);
1914 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, FALSE); /* set it again so we don't reboot */
1915 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1916 if (hr == DISP_E_EXCEPTION) ok_exception(hr, szModeFlag);
1918 hr = Session_ModePut(pSession, MSIRUNMODE_MAINTENANCE, TRUE);
1919 ok(hr == DISP_E_EXCEPTION, "Session_ModePut failed, hresult 0x%08x\n", hr);
1920 ok_exception(hr, szModeFlag);
1922 /* Session::Database, get */
1923 hr = Session_Database(pSession, &pDatabase);
1924 ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr);
1925 if (hr == S_OK)
1927 test_Database(pDatabase, TRUE);
1928 IDispatch_Release(pDatabase);
1931 /* Session::EvaluateCondition */
1932 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1933 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1934 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1936 hr = Session_EvaluateCondition(pSession, szEmpty, &myint);
1937 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1938 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1940 hr = Session_EvaluateCondition(pSession, szEquals, &myint);
1941 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1942 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1944 /* Session::DoAction(CostInitialize) must occur before the next statements */
1945 hr = Session_DoAction(pSession, szCostInitialize, &myint);
1946 ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr);
1947 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1949 /* Session::SetInstallLevel */
1950 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1951 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
1953 /* Session::FeatureCurrentState, get */
1954 hr = Session_FeatureCurrentState(pSession, szOne, &myint);
1955 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
1956 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1958 /* Session::Message */
1959 hr = Installer_CreateRecord(0, &record);
1960 ok(hr == S_OK, "Installer_CreateRecord failed: %08x\n", hr);
1961 hr = Session_Message(pSession, INSTALLMESSAGE_INFO, record, &myint);
1962 ok(hr == S_OK, "Session_Message failed: %08x\n", hr);
1963 ok(myint == 0, "Session_Message returned %x\n", myint);
1965 /* Session::EvaluateCondition */
1966 hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint);
1967 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1968 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1970 hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint);
1971 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1972 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1974 /* Session::FeatureRequestState, put */
1975 hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED);
1976 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
1977 hr = Session_FeatureRequestStateGet(pSession, szOne, &myint);
1978 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
1979 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
1981 /* Session::EvaluateCondition */
1982 hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint);
1983 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1984 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1986 hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint);
1987 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1988 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1991 /* delete key and all its subkeys */
1992 static DWORD delete_key( HKEY hkey )
1994 char name[MAX_PATH];
1995 DWORD ret;
1997 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
1999 HKEY tmp;
2000 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
2002 ret = delete_key( tmp );
2003 RegCloseKey( tmp );
2005 if (ret) break;
2007 if (ret != ERROR_NO_MORE_ITEMS) return ret;
2008 RegDeleteKeyA( hkey, "" );
2009 return 0;
2012 static void test_Installer_RegistryValue(void)
2014 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
2015 static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 };
2016 static const WCHAR szOne[] = { 'O','n','e',0 };
2017 static const WCHAR szTwo[] = { 'T','w','o',0 };
2018 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
2019 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
2020 static const WCHAR szFour[] = { 'F','o','u','r',0 };
2021 static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 };
2022 static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 };
2023 static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 };
2024 static const WCHAR szSix[] = { 'S','i','x',0 };
2025 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
2026 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
2027 static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
2028 static const WCHAR szBlank[] = { 0 };
2029 VARIANT varresult;
2030 VARIANTARG vararg;
2031 WCHAR szString[MAX_PATH];
2032 HKEY hkey, hkey_sub;
2033 HKEY curr_user = (HKEY)1;
2034 HRESULT hr;
2035 BOOL bRet;
2036 LONG lRet;
2038 /* Delete keys */
2039 SetLastError(0xdeadbeef);
2040 lRet = RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey );
2041 if (!lRet && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2043 win_skip("Needed W-functions are not implemented\n");
2044 return;
2046 if (!lRet)
2047 delete_key( hkey );
2049 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
2050 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
2051 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
2052 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
2054 memset(szString, 0, sizeof(szString));
2055 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
2056 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2058 memset(szString, 0, sizeof(szString));
2059 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
2060 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2062 /* Create key */
2063 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
2065 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
2066 "RegSetValueExW failed\n");
2067 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
2068 "RegSetValueExW failed\n");
2069 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
2070 "RegSetValueExW failed\n");
2071 ok(SetEnvironmentVariableA("MSITEST", "Four"), "SetEnvironmentVariableA failed %d\n", GetLastError());
2072 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
2073 "RegSetValueExW failed\n");
2074 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
2075 "RegSetValueExW failed\n");
2076 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
2077 "RegSetValueExW failed\n");
2078 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, NULL, 0),
2079 "RegSetValueExW failed\n");
2081 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
2082 "RegSetValueExW failed\n");
2084 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
2086 /* Does our key exist? It should, and make sure we retrieve the correct default value */
2087 bRet = FALSE;
2088 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
2089 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
2090 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
2092 memset(szString, 0, sizeof(szString));
2093 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
2094 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2095 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
2097 /* Ask for the value of a nonexistent key */
2098 memset(szString, 0, sizeof(szString));
2099 hr = Installer_RegistryValueW(curr_user, szKey, szExpand, szString);
2100 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2102 /* Get values of keys */
2103 memset(szString, 0, sizeof(szString));
2104 hr = Installer_RegistryValueW(curr_user, szKey, szOne, szString);
2105 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2106 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
2108 VariantInit(&vararg);
2109 V_VT(&vararg) = VT_BSTR;
2110 V_BSTR(&vararg) = SysAllocString(szTwo);
2111 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_I4);
2112 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
2113 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
2114 VariantClear(&varresult);
2116 memset(szString, 0, sizeof(szString));
2117 hr = Installer_RegistryValueW(curr_user, szKey, szThree, szString);
2118 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2119 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
2121 memset(szString, 0, sizeof(szString));
2122 hr = Installer_RegistryValueW(curr_user, szKey, szFour, szString);
2123 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2124 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
2126 /* Vista does not NULL-terminate this case */
2127 memset(szString, 0, sizeof(szString));
2128 hr = Installer_RegistryValueW(curr_user, szKey, szFive, szString);
2129 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2130 ok_w2n("Registry value \"%s\" does not match expected \"%s\"\n",
2131 szString, szFiveHi, lstrlenW(szFiveHi));
2133 memset(szString, 0, sizeof(szString));
2134 hr = Installer_RegistryValueW(curr_user, szKey, szSix, szString);
2135 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2136 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_);
2138 VariantInit(&vararg);
2139 V_VT(&vararg) = VT_BSTR;
2140 V_BSTR(&vararg) = SysAllocString(szSeven);
2141 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_EMPTY);
2142 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
2144 /* Get string class name for the key */
2145 memset(szString, 0, sizeof(szString));
2146 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
2147 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2148 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank);
2150 /* Get name of a value by positive number (RegEnumValue like), valid index */
2151 memset(szString, 0, sizeof(szString));
2152 hr = Installer_RegistryValueI(curr_user, szKey, 2, szString, VT_BSTR);
2153 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2154 /* RegEnumValue order seems different on wine */
2155 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
2157 /* Get name of a value by positive number (RegEnumValue like), invalid index */
2158 memset(szString, 0, sizeof(szString));
2159 hr = Installer_RegistryValueI(curr_user, szKey, 10, szString, VT_EMPTY);
2160 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2162 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
2163 memset(szString, 0, sizeof(szString));
2164 hr = Installer_RegistryValueI(curr_user, szKey, -1, szString, VT_BSTR);
2165 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2166 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
2168 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
2169 memset(szString, 0, sizeof(szString));
2170 hr = Installer_RegistryValueI(curr_user, szKey, -10, szString, VT_EMPTY);
2171 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2173 /* clean up */
2174 delete_key(hkey);
2177 static void test_Installer_Products(BOOL bProductInstalled)
2179 WCHAR szString[MAX_PATH];
2180 HRESULT hr;
2181 int idx;
2182 IUnknown *pUnk = NULL;
2183 IEnumVARIANT *pEnum = NULL;
2184 VARIANT var;
2185 ULONG celt;
2186 int iCount, iValue;
2187 IDispatch *pStringList = NULL;
2188 BOOL bProductFound = FALSE;
2190 /* Installer::Products */
2191 hr = Installer_Products(&pStringList);
2192 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
2193 if (hr == S_OK)
2195 /* StringList::_NewEnum */
2196 hr = StringList__NewEnum(pStringList, &pUnk);
2197 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
2198 if (hr == S_OK)
2200 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
2201 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2203 if (!pEnum)
2204 skip("IEnumVARIANT tests\n");
2206 /* StringList::Count */
2207 hr = StringList_Count(pStringList, &iCount);
2208 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2210 for (idx=0; idx<iCount; idx++)
2212 /* StringList::Item */
2213 memset(szString, 0, sizeof(szString));
2214 hr = StringList_Item(pStringList, idx, szString);
2215 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2217 if (hr == S_OK)
2219 /* Installer::ProductState */
2220 hr = Installer_ProductState(szString, &iValue);
2221 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2222 if (hr == S_OK)
2223 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
2225 /* Not found our product code yet? Check */
2226 if (!bProductFound && !strcmp_ww(szString, szProductCode))
2227 bProductFound = TRUE;
2229 /* IEnumVARIANT::Next */
2230 if (pEnum)
2232 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2233 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2234 ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
2235 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2236 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2237 VariantClear(&var);
2242 if (bProductInstalled)
2244 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
2245 bProductInstalled ? "be" : "not be",
2246 bProductFound ? "found" : "not found");
2249 if (pEnum)
2251 IEnumVARIANT *pEnum2 = NULL;
2253 if (0) /* Crashes on Windows XP */
2255 /* IEnumVARIANT::Clone, NULL pointer */
2256 hr = IEnumVARIANT_Clone(pEnum, NULL);
2259 /* IEnumVARIANT::Clone */
2260 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
2261 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
2262 if (hr == S_OK)
2264 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
2266 /* IEnumVARIANT::Next of the clone */
2267 if (iCount)
2269 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
2270 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2271 ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
2272 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2273 VariantClear(&var);
2275 else
2276 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
2278 IEnumVARIANT_Release(pEnum2);
2281 /* IEnumVARIANT::Skip should fail */
2282 hr = IEnumVARIANT_Skip(pEnum, 1);
2283 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2285 /* IEnumVARIANT::Next, NULL variant pointer */
2286 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2287 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2288 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2290 /* IEnumVARIANT::Next, should not return any more items */
2291 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2292 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2293 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2294 VariantClear(&var);
2296 /* IEnumVARIANT::Reset */
2297 hr = IEnumVARIANT_Reset(pEnum);
2298 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2300 if (iCount)
2302 /* IEnumVARIANT::Skip to the last product */
2303 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2304 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2306 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2307 * NULL celt pointer. */
2308 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2309 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2310 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2311 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2312 VariantClear(&var);
2314 else
2315 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2318 /* StringList::Item using an invalid index */
2319 memset(szString, 0, sizeof(szString));
2320 hr = StringList_Item(pStringList, iCount, szString);
2321 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2323 if (pEnum) IEnumVARIANT_Release(pEnum);
2324 if (pUnk) IUnknown_Release(pUnk);
2325 IDispatch_Release(pStringList);
2329 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2330 * deleting the subkeys first) */
2331 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey)
2333 UINT ret;
2334 CHAR *string = NULL;
2335 HKEY hkey;
2336 DWORD dwSize;
2338 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2339 if (ret != ERROR_SUCCESS) return ret;
2340 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2341 if (ret != ERROR_SUCCESS) return ret;
2342 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2344 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2345 delete_registry_key(hkey, string);
2347 RegCloseKey(hkey);
2348 HeapFree(GetProcessHeap(), 0, string);
2349 RegDeleteKeyA(hkeyParent, subkey);
2350 return ERROR_SUCCESS;
2353 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2354 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, HKEY *phkey)
2356 UINT ret;
2357 CHAR *string = NULL;
2358 int idx = 0;
2359 HKEY hkey;
2360 DWORD dwSize;
2361 BOOL found = FALSE;
2363 *phkey = 0;
2365 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2366 if (ret != ERROR_SUCCESS) return ret;
2367 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2368 if (ret != ERROR_SUCCESS) return ret;
2369 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2371 while (!found &&
2372 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2374 if (!strcmp(string, findkey))
2376 *phkey = hkey;
2377 found = TRUE;
2379 else if (find_registry_key(hkey, string, findkey, phkey) == ERROR_SUCCESS) found = TRUE;
2382 if (*phkey != hkey) RegCloseKey(hkey);
2383 HeapFree(GetProcessHeap(), 0, string);
2384 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2387 static void test_Installer_InstallProduct(void)
2389 HRESULT hr;
2390 CHAR path[MAX_PATH];
2391 WCHAR szString[MAX_PATH];
2392 LONG res;
2393 HKEY hkey;
2394 DWORD num, size, type;
2395 int iValue, iCount;
2396 IDispatch *pStringList = NULL;
2398 create_test_files();
2400 /* Avoid an interactive dialog in case of insufficient privileges. */
2401 hr = Installer_UILevelPut(INSTALLUILEVEL_NONE);
2402 ok(hr == S_OK, "Expected UILevel propery put invoke to return S_OK, got 0x%08x\n", hr);
2404 /* Installer::InstallProduct */
2405 hr = Installer_InstallProduct(szMsifile, NULL);
2406 if (hr == DISP_E_EXCEPTION)
2408 skip("Installer object not supported.\n");
2409 delete_test_files();
2410 return;
2412 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2414 /* Installer::ProductState for our product code, which has been installed */
2415 hr = Installer_ProductState(szProductCode, &iValue);
2416 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2417 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2419 /* Installer::ProductInfo for our product code */
2421 /* NULL attribute */
2422 memset(szString, 0, sizeof(szString));
2423 hr = Installer_ProductInfo(szProductCode, NULL, szString);
2424 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2425 ok_exception(hr, szProductInfoException);
2427 /* Nonexistent attribute */
2428 memset(szString, 0, sizeof(szString));
2429 hr = Installer_ProductInfo(szProductCode, szMsifile, szString);
2430 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2431 ok_exception(hr, szProductInfoException);
2433 /* Package name */
2434 memset(szString, 0, sizeof(szString));
2435 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szString);
2436 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2437 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile);
2439 /* Product name */
2440 memset(szString, 0, sizeof(szString));
2441 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PRODUCTNAMEW, szString);
2442 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2443 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST);
2445 /* Installer::Products */
2446 test_Installer_Products(TRUE);
2448 /* Installer::RelatedProducts for our upgrade code */
2449 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2450 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2451 if (hr == S_OK)
2453 /* StringList::Count */
2454 hr = StringList_Count(pStringList, &iCount);
2455 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2456 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2458 /* StringList::Item */
2459 memset(szString, 0, sizeof(szString));
2460 hr = StringList_Item(pStringList, 0, szString);
2461 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2462 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
2464 IDispatch_Release(pStringList);
2467 /* Check & clean up installed files & registry keys */
2468 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2469 ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
2470 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2471 ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
2472 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2473 ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
2474 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2475 ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
2476 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2477 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2478 ok(delete_pf("msitest", FALSE), "File not installed\n");
2480 res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
2481 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2483 size = MAX_PATH;
2484 type = REG_SZ;
2485 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2486 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2487 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2489 size = MAX_PATH;
2490 type = REG_SZ;
2491 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2492 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2494 size = sizeof(num);
2495 type = REG_DWORD;
2496 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2497 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2498 ok(num == 314, "Expected 314, got %d\n", num);
2500 size = MAX_PATH;
2501 type = REG_SZ;
2502 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2503 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2504 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2506 RegCloseKey(hkey);
2508 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest");
2509 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2511 /* Remove registry keys written by RegisterProduct standard action */
2512 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F1C3AF50-8B56-4A69-A00C-00773FE42F30}");
2513 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2515 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2516 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2518 res = find_registry_key(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "05FA3C1F65B896A40AC00077F34EF203", &hkey);
2519 ok(res == ERROR_SUCCESS ||
2520 broken(res == ERROR_FILE_NOT_FOUND), /* win9x */
2521 "Expected ERROR_SUCCESS, got %d\n", res);
2522 if (res == ERROR_SUCCESS)
2524 res = delete_registry_key(hkey, "05FA3C1F65B896A40AC00077F34EF203");
2525 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2526 RegCloseKey(hkey);
2528 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203");
2529 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2531 else
2533 /* win9x defaults to a per-machine install. */
2534 RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203");
2537 /* Remove registry keys written by PublishProduct standard action */
2538 res = RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2539 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2541 res = delete_registry_key(hkey, "Products\\05FA3C1F65B896A40AC00077F34EF203");
2542 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2544 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2545 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2547 RegCloseKey(hkey);
2549 /* Delete installation files we installed */
2550 delete_test_files();
2553 static void test_Installer(void)
2555 static WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
2556 static WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
2557 WCHAR szPath[MAX_PATH];
2558 HRESULT hr;
2559 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL;
2560 int iValue, iCount;
2562 if (!pInstaller) return;
2564 /* Installer::CreateRecord */
2566 /* Test for error */
2567 hr = Installer_CreateRecord(-1, &pRecord);
2568 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2569 ok_exception(hr, szCreateRecordException);
2571 /* Test for success */
2572 hr = Installer_CreateRecord(1, &pRecord);
2573 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2574 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2575 if (pRecord)
2577 /* Record::FieldCountGet */
2578 hr = Record_FieldCountGet(pRecord, &iValue);
2579 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2580 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2582 /* Record::IntegerDataGet */
2583 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2584 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2585 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2587 /* Record::IntegerDataGet, bad index */
2588 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2589 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2590 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2592 /* Record::IntegerDataPut */
2593 hr = Record_IntegerDataPut(pRecord, 1, 100);
2594 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2596 /* Record::IntegerDataPut, bad index */
2597 hr = Record_IntegerDataPut(pRecord, 10, 100);
2598 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2599 ok_exception(hr, szIntegerDataException);
2601 /* Record::IntegerDataGet */
2602 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2603 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2604 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2606 IDispatch_Release(pRecord);
2609 create_package(szPath);
2611 /* Installer::OpenPackage */
2612 hr = Installer_OpenPackage(szPath, 0, &pSession);
2613 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2614 if (hr == S_OK)
2616 test_Session(pSession);
2617 IDispatch_Release(pSession);
2620 /* Installer::OpenDatabase */
2621 hr = Installer_OpenDatabase(szPath, (INT_PTR)MSIDBOPEN_TRANSACT, &pDatabase);
2622 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2623 if (hr == S_OK)
2625 test_Database(pDatabase, FALSE);
2626 IDispatch_Release(pDatabase);
2629 /* Installer::RegistryValue */
2630 test_Installer_RegistryValue();
2632 /* Installer::ProductState for our product code, which should not be installed */
2633 hr = Installer_ProductState(szProductCode, &iValue);
2634 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2635 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2637 /* Installer::ProductInfo for our product code, which should not be installed */
2639 /* Package name */
2640 memset(szPath, 0, sizeof(szPath));
2641 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szPath);
2642 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2643 ok_exception(hr, szProductInfoException);
2645 /* NULL attribute and NULL product code */
2646 memset(szPath, 0, sizeof(szPath));
2647 hr = Installer_ProductInfo(NULL, NULL, szPath);
2648 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2649 ok_exception(hr, szProductInfoException);
2651 /* Installer::Products */
2652 test_Installer_Products(FALSE);
2654 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2655 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2656 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2657 if (hr == S_OK)
2659 /* StringList::Count */
2660 hr = StringList_Count(pStringList, &iCount);
2661 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2662 ok(!iCount, "Expected no related products but found %d\n", iCount);
2664 IDispatch_Release(pStringList);
2667 /* Installer::Version */
2668 memset(szPath, 0, sizeof(szPath));
2669 hr = Installer_VersionGet(szPath);
2670 ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr);
2672 /* Installer::InstallProduct and other tests that depend on our product being installed */
2673 test_Installer_InstallProduct();
2676 START_TEST(automation)
2678 DWORD len;
2679 char temp_path[MAX_PATH], prev_path[MAX_PATH];
2680 HRESULT hr;
2681 CLSID clsid;
2682 IUnknown *pUnk;
2684 GetSystemTimeAsFileTime(&systemtime);
2686 GetCurrentDirectoryA(MAX_PATH, prev_path);
2687 GetTempPath(MAX_PATH, temp_path);
2688 SetCurrentDirectoryA(temp_path);
2690 lstrcpyA(CURR_DIR, temp_path);
2691 len = lstrlenA(CURR_DIR);
2693 if(len && (CURR_DIR[len - 1] == '\\'))
2694 CURR_DIR[len - 1] = 0;
2696 get_program_files_dir(PROG_FILES_DIR);
2698 hr = OleInitialize(NULL);
2699 ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr);
2700 hr = CLSIDFromProgID(szProgId, &clsid);
2701 ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr);
2702 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2703 ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr);
2705 if (pUnk)
2707 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2708 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2710 test_dispid();
2711 test_dispatch();
2712 test_Installer();
2714 IDispatch_Release(pInstaller);
2715 IUnknown_Release(pUnk);
2718 OleUninitialize();
2720 SetCurrentDirectoryA(prev_path);