wineps: Fix a couple of typos in the path painting function.
[wine/testsucceed.git] / dlls / msi / tests / automation.c
blobf062368dc749a1640a2dcb9c79a8f659ed0641e6
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 static BOOL is_wow64;
37 static LONG (WINAPI *pRegDeleteKeyExA)(HKEY, LPCSTR, REGSAM, DWORD);
38 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
40 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
42 static const char *msifile = "winetest-automation.msi";
43 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};
44 static const WCHAR szMSITEST[] = { 'M','S','I','T','E','S','T',0 };
45 static const WCHAR szProductCode[] = { '{','8','3','7','4','5','0','f','a','-','a','3','9','b','-','4','b','c','8','-','b','3','2','1','-','0','8','b','3','9','3','f','7','8','4','b','3','}',0 };
46 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 };
47 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 };
48 static const WCHAR WINE_INSTALLPROPERTY_PACKAGENAMEW[] = {'P','a','c','k','a','g','e','N','a','m','e',0};
49 static const WCHAR WINE_INSTALLPROPERTY_PRODUCTNAMEW[] = {'P','r','o','d','u','c','t','N','a','m','e',0};
50 static const WCHAR WINE_INSTALLPROPERTY_LOCALPACKAGEW[] = {'L','o','c','a','l','P','a','c','k','a','g','e',0};
51 static FILETIME systemtime;
52 static CHAR CURR_DIR[MAX_PATH];
53 static EXCEPINFO excepinfo;
56 * OLE automation data
57 **/
58 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 };
59 static IDispatch *pInstaller;
61 /* msi database data */
63 static const CHAR component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
64 "s72\tS38\ts72\ti2\tS255\tS72\n"
65 "Component\tComponent\n"
66 "Five\t{8CC92E9D-14B2-4CA4-B2AA-B11D02078087}\tNEWDIR\t2\t\tfive.txt\n"
67 "Four\t{FD37B4EA-7209-45C0-8917-535F35A2F080}\tCABOUTDIR\t2\t\tfour.txt\n"
68 "One\t{783B242E-E185-4A56-AF86-C09815EC053C}\tMSITESTDIR\t2\t\tone.txt\n"
69 "Three\t{010B6ADD-B27D-4EDD-9B3D-34C4F7D61684}\tCHANGEDDIR\t2\t\tthree.txt\n"
70 "Two\t{BF03D1A6-20DA-4A65-82F3-6CAC995915CE}\tFIRSTDIR\t2\t\ttwo.txt\n"
71 "dangler\t{6091DF25-EF96-45F1-B8E9-A9B1420C7A3C}\tTARGETDIR\t4\t\tregdata\n"
72 "component\t\tMSITESTDIR\t0\t1\tfile\n";
74 static const CHAR directory_dat[] = "Directory\tDirectory_Parent\tDefaultDir\n"
75 "s72\tS72\tl255\n"
76 "Directory\tDirectory\n"
77 "CABOUTDIR\tMSITESTDIR\tcabout\n"
78 "CHANGEDDIR\tMSITESTDIR\tchanged:second\n"
79 "FIRSTDIR\tMSITESTDIR\tfirst\n"
80 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
81 "NEWDIR\tCABOUTDIR\tnew\n"
82 "ProgramFilesFolder\tTARGETDIR\t.\n"
83 "TARGETDIR\t\tSourceDir\n";
85 static const CHAR feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
86 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
87 "Feature\tFeature\n"
88 "Five\t\tFive\tThe Five Feature\t5\t3\tNEWDIR\t0\n"
89 "Four\t\tFour\tThe Four Feature\t4\t3\tCABOUTDIR\t0\n"
90 "One\t\tOne\tThe One Feature\t1\t3\tMSITESTDIR\t0\n"
91 "Three\tOne\tThree\tThe Three Feature\t3\t3\tCHANGEDDIR\t0\n"
92 "Two\tOne\tTwo\tThe Two Feature\t2\t3\tFIRSTDIR\t0\n"
93 "feature\t\t\t\t2\t1\tTARGETDIR\t0\n";
95 static const CHAR feature_comp_dat[] = "Feature_\tComponent_\n"
96 "s38\ts72\n"
97 "FeatureComponents\tFeature_\tComponent_\n"
98 "Five\tFive\n"
99 "Four\tFour\n"
100 "One\tOne\n"
101 "Three\tThree\n"
102 "Two\tTwo\n"
103 "feature\tcomponent\n";
105 static const CHAR file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
106 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
107 "File\tFile\n"
108 "five.txt\tFive\tfive.txt\t1000\t\t\t0\t5\n"
109 "four.txt\tFour\tfour.txt\t1000\t\t\t0\t4\n"
110 "one.txt\tOne\tone.txt\t1000\t\t\t0\t1\n"
111 "three.txt\tThree\tthree.txt\t1000\t\t\t0\t3\n"
112 "two.txt\tTwo\ttwo.txt\t1000\t\t\t0\t2\n"
113 "file\tcomponent\tfilename\t100\t\t\t8192\t1\n";
115 static const CHAR install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
116 "s72\tS255\tI2\n"
117 "InstallExecuteSequence\tAction\n"
118 "AllocateRegistrySpace\tNOT Installed\t1550\n"
119 "CostFinalize\t\t1000\n"
120 "CostInitialize\t\t800\n"
121 "FileCost\t\t900\n"
122 "InstallFiles\t\t4000\n"
123 "RegisterProduct\t\t6100\n"
124 "PublishProduct\t\t6400\n"
125 "InstallFinalize\t\t6600\n"
126 "InstallInitialize\t\t1500\n"
127 "InstallValidate\t\t1400\n"
128 "LaunchConditions\t\t100\n"
129 "WriteRegistryValues\tSourceDir And SOURCEDIR\t5000\n";
131 static const CHAR media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
132 "i2\ti4\tL64\tS255\tS32\tS72\n"
133 "Media\tDiskId\n"
134 "1\t5\t\t\tDISK1\t\n";
136 static const CHAR property_dat[] = "Property\tValue\n"
137 "s72\tl0\n"
138 "Property\tProperty\n"
139 "DefaultUIFont\tDlgFont8\n"
140 "HASUIRUN\t0\n"
141 "INSTALLLEVEL\t3\n"
142 "InstallMode\tTypical\n"
143 "Manufacturer\tWine\n"
144 "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n"
145 "ProductCode\t{837450fa-a39b-4bc8-b321-08b393f784b3}\n"
146 "ProductID\tnone\n"
147 "ProductLanguage\t1033\n"
148 "ProductName\tMSITEST\n"
149 "ProductVersion\t1.1.1\n"
150 "PROMPTROLLBACKCOST\tP\n"
151 "Setup\tSetup\n"
152 "UpgradeCode\t{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}\n"
153 "MSIFASTINSTALL\t1\n";
155 static const CHAR registry_dat[] = "Registry\tRoot\tKey\tName\tValue\tComponent_\n"
156 "s72\ti2\tl255\tL255\tL0\ts72\n"
157 "Registry\tRegistry\n"
158 "Apples\t1\tSOFTWARE\\Wine\\msitest\tName\timaname\tOne\n"
159 "Oranges\t1\tSOFTWARE\\Wine\\msitest\tnumber\t#314\tTwo\n"
160 "regdata\t1\tSOFTWARE\\Wine\\msitest\tblah\tbad\tdangler\n"
161 "OrderTest\t1\tSOFTWARE\\Wine\\msitest\tOrderTestName\tOrderTestValue\tcomponent\n";
163 typedef struct _msi_table
165 const CHAR *filename;
166 const CHAR *data;
167 int size;
168 } msi_table;
170 #define ADD_TABLE(x) {#x".idt", x##_dat, sizeof(x##_dat)}
172 static const msi_table tables[] =
174 ADD_TABLE(component),
175 ADD_TABLE(directory),
176 ADD_TABLE(feature),
177 ADD_TABLE(feature_comp),
178 ADD_TABLE(file),
179 ADD_TABLE(install_exec_seq),
180 ADD_TABLE(media),
181 ADD_TABLE(property),
182 ADD_TABLE(registry)
185 typedef struct _msi_summary_info
187 UINT property;
188 UINT datatype;
189 INT iValue;
190 FILETIME *pftValue;
191 const CHAR *szValue;
192 } msi_summary_info;
194 #define ADD_INFO_I2(property, iValue) {property, VT_I2, iValue, NULL, NULL}
195 #define ADD_INFO_I4(property, iValue) {property, VT_I4, iValue, NULL, NULL}
196 #define ADD_INFO_LPSTR(property, szValue) {property, VT_LPSTR, 0, NULL, szValue}
197 #define ADD_INFO_FILETIME(property, pftValue) {property, VT_FILETIME, 0, pftValue, NULL}
199 static const msi_summary_info summary_info[] =
201 ADD_INFO_LPSTR(PID_TEMPLATE, ";1033"),
202 ADD_INFO_LPSTR(PID_REVNUMBER, "{004757CA-5092-49c2-AD20-28E1CE0DF5F2}"),
203 ADD_INFO_I4(PID_PAGECOUNT, 100),
204 ADD_INFO_I4(PID_WORDCOUNT, 0),
205 ADD_INFO_FILETIME(PID_CREATE_DTM, &systemtime),
206 ADD_INFO_FILETIME(PID_LASTPRINTED, &systemtime)
209 static void init_functionpointers(void)
211 HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll");
212 HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
214 #define GET_PROC(dll, func) \
215 p ## func = (void *)GetProcAddress(dll, #func); \
216 if(!p ## func) \
217 trace("GetProcAddress(%s) failed\n", #func);
219 GET_PROC(hadvapi32, RegDeleteKeyExA)
220 GET_PROC(hkernel32, IsWow64Process)
222 #undef GET_PROC
225 static LONG delete_key_portable( HKEY key, LPCSTR subkey, REGSAM access )
227 if (pRegDeleteKeyExA)
228 return pRegDeleteKeyExA( key, subkey, access, 0 );
229 return RegDeleteKeyA( key, subkey );
233 * Database Helpers
236 static void write_file(const CHAR *filename, const char *data, int data_size)
238 DWORD size;
240 HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL,
241 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
243 WriteFile(hf, data, data_size, &size, NULL);
244 CloseHandle(hf);
247 static void write_msi_summary_info(MSIHANDLE db, const msi_summary_info *info, int num_info)
249 MSIHANDLE summary;
250 UINT r;
251 int j;
253 r = MsiGetSummaryInformationA(db, NULL, num_info, &summary);
254 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
256 /* import summary information into the stream */
257 for (j = 0; j < num_info; j++)
259 const msi_summary_info *entry = &info[j];
261 r = MsiSummaryInfoSetPropertyA(summary, entry->property, entry->datatype,
262 entry->iValue, entry->pftValue, entry->szValue);
263 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
266 /* write the summary changes back to the stream */
267 r = MsiSummaryInfoPersist(summary);
268 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
270 MsiCloseHandle(summary);
273 static void create_database(const CHAR *name, const msi_table *tables, int num_tables,
274 const msi_summary_info *info, int num_info)
276 MSIHANDLE db;
277 UINT r;
278 int j;
280 r = MsiOpenDatabaseA(name, MSIDBOPEN_CREATE, &db);
281 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
283 /* import the tables into the database */
284 for (j = 0; j < num_tables; j++)
286 const msi_table *table = &tables[j];
288 write_file(table->filename, table->data, (table->size - 1) * sizeof(char));
290 r = MsiDatabaseImportA(db, CURR_DIR, table->filename);
291 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
293 DeleteFileA(table->filename);
296 write_msi_summary_info(db, info, num_info);
298 r = MsiDatabaseCommit(db);
299 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
301 MsiCloseHandle(db);
304 static BOOL create_package(LPWSTR path)
306 static const WCHAR slashW[] = {'\\',0};
307 DWORD len;
309 /* Prepare package */
310 create_database(msifile, tables,
311 sizeof(tables) / sizeof(msi_table), summary_info,
312 sizeof(summary_info) / sizeof(msi_summary_info));
314 len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
315 CURR_DIR, -1, path, MAX_PATH);
316 ok(len, "MultiByteToWideChar returned error %d\n", GetLastError());
317 if (!len)
318 return FALSE;
320 lstrcatW(path, slashW);
321 lstrcatW(path, szMsifile);
322 return TRUE;
326 * Installation helpers
329 static char PROG_FILES_DIR[MAX_PATH];
331 static BOOL get_program_files_dir(LPSTR buf)
333 HKEY hkey;
334 DWORD type = REG_EXPAND_SZ, size;
336 if (RegOpenKey(HKEY_LOCAL_MACHINE,
337 "Software\\Microsoft\\Windows\\CurrentVersion", &hkey))
338 return FALSE;
340 size = MAX_PATH;
341 if (RegQueryValueEx(hkey, "ProgramFilesDir (x86)", 0, &type, (LPBYTE)buf, &size) &&
342 RegQueryValueEx(hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size))
343 return FALSE;
345 RegCloseKey(hkey);
346 return TRUE;
349 static void create_file(const CHAR *name, DWORD size)
351 HANDLE file;
352 DWORD written, left;
354 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
355 ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
356 WriteFile(file, name, strlen(name), &written, NULL);
357 WriteFile(file, "\n", strlen("\n"), &written, NULL);
359 left = size - lstrlen(name) - 1;
361 SetFilePointer(file, left, NULL, FILE_CURRENT);
362 SetEndOfFile(file);
364 CloseHandle(file);
367 static void create_test_files(void)
369 CreateDirectoryA("msitest", NULL);
370 create_file("msitest\\one.txt", 100);
371 CreateDirectoryA("msitest\\first", NULL);
372 create_file("msitest\\first\\two.txt", 100);
373 CreateDirectoryA("msitest\\second", NULL);
374 create_file("msitest\\second\\three.txt", 100);
375 CreateDirectoryA("msitest\\cabout",NULL);
376 create_file("msitest\\cabout\\four.txt", 100);
377 CreateDirectoryA("msitest\\cabout\\new",NULL);
378 create_file("msitest\\cabout\\new\\five.txt", 100);
379 create_file("msitest\\filename", 100);
382 static BOOL delete_pf(const CHAR *rel_path, BOOL is_file)
384 CHAR path[MAX_PATH];
386 lstrcpyA(path, PROG_FILES_DIR);
387 lstrcatA(path, "\\");
388 lstrcatA(path, rel_path);
390 if (is_file)
391 return DeleteFileA(path);
392 else
393 return RemoveDirectoryA(path);
396 static void delete_test_files(void)
398 DeleteFileA(msifile);
399 DeleteFileA("msitest\\cabout\\new\\five.txt");
400 DeleteFileA("msitest\\cabout\\four.txt");
401 DeleteFileA("msitest\\second\\three.txt");
402 DeleteFileA("msitest\\first\\two.txt");
403 DeleteFileA("msitest\\one.txt");
404 DeleteFileA("msitest\\filename");
405 RemoveDirectoryA("msitest\\cabout\\new");
406 RemoveDirectoryA("msitest\\cabout");
407 RemoveDirectoryA("msitest\\second");
408 RemoveDirectoryA("msitest\\first");
409 RemoveDirectoryA("msitest");
413 * Automation helpers and tests
416 /* ok-like statement which takes two unicode strings or one unicode and one ANSI string as arguments */
417 static CHAR string1[MAX_PATH], string2[MAX_PATH];
419 #define ok_w2(format, szString1, szString2) \
421 do { \
422 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
423 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
424 if (lstrcmpA(string1, string2) != 0) \
425 ok(0, format, string1, string2); \
426 } while(0);
428 #define ok_w2n(format, szString1, szString2, len) \
430 if (memcmp(szString1, szString2, len * sizeof(WCHAR)) != 0) \
432 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
433 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
434 ok(0, format, string1, string2); \
437 #define ok_aw(format, aString, wString) \
439 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
440 if (lstrcmpA(string1, aString) != 0) \
441 ok(0, format, string1, aString); \
443 #define ok_awplus(format, extra, aString, wString) \
445 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
446 if (lstrcmpA(string1, aString) != 0) \
447 ok(0, format, extra, string1, aString); \
449 /* exception checker */
450 static WCHAR szSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
452 #define ok_exception(hr, szDescription) \
453 if (hr == DISP_E_EXCEPTION) \
455 /* Compare wtype, source, and destination */ \
456 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
458 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
459 if (excepinfo.bstrSource) \
460 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, szSource); \
462 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
463 if (excepinfo.bstrDescription) \
464 ok_w2("Exception description was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrDescription, szDescription); \
466 SysFreeString(excepinfo.bstrSource); \
467 SysFreeString(excepinfo.bstrDescription); \
468 SysFreeString(excepinfo.bstrHelpFile); \
471 static DISPID get_dispid( IDispatch *disp, const char *name )
473 LPOLESTR str;
474 UINT len;
475 DISPID id = -1;
476 HRESULT r;
478 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
479 str = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
480 if (str)
482 MultiByteToWideChar(CP_ACP, 0, name, -1, str, len );
483 r = IDispatch_GetIDsOfNames( disp, &IID_NULL, &str, 1, 0, &id );
484 HeapFree(GetProcessHeap(), 0, str);
485 if (r != S_OK)
486 return -1;
489 return id;
492 static void test_dispid(void)
494 DISPID dispid;
496 dispid = get_dispid(pInstaller, "CreateRecord");
497 ok(dispid == 1, "Expected 1, got %d\n", dispid);
498 dispid = get_dispid(pInstaller, "OpenPackage");
499 ok(dispid == 2, "Expected 2, got %d\n", dispid);
500 dispid = get_dispid(pInstaller, "OpenProduct");
501 ok(dispid == 3, "Expected 3, got %d\n", dispid);
502 dispid = get_dispid(pInstaller, "OpenDatabase");
503 ok(dispid == 4, "Expected 4, got %d\n", dispid);
504 dispid = get_dispid(pInstaller, "SummaryInformation");
505 ok(dispid == 5, "Expected 5, got %d\n", dispid);
506 dispid = get_dispid( pInstaller, "UILevel" );
507 ok(dispid == 6, "Expected 6, got %d\n", dispid);
508 dispid = get_dispid(pInstaller, "EnableLog");
509 ok(dispid == 7, "Expected 7, got %d\n", dispid);
510 dispid = get_dispid(pInstaller, "InstallProduct");
511 ok(dispid == 8, "Expected 8, got %d\n", dispid);
512 dispid = get_dispid(pInstaller, "Version");
513 ok(dispid == 9, "Expected 9, got %d\n", dispid);
514 dispid = get_dispid(pInstaller, "LastErrorRecord");
515 ok(dispid == 10, "Expected 10, got %d\n", dispid);
516 dispid = get_dispid(pInstaller, "RegistryValue");
517 ok(dispid == 11, "Expected 11, got %d\n", dispid);
518 dispid = get_dispid(pInstaller, "Environment");
519 ok(dispid == 12, "Expected 12, got %d\n", dispid);
520 dispid = get_dispid(pInstaller, "FileAttributes");
521 ok(dispid == 13, "Expected 13, got %d\n", dispid);
522 dispid = get_dispid(pInstaller, "FileSize");
523 ok(dispid == 15, "Expected 15, got %d\n", dispid);
524 dispid = get_dispid(pInstaller, "FileVersion");
525 ok(dispid == 16, "Expected 16, got %d\n", dispid);
526 dispid = get_dispid(pInstaller, "ProductState");
527 ok(dispid == 17, "Expected 17, got %d\n", dispid);
528 dispid = get_dispid(pInstaller, "ProductInfo");
529 ok(dispid == 18, "Expected 18, got %d\n", dispid);
530 todo_wine
532 dispid = get_dispid(pInstaller, "ConfigureProduct");
533 ok(dispid == 19, "Expected 19, got %d\n", dispid);
534 dispid = get_dispid(pInstaller, "ReinstallProduct");
535 ok(dispid == 20 , "Expected 20, got %d\n", dispid);
536 dispid = get_dispid(pInstaller, "CollectUserInfo");
537 ok(dispid == 21, "Expected 21, got %d\n", dispid);
538 dispid = get_dispid(pInstaller, "ApplyPatch");
539 ok(dispid == 22, "Expected 22, got %d\n", dispid);
540 dispid = get_dispid(pInstaller, "FeatureParent");
541 ok(dispid == 23, "Expected 23, got %d\n", dispid);
542 dispid = get_dispid(pInstaller, "FeatureState");
543 ok(dispid == 24, "Expected 24, got %d\n", dispid);
544 dispid = get_dispid(pInstaller, "UseFeature");
545 ok(dispid == 25, "Expected 25, got %d\n", dispid);
546 dispid = get_dispid(pInstaller, "FeatureUsageCount");
547 ok(dispid == 26, "Expected 26, got %d\n", dispid);
548 dispid = get_dispid(pInstaller, "FeatureUsageDate");
549 ok(dispid == 27, "Expected 27, got %d\n", dispid);
550 dispid = get_dispid(pInstaller, "ConfigureFeature");
551 ok(dispid == 28, "Expected 28, got %d\n", dispid);
552 dispid = get_dispid(pInstaller, "ReinstallFeature");
553 ok(dispid == 29, "Expected 29, got %d\n", dispid);
554 dispid = get_dispid(pInstaller, "ProvideComponent");
555 ok(dispid == 30, "Expected 30, got %d\n", dispid);
556 dispid = get_dispid(pInstaller, "ComponentPath");
557 ok(dispid == 31, "Expected 31, got %d\n", dispid);
558 dispid = get_dispid(pInstaller, "ProvideQualifiedComponent");
559 ok(dispid == 32, "Expected 32, got %d\n", dispid);
560 dispid = get_dispid(pInstaller, "QualifierDescription");
561 ok(dispid == 33, "Expected 33, got %d\n", dispid);
562 dispid = get_dispid(pInstaller, "ComponentQualifiers");
563 ok(dispid == 34, "Expected 34, got %d\n", dispid);
565 dispid = get_dispid(pInstaller, "Products");
566 ok(dispid == 35, "Expected 35, got %d\n", dispid);
567 todo_wine
569 dispid = get_dispid(pInstaller, "Features");
570 ok(dispid == 36, "Expected 36, got %d\n", dispid);
571 dispid = get_dispid(pInstaller, "Components");
572 ok(dispid == 37, "Expected 37, got %d\n", dispid);
573 dispid = get_dispid(pInstaller, "ComponentClients");
574 ok(dispid == 38, "Expected 38, got %d\n", dispid);
575 dispid = get_dispid(pInstaller, "Patches");
576 ok(dispid == 39, "Expected 39, got %d\n", dispid);
578 dispid = get_dispid(pInstaller, "RelatedProducts");
579 ok(dispid == 40, "Expected 40, got %d\n", dispid);
580 todo_wine
582 dispid = get_dispid(pInstaller, "PatchInfo");
583 ok(dispid == 41, "Expected 41, got %d\n", dispid);
584 dispid = get_dispid(pInstaller, "PatchTransforms");
585 ok(dispid == 42, "Expected 42, got %d\n", dispid);
586 dispid = get_dispid(pInstaller, "AddSource");
587 ok(dispid == 43, "Expected 43, got %d\n", dispid);
588 dispid = get_dispid(pInstaller, "ClearSourceList");
589 ok(dispid == 44, "Expected 44, got %d\n", dispid);
590 dispid = get_dispid(pInstaller, "ForceSourceListResolution");
591 ok(dispid == 45, "Expected 45, got %d\n", dispid);
592 dispid = get_dispid(pInstaller, "ShortcutTarget");
593 ok(dispid == 46, "Expected 46, got %d\n", dispid);
594 dispid = get_dispid(pInstaller, "FileHash");
595 ok(dispid == 47, "Expected 47, got %d\n", dispid);
596 dispid = get_dispid(pInstaller, "FileSignatureInfo");
597 ok(dispid == 48, "Expected 48, got %d\n", dispid);
599 dispid = get_dispid(pInstaller, "RemovePatches");
600 ok(dispid == 49 || dispid == -1, "Expected 49 or -1, got %d\n", dispid);
601 dispid = get_dispid(pInstaller, "ApplyMultiplePatches");
602 ok(dispid == 51 || dispid == -1, "Expected 51 or -1, got %d\n", dispid);
603 dispid = get_dispid(pInstaller, "ProductsEx");
604 ok(dispid == 52 || dispid == -1, "Expected 52 or -1, got %d\n", dispid);
605 dispid = get_dispid(pInstaller, "PatchesEx");
606 ok(dispid == 55 || dispid == -1, "Expected 55 or -1, got %d\n", dispid);
607 dispid = get_dispid(pInstaller, "ExtractPatchXMLData");
608 ok(dispid == 57 || dispid == -1, "Expected 57 or -1, got %d\n", dispid);
609 dispid = get_dispid( pInstaller, "ProductElevated" );
610 ok(dispid == 59 || dispid == -1, "Expected 59 or -1, got %d\n", dispid);
611 dispid = get_dispid( pInstaller, "ProvideAssembly" );
612 ok(dispid == 60 || dispid == -1, "Expected 60 or -1, got %d\n", dispid);
613 dispid = get_dispid( pInstaller, "ProductInfoFromScript" );
614 ok(dispid == 61 || dispid == -1, "Expected 61 or -1, got %d\n", dispid);
615 dispid = get_dispid( pInstaller, "AdvertiseProduct" );
616 ok(dispid == 62 || dispid == -1, "Expected 62 or -1, got %d\n", dispid);
617 dispid = get_dispid( pInstaller, "CreateAdvertiseScript" );
618 ok(dispid == 63 || dispid == -1, "Expected 63 or -1, got %d\n", dispid);
619 dispid = get_dispid( pInstaller, "PatchFiles" );
620 ok(dispid == 65 || dispid == -1, "Expected 65 or -1, got %d\n", dispid);
623 /* Test basic IDispatch functions */
624 static void test_dispatch(void)
626 static WCHAR szOpenPackage[] = { 'O','p','e','n','P','a','c','k','a','g','e',0 };
627 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};
628 static WCHAR szProductState[] = { 'P','r','o','d','u','c','t','S','t','a','t','e',0 };
629 HRESULT hr;
630 DISPID dispid;
631 OLECHAR *name;
632 VARIANT varresult;
633 VARIANTARG vararg[3];
634 WCHAR path[MAX_PATH];
635 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
637 /* Test getting ID of a function name that does not exist */
638 name = (WCHAR *)szMsifile;
639 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
640 ok(hr == DISP_E_UNKNOWNNAME, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
642 /* Test invoking this function */
643 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
644 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
646 /* Test getting ID of a function name that does exist */
647 name = szOpenPackage;
648 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
649 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
651 /* Test invoking this function (without parameters passed) */
652 if (0) /* All of these crash MSI on Windows XP */
654 IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
655 IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL);
656 VariantInit(&varresult);
657 IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, &varresult, &excepinfo, NULL);
660 /* Try with NULL params */
661 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
662 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
664 /* Try one empty parameter */
665 dispparams.rgvarg = vararg;
666 dispparams.cArgs = 1;
667 VariantInit(&vararg[0]);
668 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
669 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
671 /* Try two empty parameters */
672 dispparams.cArgs = 2;
673 VariantInit(&vararg[0]);
674 VariantInit(&vararg[1]);
675 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
676 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
678 /* Try one parameter, the required BSTR. Second parameter is optional.
679 * NOTE: The specified package does not exist, which is why the call fails.
681 dispparams.cArgs = 1;
682 VariantInit(&vararg[0]);
683 V_VT(&vararg[0]) = VT_BSTR;
684 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
685 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
686 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
687 ok_exception(hr, szOpenPackageException);
688 VariantClear(&vararg[0]);
690 /* Provide the required BSTR and an empty second parameter.
691 * NOTE: The specified package does not exist, which is why the call fails.
693 dispparams.cArgs = 2;
694 VariantInit(&vararg[1]);
695 V_VT(&vararg[1]) = VT_BSTR;
696 V_BSTR(&vararg[1]) = SysAllocString(szMsifile);
697 VariantInit(&vararg[0]);
698 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
699 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
700 ok_exception(hr, szOpenPackageException);
701 VariantClear(&vararg[1]);
703 /* Provide the required BSTR and two empty parameters.
704 * NOTE: The specified package does not exist, which is why the call fails.
706 dispparams.cArgs = 3;
707 VariantInit(&vararg[2]);
708 V_VT(&vararg[2]) = VT_BSTR;
709 V_BSTR(&vararg[2]) = SysAllocString(szMsifile);
710 VariantInit(&vararg[1]);
711 VariantInit(&vararg[0]);
712 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
713 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
714 ok_exception(hr, szOpenPackageException);
715 VariantClear(&vararg[2]);
717 /* Provide the required BSTR and a second parameter with the wrong type. */
718 dispparams.cArgs = 2;
719 VariantInit(&vararg[1]);
720 V_VT(&vararg[1]) = VT_BSTR;
721 V_BSTR(&vararg[1]) = SysAllocString(szMsifile);
722 VariantInit(&vararg[0]);
723 V_VT(&vararg[0]) = VT_BSTR;
724 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
725 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
726 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
727 VariantClear(&vararg[0]);
728 VariantClear(&vararg[1]);
730 /* Create a proper installer package. */
731 create_package(path);
733 /* Try one parameter, the required BSTR. Second parameter is optional.
734 * Proper installer package exists. Path to the package is relative.
736 dispparams.cArgs = 1;
737 VariantInit(&vararg[0]);
738 V_VT(&vararg[0]) = VT_BSTR;
739 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
740 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
741 todo_wine ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
742 ok_exception(hr, szOpenPackageException);
743 VariantClear(&vararg[0]);
744 if (hr != DISP_E_EXCEPTION)
745 VariantClear(&varresult);
747 /* Try one parameter, the required BSTR. Second parameter is optional.
748 * Proper installer package exists. Path to the package is absolute.
750 dispparams.cArgs = 1;
751 VariantInit(&vararg[0]);
752 V_VT(&vararg[0]) = VT_BSTR;
753 V_BSTR(&vararg[0]) = SysAllocString(path);
754 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
755 if (hr == DISP_E_EXCEPTION)
757 skip("OpenPackage failed, insufficient rights?\n");
758 DeleteFileW(path);
759 return;
761 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
762 VariantClear(&vararg[0]);
763 VariantClear(&varresult);
765 /* Provide the required BSTR and an empty second parameter. Proper
766 * installation package exists.
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 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
774 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
775 VariantClear(&vararg[1]);
776 VariantClear(&varresult);
778 /* Provide the required BSTR and two empty parameters. Proper
779 * installation package exists.
781 dispparams.cArgs = 3;
782 VariantInit(&vararg[2]);
783 V_VT(&vararg[2]) = VT_BSTR;
784 V_BSTR(&vararg[2]) = SysAllocString(path);
785 VariantInit(&vararg[1]);
786 VariantInit(&vararg[0]);
787 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
788 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
789 VariantClear(&vararg[2]);
790 VariantClear(&varresult);
792 /* Provide the required BSTR and a second parameter with the wrong type. */
793 dispparams.cArgs = 2;
794 VariantInit(&vararg[1]);
795 V_VT(&vararg[1]) = VT_BSTR;
796 V_BSTR(&vararg[1]) = SysAllocString(path);
797 VariantInit(&vararg[0]);
798 V_VT(&vararg[0]) = VT_BSTR;
799 V_BSTR(&vararg[0]) = SysAllocString(path);
800 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
801 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
802 VariantClear(&vararg[0]);
803 VariantClear(&vararg[1]);
805 /* Provide the required BSTR and a second parameter that can be coerced to
806 * VT_I4.
808 dispparams.cArgs = 2;
809 VariantInit(&vararg[1]);
810 V_VT(&vararg[1]) = VT_BSTR;
811 V_BSTR(&vararg[1]) = SysAllocString(path);
812 VariantInit(&vararg[0]);
813 V_VT(&vararg[0]) = VT_I2;
814 V_BSTR(&vararg[0]) = 0;
815 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
816 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
817 VariantClear(&vararg[1]);
818 VariantClear(&varresult);
820 DeleteFileW(path);
822 /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
823 VariantInit(&vararg[0]);
824 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
825 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
827 VariantInit(&vararg[0]);
828 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
829 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
831 /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
832 name = szProductState;
833 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
834 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
836 dispparams.rgvarg = NULL;
837 dispparams.cArgs = 0;
838 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
839 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
841 dispparams.rgvarg = NULL;
842 dispparams.cArgs = 0;
843 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
844 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
847 /* invocation helper function */
848 static int _invoke_todo_vtResult = 0;
850 static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult)
852 OLECHAR *name = NULL;
853 DISPID dispid;
854 HRESULT hr;
855 UINT i;
856 UINT len;
858 memset(pVarResult, 0, sizeof(VARIANT));
859 VariantInit(pVarResult);
861 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 );
862 name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
863 if (!name) return E_FAIL;
864 MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len );
865 hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
866 HeapFree(GetProcessHeap(), 0, name);
867 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
868 if (!hr == S_OK) return hr;
870 memset(&excepinfo, 0, sizeof(excepinfo));
871 hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL);
873 if (hr == S_OK)
875 if (_invoke_todo_vtResult) todo_wine
876 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
877 else
878 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
879 if (vtResult != VT_EMPTY)
881 hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult);
882 ok(hr == S_OK, "VariantChangeTypeEx returned 0x%08x\n", hr);
886 for (i=0; i<pDispParams->cArgs; i++)
887 VariantClear(&pDispParams->rgvarg[i]);
889 return hr;
892 /* Object_Property helper functions */
894 static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord)
896 VARIANT varresult;
897 VARIANTARG vararg[1];
898 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
899 HRESULT hr;
901 VariantInit(&vararg[0]);
902 V_VT(&vararg[0]) = VT_I4;
903 V_I4(&vararg[0]) = count;
905 hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
906 *pRecord = V_DISPATCH(&varresult);
907 return hr;
910 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
912 VARIANTARG vararg[3];
913 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
915 VariantInit(&vararg[2]);
916 V_VT(&vararg[2]) = VT_I4;
917 V_I4(&vararg[2]) = (INT_PTR)hkey;
918 VariantInit(&vararg[1]);
919 V_VT(&vararg[1]) = VT_BSTR;
920 V_BSTR(&vararg[1]) = SysAllocString(szKey);
921 VariantInit(&vararg[0]);
922 VariantCopy(&vararg[0], &vValue);
923 VariantClear(&vValue);
925 return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect);
928 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
930 VARIANT varresult;
931 VARIANTARG vararg;
932 HRESULT hr;
934 VariantInit(&vararg);
935 V_VT(&vararg) = VT_EMPTY;
936 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL);
937 *pBool = V_BOOL(&varresult);
938 VariantClear(&varresult);
939 return hr;
942 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
944 VARIANT varresult;
945 VARIANTARG vararg;
946 HRESULT hr;
948 VariantInit(&vararg);
949 V_VT(&vararg) = VT_BSTR;
950 V_BSTR(&vararg) = SysAllocString(szValue);
952 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR);
953 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
954 VariantClear(&varresult);
955 return hr;
958 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
960 VARIANT varresult;
961 VARIANTARG vararg;
962 HRESULT hr;
964 VariantInit(&vararg);
965 V_VT(&vararg) = VT_I4;
966 V_I4(&vararg) = iValue;
968 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult);
969 if (SUCCEEDED(hr) && vtResult == VT_BSTR) lstrcpyW(szString, V_BSTR(&varresult));
970 VariantClear(&varresult);
971 return hr;
974 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
976 VARIANT varresult;
977 VARIANTARG vararg[2];
978 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
979 HRESULT hr;
981 VariantInit(&vararg[1]);
982 V_VT(&vararg[1]) = VT_BSTR;
983 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
984 VariantInit(&vararg[0]);
985 V_VT(&vararg[0]) = VT_I4;
986 V_I4(&vararg[0]) = options;
988 hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
989 *pSession = V_DISPATCH(&varresult);
990 return hr;
993 static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase)
995 VARIANT varresult;
996 VARIANTARG vararg[2];
997 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
998 HRESULT hr;
1000 VariantInit(&vararg[1]);
1001 V_VT(&vararg[1]) = VT_BSTR;
1002 V_BSTR(&vararg[1]) = SysAllocString(szDatabasePath);
1003 VariantInit(&vararg[0]);
1004 V_VT(&vararg[0]) = VT_I4;
1005 V_I4(&vararg[0]) = openmode;
1007 hr = invoke(pInstaller, "OpenDatabase", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1008 *pDatabase = V_DISPATCH(&varresult);
1009 return hr;
1012 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
1014 VARIANT varresult;
1015 VARIANTARG vararg[2];
1016 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1018 VariantInit(&vararg[1]);
1019 V_VT(&vararg[1]) = VT_BSTR;
1020 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
1021 VariantInit(&vararg[0]);
1022 V_VT(&vararg[0]) = VT_BSTR;
1023 V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues);
1025 return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1028 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
1030 VARIANT varresult;
1031 VARIANTARG vararg[1];
1032 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1033 HRESULT hr;
1035 VariantInit(&vararg[0]);
1036 V_VT(&vararg[0]) = VT_BSTR;
1037 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
1039 hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1040 *pInstallState = V_I4(&varresult);
1041 VariantClear(&varresult);
1042 return hr;
1045 static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szString)
1047 VARIANT varresult;
1048 VARIANTARG vararg[2];
1049 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1050 HRESULT hr;
1052 VariantInit(&vararg[1]);
1053 V_VT(&vararg[1]) = VT_BSTR;
1054 V_BSTR(&vararg[1]) = SysAllocString(szProduct);
1055 VariantInit(&vararg[0]);
1056 V_VT(&vararg[0]) = VT_BSTR;
1057 V_BSTR(&vararg[0]) = SysAllocString(szAttribute);
1059 hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1060 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1061 VariantClear(&varresult);
1062 return hr;
1065 static HRESULT Installer_Products(IDispatch **pStringList)
1067 VARIANT varresult;
1068 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1069 HRESULT hr;
1071 hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1072 *pStringList = V_DISPATCH(&varresult);
1073 return hr;
1076 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
1078 VARIANT varresult;
1079 VARIANTARG vararg[1];
1080 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1081 HRESULT hr;
1083 VariantInit(&vararg[0]);
1084 V_VT(&vararg[0]) = VT_BSTR;
1085 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
1087 hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1088 *pStringList = V_DISPATCH(&varresult);
1089 return hr;
1092 static HRESULT Installer_VersionGet(LPWSTR szVersion)
1094 VARIANT varresult;
1095 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1096 HRESULT hr;
1098 hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1099 if (V_BSTR(&varresult)) lstrcpyW(szVersion, V_BSTR(&varresult));
1100 VariantClear(&varresult);
1101 return hr;
1104 static HRESULT Installer_UILevelPut(int level)
1106 VARIANT varresult;
1107 VARIANTARG vararg;
1108 DISPID dispid = DISPID_PROPERTYPUT;
1109 DISPPARAMS dispparams = {&vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1111 VariantInit(&vararg);
1112 V_VT(&vararg) = VT_I4;
1113 V_I4(&vararg) = level;
1115 return invoke(pInstaller, "UILevel", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1118 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
1120 VARIANT varresult;
1121 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1122 HRESULT hr;
1124 hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1125 *pInst = V_DISPATCH(&varresult);
1126 return hr;
1129 static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn)
1131 VARIANT varresult;
1132 VARIANTARG vararg[1];
1133 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1134 HRESULT hr;
1136 VariantInit(&vararg[0]);
1137 V_VT(&vararg[0]) = VT_BSTR;
1138 V_BSTR(&vararg[0]) = SysAllocString(szName);
1140 hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1141 if (V_BSTR(&varresult)) lstrcpyW(szReturn, V_BSTR(&varresult));
1142 VariantClear(&varresult);
1143 return hr;
1146 static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue)
1148 VARIANT varresult;
1149 VARIANTARG vararg[2];
1150 DISPID dispid = DISPID_PROPERTYPUT;
1151 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1153 VariantInit(&vararg[1]);
1154 V_VT(&vararg[1]) = VT_BSTR;
1155 V_BSTR(&vararg[1]) = SysAllocString(szName);
1156 VariantInit(&vararg[0]);
1157 V_VT(&vararg[0]) = VT_BSTR;
1158 V_BSTR(&vararg[0]) = SysAllocString(szValue);
1160 return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1163 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
1165 VARIANT varresult;
1166 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1167 HRESULT hr;
1169 hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1170 *pLangId = V_I4(&varresult);
1171 VariantClear(&varresult);
1172 return hr;
1175 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, BOOL *pMode)
1177 VARIANT varresult;
1178 VARIANTARG vararg[1];
1179 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1180 HRESULT hr;
1182 VariantInit(&vararg[0]);
1183 V_VT(&vararg[0]) = VT_I4;
1184 V_I4(&vararg[0]) = iFlag;
1186 hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL);
1187 *pMode = V_BOOL(&varresult);
1188 VariantClear(&varresult);
1189 return hr;
1192 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, BOOL bMode)
1194 VARIANT varresult;
1195 VARIANTARG vararg[2];
1196 DISPID dispid = DISPID_PROPERTYPUT;
1197 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1199 VariantInit(&vararg[1]);
1200 V_VT(&vararg[1]) = VT_I4;
1201 V_I4(&vararg[1]) = iFlag;
1202 VariantInit(&vararg[0]);
1203 V_VT(&vararg[0]) = VT_BOOL;
1204 V_BOOL(&vararg[0]) = bMode;
1206 return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1209 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
1211 VARIANT varresult;
1212 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1213 HRESULT hr;
1215 hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1216 *pDatabase = V_DISPATCH(&varresult);
1217 return hr;
1220 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn)
1222 VARIANT varresult;
1223 VARIANTARG vararg[1];
1224 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1225 HRESULT hr;
1227 VariantInit(&vararg[0]);
1228 V_VT(&vararg[0]) = VT_BSTR;
1229 V_BSTR(&vararg[0]) = SysAllocString(szAction);
1231 hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1232 *iReturn = V_I4(&varresult);
1233 VariantClear(&varresult);
1234 return hr;
1237 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
1239 VARIANT varresult;
1240 VARIANTARG vararg[1];
1241 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1242 HRESULT hr;
1244 VariantInit(&vararg[0]);
1245 V_VT(&vararg[0]) = VT_BSTR;
1246 V_BSTR(&vararg[0]) = SysAllocString(szCondition);
1248 hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1249 *iReturn = V_I4(&varresult);
1250 VariantClear(&varresult);
1251 return hr;
1254 static HRESULT Session_Message(IDispatch *pSession, LONG kind, IDispatch *record, int *ret)
1256 VARIANT varresult;
1257 VARIANTARG vararg[2];
1258 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1259 HRESULT hr;
1261 VariantInit(&varresult);
1262 V_VT(vararg) = VT_DISPATCH;
1263 V_DISPATCH(vararg) = record;
1264 V_VT(vararg+1) = VT_I4;
1265 V_I4(vararg+1) = kind;
1267 hr = invoke(pSession, "Message", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1269 ok(V_VT(&varresult) == VT_I4, "V_VT(varresult) = %d\n", V_VT(&varresult));
1270 *ret = V_I4(&varresult);
1272 return hr;
1275 static HRESULT Session_SetInstallLevel(IDispatch *pSession, LONG iInstallLevel)
1277 VARIANT varresult;
1278 VARIANTARG vararg[1];
1279 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1281 VariantInit(&vararg[0]);
1282 V_VT(&vararg[0]) = VT_I4;
1283 V_I4(&vararg[0]) = iInstallLevel;
1285 return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1288 static HRESULT Session_FeatureCurrentState(IDispatch *pSession, LPCWSTR szName, int *pState)
1290 VARIANT varresult;
1291 VARIANTARG vararg[1];
1292 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1293 HRESULT hr;
1295 VariantInit(&vararg[0]);
1296 V_VT(&vararg[0]) = VT_BSTR;
1297 V_BSTR(&vararg[0]) = SysAllocString(szName);
1299 hr = invoke(pSession, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1300 *pState = V_I4(&varresult);
1301 VariantClear(&varresult);
1302 return hr;
1305 static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState)
1307 VARIANT varresult;
1308 VARIANTARG vararg[1];
1309 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1310 HRESULT hr;
1312 VariantInit(&vararg[0]);
1313 V_VT(&vararg[0]) = VT_BSTR;
1314 V_BSTR(&vararg[0]) = SysAllocString(szName);
1316 hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1317 *pState = V_I4(&varresult);
1318 VariantClear(&varresult);
1319 return hr;
1322 static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState)
1324 VARIANT varresult;
1325 VARIANTARG vararg[2];
1326 DISPID dispid = DISPID_PROPERTYPUT;
1327 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1329 VariantInit(&vararg[1]);
1330 V_VT(&vararg[1]) = VT_BSTR;
1331 V_BSTR(&vararg[1]) = SysAllocString(szName);
1332 VariantInit(&vararg[0]);
1333 V_VT(&vararg[0]) = VT_I4;
1334 V_I4(&vararg[0]) = iState;
1336 return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1339 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
1341 VARIANT varresult;
1342 VARIANTARG vararg[1];
1343 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1344 HRESULT hr;
1346 VariantInit(&vararg[0]);
1347 V_VT(&vararg[0]) = VT_BSTR;
1348 V_BSTR(&vararg[0]) = SysAllocString(szSql);
1350 hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1351 *pView = V_DISPATCH(&varresult);
1352 return hr;
1355 static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo)
1357 VARIANT varresult;
1358 VARIANTARG vararg[1];
1359 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1360 HRESULT hr;
1362 VariantInit(&vararg[0]);
1363 V_VT(&vararg[0]) = VT_I4;
1364 V_I4(&vararg[0]) = iUpdateCount;
1366 hr = invoke(pDatabase, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1367 *pSummaryInfo = V_DISPATCH(&varresult);
1368 return hr;
1371 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
1373 VARIANT varresult;
1374 VARIANTARG vararg[1];
1375 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1377 VariantInit(&vararg[0]);
1378 V_VT(&vararg[0]) = VT_DISPATCH;
1379 V_DISPATCH(&vararg[0]) = pRecord;
1381 return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1384 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
1386 VARIANT varresult;
1387 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1388 HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1389 *ppRecord = V_DISPATCH(&varresult);
1390 return hr;
1393 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
1395 VARIANT varresult;
1396 VARIANTARG vararg[2];
1397 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1399 VariantInit(&vararg[1]);
1400 V_VT(&vararg[1]) = VT_I4;
1401 V_I4(&vararg[1]) = iMode;
1402 VariantInit(&vararg[0]);
1403 V_VT(&vararg[0]) = VT_DISPATCH;
1404 V_DISPATCH(&vararg[0]) = pRecord;
1405 if (pRecord)
1406 IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */
1408 return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1411 static HRESULT View_Close(IDispatch *pView)
1413 VARIANT varresult;
1414 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1415 return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1418 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
1420 VARIANT varresult;
1421 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1422 HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1423 *pFieldCount = V_I4(&varresult);
1424 VariantClear(&varresult);
1425 return hr;
1428 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString)
1430 VARIANT varresult;
1431 VARIANTARG vararg[1];
1432 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1433 HRESULT hr;
1435 VariantInit(&vararg[0]);
1436 V_VT(&vararg[0]) = VT_I4;
1437 V_I4(&vararg[0]) = iField;
1439 hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1440 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1441 VariantClear(&varresult);
1442 return hr;
1445 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
1447 VARIANT varresult;
1448 VARIANTARG vararg[2];
1449 DISPID dispid = DISPID_PROPERTYPUT;
1450 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1452 VariantInit(&vararg[1]);
1453 V_VT(&vararg[1]) = VT_I4;
1454 V_I4(&vararg[1]) = iField;
1455 VariantInit(&vararg[0]);
1456 V_VT(&vararg[0]) = VT_BSTR;
1457 V_BSTR(&vararg[0]) = SysAllocString(szString);
1459 return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1462 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
1464 VARIANT varresult;
1465 VARIANTARG vararg[1];
1466 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1467 HRESULT hr;
1469 VariantInit(&vararg[0]);
1470 V_VT(&vararg[0]) = VT_I4;
1471 V_I4(&vararg[0]) = iField;
1473 hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1474 *pValue = V_I4(&varresult);
1475 VariantClear(&varresult);
1476 return hr;
1479 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
1481 VARIANT varresult;
1482 VARIANTARG vararg[2];
1483 DISPID dispid = DISPID_PROPERTYPUT;
1484 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1486 VariantInit(&vararg[1]);
1487 V_VT(&vararg[1]) = VT_I4;
1488 V_I4(&vararg[1]) = iField;
1489 VariantInit(&vararg[0]);
1490 V_VT(&vararg[0]) = VT_I4;
1491 V_I4(&vararg[0]) = iValue;
1493 return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1496 static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT)
1498 VARIANT varresult;
1499 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1500 HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN);
1501 *ppEnumVARIANT = V_UNKNOWN(&varresult);
1502 return hr;
1505 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
1507 VARIANT varresult;
1508 VARIANTARG vararg[1];
1509 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1510 HRESULT hr;
1512 VariantInit(&vararg[0]);
1513 V_VT(&vararg[0]) = VT_I4;
1514 V_I4(&vararg[0]) = iIndex;
1516 hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1517 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1518 VariantClear(&varresult);
1519 return hr;
1522 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
1524 VARIANT varresult;
1525 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1526 HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1527 *pCount = V_I4(&varresult);
1528 VariantClear(&varresult);
1529 return hr;
1532 static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect)
1534 VARIANTARG vararg[1];
1535 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1537 VariantInit(&vararg[0]);
1538 V_VT(&vararg[0]) = VT_I4;
1539 V_I4(&vararg[0]) = pid;
1540 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYGET, &dispparams, pVarResult, vtExpect);
1543 static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant)
1545 VARIANT varresult;
1546 VARIANTARG vararg[2];
1547 DISPID dispid = DISPID_PROPERTYPUT;
1548 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1550 VariantInit(&vararg[1]);
1551 V_VT(&vararg[1]) = VT_I4;
1552 V_I4(&vararg[1]) = pid;
1553 VariantInit(&vararg[0]);
1554 VariantCopyInd(vararg, pVariant);
1556 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1559 static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount)
1561 VARIANT varresult;
1562 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1563 HRESULT hr;
1565 hr = invoke(pSummaryInfo, "PropertyCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1566 *pCount = V_I4(&varresult);
1567 VariantClear(&varresult);
1568 return hr;
1571 /* Test the various objects */
1573 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4
1575 static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly)
1577 static const WCHAR szPropertyException[] = { 'P','r','o','p','e','r','t','y',',','P','i','d',0 };
1578 static const WCHAR szTitle[] = { 'T','i','t','l','e',0 };
1579 VARIANT varresult, var;
1580 SYSTEMTIME st;
1581 HRESULT hr;
1582 int j;
1584 /* SummaryInfo::PropertyCount */
1585 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1586 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1587 ok(j == num_info, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1589 /* SummaryInfo::Property, get for properties we have set */
1590 for (j = 0; j < num_info; j++)
1592 const msi_summary_info *entry = &info[j];
1594 int vt = entry->datatype;
1595 if (vt == VT_LPSTR) vt = VT_BSTR;
1596 else if (vt == VT_FILETIME) vt = VT_DATE;
1597 else if (vt == VT_I2) vt = VT_I4;
1599 hr = SummaryInfo_PropertyGet(pSummaryInfo, entry->property, &varresult, vt);
1600 ok(hr == S_OK, "SummaryInfo_Property (pid %d) failed, hresult 0x%08x\n", entry->property, hr);
1601 if (V_VT(&varresult) != vt)
1602 skip("Skipping property tests due to type mismatch\n");
1603 else if (vt == VT_I4)
1604 ok(V_I4(&varresult) == entry->iValue, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %d\n",
1605 entry->property, entry->iValue, V_I4(&varresult));
1606 else if (vt == VT_DATE)
1608 FILETIME ft;
1609 DATE d;
1611 FileTimeToLocalFileTime(entry->pftValue, &ft);
1612 FileTimeToSystemTime(&ft, &st);
1613 SystemTimeToVariantTime(&st, &d);
1614 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));
1616 else if (vt == VT_BSTR)
1618 ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry->property, entry->szValue, V_BSTR(&varresult));
1620 else
1621 skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry->property, vt);
1623 VariantClear(&varresult);
1626 /* SummaryInfo::Property, get; invalid arguments */
1628 /* Invalid pids */
1629 hr = SummaryInfo_PropertyGet(pSummaryInfo, -1, &varresult, VT_EMPTY);
1630 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1631 ok_exception(hr, szPropertyException);
1633 hr = SummaryInfo_PropertyGet(pSummaryInfo, 1000, &varresult, VT_EMPTY);
1634 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1635 ok_exception(hr, szPropertyException);
1637 /* Unsupported pids */
1638 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_DICTIONARY, &varresult, VT_EMPTY);
1639 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1641 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY);
1642 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1644 /* Pids we have not set, one for each type */
1645 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_EMPTY);
1646 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1648 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY);
1649 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1651 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY);
1652 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1654 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY);
1655 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1657 if (!readonly)
1659 /* SummaryInfo::Property, put; one for each type */
1661 /* VT_I2 */
1662 VariantInit(&var);
1663 V_VT(&var) = VT_I2;
1664 V_I2(&var) = 1;
1665 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CODEPAGE, &var);
1666 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1668 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */);
1669 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1670 ok(V_I2(&var) == V_I2(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var), V_I2(&varresult));
1671 VariantClear(&varresult);
1672 VariantClear(&var);
1674 /* VT_BSTR */
1675 V_VT(&var) = VT_BSTR;
1676 V_BSTR(&var) = SysAllocString(szTitle);
1677 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_TITLE, &var);
1678 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1680 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var));
1681 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1682 ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var), V_BSTR(&varresult));
1683 VariantClear(&varresult);
1684 VariantClear(&var);
1686 /* VT_DATE */
1687 V_VT(&var) = VT_DATE;
1688 FileTimeToSystemTime(&systemtime, &st);
1689 SystemTimeToVariantTime(&st, &V_DATE(&var));
1690 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_LASTSAVE_DTM, &var);
1691 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1693 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var));
1694 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1695 ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1696 VariantClear(&varresult);
1697 VariantClear(&var);
1699 /* VT_I4 */
1700 V_VT(&var) = VT_I4;
1701 V_I4(&var) = 1000;
1702 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1703 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1705 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1706 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1707 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult));
1708 VariantClear(&varresult);
1709 VariantClear(&var);
1711 /* SummaryInfo::PropertyCount */
1712 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1713 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1714 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1718 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1720 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 };
1721 static WCHAR szThree[] = { 'T','h','r','e','e',0 };
1722 static WCHAR szTwo[] = { 'T','w','o',0 };
1723 static WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
1724 static WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 };
1725 IDispatch *pView = NULL, *pSummaryInfo = NULL;
1726 HRESULT hr;
1728 hr = Database_OpenView(pDatabase, szSql, &pView);
1729 ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr);
1730 if (hr == S_OK)
1732 IDispatch *pRecord = NULL;
1733 WCHAR szString[MAX_PATH];
1735 /* View::Execute */
1736 hr = View_Execute(pView, NULL);
1737 ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr);
1739 /* View::Fetch */
1740 hr = View_Fetch(pView, &pRecord);
1741 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1742 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1743 if (pRecord)
1745 /* Record::StringDataGet */
1746 memset(szString, 0, sizeof(szString));
1747 hr = Record_StringDataGet(pRecord, 1, szString);
1748 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1749 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1751 /* Record::StringDataPut with correct index */
1752 hr = Record_StringDataPut(pRecord, 1, szTwo);
1753 ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1755 /* Record::StringDataGet */
1756 memset(szString, 0, sizeof(szString));
1757 hr = Record_StringDataGet(pRecord, 1, szString);
1758 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1759 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1761 /* Record::StringDataPut with incorrect index */
1762 hr = Record_StringDataPut(pRecord, -1, szString);
1763 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1764 ok_exception(hr, szStringDataField);
1766 /* View::Modify with incorrect parameters */
1767 hr = View_Modify(pView, -5, NULL);
1768 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1769 ok_exception(hr, szModifyModeRecord);
1771 hr = View_Modify(pView, -5, pRecord);
1772 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1773 ok_exception(hr, szModifyModeRecord);
1775 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1776 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1777 ok_exception(hr, szModifyModeRecord);
1779 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1780 ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr);
1782 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1783 memset(szString, 0, sizeof(szString));
1784 hr = Record_StringDataGet(pRecord, 1, szString);
1785 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1786 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1788 IDispatch_Release(pRecord);
1791 /* View::Fetch */
1792 hr = View_Fetch(pView, &pRecord);
1793 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1794 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1795 if (pRecord)
1797 /* Record::StringDataGet */
1798 memset(szString, 0, sizeof(szString));
1799 hr = Record_StringDataGet(pRecord, 1, szString);
1800 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1801 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1803 IDispatch_Release(pRecord);
1806 /* View::Fetch */
1807 hr = View_Fetch(pView, &pRecord);
1808 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1809 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1810 if (pRecord)
1811 IDispatch_Release(pRecord);
1813 /* View::Close */
1814 hr = View_Close(pView);
1815 ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr);
1817 IDispatch_Release(pView);
1820 /* Database::SummaryInformation */
1821 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo);
1822 ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr);
1823 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1824 if (pSummaryInfo)
1826 test_SummaryInfo(pSummaryInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), readonly);
1827 IDispatch_Release(pSummaryInfo);
1831 static void test_Session(IDispatch *pSession)
1833 static WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
1834 static WCHAR szOne[] = { 'O','n','e',0 };
1835 static WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 };
1836 static WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 };
1837 static WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 };
1838 static WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 };
1839 static WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1840 static WCHAR szEmpty[] = { 0 };
1841 static WCHAR szEquals[] = { '=',0 };
1842 static WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
1843 static WCHAR szModeFlag[] = { 'M','o','d','e',',','F','l','a','g',0 };
1844 WCHAR stringw[MAX_PATH];
1845 CHAR string[MAX_PATH];
1846 UINT len;
1847 BOOL bool;
1848 int myint;
1849 IDispatch *pDatabase = NULL, *pInst = NULL, *record = NULL;
1850 ULONG refs_before, refs_after;
1851 HRESULT hr;
1853 /* Session::Installer */
1854 hr = Session_Installer(pSession, &pInst);
1855 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1856 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1857 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1858 refs_before = IDispatch_AddRef(pInst);
1860 hr = Session_Installer(pSession, &pInst);
1861 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1862 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1863 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1864 refs_after = IDispatch_Release(pInst);
1865 ok(refs_before == refs_after, "got %u and %u\n", refs_before, refs_after);
1867 /* Session::Property, get */
1868 memset(stringw, 0, sizeof(stringw));
1869 hr = Session_PropertyGet(pSession, szProductName, stringw);
1870 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1871 if (lstrcmpW(stringw, szMSITEST) != 0)
1873 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1874 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1875 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1878 /* Session::Property, put */
1879 hr = Session_PropertyPut(pSession, szProductName, szProductName);
1880 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1881 memset(stringw, 0, sizeof(stringw));
1882 hr = Session_PropertyGet(pSession, szProductName, stringw);
1883 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1884 if (lstrcmpW(stringw, szProductName) != 0)
1886 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1887 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1888 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1891 /* Try putting a property using empty property identifier */
1892 hr = Session_PropertyPut(pSession, szEmpty, szProductName);
1893 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1894 ok_exception(hr, szPropertyName);
1896 /* Try putting a property using illegal property identifier */
1897 hr = Session_PropertyPut(pSession, szEquals, szProductName);
1898 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1900 /* Session::Language, get */
1901 hr = Session_LanguageGet(pSession, &len);
1902 ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1903 /* Not sure how to check the language is correct */
1905 /* Session::Mode, get */
1906 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1907 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1908 ok(!bool, "Reboot at end session mode is %d\n", bool);
1910 hr = Session_ModeGet(pSession, MSIRUNMODE_MAINTENANCE, &bool);
1911 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1912 ok(!bool, "Maintenance mode is %d\n", bool);
1914 /* Session::Mode, put */
1915 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE);
1916 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1917 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1918 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1919 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1920 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE); /* set it again so we don't reboot */
1921 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1923 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, TRUE);
1924 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1925 if (hr == DISP_E_EXCEPTION) ok_exception(hr, szModeFlag);
1927 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTNOW, &bool);
1928 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1929 ok(bool, "Reboot now mode is %d, expected 1\n", bool);
1931 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, FALSE); /* set it again so we don't reboot */
1932 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1933 if (hr == DISP_E_EXCEPTION) ok_exception(hr, szModeFlag);
1935 hr = Session_ModePut(pSession, MSIRUNMODE_MAINTENANCE, TRUE);
1936 ok(hr == DISP_E_EXCEPTION, "Session_ModePut failed, hresult 0x%08x\n", hr);
1937 ok_exception(hr, szModeFlag);
1939 /* Session::Database, get */
1940 hr = Session_Database(pSession, &pDatabase);
1941 ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr);
1942 if (hr == S_OK)
1944 test_Database(pDatabase, TRUE);
1945 IDispatch_Release(pDatabase);
1948 /* Session::EvaluateCondition */
1949 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1950 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1951 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1953 hr = Session_EvaluateCondition(pSession, szEmpty, &myint);
1954 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1955 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1957 hr = Session_EvaluateCondition(pSession, szEquals, &myint);
1958 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1959 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1961 /* Session::DoAction(CostInitialize) must occur before the next statements */
1962 hr = Session_DoAction(pSession, szCostInitialize, &myint);
1963 ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr);
1964 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1966 /* Session::SetInstallLevel */
1967 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1968 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
1970 /* Session::FeatureCurrentState, get */
1971 hr = Session_FeatureCurrentState(pSession, szOne, &myint);
1972 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
1973 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1975 /* Session::Message */
1976 hr = Installer_CreateRecord(0, &record);
1977 ok(hr == S_OK, "Installer_CreateRecord failed: %08x\n", hr);
1978 hr = Session_Message(pSession, INSTALLMESSAGE_INFO, record, &myint);
1979 ok(hr == S_OK, "Session_Message failed: %08x\n", hr);
1980 ok(myint == 0, "Session_Message returned %x\n", myint);
1982 /* Session::EvaluateCondition */
1983 hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint);
1984 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1985 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1987 hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint);
1988 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1989 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1991 /* Session::FeatureRequestState, put */
1992 hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED);
1993 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
1994 hr = Session_FeatureRequestStateGet(pSession, szOne, &myint);
1995 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
1996 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
1998 /* Session::EvaluateCondition */
1999 hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint);
2000 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2001 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2003 hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint);
2004 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2005 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2008 /* delete key and all its subkeys */
2009 static DWORD delete_key( HKEY hkey )
2011 char name[MAX_PATH];
2012 DWORD ret;
2014 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
2016 HKEY tmp;
2017 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
2019 ret = delete_key( tmp );
2020 RegCloseKey( tmp );
2022 if (ret) break;
2024 if (ret != ERROR_NO_MORE_ITEMS) return ret;
2025 RegDeleteKeyA( hkey, "" );
2026 return 0;
2029 static void test_Installer_RegistryValue(void)
2031 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
2032 static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 };
2033 static const WCHAR szOne[] = { 'O','n','e',0 };
2034 static const WCHAR szTwo[] = { 'T','w','o',0 };
2035 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
2036 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
2037 static const WCHAR szFour[] = { 'F','o','u','r',0 };
2038 static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 };
2039 static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 };
2040 static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 };
2041 static const WCHAR szSix[] = { 'S','i','x',0 };
2042 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
2043 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
2044 static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
2045 static const WCHAR szBlank[] = { 0 };
2046 VARIANT varresult;
2047 VARIANTARG vararg;
2048 WCHAR szString[MAX_PATH];
2049 HKEY hkey, hkey_sub;
2050 HKEY curr_user = (HKEY)1;
2051 HRESULT hr;
2052 BOOL bRet;
2053 LONG lRet;
2055 /* Delete keys */
2056 SetLastError(0xdeadbeef);
2057 lRet = RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey );
2058 if (!lRet && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2060 win_skip("Needed W-functions are not implemented\n");
2061 return;
2063 if (!lRet)
2064 delete_key( hkey );
2066 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
2067 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
2068 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
2069 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
2071 memset(szString, 0, sizeof(szString));
2072 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
2073 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2075 memset(szString, 0, sizeof(szString));
2076 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
2077 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2079 /* Create key */
2080 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
2082 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
2083 "RegSetValueExW failed\n");
2084 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
2085 "RegSetValueExW failed\n");
2086 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
2087 "RegSetValueExW failed\n");
2088 bRet = SetEnvironmentVariableA("MSITEST", "Four");
2089 ok(bRet, "SetEnvironmentVariableA failed %d\n", GetLastError());
2090 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
2091 "RegSetValueExW failed\n");
2092 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
2093 "RegSetValueExW failed\n");
2094 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
2095 "RegSetValueExW failed\n");
2096 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, NULL, 0),
2097 "RegSetValueExW failed\n");
2099 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
2100 "RegSetValueExW failed\n");
2102 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
2104 /* Does our key exist? It should, and make sure we retrieve the correct default value */
2105 bRet = FALSE;
2106 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
2107 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
2108 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
2110 memset(szString, 0, sizeof(szString));
2111 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
2112 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2113 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
2115 /* Ask for the value of a nonexistent key */
2116 memset(szString, 0, sizeof(szString));
2117 hr = Installer_RegistryValueW(curr_user, szKey, szExpand, szString);
2118 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2120 /* Get values of keys */
2121 memset(szString, 0, sizeof(szString));
2122 hr = Installer_RegistryValueW(curr_user, szKey, szOne, 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, szOne);
2126 VariantInit(&vararg);
2127 V_VT(&vararg) = VT_BSTR;
2128 V_BSTR(&vararg) = SysAllocString(szTwo);
2129 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_I4);
2130 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
2131 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
2132 VariantClear(&varresult);
2134 memset(szString, 0, sizeof(szString));
2135 hr = Installer_RegistryValueW(curr_user, szKey, szThree, szString);
2136 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2137 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
2139 memset(szString, 0, sizeof(szString));
2140 hr = Installer_RegistryValueW(curr_user, szKey, szFour, szString);
2141 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2142 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
2144 /* Vista does not NULL-terminate this case */
2145 memset(szString, 0, sizeof(szString));
2146 hr = Installer_RegistryValueW(curr_user, szKey, szFive, szString);
2147 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2148 ok_w2n("Registry value \"%s\" does not match expected \"%s\"\n",
2149 szString, szFiveHi, lstrlenW(szFiveHi));
2151 memset(szString, 0, sizeof(szString));
2152 hr = Installer_RegistryValueW(curr_user, szKey, szSix, szString);
2153 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2154 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_);
2156 VariantInit(&vararg);
2157 V_VT(&vararg) = VT_BSTR;
2158 V_BSTR(&vararg) = SysAllocString(szSeven);
2159 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_EMPTY);
2160 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
2162 /* Get string class name for the key */
2163 memset(szString, 0, sizeof(szString));
2164 hr = Installer_RegistryValueI(curr_user, szKey, 0, 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, szBlank);
2168 /* Get name of a value by positive number (RegEnumValue like), valid index */
2169 memset(szString, 0, sizeof(szString));
2170 hr = Installer_RegistryValueI(curr_user, szKey, 2, szString, VT_BSTR);
2171 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2172 /* RegEnumValue order seems different on wine */
2173 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
2175 /* Get name of a value by positive number (RegEnumValue like), invalid index */
2176 memset(szString, 0, sizeof(szString));
2177 hr = Installer_RegistryValueI(curr_user, szKey, 10, szString, VT_EMPTY);
2178 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2180 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
2181 memset(szString, 0, sizeof(szString));
2182 hr = Installer_RegistryValueI(curr_user, szKey, -1, szString, VT_BSTR);
2183 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2184 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
2186 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
2187 memset(szString, 0, sizeof(szString));
2188 hr = Installer_RegistryValueI(curr_user, szKey, -10, szString, VT_EMPTY);
2189 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2191 /* clean up */
2192 delete_key(hkey);
2195 static void test_Installer_Products(BOOL bProductInstalled)
2197 WCHAR szString[MAX_PATH];
2198 HRESULT hr;
2199 int idx;
2200 IUnknown *pUnk = NULL;
2201 IEnumVARIANT *pEnum = NULL;
2202 VARIANT var;
2203 ULONG celt;
2204 int iCount, iValue;
2205 IDispatch *pStringList = NULL;
2206 BOOL bProductFound = FALSE;
2208 /* Installer::Products */
2209 hr = Installer_Products(&pStringList);
2210 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
2211 if (hr == S_OK)
2213 /* StringList::_NewEnum */
2214 hr = StringList__NewEnum(pStringList, &pUnk);
2215 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
2216 if (hr == S_OK)
2218 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
2219 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2221 if (!pEnum)
2222 skip("IEnumVARIANT tests\n");
2224 /* StringList::Count */
2225 hr = StringList_Count(pStringList, &iCount);
2226 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2228 for (idx=0; idx<iCount; idx++)
2230 /* StringList::Item */
2231 memset(szString, 0, sizeof(szString));
2232 hr = StringList_Item(pStringList, idx, szString);
2233 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2235 if (hr == S_OK)
2237 /* Installer::ProductState */
2238 hr = Installer_ProductState(szString, &iValue);
2239 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2240 if (hr == S_OK)
2241 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
2243 /* Not found our product code yet? Check */
2244 if (!bProductFound && !lstrcmpW(szString, szProductCode))
2245 bProductFound = TRUE;
2247 /* IEnumVARIANT::Next */
2248 if (pEnum)
2250 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2251 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2252 ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
2253 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2254 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2255 VariantClear(&var);
2260 if (bProductInstalled)
2262 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
2263 bProductInstalled ? "be" : "not be",
2264 bProductFound ? "found" : "not found");
2267 if (pEnum)
2269 IEnumVARIANT *pEnum2 = NULL;
2271 if (0) /* Crashes on Windows XP */
2273 /* IEnumVARIANT::Clone, NULL pointer */
2274 IEnumVARIANT_Clone(pEnum, NULL);
2277 /* IEnumVARIANT::Clone */
2278 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
2279 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
2280 if (hr == S_OK)
2282 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
2284 /* IEnumVARIANT::Next of the clone */
2285 if (iCount)
2287 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
2288 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2289 ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
2290 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2291 VariantClear(&var);
2293 else
2294 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
2296 IEnumVARIANT_Release(pEnum2);
2299 /* IEnumVARIANT::Skip should fail */
2300 hr = IEnumVARIANT_Skip(pEnum, 1);
2301 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2303 /* IEnumVARIANT::Next, NULL variant pointer */
2304 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2305 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2306 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2308 /* IEnumVARIANT::Next, should not return any more items */
2309 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2310 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2311 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2312 VariantClear(&var);
2314 /* IEnumVARIANT::Reset */
2315 hr = IEnumVARIANT_Reset(pEnum);
2316 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2318 if (iCount)
2320 /* IEnumVARIANT::Skip to the last product */
2321 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2322 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2324 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2325 * NULL celt pointer. */
2326 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2327 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2328 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2329 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2330 VariantClear(&var);
2332 else
2333 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2336 /* StringList::Item using an invalid index */
2337 memset(szString, 0, sizeof(szString));
2338 hr = StringList_Item(pStringList, iCount, szString);
2339 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2341 if (pEnum) IEnumVARIANT_Release(pEnum);
2342 if (pUnk) IUnknown_Release(pUnk);
2343 IDispatch_Release(pStringList);
2347 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2348 * deleting the subkeys first) */
2349 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey, REGSAM access)
2351 UINT ret;
2352 CHAR *string = NULL;
2353 HKEY hkey;
2354 DWORD dwSize;
2356 ret = RegOpenKeyEx(hkeyParent, subkey, 0, access, &hkey);
2357 if (ret != ERROR_SUCCESS) return ret;
2358 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2359 if (ret != ERROR_SUCCESS) return ret;
2360 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2362 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2363 delete_registry_key(hkey, string, access);
2365 RegCloseKey(hkey);
2366 HeapFree(GetProcessHeap(), 0, string);
2367 delete_key_portable(hkeyParent, subkey, access);
2368 return ERROR_SUCCESS;
2371 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2372 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, REGSAM access, HKEY *phkey)
2374 UINT ret;
2375 CHAR *string = NULL;
2376 int idx = 0;
2377 HKEY hkey;
2378 DWORD dwSize;
2379 BOOL found = FALSE;
2381 *phkey = 0;
2383 ret = RegOpenKeyEx(hkeyParent, subkey, 0, access, &hkey);
2384 if (ret != ERROR_SUCCESS) return ret;
2385 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2386 if (ret != ERROR_SUCCESS) return ret;
2387 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2389 while (!found &&
2390 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2392 if (!strcmp(string, findkey))
2394 *phkey = hkey;
2395 found = TRUE;
2397 else if (find_registry_key(hkey, string, findkey, access, phkey) == ERROR_SUCCESS) found = TRUE;
2400 if (*phkey != hkey) RegCloseKey(hkey);
2401 HeapFree(GetProcessHeap(), 0, string);
2402 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2405 static void test_Installer_InstallProduct(void)
2407 HRESULT hr;
2408 CHAR path[MAX_PATH];
2409 WCHAR szString[MAX_PATH];
2410 LONG res;
2411 HKEY hkey;
2412 DWORD num, size, type;
2413 int iValue, iCount;
2414 IDispatch *pStringList = NULL;
2415 REGSAM access = KEY_ALL_ACCESS;
2417 if (is_wow64)
2418 access |= KEY_WOW64_64KEY;
2420 create_test_files();
2422 /* Avoid an interactive dialog in case of insufficient privileges. */
2423 hr = Installer_UILevelPut(INSTALLUILEVEL_NONE);
2424 ok(hr == S_OK, "Expected UILevel property put invoke to return S_OK, got 0x%08x\n", hr);
2426 /* Installer::InstallProduct */
2427 hr = Installer_InstallProduct(szMsifile, NULL);
2428 if (hr == DISP_E_EXCEPTION)
2430 skip("InstallProduct failed, insufficient rights?\n");
2431 delete_test_files();
2432 return;
2434 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2436 /* Installer::ProductState for our product code, which has been installed */
2437 hr = Installer_ProductState(szProductCode, &iValue);
2438 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2439 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2441 /* Installer::ProductInfo for our product code */
2443 /* NULL attribute */
2444 memset(szString, 0, sizeof(szString));
2445 hr = Installer_ProductInfo(szProductCode, NULL, szString);
2446 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2447 ok_exception(hr, szProductInfoException);
2449 /* Nonexistent attribute */
2450 memset(szString, 0, sizeof(szString));
2451 hr = Installer_ProductInfo(szProductCode, szMsifile, szString);
2452 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2453 ok_exception(hr, szProductInfoException);
2455 /* Package name */
2456 memset(szString, 0, sizeof(szString));
2457 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szString);
2458 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2459 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile);
2461 /* Product name */
2462 memset(szString, 0, sizeof(szString));
2463 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PRODUCTNAMEW, szString);
2464 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2465 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST);
2467 /* Installer::Products */
2468 test_Installer_Products(TRUE);
2470 /* Installer::RelatedProducts for our upgrade code */
2471 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2472 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2473 if (hr == S_OK)
2475 /* StringList::Count */
2476 hr = StringList_Count(pStringList, &iCount);
2477 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2478 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2480 /* StringList::Item */
2481 memset(szString, 0, sizeof(szString));
2482 hr = StringList_Item(pStringList, 0, szString);
2483 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2484 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
2486 IDispatch_Release(pStringList);
2489 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_LOCALPACKAGEW, szString);
2490 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2491 DeleteFileW( szString );
2493 /* Check & clean up installed files & registry keys */
2494 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2495 ok(delete_pf("msitest\\cabout\\new", FALSE), "Directory not created\n");
2496 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2497 ok(delete_pf("msitest\\cabout", FALSE), "Directory not created\n");
2498 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2499 ok(delete_pf("msitest\\changed", FALSE), "Directory not created\n");
2500 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2501 ok(delete_pf("msitest\\first", FALSE), "Directory not created\n");
2502 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2503 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2504 ok(delete_pf("msitest", FALSE), "Directory not created\n");
2506 res = RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest", &hkey);
2507 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2509 size = MAX_PATH;
2510 type = REG_SZ;
2511 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2512 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2513 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2515 size = MAX_PATH;
2516 type = REG_SZ;
2517 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2518 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2520 size = sizeof(num);
2521 type = REG_DWORD;
2522 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2523 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2524 ok(num == 314, "Expected 314, got %d\n", num);
2526 size = MAX_PATH;
2527 type = REG_SZ;
2528 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2529 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2530 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2532 RegCloseKey(hkey);
2534 res = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest");
2535 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2537 /* Remove registry keys written by RegisterProduct standard action */
2538 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2539 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{837450fa-a39b-4bc8-b321-08b393f784b3}",
2540 KEY_WOW64_32KEY);
2541 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2543 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2544 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656", access);
2545 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2547 res = find_registry_key(HKEY_LOCAL_MACHINE,
2548 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "af054738b93a8cb43b12803b397f483b", access, &hkey);
2549 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2551 res = delete_registry_key(hkey, "af054738b93a8cb43b12803b397f483b", access);
2552 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2553 RegCloseKey(hkey);
2555 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2556 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\af054738b93a8cb43b12803b397f483b", access);
2557 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2559 /* Remove registry keys written by PublishProduct standard action */
2560 res = RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2561 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2563 res = delete_registry_key(hkey, "Products\\af054738b93a8cb43b12803b397f483b", KEY_ALL_ACCESS);
2564 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2566 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2567 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2569 RegCloseKey(hkey);
2571 /* Delete installation files we created */
2572 delete_test_files();
2575 static void test_Installer(void)
2577 static WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
2578 static WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
2579 WCHAR szPath[MAX_PATH];
2580 HRESULT hr;
2581 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL;
2582 int iValue, iCount;
2584 if (!pInstaller) return;
2586 /* Installer::CreateRecord */
2588 /* Test for error */
2589 hr = Installer_CreateRecord(-1, &pRecord);
2590 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2591 ok_exception(hr, szCreateRecordException);
2593 /* Test for success */
2594 hr = Installer_CreateRecord(1, &pRecord);
2595 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2596 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2597 if (pRecord)
2599 /* Record::FieldCountGet */
2600 hr = Record_FieldCountGet(pRecord, &iValue);
2601 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2602 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2604 /* Record::IntegerDataGet */
2605 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2606 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2607 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2609 /* Record::IntegerDataGet, bad index */
2610 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2611 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2612 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2614 /* Record::IntegerDataPut */
2615 hr = Record_IntegerDataPut(pRecord, 1, 100);
2616 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2618 /* Record::IntegerDataPut, bad index */
2619 hr = Record_IntegerDataPut(pRecord, 10, 100);
2620 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2621 ok_exception(hr, szIntegerDataException);
2623 /* Record::IntegerDataGet */
2624 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2625 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2626 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2628 IDispatch_Release(pRecord);
2631 create_package(szPath);
2633 /* Installer::OpenPackage */
2634 hr = Installer_OpenPackage(szPath, 0, &pSession);
2635 if (hr == DISP_E_EXCEPTION)
2637 skip("OpenPackage failed, insufficient rights?\n");
2638 DeleteFileW(szPath);
2639 return;
2641 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2642 if (hr == S_OK)
2644 test_Session(pSession);
2645 IDispatch_Release(pSession);
2648 /* Installer::OpenDatabase */
2649 hr = Installer_OpenDatabase(szPath, (INT_PTR)MSIDBOPEN_TRANSACT, &pDatabase);
2650 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2651 if (hr == S_OK)
2653 test_Database(pDatabase, FALSE);
2654 IDispatch_Release(pDatabase);
2657 /* Installer::RegistryValue */
2658 test_Installer_RegistryValue();
2660 /* Installer::ProductState for our product code, which should not be installed */
2661 hr = Installer_ProductState(szProductCode, &iValue);
2662 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2663 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2665 /* Installer::ProductInfo for our product code, which should not be installed */
2667 /* Package name */
2668 memset(szPath, 0, sizeof(szPath));
2669 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szPath);
2670 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2671 ok_exception(hr, szProductInfoException);
2673 /* NULL attribute and NULL product code */
2674 memset(szPath, 0, sizeof(szPath));
2675 hr = Installer_ProductInfo(NULL, NULL, szPath);
2676 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2677 ok_exception(hr, szProductInfoException);
2679 /* Installer::Products */
2680 test_Installer_Products(FALSE);
2682 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2683 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2684 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2685 if (hr == S_OK)
2687 /* StringList::Count */
2688 hr = StringList_Count(pStringList, &iCount);
2689 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2690 ok(!iCount, "Expected no related products but found %d\n", iCount);
2692 IDispatch_Release(pStringList);
2695 /* Installer::Version */
2696 memset(szPath, 0, sizeof(szPath));
2697 hr = Installer_VersionGet(szPath);
2698 ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr);
2700 /* Installer::InstallProduct and other tests that depend on our product being installed */
2701 test_Installer_InstallProduct();
2704 START_TEST(automation)
2706 DWORD len;
2707 char temp_path[MAX_PATH], prev_path[MAX_PATH];
2708 HRESULT hr;
2709 CLSID clsid;
2710 IUnknown *pUnk;
2712 init_functionpointers();
2714 if (pIsWow64Process)
2715 pIsWow64Process(GetCurrentProcess(), &is_wow64);
2717 GetSystemTimeAsFileTime(&systemtime);
2719 GetCurrentDirectoryA(MAX_PATH, prev_path);
2720 GetTempPath(MAX_PATH, temp_path);
2721 SetCurrentDirectoryA(temp_path);
2723 lstrcpyA(CURR_DIR, temp_path);
2724 len = lstrlenA(CURR_DIR);
2726 if(len && (CURR_DIR[len - 1] == '\\'))
2727 CURR_DIR[len - 1] = 0;
2729 get_program_files_dir(PROG_FILES_DIR);
2731 hr = OleInitialize(NULL);
2732 ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr);
2733 hr = CLSIDFromProgID(szProgId, &clsid);
2734 ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr);
2735 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2736 ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr);
2738 if (pUnk)
2740 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2741 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2743 test_dispid();
2744 test_dispatch();
2745 test_Installer();
2747 IDispatch_Release(pInstaller);
2748 IUnknown_Release(pUnk);
2751 OleUninitialize();
2753 SetCurrentDirectoryA(prev_path);