msi/tests: Determine Wow64 mode just once.
[wine.git] / dlls / msi / tests / automation.c
blob310090640186bdb6fc1d8676dafe5378bfe9b05b
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[] = { '{','F','1','C','3','A','F','5','0','-','8','B','5','6','-','4','A','6','9','-','A','0','0','C','-','0','0','7','7','3','F','E','4','2','F','3','0','}',0 };
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 FILETIME systemtime;
51 static CHAR CURR_DIR[MAX_PATH];
52 static EXCEPINFO excepinfo;
55 * OLE automation data
56 **/
57 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 };
58 static IDispatch *pInstaller;
60 /* msi database data */
62 static const CHAR component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
63 "s72\tS38\ts72\ti2\tS255\tS72\n"
64 "Component\tComponent\n"
65 "Five\t{8CC92E9D-14B2-4CA4-B2AA-B11D02078087}\tNEWDIR\t2\t\tfive.txt\n"
66 "Four\t{FD37B4EA-7209-45C0-8917-535F35A2F080}\tCABOUTDIR\t2\t\tfour.txt\n"
67 "One\t{783B242E-E185-4A56-AF86-C09815EC053C}\tMSITESTDIR\t2\t\tone.txt\n"
68 "Three\t{010B6ADD-B27D-4EDD-9B3D-34C4F7D61684}\tCHANGEDDIR\t2\t\tthree.txt\n"
69 "Two\t{BF03D1A6-20DA-4A65-82F3-6CAC995915CE}\tFIRSTDIR\t2\t\ttwo.txt\n"
70 "dangler\t{6091DF25-EF96-45F1-B8E9-A9B1420C7A3C}\tTARGETDIR\t4\t\tregdata\n"
71 "component\t\tMSITESTDIR\t0\t1\tfile\n";
73 static const CHAR directory_dat[] = "Directory\tDirectory_Parent\tDefaultDir\n"
74 "s72\tS72\tl255\n"
75 "Directory\tDirectory\n"
76 "CABOUTDIR\tMSITESTDIR\tcabout\n"
77 "CHANGEDDIR\tMSITESTDIR\tchanged:second\n"
78 "FIRSTDIR\tMSITESTDIR\tfirst\n"
79 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
80 "NEWDIR\tCABOUTDIR\tnew\n"
81 "ProgramFilesFolder\tTARGETDIR\t.\n"
82 "TARGETDIR\t\tSourceDir";
84 static const CHAR feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
85 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
86 "Feature\tFeature\n"
87 "Five\t\tFive\tThe Five Feature\t5\t3\tNEWDIR\t0\n"
88 "Four\t\tFour\tThe Four Feature\t4\t3\tCABOUTDIR\t0\n"
89 "One\t\tOne\tThe One Feature\t1\t3\tMSITESTDIR\t0\n"
90 "Three\tOne\tThree\tThe Three Feature\t3\t3\tCHANGEDDIR\t0\n"
91 "Two\tOne\tTwo\tThe Two Feature\t2\t3\tFIRSTDIR\t0\n"
92 "feature\t\t\t\t2\t1\tTARGETDIR\t0\n";
94 static const CHAR feature_comp_dat[] = "Feature_\tComponent_\n"
95 "s38\ts72\n"
96 "FeatureComponents\tFeature_\tComponent_\n"
97 "Five\tFive\n"
98 "Four\tFour\n"
99 "One\tOne\n"
100 "Three\tThree\n"
101 "Two\tTwo\n"
102 "feature\tcomponent\n";
104 static const CHAR file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
105 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
106 "File\tFile\n"
107 "five.txt\tFive\tfive.txt\t1000\t\t\t0\t5\n"
108 "four.txt\tFour\tfour.txt\t1000\t\t\t0\t4\n"
109 "one.txt\tOne\tone.txt\t1000\t\t\t0\t1\n"
110 "three.txt\tThree\tthree.txt\t1000\t\t\t0\t3\n"
111 "two.txt\tTwo\ttwo.txt\t1000\t\t\t0\t2\n"
112 "file\tcomponent\tfilename\t100\t\t\t8192\t1\n";
114 static const CHAR install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
115 "s72\tS255\tI2\n"
116 "InstallExecuteSequence\tAction\n"
117 "AllocateRegistrySpace\tNOT Installed\t1550\n"
118 "CostFinalize\t\t1000\n"
119 "CostInitialize\t\t800\n"
120 "FileCost\t\t900\n"
121 "InstallFiles\t\t4000\n"
122 "RegisterProduct\t\t6100\n"
123 "PublishProduct\t\t6400\n"
124 "InstallFinalize\t\t6600\n"
125 "InstallInitialize\t\t1500\n"
126 "InstallValidate\t\t1400\n"
127 "LaunchConditions\t\t100\n"
128 "WriteRegistryValues\tSourceDir And SOURCEDIR\t5000";
130 static const CHAR media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
131 "i2\ti4\tL64\tS255\tS32\tS72\n"
132 "Media\tDiskId\n"
133 "1\t5\t\t\tDISK1\t\n";
135 static const CHAR property_dat[] = "Property\tValue\n"
136 "s72\tl0\n"
137 "Property\tProperty\n"
138 "DefaultUIFont\tDlgFont8\n"
139 "HASUIRUN\t0\n"
140 "INSTALLLEVEL\t3\n"
141 "InstallMode\tTypical\n"
142 "Manufacturer\tWine\n"
143 "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n"
144 "ProductCode\t{F1C3AF50-8B56-4A69-A00C-00773FE42F30}\n"
145 "ProductID\tnone\n"
146 "ProductLanguage\t1033\n"
147 "ProductName\tMSITEST\n"
148 "ProductVersion\t1.1.1\n"
149 "PROMPTROLLBACKCOST\tP\n"
150 "Setup\tSetup\n"
151 "UpgradeCode\t{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}";
153 static const CHAR registry_dat[] = "Registry\tRoot\tKey\tName\tValue\tComponent_\n"
154 "s72\ti2\tl255\tL255\tL0\ts72\n"
155 "Registry\tRegistry\n"
156 "Apples\t1\tSOFTWARE\\Wine\\msitest\tName\timaname\tOne\n"
157 "Oranges\t1\tSOFTWARE\\Wine\\msitest\tnumber\t#314\tTwo\n"
158 "regdata\t1\tSOFTWARE\\Wine\\msitest\tblah\tbad\tdangler\n"
159 "OrderTest\t1\tSOFTWARE\\Wine\\msitest\tOrderTestName\tOrderTestValue\tcomponent";
161 typedef struct _msi_table
163 const CHAR *filename;
164 const CHAR *data;
165 int size;
166 } msi_table;
168 #define ADD_TABLE(x) {#x".idt", x##_dat, sizeof(x##_dat)}
170 static const msi_table tables[] =
172 ADD_TABLE(component),
173 ADD_TABLE(directory),
174 ADD_TABLE(feature),
175 ADD_TABLE(feature_comp),
176 ADD_TABLE(file),
177 ADD_TABLE(install_exec_seq),
178 ADD_TABLE(media),
179 ADD_TABLE(property),
180 ADD_TABLE(registry)
183 typedef struct _msi_summary_info
185 UINT property;
186 UINT datatype;
187 INT iValue;
188 FILETIME *pftValue;
189 const CHAR *szValue;
190 } msi_summary_info;
192 #define ADD_INFO_I2(property, iValue) {property, VT_I2, iValue, NULL, NULL}
193 #define ADD_INFO_I4(property, iValue) {property, VT_I4, iValue, NULL, NULL}
194 #define ADD_INFO_LPSTR(property, szValue) {property, VT_LPSTR, 0, NULL, szValue}
195 #define ADD_INFO_FILETIME(property, pftValue) {property, VT_FILETIME, 0, pftValue, NULL}
197 static const msi_summary_info summary_info[] =
199 ADD_INFO_LPSTR(PID_TEMPLATE, ";1033"),
200 ADD_INFO_LPSTR(PID_REVNUMBER, "{004757CA-5092-49c2-AD20-28E1CE0DF5F2}"),
201 ADD_INFO_I4(PID_PAGECOUNT, 100),
202 ADD_INFO_I4(PID_WORDCOUNT, 0),
203 ADD_INFO_FILETIME(PID_CREATE_DTM, &systemtime),
204 ADD_INFO_FILETIME(PID_LASTPRINTED, &systemtime)
207 static void init_functionpointers(void)
209 HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll");
210 HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
212 #define GET_PROC(dll, func) \
213 p ## func = (void *)GetProcAddress(dll, #func); \
214 if(!p ## func) \
215 trace("GetProcAddress(%s) failed\n", #func);
217 GET_PROC(hadvapi32, RegDeleteKeyExA)
218 GET_PROC(hkernel32, IsWow64Process)
220 #undef GET_PROC
223 static LONG delete_key_portable( HKEY key, LPCSTR subkey, REGSAM access )
225 if (pRegDeleteKeyExA)
226 return pRegDeleteKeyExA( key, subkey, access, 0 );
227 return RegDeleteKeyA( key, subkey );
231 * Database Helpers
234 static void write_file(const CHAR *filename, const char *data, int data_size)
236 DWORD size;
238 HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL,
239 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
241 WriteFile(hf, data, data_size, &size, NULL);
242 CloseHandle(hf);
245 static void write_msi_summary_info(MSIHANDLE db, const msi_summary_info *info, int num_info)
247 MSIHANDLE summary;
248 UINT r;
249 int j;
251 r = MsiGetSummaryInformationA(db, NULL, num_info, &summary);
252 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
254 /* import summary information into the stream */
255 for (j = 0; j < num_info; j++)
257 const msi_summary_info *entry = &info[j];
259 r = MsiSummaryInfoSetPropertyA(summary, entry->property, entry->datatype,
260 entry->iValue, entry->pftValue, entry->szValue);
261 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
264 /* write the summary changes back to the stream */
265 r = MsiSummaryInfoPersist(summary);
266 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
268 MsiCloseHandle(summary);
271 static void create_database(const CHAR *name, const msi_table *tables, int num_tables,
272 const msi_summary_info *info, int num_info)
274 MSIHANDLE db;
275 UINT r;
276 int j;
278 r = MsiOpenDatabaseA(name, MSIDBOPEN_CREATE, &db);
279 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
281 /* import the tables into the database */
282 for (j = 0; j < num_tables; j++)
284 const msi_table *table = &tables[j];
286 write_file(table->filename, table->data, (table->size - 1) * sizeof(char));
288 r = MsiDatabaseImportA(db, CURR_DIR, table->filename);
289 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
291 DeleteFileA(table->filename);
294 write_msi_summary_info(db, info, num_info);
296 r = MsiDatabaseCommit(db);
297 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
299 MsiCloseHandle(db);
302 static BOOL create_package(LPWSTR path)
304 DWORD len;
306 /* Prepare package */
307 create_database(msifile, tables,
308 sizeof(tables) / sizeof(msi_table), summary_info,
309 sizeof(summary_info) / sizeof(msi_summary_info));
311 len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
312 CURR_DIR, -1, path, MAX_PATH);
313 ok(len, "MultiByteToWideChar returned error %d\n", GetLastError());
314 if (!len)
315 return FALSE;
317 /* lstrcatW does not work on win95 */
318 path[len - 1] = '\\';
319 memcpy(&path[len], szMsifile, sizeof(szMsifile));
320 return TRUE;
324 * Installation helpers
327 static char PROG_FILES_DIR[MAX_PATH];
329 static BOOL get_program_files_dir(LPSTR buf)
331 HKEY hkey;
332 DWORD type = REG_EXPAND_SZ, size;
334 if (RegOpenKey(HKEY_LOCAL_MACHINE,
335 "Software\\Microsoft\\Windows\\CurrentVersion", &hkey))
336 return FALSE;
338 size = MAX_PATH;
339 if (RegQueryValueEx(hkey, "ProgramFilesDir (x86)", 0, &type, (LPBYTE)buf, &size) &&
340 RegQueryValueEx(hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size))
341 return FALSE;
343 RegCloseKey(hkey);
344 return TRUE;
347 static void create_file(const CHAR *name, DWORD size)
349 HANDLE file;
350 DWORD written, left;
352 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
353 ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
354 WriteFile(file, name, strlen(name), &written, NULL);
355 WriteFile(file, "\n", strlen("\n"), &written, NULL);
357 left = size - lstrlen(name) - 1;
359 SetFilePointer(file, left, NULL, FILE_CURRENT);
360 SetEndOfFile(file);
362 CloseHandle(file);
365 static void create_test_files(void)
367 CreateDirectoryA("msitest", NULL);
368 create_file("msitest\\one.txt", 100);
369 CreateDirectoryA("msitest\\first", NULL);
370 create_file("msitest\\first\\two.txt", 100);
371 CreateDirectoryA("msitest\\second", NULL);
372 create_file("msitest\\second\\three.txt", 100);
373 CreateDirectoryA("msitest\\cabout",NULL);
374 create_file("msitest\\cabout\\four.txt", 100);
375 CreateDirectoryA("msitest\\cabout\\new",NULL);
376 create_file("msitest\\cabout\\new\\five.txt", 100);
377 create_file("msitest\\filename", 100);
380 static BOOL delete_pf(const CHAR *rel_path, BOOL is_file)
382 CHAR path[MAX_PATH];
384 lstrcpyA(path, PROG_FILES_DIR);
385 lstrcatA(path, "\\");
386 lstrcatA(path, rel_path);
388 if (is_file)
389 return DeleteFileA(path);
390 else
391 return RemoveDirectoryA(path);
394 static void delete_test_files(void)
396 DeleteFileA(msifile);
397 DeleteFileA("msitest\\cabout\\new\\five.txt");
398 DeleteFileA("msitest\\cabout\\four.txt");
399 DeleteFileA("msitest\\second\\three.txt");
400 DeleteFileA("msitest\\first\\two.txt");
401 DeleteFileA("msitest\\one.txt");
402 DeleteFileA("msitest\\filename");
403 RemoveDirectoryA("msitest\\cabout\\new");
404 RemoveDirectoryA("msitest\\cabout");
405 RemoveDirectoryA("msitest\\second");
406 RemoveDirectoryA("msitest\\first");
407 RemoveDirectoryA("msitest");
411 * Automation helpers and tests
414 /* ok-like statement which takes two unicode strings or one unicode and one ANSI string as arguments */
415 static CHAR string1[MAX_PATH], string2[MAX_PATH];
417 /* lstrcmpW is not supported on Win9x */
418 static int strcmp_ww(const WCHAR* str1, const WCHAR* str2)
420 CHAR str1A[MAX_PATH], str2A[MAX_PATH];
422 WideCharToMultiByte(CP_ACP, 0, str1, -1, str1A, MAX_PATH, NULL, NULL);
423 WideCharToMultiByte(CP_ACP, 0, str2, -1, str2A, MAX_PATH, NULL, NULL);
425 return lstrcmpA(str1A, str2A);
428 #define ok_w2(format, szString1, szString2) \
430 do { \
431 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
432 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
433 if (lstrcmpA(string1, string2) != 0) \
434 ok(0, format, string1, string2); \
435 } while(0);
437 #define ok_w2n(format, szString1, szString2, len) \
439 if (memcmp(szString1, szString2, len * sizeof(WCHAR)) != 0) \
441 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
442 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
443 ok(0, format, string1, string2); \
446 #define ok_aw(format, aString, wString) \
448 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
449 if (lstrcmpA(string1, aString) != 0) \
450 ok(0, format, string1, aString); \
452 #define ok_awplus(format, extra, aString, wString) \
454 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
455 if (lstrcmpA(string1, aString) != 0) \
456 ok(0, format, extra, string1, aString); \
458 /* exception checker */
459 static WCHAR szSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
461 #define ok_exception(hr, szDescription) \
462 if (hr == DISP_E_EXCEPTION) \
464 /* Compare wtype, source, and destination */ \
465 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
467 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
468 if (excepinfo.bstrSource) \
469 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, szSource); \
471 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
472 if (excepinfo.bstrDescription) \
473 ok_w2("Exception description was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrDescription, szDescription); \
475 SysFreeString(excepinfo.bstrSource); \
476 SysFreeString(excepinfo.bstrDescription); \
477 SysFreeString(excepinfo.bstrHelpFile); \
480 static DISPID get_dispid( IDispatch *disp, const char *name )
482 LPOLESTR str;
483 UINT len;
484 DISPID id = -1;
485 HRESULT r;
487 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
488 str = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
489 if (str)
491 len = MultiByteToWideChar(CP_ACP, 0, name, -1, str, len );
492 r = IDispatch_GetIDsOfNames( disp, &IID_NULL, &str, 1, 0, &id );
493 HeapFree(GetProcessHeap(), 0, str);
494 if (r != S_OK)
495 return -1;
498 return id;
501 static void test_dispid(void)
503 DISPID dispid;
505 dispid = get_dispid(pInstaller, "CreateRecord");
506 ok(dispid == 1, "Expected 1, got %d\n", dispid);
507 dispid = get_dispid(pInstaller, "OpenPackage");
508 ok(dispid == 2, "Expected 2, got %d\n", dispid);
509 dispid = get_dispid(pInstaller, "OpenProduct");
510 ok(dispid == 3, "Expected 3, got %d\n", dispid);
511 dispid = get_dispid(pInstaller, "OpenDatabase");
512 ok(dispid == 4, "Expected 4, got %d\n", dispid);
513 dispid = get_dispid(pInstaller, "SummaryInformation");
514 ok(dispid == 5, "Expected 5, got %d\n", dispid);
515 dispid = get_dispid( pInstaller, "UILevel" );
516 ok(dispid == 6, "Expected 6, got %d\n", dispid);
517 dispid = get_dispid(pInstaller, "EnableLog");
518 ok(dispid == 7, "Expected 7, got %d\n", dispid);
519 dispid = get_dispid(pInstaller, "InstallProduct");
520 ok(dispid == 8, "Expected 8, got %d\n", dispid);
521 dispid = get_dispid(pInstaller, "Version");
522 ok(dispid == 9, "Expected 9, got %d\n", dispid);
523 dispid = get_dispid(pInstaller, "LastErrorRecord");
524 ok(dispid == 10, "Expected 10, got %d\n", dispid);
525 dispid = get_dispid(pInstaller, "RegistryValue");
526 ok(dispid == 11, "Expected 11, got %d\n", dispid);
527 dispid = get_dispid(pInstaller, "Environment");
528 ok(dispid == 12, "Expected 12, got %d\n", dispid);
529 dispid = get_dispid(pInstaller, "FileAttributes");
530 ok(dispid == 13, "Expected 13, got %d\n", dispid);
531 dispid = get_dispid(pInstaller, "FileSize");
532 ok(dispid == 15, "Expected 15, got %d\n", dispid);
533 dispid = get_dispid(pInstaller, "FileVersion");
534 ok(dispid == 16, "Expected 16, got %d\n", dispid);
535 dispid = get_dispid(pInstaller, "ProductState");
536 ok(dispid == 17, "Expected 17, got %d\n", dispid);
537 dispid = get_dispid(pInstaller, "ProductInfo");
538 ok(dispid == 18, "Expected 18, got %d\n", dispid);
539 todo_wine
541 dispid = get_dispid(pInstaller, "ConfigureProduct");
542 ok(dispid == 19, "Expected 19, got %d\n", dispid);
543 dispid = get_dispid(pInstaller, "ReinstallProduct");
544 ok(dispid == 20 , "Expected 20, got %d\n", dispid);
545 dispid = get_dispid(pInstaller, "CollectUserInfo");
546 ok(dispid == 21, "Expected 21, got %d\n", dispid);
547 dispid = get_dispid(pInstaller, "ApplyPatch");
548 ok(dispid == 22, "Expected 22, got %d\n", dispid);
549 dispid = get_dispid(pInstaller, "FeatureParent");
550 ok(dispid == 23, "Expected 23, got %d\n", dispid);
551 dispid = get_dispid(pInstaller, "FeatureState");
552 ok(dispid == 24, "Expected 24, got %d\n", dispid);
553 dispid = get_dispid(pInstaller, "UseFeature");
554 ok(dispid == 25, "Expected 25, got %d\n", dispid);
555 dispid = get_dispid(pInstaller, "FeatureUsageCount");
556 ok(dispid == 26, "Expected 26, got %d\n", dispid);
557 dispid = get_dispid(pInstaller, "FeatureUsageDate");
558 ok(dispid == 27, "Expected 27, got %d\n", dispid);
559 dispid = get_dispid(pInstaller, "ConfigureFeature");
560 ok(dispid == 28, "Expected 28, got %d\n", dispid);
561 dispid = get_dispid(pInstaller, "ReinstallFeature");
562 ok(dispid == 29, "Expected 29, got %d\n", dispid);
563 dispid = get_dispid(pInstaller, "ProvideComponent");
564 ok(dispid == 30, "Expected 30, got %d\n", dispid);
565 dispid = get_dispid(pInstaller, "ComponentPath");
566 ok(dispid == 31, "Expected 31, got %d\n", dispid);
567 dispid = get_dispid(pInstaller, "ProvideQualifiedComponent");
568 ok(dispid == 32, "Expected 32, got %d\n", dispid);
569 dispid = get_dispid(pInstaller, "QualifierDescription");
570 ok(dispid == 33, "Expected 33, got %d\n", dispid);
571 dispid = get_dispid(pInstaller, "ComponentQualifiers");
572 ok(dispid == 34, "Expected 34, got %d\n", dispid);
574 dispid = get_dispid(pInstaller, "Products");
575 ok(dispid == 35, "Expected 35, got %d\n", dispid);
576 todo_wine
578 dispid = get_dispid(pInstaller, "Features");
579 ok(dispid == 36, "Expected 36, got %d\n", dispid);
580 dispid = get_dispid(pInstaller, "Components");
581 ok(dispid == 37, "Expected 37, got %d\n", dispid);
582 dispid = get_dispid(pInstaller, "ComponentClients");
583 ok(dispid == 38, "Expected 38, got %d\n", dispid);
584 dispid = get_dispid(pInstaller, "Patches");
585 ok(dispid == 39, "Expected 39, got %d\n", dispid);
587 dispid = get_dispid(pInstaller, "RelatedProducts");
588 ok(dispid == 40, "Expected 40, got %d\n", dispid);
589 todo_wine
591 dispid = get_dispid(pInstaller, "PatchInfo");
592 ok(dispid == 41, "Expected 41, got %d\n", dispid);
593 dispid = get_dispid(pInstaller, "PatchTransforms");
594 ok(dispid == 42, "Expected 42, got %d\n", dispid);
595 dispid = get_dispid(pInstaller, "AddSource");
596 ok(dispid == 43, "Expected 43, got %d\n", dispid);
597 dispid = get_dispid(pInstaller, "ClearSourceList");
598 ok(dispid == 44, "Expected 44, got %d\n", dispid);
599 dispid = get_dispid(pInstaller, "ForceSourceListResolution");
600 ok(dispid == 45, "Expected 45, got %d\n", dispid);
601 dispid = get_dispid(pInstaller, "ShortcutTarget");
602 ok(dispid == 46, "Expected 46, got %d\n", dispid);
603 dispid = get_dispid(pInstaller, "FileHash");
604 ok(dispid == 47, "Expected 47, got %d\n", dispid);
605 dispid = get_dispid(pInstaller, "FileSignatureInfo");
606 ok(dispid == 48, "Expected 48, got %d\n", dispid);
608 dispid = get_dispid(pInstaller, "RemovePatches");
609 ok(dispid == 49 || dispid == -1, "Expected 49 or -1, got %d\n", dispid);
610 dispid = get_dispid(pInstaller, "ApplyMultiplePatches");
611 ok(dispid == 51 || dispid == -1, "Expected 51 or -1, got %d\n", dispid);
612 dispid = get_dispid(pInstaller, "ProductsEx");
613 ok(dispid == 52 || dispid == -1, "Expected 52 or -1, got %d\n", dispid);
614 dispid = get_dispid(pInstaller, "PatchesEx");
615 ok(dispid == 55 || dispid == -1, "Expected 55 or -1, got %d\n", dispid);
616 dispid = get_dispid(pInstaller, "ExtractPatchXMLData");
617 ok(dispid == 57 || dispid == -1, "Expected 57 or -1, got %d\n", dispid);
618 dispid = get_dispid( pInstaller, "ProductElevated" );
619 ok(dispid == 59 || dispid == -1, "Expected 59 or -1, got %d\n", dispid);
620 dispid = get_dispid( pInstaller, "ProvideAssembly" );
621 ok(dispid == 60 || dispid == -1, "Expected 60 or -1, got %d\n", dispid);
622 dispid = get_dispid( pInstaller, "ProductInfoFromScript" );
623 ok(dispid == 61 || dispid == -1, "Expected 61 or -1, got %d\n", dispid);
624 dispid = get_dispid( pInstaller, "AdvertiseProduct" );
625 ok(dispid == 62 || dispid == -1, "Expected 62 or -1, got %d\n", dispid);
626 dispid = get_dispid( pInstaller, "CreateAdvertiseScript" );
627 ok(dispid == 63 || dispid == -1, "Expected 63 or -1, got %d\n", dispid);
628 dispid = get_dispid( pInstaller, "PatchFiles" );
629 ok(dispid == 65 || dispid == -1, "Expected 65 or -1, got %d\n", dispid);
632 /* Test basic IDispatch functions */
633 static void test_dispatch(void)
635 static WCHAR szOpenPackage[] = { 'O','p','e','n','P','a','c','k','a','g','e',0 };
636 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};
637 static WCHAR szProductState[] = { 'P','r','o','d','u','c','t','S','t','a','t','e',0 };
638 HRESULT hr;
639 DISPID dispid;
640 OLECHAR *name;
641 VARIANT varresult;
642 VARIANTARG vararg[3];
643 WCHAR path[MAX_PATH];
644 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
646 /* Test getting ID of a function name that does not exist */
647 name = (WCHAR *)szMsifile;
648 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
649 ok(hr == DISP_E_UNKNOWNNAME, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
651 /* Test invoking this function */
652 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
653 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
655 /* Test getting ID of a function name that does exist */
656 name = szOpenPackage;
657 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
658 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
660 /* Test invoking this function (without parameters passed) */
661 if (0) /* All of these crash MSI on Windows XP */
663 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
664 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL);
665 VariantInit(&varresult);
666 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, &varresult, &excepinfo, NULL);
669 /* Try with NULL params */
670 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
671 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
673 /* Try one empty parameter */
674 dispparams.rgvarg = vararg;
675 dispparams.cArgs = 1;
676 VariantInit(&vararg[0]);
677 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
678 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
680 /* Try two empty parameters */
681 dispparams.cArgs = 2;
682 VariantInit(&vararg[0]);
683 VariantInit(&vararg[1]);
684 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
685 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
687 /* Try one parameter, the required BSTR. Second parameter is optional.
688 * NOTE: The specified package does not exist, which is why the call fails.
690 dispparams.cArgs = 1;
691 VariantInit(&vararg[0]);
692 V_VT(&vararg[0]) = VT_BSTR;
693 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
694 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
695 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
696 ok_exception(hr, szOpenPackageException);
697 VariantClear(&vararg[0]);
699 /* Provide the required BSTR and an empty second parameter.
700 * NOTE: The specified package does not exist, which is why the call fails.
702 dispparams.cArgs = 2;
703 VariantInit(&vararg[1]);
704 V_VT(&vararg[1]) = VT_BSTR;
705 V_BSTR(&vararg[1]) = SysAllocString(szMsifile);
706 VariantInit(&vararg[0]);
707 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
708 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
709 ok_exception(hr, szOpenPackageException);
710 VariantClear(&vararg[1]);
712 /* Provide the required BSTR and two empty parameters.
713 * NOTE: The specified package does not exist, which is why the call fails.
715 dispparams.cArgs = 3;
716 VariantInit(&vararg[2]);
717 V_VT(&vararg[2]) = VT_BSTR;
718 V_BSTR(&vararg[2]) = SysAllocString(szMsifile);
719 VariantInit(&vararg[1]);
720 VariantInit(&vararg[0]);
721 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
722 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
723 ok_exception(hr, szOpenPackageException);
724 VariantClear(&vararg[2]);
726 /* Provide the required BSTR and a second parameter with the wrong type. */
727 dispparams.cArgs = 2;
728 VariantInit(&vararg[1]);
729 V_VT(&vararg[1]) = VT_BSTR;
730 V_BSTR(&vararg[1]) = SysAllocString(szMsifile);
731 VariantInit(&vararg[0]);
732 V_VT(&vararg[0]) = VT_BSTR;
733 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
734 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
735 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
736 VariantClear(&vararg[0]);
737 VariantClear(&vararg[1]);
739 /* Create a proper installer package. */
740 create_package(path);
742 /* Try one parameter, the required BSTR. Second parameter is optional.
743 * Proper installer package exists. Path to the package is relative.
745 dispparams.cArgs = 1;
746 VariantInit(&vararg[0]);
747 V_VT(&vararg[0]) = VT_BSTR;
748 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
749 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
750 todo_wine ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
751 ok_exception(hr, szOpenPackageException);
752 VariantClear(&vararg[0]);
753 if (hr != DISP_E_EXCEPTION)
754 VariantClear(&varresult);
756 /* Try one parameter, the required BSTR. Second parameter is optional.
757 * Proper installer package exists. Path to the package is absolute.
759 dispparams.cArgs = 1;
760 VariantInit(&vararg[0]);
761 V_VT(&vararg[0]) = VT_BSTR;
762 V_BSTR(&vararg[0]) = SysAllocString(path);
763 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
764 if (hr == DISP_E_EXCEPTION)
766 skip("OpenPackage failed, insufficient rights?\n");
767 DeleteFileW(path);
768 return;
770 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
771 VariantClear(&vararg[0]);
772 VariantClear(&varresult);
774 /* Provide the required BSTR and an empty second parameter. Proper
775 * installation package exists.
777 dispparams.cArgs = 2;
778 VariantInit(&vararg[1]);
779 V_VT(&vararg[1]) = VT_BSTR;
780 V_BSTR(&vararg[1]) = SysAllocString(path);
781 VariantInit(&vararg[0]);
782 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
783 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
784 VariantClear(&vararg[1]);
785 VariantClear(&varresult);
787 /* Provide the required BSTR and two empty parameters. Proper
788 * installation package exists.
790 dispparams.cArgs = 3;
791 VariantInit(&vararg[2]);
792 V_VT(&vararg[2]) = VT_BSTR;
793 V_BSTR(&vararg[2]) = SysAllocString(path);
794 VariantInit(&vararg[1]);
795 VariantInit(&vararg[0]);
796 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
797 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
798 VariantClear(&vararg[2]);
799 VariantClear(&varresult);
801 /* Provide the required BSTR and a second parameter with the wrong type. */
802 dispparams.cArgs = 2;
803 VariantInit(&vararg[1]);
804 V_VT(&vararg[1]) = VT_BSTR;
805 V_BSTR(&vararg[1]) = SysAllocString(path);
806 VariantInit(&vararg[0]);
807 V_VT(&vararg[0]) = VT_BSTR;
808 V_BSTR(&vararg[0]) = SysAllocString(path);
809 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
810 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
811 VariantClear(&vararg[0]);
812 VariantClear(&vararg[1]);
814 /* Provide the required BSTR and a second parameter that can be coerced to
815 * VT_I4.
817 dispparams.cArgs = 2;
818 VariantInit(&vararg[1]);
819 V_VT(&vararg[1]) = VT_BSTR;
820 V_BSTR(&vararg[1]) = SysAllocString(path);
821 VariantInit(&vararg[0]);
822 V_VT(&vararg[0]) = VT_I2;
823 V_BSTR(&vararg[0]) = 0;
824 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
825 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
826 VariantClear(&vararg[1]);
827 VariantClear(&varresult);
829 DeleteFileW(path);
831 /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
832 VariantInit(&vararg[0]);
833 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
834 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
836 VariantInit(&vararg[0]);
837 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
838 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
840 /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
841 name = szProductState;
842 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
843 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
845 dispparams.rgvarg = NULL;
846 dispparams.cArgs = 0;
847 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
848 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
850 dispparams.rgvarg = NULL;
851 dispparams.cArgs = 0;
852 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
853 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
856 /* invocation helper function */
857 static int _invoke_todo_vtResult = 0;
859 static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult)
861 OLECHAR *name = NULL;
862 DISPID dispid;
863 HRESULT hr;
864 UINT i;
865 UINT len;
867 memset(pVarResult, 0, sizeof(VARIANT));
868 VariantInit(pVarResult);
870 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 );
871 name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
872 if (!name) return E_FAIL;
873 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len );
874 hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
875 HeapFree(GetProcessHeap(), 0, name);
876 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
877 if (!hr == S_OK) return hr;
879 memset(&excepinfo, 0, sizeof(excepinfo));
880 hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL);
882 if (hr == S_OK)
884 if (_invoke_todo_vtResult) todo_wine
885 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
886 else
887 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
888 if (vtResult != VT_EMPTY)
890 hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult);
891 ok(hr == S_OK, "VariantChangeTypeEx returned 0x%08x\n", hr);
895 for (i=0; i<pDispParams->cArgs; i++)
896 VariantClear(&pDispParams->rgvarg[i]);
898 return hr;
901 /* Object_Property helper functions */
903 static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord)
905 VARIANT varresult;
906 VARIANTARG vararg[1];
907 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
908 HRESULT hr;
910 VariantInit(&vararg[0]);
911 V_VT(&vararg[0]) = VT_I4;
912 V_I4(&vararg[0]) = count;
914 hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
915 *pRecord = V_DISPATCH(&varresult);
916 return hr;
919 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
921 VARIANTARG vararg[3];
922 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
924 VariantInit(&vararg[2]);
925 V_VT(&vararg[2]) = VT_I4;
926 V_I4(&vararg[2]) = (INT_PTR)hkey;
927 VariantInit(&vararg[1]);
928 V_VT(&vararg[1]) = VT_BSTR;
929 V_BSTR(&vararg[1]) = SysAllocString(szKey);
930 VariantInit(&vararg[0]);
931 VariantCopy(&vararg[0], &vValue);
932 VariantClear(&vValue);
934 return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect);
937 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
939 VARIANT varresult;
940 VARIANTARG vararg;
941 HRESULT hr;
943 VariantInit(&vararg);
944 V_VT(&vararg) = VT_EMPTY;
945 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL);
946 *pBool = V_BOOL(&varresult);
947 VariantClear(&varresult);
948 return hr;
951 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
953 VARIANT varresult;
954 VARIANTARG vararg;
955 HRESULT hr;
957 VariantInit(&vararg);
958 V_VT(&vararg) = VT_BSTR;
959 V_BSTR(&vararg) = SysAllocString(szValue);
961 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR);
962 if (V_BSTR(&varresult))
963 /* lstrcpyW is not implemented on Win95 (lstrlenW is though) */
964 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
965 VariantClear(&varresult);
966 return hr;
969 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
971 VARIANT varresult;
972 VARIANTARG vararg;
973 HRESULT hr;
975 VariantInit(&vararg);
976 V_VT(&vararg) = VT_I4;
977 V_I4(&vararg) = iValue;
979 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult);
980 if (SUCCEEDED(hr) && vtResult == VT_BSTR)
981 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
982 VariantClear(&varresult);
983 return hr;
986 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
988 VARIANT varresult;
989 VARIANTARG vararg[2];
990 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
991 HRESULT hr;
993 VariantInit(&vararg[1]);
994 V_VT(&vararg[1]) = VT_BSTR;
995 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
996 VariantInit(&vararg[0]);
997 V_VT(&vararg[0]) = VT_I4;
998 V_I4(&vararg[0]) = options;
1000 hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1001 *pSession = V_DISPATCH(&varresult);
1002 return hr;
1005 static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase)
1007 VARIANT varresult;
1008 VARIANTARG vararg[2];
1009 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1010 HRESULT hr;
1012 VariantInit(&vararg[1]);
1013 V_VT(&vararg[1]) = VT_BSTR;
1014 V_BSTR(&vararg[1]) = SysAllocString(szDatabasePath);
1015 VariantInit(&vararg[0]);
1016 V_VT(&vararg[0]) = VT_I4;
1017 V_I4(&vararg[0]) = openmode;
1019 hr = invoke(pInstaller, "OpenDatabase", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1020 *pDatabase = V_DISPATCH(&varresult);
1021 return hr;
1024 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
1026 VARIANT varresult;
1027 VARIANTARG vararg[2];
1028 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1030 VariantInit(&vararg[1]);
1031 V_VT(&vararg[1]) = VT_BSTR;
1032 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
1033 VariantInit(&vararg[0]);
1034 V_VT(&vararg[0]) = VT_BSTR;
1035 V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues);
1037 return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1040 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
1042 VARIANT varresult;
1043 VARIANTARG vararg[1];
1044 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1045 HRESULT hr;
1047 VariantInit(&vararg[0]);
1048 V_VT(&vararg[0]) = VT_BSTR;
1049 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
1051 hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1052 *pInstallState = V_I4(&varresult);
1053 VariantClear(&varresult);
1054 return hr;
1057 static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szString)
1059 VARIANT varresult;
1060 VARIANTARG vararg[2];
1061 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1062 HRESULT hr;
1064 VariantInit(&vararg[1]);
1065 V_VT(&vararg[1]) = VT_BSTR;
1066 V_BSTR(&vararg[1]) = SysAllocString(szProduct);
1067 VariantInit(&vararg[0]);
1068 V_VT(&vararg[0]) = VT_BSTR;
1069 V_BSTR(&vararg[0]) = SysAllocString(szAttribute);
1071 hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1072 if (V_BSTR(&varresult))
1073 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
1074 VariantClear(&varresult);
1075 return hr;
1078 static HRESULT Installer_Products(IDispatch **pStringList)
1080 VARIANT varresult;
1081 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1082 HRESULT hr;
1084 hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1085 *pStringList = V_DISPATCH(&varresult);
1086 return hr;
1089 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
1091 VARIANT varresult;
1092 VARIANTARG vararg[1];
1093 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1094 HRESULT hr;
1096 VariantInit(&vararg[0]);
1097 V_VT(&vararg[0]) = VT_BSTR;
1098 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
1100 hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1101 *pStringList = V_DISPATCH(&varresult);
1102 return hr;
1105 static HRESULT Installer_VersionGet(LPWSTR szVersion)
1107 VARIANT varresult;
1108 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1109 HRESULT hr;
1111 hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1112 if (V_BSTR(&varresult))
1113 memcpy(szVersion, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
1114 VariantClear(&varresult);
1115 return hr;
1118 static HRESULT Installer_UILevelPut(int level)
1120 VARIANT varresult;
1121 VARIANTARG vararg;
1122 DISPID dispid = DISPID_PROPERTYPUT;
1123 DISPPARAMS dispparams = {&vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1125 VariantInit(&vararg);
1126 V_VT(&vararg) = VT_I4;
1127 V_I4(&vararg) = level;
1129 return invoke(pInstaller, "UILevel", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1132 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
1134 VARIANT varresult;
1135 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1136 HRESULT hr;
1138 hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1139 *pInst = V_DISPATCH(&varresult);
1140 return hr;
1143 static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn)
1145 VARIANT varresult;
1146 VARIANTARG vararg[1];
1147 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1148 HRESULT hr;
1150 VariantInit(&vararg[0]);
1151 V_VT(&vararg[0]) = VT_BSTR;
1152 V_BSTR(&vararg[0]) = SysAllocString(szName);
1154 hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1155 if (V_BSTR(&varresult))
1156 memcpy(szReturn, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
1157 VariantClear(&varresult);
1158 return hr;
1161 static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue)
1163 VARIANT varresult;
1164 VARIANTARG vararg[2];
1165 DISPID dispid = DISPID_PROPERTYPUT;
1166 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1168 VariantInit(&vararg[1]);
1169 V_VT(&vararg[1]) = VT_BSTR;
1170 V_BSTR(&vararg[1]) = SysAllocString(szName);
1171 VariantInit(&vararg[0]);
1172 V_VT(&vararg[0]) = VT_BSTR;
1173 V_BSTR(&vararg[0]) = SysAllocString(szValue);
1175 return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1178 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
1180 VARIANT varresult;
1181 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1182 HRESULT hr;
1184 hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1185 *pLangId = V_I4(&varresult);
1186 VariantClear(&varresult);
1187 return hr;
1190 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, BOOL *pMode)
1192 VARIANT varresult;
1193 VARIANTARG vararg[1];
1194 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1195 HRESULT hr;
1197 VariantInit(&vararg[0]);
1198 V_VT(&vararg[0]) = VT_I4;
1199 V_I4(&vararg[0]) = iFlag;
1201 hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL);
1202 *pMode = V_BOOL(&varresult);
1203 VariantClear(&varresult);
1204 return hr;
1207 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, BOOL bMode)
1209 VARIANT varresult;
1210 VARIANTARG vararg[2];
1211 DISPID dispid = DISPID_PROPERTYPUT;
1212 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1214 VariantInit(&vararg[1]);
1215 V_VT(&vararg[1]) = VT_I4;
1216 V_I4(&vararg[1]) = iFlag;
1217 VariantInit(&vararg[0]);
1218 V_VT(&vararg[0]) = VT_BOOL;
1219 V_BOOL(&vararg[0]) = bMode;
1221 return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1224 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
1226 VARIANT varresult;
1227 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1228 HRESULT hr;
1230 hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1231 *pDatabase = V_DISPATCH(&varresult);
1232 return hr;
1235 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn)
1237 VARIANT varresult;
1238 VARIANTARG vararg[1];
1239 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1240 HRESULT hr;
1242 VariantInit(&vararg[0]);
1243 V_VT(&vararg[0]) = VT_BSTR;
1244 V_BSTR(&vararg[0]) = SysAllocString(szAction);
1246 hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1247 *iReturn = V_I4(&varresult);
1248 VariantClear(&varresult);
1249 return hr;
1252 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
1254 VARIANT varresult;
1255 VARIANTARG vararg[1];
1256 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1257 HRESULT hr;
1259 VariantInit(&vararg[0]);
1260 V_VT(&vararg[0]) = VT_BSTR;
1261 V_BSTR(&vararg[0]) = SysAllocString(szCondition);
1263 hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1264 *iReturn = V_I4(&varresult);
1265 VariantClear(&varresult);
1266 return hr;
1269 static HRESULT Session_Message(IDispatch *pSession, LONG kind, IDispatch *record, int *ret)
1271 VARIANT varresult;
1272 VARIANTARG vararg[2];
1273 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1274 HRESULT hr;
1276 VariantInit(&varresult);
1277 V_VT(vararg) = VT_DISPATCH;
1278 V_DISPATCH(vararg) = record;
1279 V_VT(vararg+1) = VT_I4;
1280 V_I4(vararg+1) = kind;
1282 hr = invoke(pSession, "Message", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1284 ok(V_VT(&varresult) == VT_I4, "V_VT(varresult) = %d\n", V_VT(&varresult));
1285 *ret = V_I4(&varresult);
1287 return hr;
1290 static HRESULT Session_SetInstallLevel(IDispatch *pSession, LONG iInstallLevel)
1292 VARIANT varresult;
1293 VARIANTARG vararg[1];
1294 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1296 VariantInit(&vararg[0]);
1297 V_VT(&vararg[0]) = VT_I4;
1298 V_I4(&vararg[0]) = iInstallLevel;
1300 return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1303 static HRESULT Session_FeatureCurrentState(IDispatch *pSession, LPCWSTR szName, int *pState)
1305 VARIANT varresult;
1306 VARIANTARG vararg[1];
1307 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1308 HRESULT hr;
1310 VariantInit(&vararg[0]);
1311 V_VT(&vararg[0]) = VT_BSTR;
1312 V_BSTR(&vararg[0]) = SysAllocString(szName);
1314 hr = invoke(pSession, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1315 *pState = V_I4(&varresult);
1316 VariantClear(&varresult);
1317 return hr;
1320 static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState)
1322 VARIANT varresult;
1323 VARIANTARG vararg[1];
1324 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1325 HRESULT hr;
1327 VariantInit(&vararg[0]);
1328 V_VT(&vararg[0]) = VT_BSTR;
1329 V_BSTR(&vararg[0]) = SysAllocString(szName);
1331 hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1332 *pState = V_I4(&varresult);
1333 VariantClear(&varresult);
1334 return hr;
1337 static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState)
1339 VARIANT varresult;
1340 VARIANTARG vararg[2];
1341 DISPID dispid = DISPID_PROPERTYPUT;
1342 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1344 VariantInit(&vararg[1]);
1345 V_VT(&vararg[1]) = VT_BSTR;
1346 V_BSTR(&vararg[1]) = SysAllocString(szName);
1347 VariantInit(&vararg[0]);
1348 V_VT(&vararg[0]) = VT_I4;
1349 V_I4(&vararg[0]) = iState;
1351 return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1354 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
1356 VARIANT varresult;
1357 VARIANTARG vararg[1];
1358 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1359 HRESULT hr;
1361 VariantInit(&vararg[0]);
1362 V_VT(&vararg[0]) = VT_BSTR;
1363 V_BSTR(&vararg[0]) = SysAllocString(szSql);
1365 hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1366 *pView = V_DISPATCH(&varresult);
1367 return hr;
1370 static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo)
1372 VARIANT varresult;
1373 VARIANTARG vararg[1];
1374 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1375 HRESULT hr;
1377 VariantInit(&vararg[0]);
1378 V_VT(&vararg[0]) = VT_I4;
1379 V_I4(&vararg[0]) = iUpdateCount;
1381 hr = invoke(pDatabase, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1382 *pSummaryInfo = V_DISPATCH(&varresult);
1383 return hr;
1386 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
1388 VARIANT varresult;
1389 VARIANTARG vararg[1];
1390 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1392 VariantInit(&vararg[0]);
1393 V_VT(&vararg[0]) = VT_DISPATCH;
1394 V_DISPATCH(&vararg[0]) = pRecord;
1396 return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1399 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
1401 VARIANT varresult;
1402 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1403 HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1404 *ppRecord = V_DISPATCH(&varresult);
1405 return hr;
1408 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
1410 VARIANT varresult;
1411 VARIANTARG vararg[2];
1412 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1414 VariantInit(&vararg[1]);
1415 V_VT(&vararg[1]) = VT_I4;
1416 V_I4(&vararg[1]) = iMode;
1417 VariantInit(&vararg[0]);
1418 V_VT(&vararg[0]) = VT_DISPATCH;
1419 V_DISPATCH(&vararg[0]) = pRecord;
1420 if (pRecord)
1421 IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */
1423 return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1426 static HRESULT View_Close(IDispatch *pView)
1428 VARIANT varresult;
1429 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1430 return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1433 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
1435 VARIANT varresult;
1436 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1437 HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1438 *pFieldCount = V_I4(&varresult);
1439 VariantClear(&varresult);
1440 return hr;
1443 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString)
1445 VARIANT varresult;
1446 VARIANTARG vararg[1];
1447 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1448 HRESULT hr;
1450 VariantInit(&vararg[0]);
1451 V_VT(&vararg[0]) = VT_I4;
1452 V_I4(&vararg[0]) = iField;
1454 hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1455 if (V_BSTR(&varresult))
1456 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
1457 VariantClear(&varresult);
1458 return hr;
1461 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
1463 VARIANT varresult;
1464 VARIANTARG vararg[2];
1465 DISPID dispid = DISPID_PROPERTYPUT;
1466 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1468 VariantInit(&vararg[1]);
1469 V_VT(&vararg[1]) = VT_I4;
1470 V_I4(&vararg[1]) = iField;
1471 VariantInit(&vararg[0]);
1472 V_VT(&vararg[0]) = VT_BSTR;
1473 V_BSTR(&vararg[0]) = SysAllocString(szString);
1475 return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1478 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
1480 VARIANT varresult;
1481 VARIANTARG vararg[1];
1482 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1483 HRESULT hr;
1485 VariantInit(&vararg[0]);
1486 V_VT(&vararg[0]) = VT_I4;
1487 V_I4(&vararg[0]) = iField;
1489 hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1490 *pValue = V_I4(&varresult);
1491 VariantClear(&varresult);
1492 return hr;
1495 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
1497 VARIANT varresult;
1498 VARIANTARG vararg[2];
1499 DISPID dispid = DISPID_PROPERTYPUT;
1500 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1502 VariantInit(&vararg[1]);
1503 V_VT(&vararg[1]) = VT_I4;
1504 V_I4(&vararg[1]) = iField;
1505 VariantInit(&vararg[0]);
1506 V_VT(&vararg[0]) = VT_I4;
1507 V_I4(&vararg[0]) = iValue;
1509 return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1512 static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT)
1514 VARIANT varresult;
1515 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1516 HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN);
1517 *ppEnumVARIANT = V_UNKNOWN(&varresult);
1518 return hr;
1521 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
1523 VARIANT varresult;
1524 VARIANTARG vararg[1];
1525 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1526 HRESULT hr;
1528 VariantInit(&vararg[0]);
1529 V_VT(&vararg[0]) = VT_I4;
1530 V_I4(&vararg[0]) = iIndex;
1532 hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1533 if (V_BSTR(&varresult))
1534 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
1535 VariantClear(&varresult);
1536 return hr;
1539 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
1541 VARIANT varresult;
1542 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1543 HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1544 *pCount = V_I4(&varresult);
1545 VariantClear(&varresult);
1546 return hr;
1549 static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect)
1551 VARIANTARG vararg[1];
1552 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1554 VariantInit(&vararg[0]);
1555 V_VT(&vararg[0]) = VT_I4;
1556 V_I4(&vararg[0]) = pid;
1557 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYGET, &dispparams, pVarResult, vtExpect);
1560 static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant)
1562 VARIANT varresult;
1563 VARIANTARG vararg[2];
1564 DISPID dispid = DISPID_PROPERTYPUT;
1565 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1567 VariantInit(&vararg[1]);
1568 V_VT(&vararg[1]) = VT_I4;
1569 V_I4(&vararg[1]) = pid;
1570 VariantInit(&vararg[0]);
1571 VariantCopyInd(vararg, pVariant);
1573 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1576 static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount)
1578 VARIANT varresult;
1579 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1580 HRESULT hr;
1582 hr = invoke(pSummaryInfo, "PropertyCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1583 *pCount = V_I4(&varresult);
1584 VariantClear(&varresult);
1585 return hr;
1588 /* Test the various objects */
1590 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4
1592 static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly)
1594 static const WCHAR szPropertyException[] = { 'P','r','o','p','e','r','t','y',',','P','i','d',0 };
1595 static const WCHAR szTitle[] = { 'T','i','t','l','e',0 };
1596 VARIANT varresult, var;
1597 SYSTEMTIME st;
1598 HRESULT hr;
1599 int j;
1601 /* SummaryInfo::PropertyCount */
1602 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1603 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1604 ok(j == num_info, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1606 /* SummaryInfo::Property, get for properties we have set */
1607 for (j = 0; j < num_info; j++)
1609 const msi_summary_info *entry = &info[j];
1611 int vt = entry->datatype;
1612 if (vt == VT_LPSTR) vt = VT_BSTR;
1613 else if (vt == VT_FILETIME) vt = VT_DATE;
1614 else if (vt == VT_I2) vt = VT_I4;
1616 hr = SummaryInfo_PropertyGet(pSummaryInfo, entry->property, &varresult, vt);
1617 ok(hr == S_OK, "SummaryInfo_Property (pid %d) failed, hresult 0x%08x\n", entry->property, hr);
1618 if (V_VT(&varresult) != vt)
1619 skip("Skipping property tests due to type mismatch\n");
1620 else if (vt == VT_I4)
1621 ok(V_I4(&varresult) == entry->iValue, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %d\n",
1622 entry->property, entry->iValue, V_I4(&varresult));
1623 else if (vt == VT_DATE)
1625 FILETIME ft;
1626 DATE d;
1628 FileTimeToLocalFileTime(entry->pftValue, &ft);
1629 FileTimeToSystemTime(&ft, &st);
1630 SystemTimeToVariantTime(&st, &d);
1631 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));
1633 else if (vt == VT_BSTR)
1635 ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry->property, entry->szValue, V_BSTR(&varresult));
1637 else
1638 skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry->property, vt);
1640 VariantClear(&varresult);
1643 /* SummaryInfo::Property, get; invalid arguments */
1645 /* Invalid pids */
1646 hr = SummaryInfo_PropertyGet(pSummaryInfo, -1, &varresult, VT_EMPTY);
1647 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1648 ok_exception(hr, szPropertyException);
1650 hr = SummaryInfo_PropertyGet(pSummaryInfo, 1000, &varresult, VT_EMPTY);
1651 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1652 ok_exception(hr, szPropertyException);
1654 /* Unsupported pids */
1655 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_DICTIONARY, &varresult, VT_EMPTY);
1656 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1658 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY);
1659 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1661 /* Pids we have not set, one for each type */
1662 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_EMPTY);
1663 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1665 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY);
1666 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1668 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY);
1669 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1671 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY);
1672 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1674 if (!readonly)
1676 /* SummaryInfo::Property, put; one for each type */
1678 /* VT_I2 */
1679 VariantInit(&var);
1680 V_VT(&var) = VT_I2;
1681 V_I2(&var) = 1;
1682 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CODEPAGE, &var);
1683 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1685 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */);
1686 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1687 ok(V_I2(&var) == V_I2(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var), V_I2(&varresult));
1688 VariantClear(&varresult);
1689 VariantClear(&var);
1691 /* VT_BSTR */
1692 V_VT(&var) = VT_BSTR;
1693 V_BSTR(&var) = SysAllocString(szTitle);
1694 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_TITLE, &var);
1695 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1697 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var));
1698 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1699 ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var), V_BSTR(&varresult));
1700 VariantClear(&varresult);
1701 VariantClear(&var);
1703 /* VT_DATE */
1704 V_VT(&var) = VT_DATE;
1705 FileTimeToSystemTime(&systemtime, &st);
1706 SystemTimeToVariantTime(&st, &V_DATE(&var));
1707 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_LASTSAVE_DTM, &var);
1708 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1710 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var));
1711 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1712 ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1713 VariantClear(&varresult);
1714 VariantClear(&var);
1716 /* VT_I4 */
1717 V_VT(&var) = VT_I4;
1718 V_I4(&var) = 1000;
1719 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1720 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1722 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1723 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1724 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult));
1725 VariantClear(&varresult);
1726 VariantClear(&var);
1728 /* SummaryInfo::PropertyCount */
1729 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1730 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1731 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1735 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1737 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 };
1738 static WCHAR szThree[] = { 'T','h','r','e','e',0 };
1739 static WCHAR szTwo[] = { 'T','w','o',0 };
1740 static WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
1741 static WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 };
1742 IDispatch *pView = NULL, *pSummaryInfo = NULL;
1743 HRESULT hr;
1745 hr = Database_OpenView(pDatabase, szSql, &pView);
1746 ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr);
1747 if (hr == S_OK)
1749 IDispatch *pRecord = NULL;
1750 WCHAR szString[MAX_PATH];
1752 /* View::Execute */
1753 hr = View_Execute(pView, NULL);
1754 ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr);
1756 /* View::Fetch */
1757 hr = View_Fetch(pView, &pRecord);
1758 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1759 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1760 if (pRecord)
1762 /* Record::StringDataGet */
1763 memset(szString, 0, sizeof(szString));
1764 hr = Record_StringDataGet(pRecord, 1, szString);
1765 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1766 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1768 /* Record::StringDataPut with correct index */
1769 hr = Record_StringDataPut(pRecord, 1, szTwo);
1770 ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1772 /* Record::StringDataGet */
1773 memset(szString, 0, sizeof(szString));
1774 hr = Record_StringDataGet(pRecord, 1, szString);
1775 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1776 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1778 /* Record::StringDataPut with incorrect index */
1779 hr = Record_StringDataPut(pRecord, -1, szString);
1780 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1781 ok_exception(hr, szStringDataField);
1783 /* View::Modify with incorrect parameters */
1784 hr = View_Modify(pView, -5, NULL);
1785 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1786 ok_exception(hr, szModifyModeRecord);
1788 hr = View_Modify(pView, -5, pRecord);
1789 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1790 ok_exception(hr, szModifyModeRecord);
1792 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1793 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1794 ok_exception(hr, szModifyModeRecord);
1796 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1797 ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr);
1799 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1800 memset(szString, 0, sizeof(szString));
1801 hr = Record_StringDataGet(pRecord, 1, szString);
1802 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1803 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1805 IDispatch_Release(pRecord);
1808 /* View::Fetch */
1809 hr = View_Fetch(pView, &pRecord);
1810 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1811 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1812 if (pRecord)
1814 /* Record::StringDataGet */
1815 memset(szString, 0, sizeof(szString));
1816 hr = Record_StringDataGet(pRecord, 1, szString);
1817 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1818 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1820 IDispatch_Release(pRecord);
1823 /* View::Fetch */
1824 hr = View_Fetch(pView, &pRecord);
1825 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1826 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1827 if (pRecord)
1828 IDispatch_Release(pRecord);
1830 /* View::Close */
1831 hr = View_Close(pView);
1832 ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr);
1834 IDispatch_Release(pView);
1837 /* Database::SummaryInformation */
1838 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo);
1839 ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr);
1840 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1841 if (pSummaryInfo)
1843 test_SummaryInfo(pSummaryInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), readonly);
1844 IDispatch_Release(pSummaryInfo);
1848 static void test_Session(IDispatch *pSession)
1850 static WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
1851 static WCHAR szOne[] = { 'O','n','e',0 };
1852 static WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 };
1853 static WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 };
1854 static WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 };
1855 static WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 };
1856 static WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1857 static WCHAR szEmpty[] = { 0 };
1858 static WCHAR szEquals[] = { '=',0 };
1859 static WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
1860 static WCHAR szModeFlag[] = { 'M','o','d','e',',','F','l','a','g',0 };
1861 WCHAR stringw[MAX_PATH];
1862 CHAR string[MAX_PATH];
1863 UINT len;
1864 BOOL bool;
1865 int myint;
1866 IDispatch *pDatabase = NULL, *pInst = NULL, *record = NULL;
1867 ULONG refs_before, refs_after;
1868 HRESULT hr;
1870 /* Session::Installer */
1871 hr = Session_Installer(pSession, &pInst);
1872 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1873 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1874 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1875 refs_before = IDispatch_AddRef(pInst);
1877 hr = Session_Installer(pSession, &pInst);
1878 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1879 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1880 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1881 refs_after = IDispatch_Release(pInst);
1882 ok(refs_before == refs_after, "got %u and %u\n", refs_before, refs_after);
1884 /* Session::Property, get */
1885 memset(stringw, 0, sizeof(stringw));
1886 hr = Session_PropertyGet(pSession, szProductName, stringw);
1887 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1888 if (strcmp_ww(stringw, szMSITEST) != 0)
1890 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1891 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1892 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1895 /* Session::Property, put */
1896 hr = Session_PropertyPut(pSession, szProductName, szProductName);
1897 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1898 memset(stringw, 0, sizeof(stringw));
1899 hr = Session_PropertyGet(pSession, szProductName, stringw);
1900 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1901 if (strcmp_ww(stringw, szProductName) != 0)
1903 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1904 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1905 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1908 /* Try putting a property using empty property identifier */
1909 hr = Session_PropertyPut(pSession, szEmpty, szProductName);
1910 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1911 ok_exception(hr, szPropertyName);
1913 /* Try putting a property using illegal property identifier */
1914 hr = Session_PropertyPut(pSession, szEquals, szProductName);
1915 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1917 /* Session::Language, get */
1918 hr = Session_LanguageGet(pSession, &len);
1919 ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1920 /* Not sure how to check the language is correct */
1922 /* Session::Mode, get */
1923 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1924 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1925 ok(!bool, "Reboot at end session mode is %d\n", bool);
1927 hr = Session_ModeGet(pSession, MSIRUNMODE_MAINTENANCE, &bool);
1928 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1929 ok(!bool, "Maintenance mode is %d\n", bool);
1931 /* Session::Mode, put */
1932 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE);
1933 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1934 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1935 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1936 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1937 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE); /* set it again so we don't reboot */
1938 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1940 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, TRUE);
1941 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1942 if (hr == DISP_E_EXCEPTION) ok_exception(hr, szModeFlag);
1944 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTNOW, &bool);
1945 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1946 ok(bool, "Reboot now mode is %d, expected 1\n", bool);
1948 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, FALSE); /* set it again so we don't reboot */
1949 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1950 if (hr == DISP_E_EXCEPTION) ok_exception(hr, szModeFlag);
1952 hr = Session_ModePut(pSession, MSIRUNMODE_MAINTENANCE, TRUE);
1953 ok(hr == DISP_E_EXCEPTION, "Session_ModePut failed, hresult 0x%08x\n", hr);
1954 ok_exception(hr, szModeFlag);
1956 /* Session::Database, get */
1957 hr = Session_Database(pSession, &pDatabase);
1958 ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr);
1959 if (hr == S_OK)
1961 test_Database(pDatabase, TRUE);
1962 IDispatch_Release(pDatabase);
1965 /* Session::EvaluateCondition */
1966 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1967 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1968 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1970 hr = Session_EvaluateCondition(pSession, szEmpty, &myint);
1971 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1972 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1974 hr = Session_EvaluateCondition(pSession, szEquals, &myint);
1975 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1976 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1978 /* Session::DoAction(CostInitialize) must occur before the next statements */
1979 hr = Session_DoAction(pSession, szCostInitialize, &myint);
1980 ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr);
1981 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1983 /* Session::SetInstallLevel */
1984 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1985 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
1987 /* Session::FeatureCurrentState, get */
1988 hr = Session_FeatureCurrentState(pSession, szOne, &myint);
1989 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
1990 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1992 /* Session::Message */
1993 hr = Installer_CreateRecord(0, &record);
1994 ok(hr == S_OK, "Installer_CreateRecord failed: %08x\n", hr);
1995 hr = Session_Message(pSession, INSTALLMESSAGE_INFO, record, &myint);
1996 ok(hr == S_OK, "Session_Message failed: %08x\n", hr);
1997 ok(myint == 0, "Session_Message returned %x\n", myint);
1999 /* Session::EvaluateCondition */
2000 hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint);
2001 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2002 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2004 hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint);
2005 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2006 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2008 /* Session::FeatureRequestState, put */
2009 hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED);
2010 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
2011 hr = Session_FeatureRequestStateGet(pSession, szOne, &myint);
2012 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
2013 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
2015 /* Session::EvaluateCondition */
2016 hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint);
2017 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2018 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2020 hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint);
2021 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2022 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2025 /* delete key and all its subkeys */
2026 static DWORD delete_key( HKEY hkey )
2028 char name[MAX_PATH];
2029 DWORD ret;
2031 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
2033 HKEY tmp;
2034 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
2036 ret = delete_key( tmp );
2037 RegCloseKey( tmp );
2039 if (ret) break;
2041 if (ret != ERROR_NO_MORE_ITEMS) return ret;
2042 RegDeleteKeyA( hkey, "" );
2043 return 0;
2046 static void test_Installer_RegistryValue(void)
2048 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
2049 static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 };
2050 static const WCHAR szOne[] = { 'O','n','e',0 };
2051 static const WCHAR szTwo[] = { 'T','w','o',0 };
2052 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
2053 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
2054 static const WCHAR szFour[] = { 'F','o','u','r',0 };
2055 static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 };
2056 static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 };
2057 static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 };
2058 static const WCHAR szSix[] = { 'S','i','x',0 };
2059 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
2060 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
2061 static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
2062 static const WCHAR szBlank[] = { 0 };
2063 VARIANT varresult;
2064 VARIANTARG vararg;
2065 WCHAR szString[MAX_PATH];
2066 HKEY hkey, hkey_sub;
2067 HKEY curr_user = (HKEY)1;
2068 HRESULT hr;
2069 BOOL bRet;
2070 LONG lRet;
2072 /* Delete keys */
2073 SetLastError(0xdeadbeef);
2074 lRet = RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey );
2075 if (!lRet && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2077 win_skip("Needed W-functions are not implemented\n");
2078 return;
2080 if (!lRet)
2081 delete_key( hkey );
2083 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
2084 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
2085 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
2086 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
2088 memset(szString, 0, sizeof(szString));
2089 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
2090 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2092 memset(szString, 0, sizeof(szString));
2093 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
2094 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2096 /* Create key */
2097 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
2099 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
2100 "RegSetValueExW failed\n");
2101 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
2102 "RegSetValueExW failed\n");
2103 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
2104 "RegSetValueExW failed\n");
2105 ok(SetEnvironmentVariableA("MSITEST", "Four"), "SetEnvironmentVariableA failed %d\n", GetLastError());
2106 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
2107 "RegSetValueExW failed\n");
2108 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
2109 "RegSetValueExW failed\n");
2110 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
2111 "RegSetValueExW failed\n");
2112 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, NULL, 0),
2113 "RegSetValueExW failed\n");
2115 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
2116 "RegSetValueExW failed\n");
2118 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
2120 /* Does our key exist? It should, and make sure we retrieve the correct default value */
2121 bRet = FALSE;
2122 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
2123 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
2124 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
2126 memset(szString, 0, sizeof(szString));
2127 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
2128 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2129 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
2131 /* Ask for the value of a nonexistent key */
2132 memset(szString, 0, sizeof(szString));
2133 hr = Installer_RegistryValueW(curr_user, szKey, szExpand, szString);
2134 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2136 /* Get values of keys */
2137 memset(szString, 0, sizeof(szString));
2138 hr = Installer_RegistryValueW(curr_user, szKey, szOne, szString);
2139 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2140 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
2142 VariantInit(&vararg);
2143 V_VT(&vararg) = VT_BSTR;
2144 V_BSTR(&vararg) = SysAllocString(szTwo);
2145 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_I4);
2146 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
2147 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
2148 VariantClear(&varresult);
2150 memset(szString, 0, sizeof(szString));
2151 hr = Installer_RegistryValueW(curr_user, szKey, szThree, szString);
2152 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2153 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
2155 memset(szString, 0, sizeof(szString));
2156 hr = Installer_RegistryValueW(curr_user, szKey, szFour, szString);
2157 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2158 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
2160 /* Vista does not NULL-terminate this case */
2161 memset(szString, 0, sizeof(szString));
2162 hr = Installer_RegistryValueW(curr_user, szKey, szFive, szString);
2163 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2164 ok_w2n("Registry value \"%s\" does not match expected \"%s\"\n",
2165 szString, szFiveHi, lstrlenW(szFiveHi));
2167 memset(szString, 0, sizeof(szString));
2168 hr = Installer_RegistryValueW(curr_user, szKey, szSix, szString);
2169 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2170 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_);
2172 VariantInit(&vararg);
2173 V_VT(&vararg) = VT_BSTR;
2174 V_BSTR(&vararg) = SysAllocString(szSeven);
2175 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_EMPTY);
2176 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
2178 /* Get string class name for the key */
2179 memset(szString, 0, sizeof(szString));
2180 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
2181 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2182 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank);
2184 /* Get name of a value by positive number (RegEnumValue like), valid index */
2185 memset(szString, 0, sizeof(szString));
2186 hr = Installer_RegistryValueI(curr_user, szKey, 2, szString, VT_BSTR);
2187 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2188 /* RegEnumValue order seems different on wine */
2189 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
2191 /* Get name of a value by positive number (RegEnumValue like), invalid index */
2192 memset(szString, 0, sizeof(szString));
2193 hr = Installer_RegistryValueI(curr_user, szKey, 10, szString, VT_EMPTY);
2194 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2196 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
2197 memset(szString, 0, sizeof(szString));
2198 hr = Installer_RegistryValueI(curr_user, szKey, -1, szString, VT_BSTR);
2199 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2200 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
2202 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
2203 memset(szString, 0, sizeof(szString));
2204 hr = Installer_RegistryValueI(curr_user, szKey, -10, szString, VT_EMPTY);
2205 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2207 /* clean up */
2208 delete_key(hkey);
2211 static void test_Installer_Products(BOOL bProductInstalled)
2213 WCHAR szString[MAX_PATH];
2214 HRESULT hr;
2215 int idx;
2216 IUnknown *pUnk = NULL;
2217 IEnumVARIANT *pEnum = NULL;
2218 VARIANT var;
2219 ULONG celt;
2220 int iCount, iValue;
2221 IDispatch *pStringList = NULL;
2222 BOOL bProductFound = FALSE;
2224 /* Installer::Products */
2225 hr = Installer_Products(&pStringList);
2226 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
2227 if (hr == S_OK)
2229 /* StringList::_NewEnum */
2230 hr = StringList__NewEnum(pStringList, &pUnk);
2231 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
2232 if (hr == S_OK)
2234 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
2235 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2237 if (!pEnum)
2238 skip("IEnumVARIANT tests\n");
2240 /* StringList::Count */
2241 hr = StringList_Count(pStringList, &iCount);
2242 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2244 for (idx=0; idx<iCount; idx++)
2246 /* StringList::Item */
2247 memset(szString, 0, sizeof(szString));
2248 hr = StringList_Item(pStringList, idx, szString);
2249 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2251 if (hr == S_OK)
2253 /* Installer::ProductState */
2254 hr = Installer_ProductState(szString, &iValue);
2255 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2256 if (hr == S_OK)
2257 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
2259 /* Not found our product code yet? Check */
2260 if (!bProductFound && !strcmp_ww(szString, szProductCode))
2261 bProductFound = TRUE;
2263 /* IEnumVARIANT::Next */
2264 if (pEnum)
2266 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2267 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2268 ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
2269 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2270 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2271 VariantClear(&var);
2276 if (bProductInstalled)
2278 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
2279 bProductInstalled ? "be" : "not be",
2280 bProductFound ? "found" : "not found");
2283 if (pEnum)
2285 IEnumVARIANT *pEnum2 = NULL;
2287 if (0) /* Crashes on Windows XP */
2289 /* IEnumVARIANT::Clone, NULL pointer */
2290 hr = IEnumVARIANT_Clone(pEnum, NULL);
2293 /* IEnumVARIANT::Clone */
2294 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
2295 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
2296 if (hr == S_OK)
2298 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
2300 /* IEnumVARIANT::Next of the clone */
2301 if (iCount)
2303 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
2304 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2305 ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
2306 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2307 VariantClear(&var);
2309 else
2310 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
2312 IEnumVARIANT_Release(pEnum2);
2315 /* IEnumVARIANT::Skip should fail */
2316 hr = IEnumVARIANT_Skip(pEnum, 1);
2317 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2319 /* IEnumVARIANT::Next, NULL variant pointer */
2320 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2321 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2322 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2324 /* IEnumVARIANT::Next, should not return any more items */
2325 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2326 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2327 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2328 VariantClear(&var);
2330 /* IEnumVARIANT::Reset */
2331 hr = IEnumVARIANT_Reset(pEnum);
2332 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2334 if (iCount)
2336 /* IEnumVARIANT::Skip to the last product */
2337 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2338 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2340 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2341 * NULL celt pointer. */
2342 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2343 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2344 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2345 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2346 VariantClear(&var);
2348 else
2349 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2352 /* StringList::Item using an invalid index */
2353 memset(szString, 0, sizeof(szString));
2354 hr = StringList_Item(pStringList, iCount, szString);
2355 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2357 if (pEnum) IEnumVARIANT_Release(pEnum);
2358 if (pUnk) IUnknown_Release(pUnk);
2359 IDispatch_Release(pStringList);
2363 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2364 * deleting the subkeys first) */
2365 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey, REGSAM access)
2367 UINT ret;
2368 CHAR *string = NULL;
2369 HKEY hkey;
2370 DWORD dwSize;
2372 ret = RegOpenKeyEx(hkeyParent, subkey, 0, access, &hkey);
2373 if (ret != ERROR_SUCCESS) return ret;
2374 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2375 if (ret != ERROR_SUCCESS) return ret;
2376 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2378 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2379 delete_registry_key(hkey, string, access);
2381 RegCloseKey(hkey);
2382 HeapFree(GetProcessHeap(), 0, string);
2383 delete_key_portable(hkeyParent, subkey, access);
2384 return ERROR_SUCCESS;
2387 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2388 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, REGSAM access, HKEY *phkey)
2390 UINT ret;
2391 CHAR *string = NULL;
2392 int idx = 0;
2393 HKEY hkey;
2394 DWORD dwSize;
2395 BOOL found = FALSE;
2397 *phkey = 0;
2399 ret = RegOpenKeyEx(hkeyParent, subkey, 0, access, &hkey);
2400 if (ret != ERROR_SUCCESS) return ret;
2401 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2402 if (ret != ERROR_SUCCESS) return ret;
2403 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2405 while (!found &&
2406 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2408 if (!strcmp(string, findkey))
2410 *phkey = hkey;
2411 found = TRUE;
2413 else if (find_registry_key(hkey, string, findkey, access, phkey) == ERROR_SUCCESS) found = TRUE;
2416 if (*phkey != hkey) RegCloseKey(hkey);
2417 HeapFree(GetProcessHeap(), 0, string);
2418 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2421 static void test_Installer_InstallProduct(void)
2423 HRESULT hr;
2424 CHAR path[MAX_PATH];
2425 WCHAR szString[MAX_PATH];
2426 LONG res;
2427 HKEY hkey;
2428 DWORD num, size, type;
2429 int iValue, iCount;
2430 IDispatch *pStringList = NULL;
2431 REGSAM access = KEY_ALL_ACCESS;
2433 if (is_wow64)
2434 access |= KEY_WOW64_64KEY;
2436 create_test_files();
2438 /* Avoid an interactive dialog in case of insufficient privileges. */
2439 hr = Installer_UILevelPut(INSTALLUILEVEL_NONE);
2440 ok(hr == S_OK, "Expected UILevel propery put invoke to return S_OK, got 0x%08x\n", hr);
2442 /* Installer::InstallProduct */
2443 hr = Installer_InstallProduct(szMsifile, NULL);
2444 if (hr == DISP_E_EXCEPTION)
2446 skip("InstallProduct failed, insufficient rights?\n");
2447 delete_test_files();
2448 return;
2450 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2452 /* Installer::ProductState for our product code, which has been installed */
2453 hr = Installer_ProductState(szProductCode, &iValue);
2454 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2455 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2457 /* Installer::ProductInfo for our product code */
2459 /* NULL attribute */
2460 memset(szString, 0, sizeof(szString));
2461 hr = Installer_ProductInfo(szProductCode, NULL, szString);
2462 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2463 ok_exception(hr, szProductInfoException);
2465 /* Nonexistent attribute */
2466 memset(szString, 0, sizeof(szString));
2467 hr = Installer_ProductInfo(szProductCode, szMsifile, szString);
2468 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2469 ok_exception(hr, szProductInfoException);
2471 /* Package name */
2472 memset(szString, 0, sizeof(szString));
2473 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szString);
2474 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2475 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile);
2477 /* Product name */
2478 memset(szString, 0, sizeof(szString));
2479 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PRODUCTNAMEW, szString);
2480 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2481 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST);
2483 /* Installer::Products */
2484 test_Installer_Products(TRUE);
2486 /* Installer::RelatedProducts for our upgrade code */
2487 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2488 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2489 if (hr == S_OK)
2491 /* StringList::Count */
2492 hr = StringList_Count(pStringList, &iCount);
2493 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2494 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2496 /* StringList::Item */
2497 memset(szString, 0, sizeof(szString));
2498 hr = StringList_Item(pStringList, 0, szString);
2499 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2500 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
2502 IDispatch_Release(pStringList);
2505 /* Check & clean up installed files & registry keys */
2506 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2507 ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
2508 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2509 ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
2510 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2511 ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
2512 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2513 ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
2514 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2515 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2516 ok(delete_pf("msitest", FALSE), "File not installed\n");
2518 res = RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest", &hkey);
2519 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2521 size = MAX_PATH;
2522 type = REG_SZ;
2523 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2524 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2525 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2527 size = MAX_PATH;
2528 type = REG_SZ;
2529 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2530 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2532 size = sizeof(num);
2533 type = REG_DWORD;
2534 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2535 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2536 ok(num == 314, "Expected 314, got %d\n", num);
2538 size = MAX_PATH;
2539 type = REG_SZ;
2540 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2541 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2542 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2544 RegCloseKey(hkey);
2546 res = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest");
2547 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2549 /* Remove registry keys written by RegisterProduct standard action */
2550 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2551 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F1C3AF50-8B56-4A69-A00C-00773FE42F30}",
2552 KEY_WOW64_32KEY);
2553 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2555 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2556 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656", access);
2557 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2559 res = find_registry_key(HKEY_LOCAL_MACHINE,
2560 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "05FA3C1F65B896A40AC00077F34EF203", access, &hkey);
2561 ok(res == ERROR_SUCCESS ||
2562 broken(res == ERROR_FILE_NOT_FOUND), /* win9x */
2563 "Expected ERROR_SUCCESS, got %d\n", res);
2564 if (res == ERROR_SUCCESS)
2566 res = delete_registry_key(hkey, "05FA3C1F65B896A40AC00077F34EF203", access);
2567 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2568 RegCloseKey(hkey);
2570 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2571 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203", access);
2572 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2574 else
2576 /* win9x defaults to a per-machine install. */
2577 delete_key_portable(HKEY_LOCAL_MACHINE,
2578 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203", access);
2581 /* Remove registry keys written by PublishProduct standard action */
2582 res = RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2583 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2585 res = delete_registry_key(hkey, "Products\\05FA3C1F65B896A40AC00077F34EF203", KEY_ALL_ACCESS);
2586 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2588 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2589 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2591 RegCloseKey(hkey);
2593 /* Delete installation files we installed */
2594 delete_test_files();
2597 static void test_Installer(void)
2599 static WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
2600 static WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
2601 WCHAR szPath[MAX_PATH];
2602 HRESULT hr;
2603 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL;
2604 int iValue, iCount;
2606 if (!pInstaller) return;
2608 /* Installer::CreateRecord */
2610 /* Test for error */
2611 hr = Installer_CreateRecord(-1, &pRecord);
2612 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2613 ok_exception(hr, szCreateRecordException);
2615 /* Test for success */
2616 hr = Installer_CreateRecord(1, &pRecord);
2617 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2618 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2619 if (pRecord)
2621 /* Record::FieldCountGet */
2622 hr = Record_FieldCountGet(pRecord, &iValue);
2623 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2624 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2626 /* Record::IntegerDataGet */
2627 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2628 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2629 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2631 /* Record::IntegerDataGet, bad index */
2632 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2633 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2634 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2636 /* Record::IntegerDataPut */
2637 hr = Record_IntegerDataPut(pRecord, 1, 100);
2638 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2640 /* Record::IntegerDataPut, bad index */
2641 hr = Record_IntegerDataPut(pRecord, 10, 100);
2642 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2643 ok_exception(hr, szIntegerDataException);
2645 /* Record::IntegerDataGet */
2646 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2647 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2648 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2650 IDispatch_Release(pRecord);
2653 create_package(szPath);
2655 /* Installer::OpenPackage */
2656 hr = Installer_OpenPackage(szPath, 0, &pSession);
2657 if (hr == DISP_E_EXCEPTION)
2659 skip("OpenPackage failed, insufficient rights?\n");
2660 DeleteFileW(szPath);
2661 return;
2663 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2664 if (hr == S_OK)
2666 test_Session(pSession);
2667 IDispatch_Release(pSession);
2670 /* Installer::OpenDatabase */
2671 hr = Installer_OpenDatabase(szPath, (INT_PTR)MSIDBOPEN_TRANSACT, &pDatabase);
2672 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2673 if (hr == S_OK)
2675 test_Database(pDatabase, FALSE);
2676 IDispatch_Release(pDatabase);
2679 /* Installer::RegistryValue */
2680 test_Installer_RegistryValue();
2682 /* Installer::ProductState for our product code, which should not be installed */
2683 hr = Installer_ProductState(szProductCode, &iValue);
2684 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2685 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2687 /* Installer::ProductInfo for our product code, which should not be installed */
2689 /* Package name */
2690 memset(szPath, 0, sizeof(szPath));
2691 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szPath);
2692 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2693 ok_exception(hr, szProductInfoException);
2695 /* NULL attribute and NULL product code */
2696 memset(szPath, 0, sizeof(szPath));
2697 hr = Installer_ProductInfo(NULL, NULL, szPath);
2698 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2699 ok_exception(hr, szProductInfoException);
2701 /* Installer::Products */
2702 test_Installer_Products(FALSE);
2704 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2705 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2706 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2707 if (hr == S_OK)
2709 /* StringList::Count */
2710 hr = StringList_Count(pStringList, &iCount);
2711 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2712 ok(!iCount, "Expected no related products but found %d\n", iCount);
2714 IDispatch_Release(pStringList);
2717 /* Installer::Version */
2718 memset(szPath, 0, sizeof(szPath));
2719 hr = Installer_VersionGet(szPath);
2720 ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr);
2722 /* Installer::InstallProduct and other tests that depend on our product being installed */
2723 test_Installer_InstallProduct();
2726 START_TEST(automation)
2728 DWORD len;
2729 char temp_path[MAX_PATH], prev_path[MAX_PATH];
2730 HRESULT hr;
2731 CLSID clsid;
2732 IUnknown *pUnk;
2734 init_functionpointers();
2736 if (pIsWow64Process)
2737 pIsWow64Process(GetCurrentProcess(), &is_wow64);
2739 GetSystemTimeAsFileTime(&systemtime);
2741 GetCurrentDirectoryA(MAX_PATH, prev_path);
2742 GetTempPath(MAX_PATH, temp_path);
2743 SetCurrentDirectoryA(temp_path);
2745 lstrcpyA(CURR_DIR, temp_path);
2746 len = lstrlenA(CURR_DIR);
2748 if(len && (CURR_DIR[len - 1] == '\\'))
2749 CURR_DIR[len - 1] = 0;
2751 get_program_files_dir(PROG_FILES_DIR);
2753 hr = OleInitialize(NULL);
2754 ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr);
2755 hr = CLSIDFromProgID(szProgId, &clsid);
2756 ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr);
2757 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2758 ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr);
2760 if (pUnk)
2762 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2763 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2765 test_dispid();
2766 test_dispatch();
2767 test_Installer();
2769 IDispatch_Release(pInstaller);
2770 IUnknown_Release(pUnk);
2773 OleUninitialize();
2775 SetCurrentDirectoryA(prev_path);