wer: Add new stubbed wer.dll.
[wine/hramrach.git] / dlls / msi / tests / automation.c
blobf883eacad6f24efb5eb801c1c2f08270b880e151
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 LONG (WINAPI *pRegDeleteKeyExA)(HKEY, LPCSTR, REGSAM, DWORD);
36 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
38 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
40 static const char *msifile = "winetest-automation.msi";
41 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};
42 static const WCHAR szMSITEST[] = { 'M','S','I','T','E','S','T',0 };
43 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 };
44 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 };
45 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 };
46 static const WCHAR WINE_INSTALLPROPERTY_PACKAGENAMEW[] = {'P','a','c','k','a','g','e','N','a','m','e',0};
47 static const WCHAR WINE_INSTALLPROPERTY_PRODUCTNAMEW[] = {'P','r','o','d','u','c','t','N','a','m','e',0};
48 static FILETIME systemtime;
49 static CHAR CURR_DIR[MAX_PATH];
50 static EXCEPINFO excepinfo;
53 * OLE automation data
54 **/
55 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 };
56 static IDispatch *pInstaller;
58 /* msi database data */
60 static const CHAR component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
61 "s72\tS38\ts72\ti2\tS255\tS72\n"
62 "Component\tComponent\n"
63 "Five\t{8CC92E9D-14B2-4CA4-B2AA-B11D02078087}\tNEWDIR\t2\t\tfive.txt\n"
64 "Four\t{FD37B4EA-7209-45C0-8917-535F35A2F080}\tCABOUTDIR\t2\t\tfour.txt\n"
65 "One\t{783B242E-E185-4A56-AF86-C09815EC053C}\tMSITESTDIR\t2\t\tone.txt\n"
66 "Three\t{010B6ADD-B27D-4EDD-9B3D-34C4F7D61684}\tCHANGEDDIR\t2\t\tthree.txt\n"
67 "Two\t{BF03D1A6-20DA-4A65-82F3-6CAC995915CE}\tFIRSTDIR\t2\t\ttwo.txt\n"
68 "dangler\t{6091DF25-EF96-45F1-B8E9-A9B1420C7A3C}\tTARGETDIR\t4\t\tregdata\n"
69 "component\t\tMSITESTDIR\t0\t1\tfile\n";
71 static const CHAR directory_dat[] = "Directory\tDirectory_Parent\tDefaultDir\n"
72 "s72\tS72\tl255\n"
73 "Directory\tDirectory\n"
74 "CABOUTDIR\tMSITESTDIR\tcabout\n"
75 "CHANGEDDIR\tMSITESTDIR\tchanged:second\n"
76 "FIRSTDIR\tMSITESTDIR\tfirst\n"
77 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
78 "NEWDIR\tCABOUTDIR\tnew\n"
79 "ProgramFilesFolder\tTARGETDIR\t.\n"
80 "TARGETDIR\t\tSourceDir";
82 static const CHAR feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
83 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
84 "Feature\tFeature\n"
85 "Five\t\tFive\tThe Five Feature\t5\t3\tNEWDIR\t0\n"
86 "Four\t\tFour\tThe Four Feature\t4\t3\tCABOUTDIR\t0\n"
87 "One\t\tOne\tThe One Feature\t1\t3\tMSITESTDIR\t0\n"
88 "Three\tOne\tThree\tThe Three Feature\t3\t3\tCHANGEDDIR\t0\n"
89 "Two\tOne\tTwo\tThe Two Feature\t2\t3\tFIRSTDIR\t0\n"
90 "feature\t\t\t\t2\t1\tTARGETDIR\t0\n";
92 static const CHAR feature_comp_dat[] = "Feature_\tComponent_\n"
93 "s38\ts72\n"
94 "FeatureComponents\tFeature_\tComponent_\n"
95 "Five\tFive\n"
96 "Four\tFour\n"
97 "One\tOne\n"
98 "Three\tThree\n"
99 "Two\tTwo\n"
100 "feature\tcomponent\n";
102 static const CHAR file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
103 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
104 "File\tFile\n"
105 "five.txt\tFive\tfive.txt\t1000\t\t\t0\t5\n"
106 "four.txt\tFour\tfour.txt\t1000\t\t\t0\t4\n"
107 "one.txt\tOne\tone.txt\t1000\t\t\t0\t1\n"
108 "three.txt\tThree\tthree.txt\t1000\t\t\t0\t3\n"
109 "two.txt\tTwo\ttwo.txt\t1000\t\t\t0\t2\n"
110 "file\tcomponent\tfilename\t100\t\t\t8192\t1\n";
112 static const CHAR install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
113 "s72\tS255\tI2\n"
114 "InstallExecuteSequence\tAction\n"
115 "AllocateRegistrySpace\tNOT Installed\t1550\n"
116 "CostFinalize\t\t1000\n"
117 "CostInitialize\t\t800\n"
118 "FileCost\t\t900\n"
119 "InstallFiles\t\t4000\n"
120 "RegisterProduct\t\t6100\n"
121 "PublishProduct\t\t6400\n"
122 "InstallFinalize\t\t6600\n"
123 "InstallInitialize\t\t1500\n"
124 "InstallValidate\t\t1400\n"
125 "LaunchConditions\t\t100\n"
126 "WriteRegistryValues\tSourceDir And SOURCEDIR\t5000";
128 static const CHAR media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
129 "i2\ti4\tL64\tS255\tS32\tS72\n"
130 "Media\tDiskId\n"
131 "1\t5\t\t\tDISK1\t\n";
133 static const CHAR property_dat[] = "Property\tValue\n"
134 "s72\tl0\n"
135 "Property\tProperty\n"
136 "DefaultUIFont\tDlgFont8\n"
137 "HASUIRUN\t0\n"
138 "INSTALLLEVEL\t3\n"
139 "InstallMode\tTypical\n"
140 "Manufacturer\tWine\n"
141 "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n"
142 "ProductCode\t{F1C3AF50-8B56-4A69-A00C-00773FE42F30}\n"
143 "ProductID\tnone\n"
144 "ProductLanguage\t1033\n"
145 "ProductName\tMSITEST\n"
146 "ProductVersion\t1.1.1\n"
147 "PROMPTROLLBACKCOST\tP\n"
148 "Setup\tSetup\n"
149 "UpgradeCode\t{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}";
151 static const CHAR registry_dat[] = "Registry\tRoot\tKey\tName\tValue\tComponent_\n"
152 "s72\ti2\tl255\tL255\tL0\ts72\n"
153 "Registry\tRegistry\n"
154 "Apples\t1\tSOFTWARE\\Wine\\msitest\tName\timaname\tOne\n"
155 "Oranges\t1\tSOFTWARE\\Wine\\msitest\tnumber\t#314\tTwo\n"
156 "regdata\t1\tSOFTWARE\\Wine\\msitest\tblah\tbad\tdangler\n"
157 "OrderTest\t1\tSOFTWARE\\Wine\\msitest\tOrderTestName\tOrderTestValue\tcomponent";
159 typedef struct _msi_table
161 const CHAR *filename;
162 const CHAR *data;
163 int size;
164 } msi_table;
166 #define ADD_TABLE(x) {#x".idt", x##_dat, sizeof(x##_dat)}
168 static const msi_table tables[] =
170 ADD_TABLE(component),
171 ADD_TABLE(directory),
172 ADD_TABLE(feature),
173 ADD_TABLE(feature_comp),
174 ADD_TABLE(file),
175 ADD_TABLE(install_exec_seq),
176 ADD_TABLE(media),
177 ADD_TABLE(property),
178 ADD_TABLE(registry)
181 typedef struct _msi_summary_info
183 UINT property;
184 UINT datatype;
185 INT iValue;
186 FILETIME *pftValue;
187 const CHAR *szValue;
188 } msi_summary_info;
190 #define ADD_INFO_I2(property, iValue) {property, VT_I2, iValue, NULL, NULL}
191 #define ADD_INFO_I4(property, iValue) {property, VT_I4, iValue, NULL, NULL}
192 #define ADD_INFO_LPSTR(property, szValue) {property, VT_LPSTR, 0, NULL, szValue}
193 #define ADD_INFO_FILETIME(property, pftValue) {property, VT_FILETIME, 0, pftValue, NULL}
195 static const msi_summary_info summary_info[] =
197 ADD_INFO_LPSTR(PID_TEMPLATE, ";1033"),
198 ADD_INFO_LPSTR(PID_REVNUMBER, "{004757CA-5092-49c2-AD20-28E1CE0DF5F2}"),
199 ADD_INFO_I4(PID_PAGECOUNT, 100),
200 ADD_INFO_I4(PID_WORDCOUNT, 0),
201 ADD_INFO_FILETIME(PID_CREATE_DTM, &systemtime),
202 ADD_INFO_FILETIME(PID_LASTPRINTED, &systemtime)
205 static void init_functionpointers(void)
207 HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll");
208 HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
210 #define GET_PROC(dll, func) \
211 p ## func = (void *)GetProcAddress(dll, #func); \
212 if(!p ## func) \
213 trace("GetProcAddress(%s) failed\n", #func);
215 GET_PROC(hadvapi32, RegDeleteKeyExA)
216 GET_PROC(hkernel32, IsWow64Process)
218 #undef GET_PROC
221 static LONG delete_key_portable( HKEY key, LPCSTR subkey, REGSAM access )
223 if (pRegDeleteKeyExA)
224 return pRegDeleteKeyExA( key, subkey, access, 0 );
225 return RegDeleteKeyA( key, subkey );
229 * Database Helpers
232 static void write_file(const CHAR *filename, const char *data, int data_size)
234 DWORD size;
236 HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL,
237 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
239 WriteFile(hf, data, data_size, &size, NULL);
240 CloseHandle(hf);
243 static void write_msi_summary_info(MSIHANDLE db, const msi_summary_info *info, int num_info)
245 MSIHANDLE summary;
246 UINT r;
247 int j;
249 r = MsiGetSummaryInformationA(db, NULL, num_info, &summary);
250 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
252 /* import summary information into the stream */
253 for (j = 0; j < num_info; j++)
255 const msi_summary_info *entry = &info[j];
257 r = MsiSummaryInfoSetPropertyA(summary, entry->property, entry->datatype,
258 entry->iValue, entry->pftValue, entry->szValue);
259 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
262 /* write the summary changes back to the stream */
263 r = MsiSummaryInfoPersist(summary);
264 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
266 MsiCloseHandle(summary);
269 static void create_database(const CHAR *name, const msi_table *tables, int num_tables,
270 const msi_summary_info *info, int num_info)
272 MSIHANDLE db;
273 UINT r;
274 int j;
276 r = MsiOpenDatabaseA(name, MSIDBOPEN_CREATE, &db);
277 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
279 /* import the tables into the database */
280 for (j = 0; j < num_tables; j++)
282 const msi_table *table = &tables[j];
284 write_file(table->filename, table->data, (table->size - 1) * sizeof(char));
286 r = MsiDatabaseImportA(db, CURR_DIR, table->filename);
287 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
289 DeleteFileA(table->filename);
292 write_msi_summary_info(db, info, num_info);
294 r = MsiDatabaseCommit(db);
295 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
297 MsiCloseHandle(db);
300 static BOOL create_package(LPWSTR path)
302 DWORD len;
304 /* Prepare package */
305 create_database(msifile, tables,
306 sizeof(tables) / sizeof(msi_table), summary_info,
307 sizeof(summary_info) / sizeof(msi_summary_info));
309 len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
310 CURR_DIR, -1, path, MAX_PATH);
311 ok(len, "MultiByteToWideChar returned error %d\n", GetLastError());
312 if (!len)
313 return FALSE;
315 /* lstrcatW does not work on win95 */
316 path[len - 1] = '\\';
317 memcpy(&path[len], szMsifile, sizeof(szMsifile));
318 return TRUE;
322 * Installation helpers
325 static char PROG_FILES_DIR[MAX_PATH];
327 static BOOL get_program_files_dir(LPSTR buf)
329 HKEY hkey;
330 DWORD type = REG_EXPAND_SZ, size;
332 if (RegOpenKey(HKEY_LOCAL_MACHINE,
333 "Software\\Microsoft\\Windows\\CurrentVersion", &hkey))
334 return FALSE;
336 size = MAX_PATH;
337 if (RegQueryValueEx(hkey, "ProgramFilesDir (x86)", 0, &type, (LPBYTE)buf, &size) &&
338 RegQueryValueEx(hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size))
339 return FALSE;
341 RegCloseKey(hkey);
342 return TRUE;
345 static void create_file(const CHAR *name, DWORD size)
347 HANDLE file;
348 DWORD written, left;
350 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
351 ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
352 WriteFile(file, name, strlen(name), &written, NULL);
353 WriteFile(file, "\n", strlen("\n"), &written, NULL);
355 left = size - lstrlen(name) - 1;
357 SetFilePointer(file, left, NULL, FILE_CURRENT);
358 SetEndOfFile(file);
360 CloseHandle(file);
363 static void create_test_files(void)
365 CreateDirectoryA("msitest", NULL);
366 create_file("msitest\\one.txt", 100);
367 CreateDirectoryA("msitest\\first", NULL);
368 create_file("msitest\\first\\two.txt", 100);
369 CreateDirectoryA("msitest\\second", NULL);
370 create_file("msitest\\second\\three.txt", 100);
371 CreateDirectoryA("msitest\\cabout",NULL);
372 create_file("msitest\\cabout\\four.txt", 100);
373 CreateDirectoryA("msitest\\cabout\\new",NULL);
374 create_file("msitest\\cabout\\new\\five.txt", 100);
375 create_file("msitest\\filename", 100);
378 static BOOL delete_pf(const CHAR *rel_path, BOOL is_file)
380 CHAR path[MAX_PATH];
382 lstrcpyA(path, PROG_FILES_DIR);
383 lstrcatA(path, "\\");
384 lstrcatA(path, rel_path);
386 if (is_file)
387 return DeleteFileA(path);
388 else
389 return RemoveDirectoryA(path);
392 static void delete_test_files(void)
394 DeleteFileA(msifile);
395 DeleteFileA("msitest\\cabout\\new\\five.txt");
396 DeleteFileA("msitest\\cabout\\four.txt");
397 DeleteFileA("msitest\\second\\three.txt");
398 DeleteFileA("msitest\\first\\two.txt");
399 DeleteFileA("msitest\\one.txt");
400 DeleteFileA("msitest\\filename");
401 RemoveDirectoryA("msitest\\cabout\\new");
402 RemoveDirectoryA("msitest\\cabout");
403 RemoveDirectoryA("msitest\\second");
404 RemoveDirectoryA("msitest\\first");
405 RemoveDirectoryA("msitest");
409 * Automation helpers and tests
412 /* ok-like statement which takes two unicode strings or one unicode and one ANSI string as arguments */
413 static CHAR string1[MAX_PATH], string2[MAX_PATH];
415 /* lstrcmpW is not supported on Win9x */
416 static int strcmp_ww(const WCHAR* str1, const WCHAR* str2)
418 CHAR str1A[MAX_PATH], str2A[MAX_PATH];
420 WideCharToMultiByte(CP_ACP, 0, str1, -1, str1A, MAX_PATH, NULL, NULL);
421 WideCharToMultiByte(CP_ACP, 0, str2, -1, str2A, MAX_PATH, NULL, NULL);
423 return lstrcmpA(str1A, str2A);
426 #define ok_w2(format, szString1, szString2) \
428 do { \
429 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
430 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
431 if (lstrcmpA(string1, string2) != 0) \
432 ok(0, format, string1, string2); \
433 } while(0);
435 #define ok_w2n(format, szString1, szString2, len) \
437 if (memcmp(szString1, szString2, len * sizeof(WCHAR)) != 0) \
439 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
440 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
441 ok(0, format, string1, string2); \
444 #define ok_aw(format, aString, wString) \
446 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
447 if (lstrcmpA(string1, aString) != 0) \
448 ok(0, format, string1, aString); \
450 #define ok_awplus(format, extra, aString, wString) \
452 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
453 if (lstrcmpA(string1, aString) != 0) \
454 ok(0, format, extra, string1, aString); \
456 /* exception checker */
457 static WCHAR szSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
459 #define ok_exception(hr, szDescription) \
460 if (hr == DISP_E_EXCEPTION) \
462 /* Compare wtype, source, and destination */ \
463 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
465 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
466 if (excepinfo.bstrSource) \
467 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, szSource); \
469 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
470 if (excepinfo.bstrDescription) \
471 ok_w2("Exception description was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrDescription, szDescription); \
473 SysFreeString(excepinfo.bstrSource); \
474 SysFreeString(excepinfo.bstrDescription); \
475 SysFreeString(excepinfo.bstrHelpFile); \
478 static DISPID get_dispid( IDispatch *disp, const char *name )
480 LPOLESTR str;
481 UINT len;
482 DISPID id = -1;
483 HRESULT r;
485 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
486 str = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
487 if (str)
489 len = MultiByteToWideChar(CP_ACP, 0, name, -1, str, len );
490 r = IDispatch_GetIDsOfNames( disp, &IID_NULL, &str, 1, 0, &id );
491 HeapFree(GetProcessHeap(), 0, str);
492 if (r != S_OK)
493 return -1;
496 return id;
499 static void test_dispid(void)
501 DISPID dispid;
503 dispid = get_dispid(pInstaller, "CreateRecord");
504 ok(dispid == 1, "Expected 1, got %d\n", dispid);
505 dispid = get_dispid(pInstaller, "OpenPackage");
506 ok(dispid == 2, "Expected 2, got %d\n", dispid);
507 dispid = get_dispid(pInstaller, "OpenProduct");
508 ok(dispid == 3, "Expected 3, got %d\n", dispid);
509 dispid = get_dispid(pInstaller, "OpenDatabase");
510 ok(dispid == 4, "Expected 4, got %d\n", dispid);
511 dispid = get_dispid(pInstaller, "SummaryInformation");
512 ok(dispid == 5, "Expected 5, got %d\n", dispid);
513 dispid = get_dispid( pInstaller, "UILevel" );
514 ok(dispid == 6, "Expected 6, got %d\n", dispid);
515 dispid = get_dispid(pInstaller, "EnableLog");
516 ok(dispid == 7, "Expected 7, got %d\n", dispid);
517 dispid = get_dispid(pInstaller, "InstallProduct");
518 ok(dispid == 8, "Expected 8, got %d\n", dispid);
519 dispid = get_dispid(pInstaller, "Version");
520 ok(dispid == 9, "Expected 9, got %d\n", dispid);
521 dispid = get_dispid(pInstaller, "LastErrorRecord");
522 ok(dispid == 10, "Expected 10, got %d\n", dispid);
523 dispid = get_dispid(pInstaller, "RegistryValue");
524 ok(dispid == 11, "Expected 11, got %d\n", dispid);
525 dispid = get_dispid(pInstaller, "Environment");
526 ok(dispid == 12, "Expected 12, got %d\n", dispid);
527 dispid = get_dispid(pInstaller, "FileAttributes");
528 ok(dispid == 13, "Expected 13, got %d\n", dispid);
529 dispid = get_dispid(pInstaller, "FileSize");
530 ok(dispid == 15, "Expected 15, got %d\n", dispid);
531 dispid = get_dispid(pInstaller, "FileVersion");
532 ok(dispid == 16, "Expected 16, got %d\n", dispid);
533 dispid = get_dispid(pInstaller, "ProductState");
534 ok(dispid == 17, "Expected 17, got %d\n", dispid);
535 dispid = get_dispid(pInstaller, "ProductInfo");
536 ok(dispid == 18, "Expected 18, got %d\n", dispid);
537 todo_wine
539 dispid = get_dispid(pInstaller, "ConfigureProduct");
540 ok(dispid == 19, "Expected 19, got %d\n", dispid);
541 dispid = get_dispid(pInstaller, "ReinstallProduct");
542 ok(dispid == 20 , "Expected 20, got %d\n", dispid);
543 dispid = get_dispid(pInstaller, "CollectUserInfo");
544 ok(dispid == 21, "Expected 21, got %d\n", dispid);
545 dispid = get_dispid(pInstaller, "ApplyPatch");
546 ok(dispid == 22, "Expected 22, got %d\n", dispid);
547 dispid = get_dispid(pInstaller, "FeatureParent");
548 ok(dispid == 23, "Expected 23, got %d\n", dispid);
549 dispid = get_dispid(pInstaller, "FeatureState");
550 ok(dispid == 24, "Expected 24, got %d\n", dispid);
551 dispid = get_dispid(pInstaller, "UseFeature");
552 ok(dispid == 25, "Expected 25, got %d\n", dispid);
553 dispid = get_dispid(pInstaller, "FeatureUsageCount");
554 ok(dispid == 26, "Expected 26, got %d\n", dispid);
555 dispid = get_dispid(pInstaller, "FeatureUsageDate");
556 ok(dispid == 27, "Expected 27, got %d\n", dispid);
557 dispid = get_dispid(pInstaller, "ConfigureFeature");
558 ok(dispid == 28, "Expected 28, got %d\n", dispid);
559 dispid = get_dispid(pInstaller, "ReinstallFeature");
560 ok(dispid == 29, "Expected 29, got %d\n", dispid);
561 dispid = get_dispid(pInstaller, "ProvideComponent");
562 ok(dispid == 30, "Expected 30, got %d\n", dispid);
563 dispid = get_dispid(pInstaller, "ComponentPath");
564 ok(dispid == 31, "Expected 31, got %d\n", dispid);
565 dispid = get_dispid(pInstaller, "ProvideQualifiedComponent");
566 ok(dispid == 32, "Expected 32, got %d\n", dispid);
567 dispid = get_dispid(pInstaller, "QualifierDescription");
568 ok(dispid == 33, "Expected 33, got %d\n", dispid);
569 dispid = get_dispid(pInstaller, "ComponentQualifiers");
570 ok(dispid == 34, "Expected 34, got %d\n", dispid);
572 dispid = get_dispid(pInstaller, "Products");
573 ok(dispid == 35, "Expected 35, got %d\n", dispid);
574 todo_wine
576 dispid = get_dispid(pInstaller, "Features");
577 ok(dispid == 36, "Expected 36, got %d\n", dispid);
578 dispid = get_dispid(pInstaller, "Components");
579 ok(dispid == 37, "Expected 37, got %d\n", dispid);
580 dispid = get_dispid(pInstaller, "ComponentClients");
581 ok(dispid == 38, "Expected 38, got %d\n", dispid);
582 dispid = get_dispid(pInstaller, "Patches");
583 ok(dispid == 39, "Expected 39, got %d\n", dispid);
585 dispid = get_dispid(pInstaller, "RelatedProducts");
586 ok(dispid == 40, "Expected 40, got %d\n", dispid);
587 todo_wine
589 dispid = get_dispid(pInstaller, "PatchInfo");
590 ok(dispid == 41, "Expected 41, got %d\n", dispid);
591 dispid = get_dispid(pInstaller, "PatchTransforms");
592 ok(dispid == 42, "Expected 42, got %d\n", dispid);
593 dispid = get_dispid(pInstaller, "AddSource");
594 ok(dispid == 43, "Expected 43, got %d\n", dispid);
595 dispid = get_dispid(pInstaller, "ClearSourceList");
596 ok(dispid == 44, "Expected 44, got %d\n", dispid);
597 dispid = get_dispid(pInstaller, "ForceSourceListResolution");
598 ok(dispid == 45, "Expected 45, got %d\n", dispid);
599 dispid = get_dispid(pInstaller, "ShortcutTarget");
600 ok(dispid == 46, "Expected 46, got %d\n", dispid);
601 dispid = get_dispid(pInstaller, "FileHash");
602 ok(dispid == 47, "Expected 47, got %d\n", dispid);
603 dispid = get_dispid(pInstaller, "FileSignatureInfo");
604 ok(dispid == 48, "Expected 48, got %d\n", dispid);
606 dispid = get_dispid(pInstaller, "RemovePatches");
607 ok(dispid == 49 || dispid == -1, "Expected 49 or -1, got %d\n", dispid);
608 dispid = get_dispid(pInstaller, "ApplyMultiplePatches");
609 ok(dispid == 51 || dispid == -1, "Expected 51 or -1, got %d\n", dispid);
610 dispid = get_dispid(pInstaller, "ProductsEx");
611 ok(dispid == 52 || dispid == -1, "Expected 52 or -1, got %d\n", dispid);
612 dispid = get_dispid(pInstaller, "PatchesEx");
613 ok(dispid == 55 || dispid == -1, "Expected 55 or -1, got %d\n", dispid);
614 dispid = get_dispid(pInstaller, "ExtractPatchXMLData");
615 ok(dispid == 57 || dispid == -1, "Expected 57 or -1, got %d\n", dispid);
616 dispid = get_dispid( pInstaller, "ProductElevated" );
617 ok(dispid == 59 || dispid == -1, "Expected 59 or -1, got %d\n", dispid);
618 dispid = get_dispid( pInstaller, "ProvideAssembly" );
619 ok(dispid == 60 || dispid == -1, "Expected 60 or -1, got %d\n", dispid);
620 dispid = get_dispid( pInstaller, "ProductInfoFromScript" );
621 ok(dispid == 61 || dispid == -1, "Expected 61 or -1, got %d\n", dispid);
622 dispid = get_dispid( pInstaller, "AdvertiseProduct" );
623 ok(dispid == 62 || dispid == -1, "Expected 62 or -1, got %d\n", dispid);
624 dispid = get_dispid( pInstaller, "CreateAdvertiseScript" );
625 ok(dispid == 63 || dispid == -1, "Expected 63 or -1, got %d\n", dispid);
626 dispid = get_dispid( pInstaller, "PatchFiles" );
627 ok(dispid == 65 || dispid == -1, "Expected 65 or -1, got %d\n", dispid);
630 /* Test basic IDispatch functions */
631 static void test_dispatch(void)
633 static WCHAR szOpenPackage[] = { 'O','p','e','n','P','a','c','k','a','g','e',0 };
634 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};
635 static WCHAR szProductState[] = { 'P','r','o','d','u','c','t','S','t','a','t','e',0 };
636 HRESULT hr;
637 DISPID dispid;
638 OLECHAR *name;
639 VARIANT varresult;
640 VARIANTARG vararg[3];
641 WCHAR path[MAX_PATH];
642 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
644 /* Test getting ID of a function name that does not exist */
645 name = (WCHAR *)szMsifile;
646 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
647 ok(hr == DISP_E_UNKNOWNNAME, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
649 /* Test invoking this function */
650 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
651 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
653 /* Test getting ID of a function name that does exist */
654 name = szOpenPackage;
655 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
656 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
658 /* Test invoking this function (without parameters passed) */
659 if (0) /* All of these crash MSI on Windows XP */
661 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
662 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL);
663 VariantInit(&varresult);
664 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, &varresult, &excepinfo, NULL);
667 /* Try with NULL params */
668 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
669 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
671 /* Try one empty parameter */
672 dispparams.rgvarg = vararg;
673 dispparams.cArgs = 1;
674 VariantInit(&vararg[0]);
675 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
676 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
678 /* Try two empty parameters */
679 dispparams.cArgs = 2;
680 VariantInit(&vararg[0]);
681 VariantInit(&vararg[1]);
682 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
683 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
685 /* Try one parameter, the required BSTR. Second parameter is optional.
686 * NOTE: The specified package does not exist, which is why the call fails.
688 dispparams.cArgs = 1;
689 VariantInit(&vararg[0]);
690 V_VT(&vararg[0]) = VT_BSTR;
691 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
692 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
693 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
694 ok_exception(hr, szOpenPackageException);
695 VariantClear(&vararg[0]);
697 /* Provide the required BSTR and an empty second parameter.
698 * NOTE: The specified package does not exist, which is why the call fails.
700 dispparams.cArgs = 2;
701 VariantInit(&vararg[1]);
702 V_VT(&vararg[1]) = VT_BSTR;
703 V_BSTR(&vararg[1]) = SysAllocString(szMsifile);
704 VariantInit(&vararg[0]);
705 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
706 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
707 ok_exception(hr, szOpenPackageException);
708 VariantClear(&vararg[1]);
710 /* Provide the required BSTR and two empty parameters.
711 * NOTE: The specified package does not exist, which is why the call fails.
713 dispparams.cArgs = 3;
714 VariantInit(&vararg[2]);
715 V_VT(&vararg[2]) = VT_BSTR;
716 V_BSTR(&vararg[2]) = SysAllocString(szMsifile);
717 VariantInit(&vararg[1]);
718 VariantInit(&vararg[0]);
719 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
720 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
721 ok_exception(hr, szOpenPackageException);
722 VariantClear(&vararg[2]);
724 /* Provide the required BSTR and a second parameter with the wrong type. */
725 dispparams.cArgs = 2;
726 VariantInit(&vararg[1]);
727 V_VT(&vararg[1]) = VT_BSTR;
728 V_BSTR(&vararg[1]) = SysAllocString(szMsifile);
729 VariantInit(&vararg[0]);
730 V_VT(&vararg[0]) = VT_BSTR;
731 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
732 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
733 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
734 VariantClear(&vararg[0]);
735 VariantClear(&vararg[1]);
737 /* Create a proper installer package. */
738 create_package(path);
740 /* Try one parameter, the required BSTR. Second parameter is optional.
741 * Proper installer package exists. Path to the package is relative.
743 dispparams.cArgs = 1;
744 VariantInit(&vararg[0]);
745 V_VT(&vararg[0]) = VT_BSTR;
746 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
747 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
748 todo_wine ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
749 ok_exception(hr, szOpenPackageException);
750 VariantClear(&vararg[0]);
751 if (hr != DISP_E_EXCEPTION)
752 VariantClear(&varresult);
754 /* Try one parameter, the required BSTR. Second parameter is optional.
755 * Proper installer package exists. Path to the package is absolute.
757 dispparams.cArgs = 1;
758 VariantInit(&vararg[0]);
759 V_VT(&vararg[0]) = VT_BSTR;
760 V_BSTR(&vararg[0]) = SysAllocString(path);
761 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
762 if (hr == DISP_E_EXCEPTION)
764 skip("OpenPackage failed, insufficient rights?\n");
765 DeleteFileW(path);
766 return;
768 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
769 VariantClear(&vararg[0]);
770 VariantClear(&varresult);
772 /* Provide the required BSTR and an empty second parameter. Proper
773 * installation package exists.
775 dispparams.cArgs = 2;
776 VariantInit(&vararg[1]);
777 V_VT(&vararg[1]) = VT_BSTR;
778 V_BSTR(&vararg[1]) = SysAllocString(path);
779 VariantInit(&vararg[0]);
780 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
781 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
782 VariantClear(&vararg[1]);
783 VariantClear(&varresult);
785 /* Provide the required BSTR and two empty parameters. Proper
786 * installation package exists.
788 dispparams.cArgs = 3;
789 VariantInit(&vararg[2]);
790 V_VT(&vararg[2]) = VT_BSTR;
791 V_BSTR(&vararg[2]) = SysAllocString(path);
792 VariantInit(&vararg[1]);
793 VariantInit(&vararg[0]);
794 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
795 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
796 VariantClear(&vararg[2]);
797 VariantClear(&varresult);
799 /* Provide the required BSTR and a second parameter with the wrong type. */
800 dispparams.cArgs = 2;
801 VariantInit(&vararg[1]);
802 V_VT(&vararg[1]) = VT_BSTR;
803 V_BSTR(&vararg[1]) = SysAllocString(path);
804 VariantInit(&vararg[0]);
805 V_VT(&vararg[0]) = VT_BSTR;
806 V_BSTR(&vararg[0]) = SysAllocString(path);
807 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
808 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
809 VariantClear(&vararg[0]);
810 VariantClear(&vararg[1]);
812 /* Provide the required BSTR and a second parameter that can be coerced to
813 * VT_I4.
815 dispparams.cArgs = 2;
816 VariantInit(&vararg[1]);
817 V_VT(&vararg[1]) = VT_BSTR;
818 V_BSTR(&vararg[1]) = SysAllocString(path);
819 VariantInit(&vararg[0]);
820 V_VT(&vararg[0]) = VT_I2;
821 V_BSTR(&vararg[0]) = 0;
822 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
823 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
824 VariantClear(&vararg[1]);
825 VariantClear(&varresult);
827 DeleteFileW(path);
829 /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
830 VariantInit(&vararg[0]);
831 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
832 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
834 VariantInit(&vararg[0]);
835 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
836 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
838 /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
839 name = szProductState;
840 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
841 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
843 dispparams.rgvarg = NULL;
844 dispparams.cArgs = 0;
845 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
846 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
848 dispparams.rgvarg = NULL;
849 dispparams.cArgs = 0;
850 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
851 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
854 /* invocation helper function */
855 static int _invoke_todo_vtResult = 0;
857 static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult)
859 OLECHAR *name = NULL;
860 DISPID dispid;
861 HRESULT hr;
862 UINT i;
863 UINT len;
865 memset(pVarResult, 0, sizeof(VARIANT));
866 VariantInit(pVarResult);
868 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 );
869 name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
870 if (!name) return E_FAIL;
871 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len );
872 hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
873 HeapFree(GetProcessHeap(), 0, name);
874 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
875 if (!hr == S_OK) return hr;
877 memset(&excepinfo, 0, sizeof(excepinfo));
878 hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL);
880 if (hr == S_OK)
882 if (_invoke_todo_vtResult) todo_wine
883 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
884 else
885 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
886 if (vtResult != VT_EMPTY)
888 hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult);
889 ok(hr == S_OK, "VariantChangeTypeEx returned 0x%08x\n", hr);
893 for (i=0; i<pDispParams->cArgs; i++)
894 VariantClear(&pDispParams->rgvarg[i]);
896 return hr;
899 /* Object_Property helper functions */
901 static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord)
903 VARIANT varresult;
904 VARIANTARG vararg[1];
905 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
906 HRESULT hr;
908 VariantInit(&vararg[0]);
909 V_VT(&vararg[0]) = VT_I4;
910 V_I4(&vararg[0]) = count;
912 hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
913 *pRecord = V_DISPATCH(&varresult);
914 return hr;
917 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
919 VARIANTARG vararg[3];
920 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
922 VariantInit(&vararg[2]);
923 V_VT(&vararg[2]) = VT_I4;
924 V_I4(&vararg[2]) = (INT_PTR)hkey;
925 VariantInit(&vararg[1]);
926 V_VT(&vararg[1]) = VT_BSTR;
927 V_BSTR(&vararg[1]) = SysAllocString(szKey);
928 VariantInit(&vararg[0]);
929 VariantCopy(&vararg[0], &vValue);
930 VariantClear(&vValue);
932 return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect);
935 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
937 VARIANT varresult;
938 VARIANTARG vararg;
939 HRESULT hr;
941 VariantInit(&vararg);
942 V_VT(&vararg) = VT_EMPTY;
943 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL);
944 *pBool = V_BOOL(&varresult);
945 VariantClear(&varresult);
946 return hr;
949 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
951 VARIANT varresult;
952 VARIANTARG vararg;
953 HRESULT hr;
955 VariantInit(&vararg);
956 V_VT(&vararg) = VT_BSTR;
957 V_BSTR(&vararg) = SysAllocString(szValue);
959 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR);
960 if (V_BSTR(&varresult))
961 /* lstrcpyW is not implemented on Win95 (lstrlenW is though) */
962 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
963 VariantClear(&varresult);
964 return hr;
967 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
969 VARIANT varresult;
970 VARIANTARG vararg;
971 HRESULT hr;
973 VariantInit(&vararg);
974 V_VT(&vararg) = VT_I4;
975 V_I4(&vararg) = iValue;
977 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult);
978 if (SUCCEEDED(hr) && vtResult == VT_BSTR)
979 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
980 VariantClear(&varresult);
981 return hr;
984 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
986 VARIANT varresult;
987 VARIANTARG vararg[2];
988 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
989 HRESULT hr;
991 VariantInit(&vararg[1]);
992 V_VT(&vararg[1]) = VT_BSTR;
993 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
994 VariantInit(&vararg[0]);
995 V_VT(&vararg[0]) = VT_I4;
996 V_I4(&vararg[0]) = options;
998 hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
999 *pSession = V_DISPATCH(&varresult);
1000 return hr;
1003 static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase)
1005 VARIANT varresult;
1006 VARIANTARG vararg[2];
1007 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1008 HRESULT hr;
1010 VariantInit(&vararg[1]);
1011 V_VT(&vararg[1]) = VT_BSTR;
1012 V_BSTR(&vararg[1]) = SysAllocString(szDatabasePath);
1013 VariantInit(&vararg[0]);
1014 V_VT(&vararg[0]) = VT_I4;
1015 V_I4(&vararg[0]) = openmode;
1017 hr = invoke(pInstaller, "OpenDatabase", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1018 *pDatabase = V_DISPATCH(&varresult);
1019 return hr;
1022 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
1024 VARIANT varresult;
1025 VARIANTARG vararg[2];
1026 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1028 VariantInit(&vararg[1]);
1029 V_VT(&vararg[1]) = VT_BSTR;
1030 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
1031 VariantInit(&vararg[0]);
1032 V_VT(&vararg[0]) = VT_BSTR;
1033 V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues);
1035 return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1038 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
1040 VARIANT varresult;
1041 VARIANTARG vararg[1];
1042 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1043 HRESULT hr;
1045 VariantInit(&vararg[0]);
1046 V_VT(&vararg[0]) = VT_BSTR;
1047 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
1049 hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1050 *pInstallState = V_I4(&varresult);
1051 VariantClear(&varresult);
1052 return hr;
1055 static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szString)
1057 VARIANT varresult;
1058 VARIANTARG vararg[2];
1059 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1060 HRESULT hr;
1062 VariantInit(&vararg[1]);
1063 V_VT(&vararg[1]) = VT_BSTR;
1064 V_BSTR(&vararg[1]) = SysAllocString(szProduct);
1065 VariantInit(&vararg[0]);
1066 V_VT(&vararg[0]) = VT_BSTR;
1067 V_BSTR(&vararg[0]) = SysAllocString(szAttribute);
1069 hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1070 if (V_BSTR(&varresult))
1071 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
1072 VariantClear(&varresult);
1073 return hr;
1076 static HRESULT Installer_Products(IDispatch **pStringList)
1078 VARIANT varresult;
1079 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1080 HRESULT hr;
1082 hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1083 *pStringList = V_DISPATCH(&varresult);
1084 return hr;
1087 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
1089 VARIANT varresult;
1090 VARIANTARG vararg[1];
1091 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1092 HRESULT hr;
1094 VariantInit(&vararg[0]);
1095 V_VT(&vararg[0]) = VT_BSTR;
1096 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
1098 hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1099 *pStringList = V_DISPATCH(&varresult);
1100 return hr;
1103 static HRESULT Installer_VersionGet(LPWSTR szVersion)
1105 VARIANT varresult;
1106 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1107 HRESULT hr;
1109 hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1110 if (V_BSTR(&varresult))
1111 memcpy(szVersion, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
1112 VariantClear(&varresult);
1113 return hr;
1116 static HRESULT Installer_UILevelPut(int level)
1118 VARIANT varresult;
1119 VARIANTARG vararg;
1120 DISPID dispid = DISPID_PROPERTYPUT;
1121 DISPPARAMS dispparams = {&vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1123 VariantInit(&vararg);
1124 V_VT(&vararg) = VT_I4;
1125 V_I4(&vararg) = level;
1127 return invoke(pInstaller, "UILevel", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1130 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
1132 VARIANT varresult;
1133 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1134 HRESULT hr;
1136 hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1137 *pInst = V_DISPATCH(&varresult);
1138 return hr;
1141 static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn)
1143 VARIANT varresult;
1144 VARIANTARG vararg[1];
1145 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1146 HRESULT hr;
1148 VariantInit(&vararg[0]);
1149 V_VT(&vararg[0]) = VT_BSTR;
1150 V_BSTR(&vararg[0]) = SysAllocString(szName);
1152 hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1153 if (V_BSTR(&varresult))
1154 memcpy(szReturn, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
1155 VariantClear(&varresult);
1156 return hr;
1159 static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue)
1161 VARIANT varresult;
1162 VARIANTARG vararg[2];
1163 DISPID dispid = DISPID_PROPERTYPUT;
1164 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1166 VariantInit(&vararg[1]);
1167 V_VT(&vararg[1]) = VT_BSTR;
1168 V_BSTR(&vararg[1]) = SysAllocString(szName);
1169 VariantInit(&vararg[0]);
1170 V_VT(&vararg[0]) = VT_BSTR;
1171 V_BSTR(&vararg[0]) = SysAllocString(szValue);
1173 return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1176 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
1178 VARIANT varresult;
1179 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1180 HRESULT hr;
1182 hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1183 *pLangId = V_I4(&varresult);
1184 VariantClear(&varresult);
1185 return hr;
1188 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, BOOL *pMode)
1190 VARIANT varresult;
1191 VARIANTARG vararg[1];
1192 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1193 HRESULT hr;
1195 VariantInit(&vararg[0]);
1196 V_VT(&vararg[0]) = VT_I4;
1197 V_I4(&vararg[0]) = iFlag;
1199 hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL);
1200 *pMode = V_BOOL(&varresult);
1201 VariantClear(&varresult);
1202 return hr;
1205 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, BOOL bMode)
1207 VARIANT varresult;
1208 VARIANTARG vararg[2];
1209 DISPID dispid = DISPID_PROPERTYPUT;
1210 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1212 VariantInit(&vararg[1]);
1213 V_VT(&vararg[1]) = VT_I4;
1214 V_I4(&vararg[1]) = iFlag;
1215 VariantInit(&vararg[0]);
1216 V_VT(&vararg[0]) = VT_BOOL;
1217 V_BOOL(&vararg[0]) = bMode;
1219 return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1222 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
1224 VARIANT varresult;
1225 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1226 HRESULT hr;
1228 hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1229 *pDatabase = V_DISPATCH(&varresult);
1230 return hr;
1233 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn)
1235 VARIANT varresult;
1236 VARIANTARG vararg[1];
1237 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1238 HRESULT hr;
1240 VariantInit(&vararg[0]);
1241 V_VT(&vararg[0]) = VT_BSTR;
1242 V_BSTR(&vararg[0]) = SysAllocString(szAction);
1244 hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1245 *iReturn = V_I4(&varresult);
1246 VariantClear(&varresult);
1247 return hr;
1250 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
1252 VARIANT varresult;
1253 VARIANTARG vararg[1];
1254 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1255 HRESULT hr;
1257 VariantInit(&vararg[0]);
1258 V_VT(&vararg[0]) = VT_BSTR;
1259 V_BSTR(&vararg[0]) = SysAllocString(szCondition);
1261 hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1262 *iReturn = V_I4(&varresult);
1263 VariantClear(&varresult);
1264 return hr;
1267 static HRESULT Session_Message(IDispatch *pSession, LONG kind, IDispatch *record, int *ret)
1269 VARIANT varresult;
1270 VARIANTARG vararg[2];
1271 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1272 HRESULT hr;
1274 VariantInit(&varresult);
1275 V_VT(vararg) = VT_DISPATCH;
1276 V_DISPATCH(vararg) = record;
1277 V_VT(vararg+1) = VT_I4;
1278 V_I4(vararg+1) = kind;
1280 hr = invoke(pSession, "Message", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1282 ok(V_VT(&varresult) == VT_I4, "V_VT(varresult) = %d\n", V_VT(&varresult));
1283 *ret = V_I4(&varresult);
1285 return hr;
1288 static HRESULT Session_SetInstallLevel(IDispatch *pSession, LONG iInstallLevel)
1290 VARIANT varresult;
1291 VARIANTARG vararg[1];
1292 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1294 VariantInit(&vararg[0]);
1295 V_VT(&vararg[0]) = VT_I4;
1296 V_I4(&vararg[0]) = iInstallLevel;
1298 return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1301 static HRESULT Session_FeatureCurrentState(IDispatch *pSession, LPCWSTR szName, int *pState)
1303 VARIANT varresult;
1304 VARIANTARG vararg[1];
1305 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1306 HRESULT hr;
1308 VariantInit(&vararg[0]);
1309 V_VT(&vararg[0]) = VT_BSTR;
1310 V_BSTR(&vararg[0]) = SysAllocString(szName);
1312 hr = invoke(pSession, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1313 *pState = V_I4(&varresult);
1314 VariantClear(&varresult);
1315 return hr;
1318 static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState)
1320 VARIANT varresult;
1321 VARIANTARG vararg[1];
1322 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1323 HRESULT hr;
1325 VariantInit(&vararg[0]);
1326 V_VT(&vararg[0]) = VT_BSTR;
1327 V_BSTR(&vararg[0]) = SysAllocString(szName);
1329 hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1330 *pState = V_I4(&varresult);
1331 VariantClear(&varresult);
1332 return hr;
1335 static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState)
1337 VARIANT varresult;
1338 VARIANTARG vararg[2];
1339 DISPID dispid = DISPID_PROPERTYPUT;
1340 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1342 VariantInit(&vararg[1]);
1343 V_VT(&vararg[1]) = VT_BSTR;
1344 V_BSTR(&vararg[1]) = SysAllocString(szName);
1345 VariantInit(&vararg[0]);
1346 V_VT(&vararg[0]) = VT_I4;
1347 V_I4(&vararg[0]) = iState;
1349 return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1352 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
1354 VARIANT varresult;
1355 VARIANTARG vararg[1];
1356 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1357 HRESULT hr;
1359 VariantInit(&vararg[0]);
1360 V_VT(&vararg[0]) = VT_BSTR;
1361 V_BSTR(&vararg[0]) = SysAllocString(szSql);
1363 hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1364 *pView = V_DISPATCH(&varresult);
1365 return hr;
1368 static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo)
1370 VARIANT varresult;
1371 VARIANTARG vararg[1];
1372 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1373 HRESULT hr;
1375 VariantInit(&vararg[0]);
1376 V_VT(&vararg[0]) = VT_I4;
1377 V_I4(&vararg[0]) = iUpdateCount;
1379 hr = invoke(pDatabase, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1380 *pSummaryInfo = V_DISPATCH(&varresult);
1381 return hr;
1384 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
1386 VARIANT varresult;
1387 VARIANTARG vararg[1];
1388 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1390 VariantInit(&vararg[0]);
1391 V_VT(&vararg[0]) = VT_DISPATCH;
1392 V_DISPATCH(&vararg[0]) = pRecord;
1394 return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1397 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
1399 VARIANT varresult;
1400 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1401 HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1402 *ppRecord = V_DISPATCH(&varresult);
1403 return hr;
1406 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
1408 VARIANT varresult;
1409 VARIANTARG vararg[2];
1410 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1412 VariantInit(&vararg[1]);
1413 V_VT(&vararg[1]) = VT_I4;
1414 V_I4(&vararg[1]) = iMode;
1415 VariantInit(&vararg[0]);
1416 V_VT(&vararg[0]) = VT_DISPATCH;
1417 V_DISPATCH(&vararg[0]) = pRecord;
1418 if (pRecord)
1419 IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */
1421 return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1424 static HRESULT View_Close(IDispatch *pView)
1426 VARIANT varresult;
1427 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1428 return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1431 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
1433 VARIANT varresult;
1434 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1435 HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1436 *pFieldCount = V_I4(&varresult);
1437 VariantClear(&varresult);
1438 return hr;
1441 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString)
1443 VARIANT varresult;
1444 VARIANTARG vararg[1];
1445 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1446 HRESULT hr;
1448 VariantInit(&vararg[0]);
1449 V_VT(&vararg[0]) = VT_I4;
1450 V_I4(&vararg[0]) = iField;
1452 hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1453 if (V_BSTR(&varresult))
1454 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
1455 VariantClear(&varresult);
1456 return hr;
1459 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
1461 VARIANT varresult;
1462 VARIANTARG vararg[2];
1463 DISPID dispid = DISPID_PROPERTYPUT;
1464 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1466 VariantInit(&vararg[1]);
1467 V_VT(&vararg[1]) = VT_I4;
1468 V_I4(&vararg[1]) = iField;
1469 VariantInit(&vararg[0]);
1470 V_VT(&vararg[0]) = VT_BSTR;
1471 V_BSTR(&vararg[0]) = SysAllocString(szString);
1473 return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1476 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
1478 VARIANT varresult;
1479 VARIANTARG vararg[1];
1480 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1481 HRESULT hr;
1483 VariantInit(&vararg[0]);
1484 V_VT(&vararg[0]) = VT_I4;
1485 V_I4(&vararg[0]) = iField;
1487 hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1488 *pValue = V_I4(&varresult);
1489 VariantClear(&varresult);
1490 return hr;
1493 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
1495 VARIANT varresult;
1496 VARIANTARG vararg[2];
1497 DISPID dispid = DISPID_PROPERTYPUT;
1498 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1500 VariantInit(&vararg[1]);
1501 V_VT(&vararg[1]) = VT_I4;
1502 V_I4(&vararg[1]) = iField;
1503 VariantInit(&vararg[0]);
1504 V_VT(&vararg[0]) = VT_I4;
1505 V_I4(&vararg[0]) = iValue;
1507 return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1510 static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT)
1512 VARIANT varresult;
1513 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1514 HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN);
1515 *ppEnumVARIANT = V_UNKNOWN(&varresult);
1516 return hr;
1519 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
1521 VARIANT varresult;
1522 VARIANTARG vararg[1];
1523 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1524 HRESULT hr;
1526 VariantInit(&vararg[0]);
1527 V_VT(&vararg[0]) = VT_I4;
1528 V_I4(&vararg[0]) = iIndex;
1530 hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1531 if (V_BSTR(&varresult))
1532 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
1533 VariantClear(&varresult);
1534 return hr;
1537 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
1539 VARIANT varresult;
1540 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1541 HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1542 *pCount = V_I4(&varresult);
1543 VariantClear(&varresult);
1544 return hr;
1547 static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect)
1549 VARIANTARG vararg[1];
1550 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1552 VariantInit(&vararg[0]);
1553 V_VT(&vararg[0]) = VT_I4;
1554 V_I4(&vararg[0]) = pid;
1555 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYGET, &dispparams, pVarResult, vtExpect);
1558 static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant)
1560 VARIANT varresult;
1561 VARIANTARG vararg[2];
1562 DISPID dispid = DISPID_PROPERTYPUT;
1563 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1565 VariantInit(&vararg[1]);
1566 V_VT(&vararg[1]) = VT_I4;
1567 V_I4(&vararg[1]) = pid;
1568 VariantInit(&vararg[0]);
1569 VariantCopyInd(vararg, pVariant);
1571 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1574 static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount)
1576 VARIANT varresult;
1577 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1578 HRESULT hr;
1580 hr = invoke(pSummaryInfo, "PropertyCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1581 *pCount = V_I4(&varresult);
1582 VariantClear(&varresult);
1583 return hr;
1586 /* Test the various objects */
1588 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4
1590 static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly)
1592 static const WCHAR szPropertyException[] = { 'P','r','o','p','e','r','t','y',',','P','i','d',0 };
1593 static const WCHAR szTitle[] = { 'T','i','t','l','e',0 };
1594 VARIANT varresult, var;
1595 SYSTEMTIME st;
1596 HRESULT hr;
1597 int j;
1599 /* SummaryInfo::PropertyCount */
1600 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1601 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1602 ok(j == num_info, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1604 /* SummaryInfo::Property, get for properties we have set */
1605 for (j = 0; j < num_info; j++)
1607 const msi_summary_info *entry = &info[j];
1609 int vt = entry->datatype;
1610 if (vt == VT_LPSTR) vt = VT_BSTR;
1611 else if (vt == VT_FILETIME) vt = VT_DATE;
1612 else if (vt == VT_I2) vt = VT_I4;
1614 hr = SummaryInfo_PropertyGet(pSummaryInfo, entry->property, &varresult, vt);
1615 ok(hr == S_OK, "SummaryInfo_Property (pid %d) failed, hresult 0x%08x\n", entry->property, hr);
1616 if (V_VT(&varresult) != vt)
1617 skip("Skipping property tests due to type mismatch\n");
1618 else if (vt == VT_I4)
1619 ok(V_I4(&varresult) == entry->iValue, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %d\n",
1620 entry->property, entry->iValue, V_I4(&varresult));
1621 else if (vt == VT_DATE)
1623 FILETIME ft;
1624 DATE d;
1626 FileTimeToLocalFileTime(entry->pftValue, &ft);
1627 FileTimeToSystemTime(&ft, &st);
1628 SystemTimeToVariantTime(&st, &d);
1629 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));
1631 else if (vt == VT_BSTR)
1633 ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry->property, entry->szValue, V_BSTR(&varresult));
1635 else
1636 skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry->property, vt);
1638 VariantClear(&varresult);
1641 /* SummaryInfo::Property, get; invalid arguments */
1643 /* Invalid pids */
1644 hr = SummaryInfo_PropertyGet(pSummaryInfo, -1, &varresult, VT_EMPTY);
1645 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1646 ok_exception(hr, szPropertyException);
1648 hr = SummaryInfo_PropertyGet(pSummaryInfo, 1000, &varresult, VT_EMPTY);
1649 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1650 ok_exception(hr, szPropertyException);
1652 /* Unsupported pids */
1653 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_DICTIONARY, &varresult, VT_EMPTY);
1654 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1656 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY);
1657 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1659 /* Pids we have not set, one for each type */
1660 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_EMPTY);
1661 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1663 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY);
1664 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1666 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY);
1667 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1669 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY);
1670 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1672 if (!readonly)
1674 /* SummaryInfo::Property, put; one for each type */
1676 /* VT_I2 */
1677 VariantInit(&var);
1678 V_VT(&var) = VT_I2;
1679 V_I2(&var) = 1;
1680 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CODEPAGE, &var);
1681 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1683 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */);
1684 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1685 ok(V_I2(&var) == V_I2(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var), V_I2(&varresult));
1686 VariantClear(&varresult);
1687 VariantClear(&var);
1689 /* VT_BSTR */
1690 V_VT(&var) = VT_BSTR;
1691 V_BSTR(&var) = SysAllocString(szTitle);
1692 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_TITLE, &var);
1693 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1695 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var));
1696 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1697 ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var), V_BSTR(&varresult));
1698 VariantClear(&varresult);
1699 VariantClear(&var);
1701 /* VT_DATE */
1702 V_VT(&var) = VT_DATE;
1703 FileTimeToSystemTime(&systemtime, &st);
1704 SystemTimeToVariantTime(&st, &V_DATE(&var));
1705 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_LASTSAVE_DTM, &var);
1706 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1708 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var));
1709 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1710 ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1711 VariantClear(&varresult);
1712 VariantClear(&var);
1714 /* VT_I4 */
1715 V_VT(&var) = VT_I4;
1716 V_I4(&var) = 1000;
1717 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1718 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1720 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1721 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1722 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult));
1723 VariantClear(&varresult);
1724 VariantClear(&var);
1726 /* SummaryInfo::PropertyCount */
1727 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1728 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1729 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1733 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1735 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 };
1736 static WCHAR szThree[] = { 'T','h','r','e','e',0 };
1737 static WCHAR szTwo[] = { 'T','w','o',0 };
1738 static WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
1739 static WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 };
1740 IDispatch *pView = NULL, *pSummaryInfo = NULL;
1741 HRESULT hr;
1743 hr = Database_OpenView(pDatabase, szSql, &pView);
1744 ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr);
1745 if (hr == S_OK)
1747 IDispatch *pRecord = NULL;
1748 WCHAR szString[MAX_PATH];
1750 /* View::Execute */
1751 hr = View_Execute(pView, NULL);
1752 ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr);
1754 /* View::Fetch */
1755 hr = View_Fetch(pView, &pRecord);
1756 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1757 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1758 if (pRecord)
1760 /* Record::StringDataGet */
1761 memset(szString, 0, sizeof(szString));
1762 hr = Record_StringDataGet(pRecord, 1, szString);
1763 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1764 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1766 /* Record::StringDataPut with correct index */
1767 hr = Record_StringDataPut(pRecord, 1, szTwo);
1768 ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1770 /* Record::StringDataGet */
1771 memset(szString, 0, sizeof(szString));
1772 hr = Record_StringDataGet(pRecord, 1, szString);
1773 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1774 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1776 /* Record::StringDataPut with incorrect index */
1777 hr = Record_StringDataPut(pRecord, -1, szString);
1778 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1779 ok_exception(hr, szStringDataField);
1781 /* View::Modify with incorrect parameters */
1782 hr = View_Modify(pView, -5, NULL);
1783 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1784 ok_exception(hr, szModifyModeRecord);
1786 hr = View_Modify(pView, -5, pRecord);
1787 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1788 ok_exception(hr, szModifyModeRecord);
1790 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1791 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1792 ok_exception(hr, szModifyModeRecord);
1794 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1795 ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr);
1797 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1798 memset(szString, 0, sizeof(szString));
1799 hr = Record_StringDataGet(pRecord, 1, szString);
1800 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1801 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1803 IDispatch_Release(pRecord);
1806 /* View::Fetch */
1807 hr = View_Fetch(pView, &pRecord);
1808 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1809 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1810 if (pRecord)
1812 /* Record::StringDataGet */
1813 memset(szString, 0, sizeof(szString));
1814 hr = Record_StringDataGet(pRecord, 1, szString);
1815 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1816 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1818 IDispatch_Release(pRecord);
1821 /* View::Fetch */
1822 hr = View_Fetch(pView, &pRecord);
1823 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1824 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1825 if (pRecord)
1826 IDispatch_Release(pRecord);
1828 /* View::Close */
1829 hr = View_Close(pView);
1830 ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr);
1832 IDispatch_Release(pView);
1835 /* Database::SummaryInformation */
1836 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo);
1837 ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr);
1838 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1839 if (pSummaryInfo)
1841 test_SummaryInfo(pSummaryInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), readonly);
1842 IDispatch_Release(pSummaryInfo);
1846 static void test_Session(IDispatch *pSession)
1848 static WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
1849 static WCHAR szOne[] = { 'O','n','e',0 };
1850 static WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 };
1851 static WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 };
1852 static WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 };
1853 static WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 };
1854 static WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1855 static WCHAR szEmpty[] = { 0 };
1856 static WCHAR szEquals[] = { '=',0 };
1857 static WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
1858 static WCHAR szModeFlag[] = { 'M','o','d','e',',','F','l','a','g',0 };
1859 WCHAR stringw[MAX_PATH];
1860 CHAR string[MAX_PATH];
1861 UINT len;
1862 BOOL bool;
1863 int myint;
1864 IDispatch *pDatabase = NULL, *pInst = NULL, *record = NULL;
1865 ULONG refs_before, refs_after;
1866 HRESULT hr;
1868 /* Session::Installer */
1869 hr = Session_Installer(pSession, &pInst);
1870 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1871 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1872 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1873 refs_before = IDispatch_AddRef(pInst);
1875 hr = Session_Installer(pSession, &pInst);
1876 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1877 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1878 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1879 refs_after = IDispatch_Release(pInst);
1880 ok(refs_before == refs_after, "got %u and %u\n", refs_before, refs_after);
1882 /* Session::Property, get */
1883 memset(stringw, 0, sizeof(stringw));
1884 hr = Session_PropertyGet(pSession, szProductName, stringw);
1885 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1886 if (strcmp_ww(stringw, szMSITEST) != 0)
1888 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1889 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1890 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1893 /* Session::Property, put */
1894 hr = Session_PropertyPut(pSession, szProductName, szProductName);
1895 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1896 memset(stringw, 0, sizeof(stringw));
1897 hr = Session_PropertyGet(pSession, szProductName, stringw);
1898 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1899 if (strcmp_ww(stringw, szProductName) != 0)
1901 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1902 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1903 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1906 /* Try putting a property using empty property identifier */
1907 hr = Session_PropertyPut(pSession, szEmpty, szProductName);
1908 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1909 ok_exception(hr, szPropertyName);
1911 /* Try putting a property using illegal property identifier */
1912 hr = Session_PropertyPut(pSession, szEquals, szProductName);
1913 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1915 /* Session::Language, get */
1916 hr = Session_LanguageGet(pSession, &len);
1917 ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1918 /* Not sure how to check the language is correct */
1920 /* Session::Mode, get */
1921 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1922 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1923 ok(!bool, "Reboot at end session mode is %d\n", bool);
1925 hr = Session_ModeGet(pSession, MSIRUNMODE_MAINTENANCE, &bool);
1926 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1927 ok(!bool, "Maintenance mode is %d\n", bool);
1929 /* Session::Mode, put */
1930 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE);
1931 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1932 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1933 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1934 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1935 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE); /* set it again so we don't reboot */
1936 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1938 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, TRUE);
1939 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1940 if (hr == DISP_E_EXCEPTION) ok_exception(hr, szModeFlag);
1942 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTNOW, &bool);
1943 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1944 ok(bool, "Reboot now mode is %d, expected 1\n", bool);
1946 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, FALSE); /* set it again so we don't reboot */
1947 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1948 if (hr == DISP_E_EXCEPTION) ok_exception(hr, szModeFlag);
1950 hr = Session_ModePut(pSession, MSIRUNMODE_MAINTENANCE, TRUE);
1951 ok(hr == DISP_E_EXCEPTION, "Session_ModePut failed, hresult 0x%08x\n", hr);
1952 ok_exception(hr, szModeFlag);
1954 /* Session::Database, get */
1955 hr = Session_Database(pSession, &pDatabase);
1956 ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr);
1957 if (hr == S_OK)
1959 test_Database(pDatabase, TRUE);
1960 IDispatch_Release(pDatabase);
1963 /* Session::EvaluateCondition */
1964 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1965 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1966 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1968 hr = Session_EvaluateCondition(pSession, szEmpty, &myint);
1969 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1970 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1972 hr = Session_EvaluateCondition(pSession, szEquals, &myint);
1973 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1974 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1976 /* Session::DoAction(CostInitialize) must occur before the next statements */
1977 hr = Session_DoAction(pSession, szCostInitialize, &myint);
1978 ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr);
1979 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1981 /* Session::SetInstallLevel */
1982 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1983 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
1985 /* Session::FeatureCurrentState, get */
1986 hr = Session_FeatureCurrentState(pSession, szOne, &myint);
1987 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
1988 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1990 /* Session::Message */
1991 hr = Installer_CreateRecord(0, &record);
1992 ok(hr == S_OK, "Installer_CreateRecord failed: %08x\n", hr);
1993 hr = Session_Message(pSession, INSTALLMESSAGE_INFO, record, &myint);
1994 ok(hr == S_OK, "Session_Message failed: %08x\n", hr);
1995 ok(myint == 0, "Session_Message returned %x\n", myint);
1997 /* Session::EvaluateCondition */
1998 hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint);
1999 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2000 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2002 hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint);
2003 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2004 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2006 /* Session::FeatureRequestState, put */
2007 hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED);
2008 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
2009 hr = Session_FeatureRequestStateGet(pSession, szOne, &myint);
2010 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
2011 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
2013 /* Session::EvaluateCondition */
2014 hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint);
2015 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2016 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2018 hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint);
2019 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2020 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2023 /* delete key and all its subkeys */
2024 static DWORD delete_key( HKEY hkey )
2026 char name[MAX_PATH];
2027 DWORD ret;
2029 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
2031 HKEY tmp;
2032 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
2034 ret = delete_key( tmp );
2035 RegCloseKey( tmp );
2037 if (ret) break;
2039 if (ret != ERROR_NO_MORE_ITEMS) return ret;
2040 RegDeleteKeyA( hkey, "" );
2041 return 0;
2044 static void test_Installer_RegistryValue(void)
2046 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
2047 static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 };
2048 static const WCHAR szOne[] = { 'O','n','e',0 };
2049 static const WCHAR szTwo[] = { 'T','w','o',0 };
2050 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
2051 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
2052 static const WCHAR szFour[] = { 'F','o','u','r',0 };
2053 static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 };
2054 static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 };
2055 static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 };
2056 static const WCHAR szSix[] = { 'S','i','x',0 };
2057 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
2058 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
2059 static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
2060 static const WCHAR szBlank[] = { 0 };
2061 VARIANT varresult;
2062 VARIANTARG vararg;
2063 WCHAR szString[MAX_PATH];
2064 HKEY hkey, hkey_sub;
2065 HKEY curr_user = (HKEY)1;
2066 HRESULT hr;
2067 BOOL bRet;
2068 LONG lRet;
2070 /* Delete keys */
2071 SetLastError(0xdeadbeef);
2072 lRet = RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey );
2073 if (!lRet && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2075 win_skip("Needed W-functions are not implemented\n");
2076 return;
2078 if (!lRet)
2079 delete_key( hkey );
2081 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
2082 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
2083 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
2084 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
2086 memset(szString, 0, sizeof(szString));
2087 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
2088 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2090 memset(szString, 0, sizeof(szString));
2091 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
2092 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2094 /* Create key */
2095 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
2097 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
2098 "RegSetValueExW failed\n");
2099 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
2100 "RegSetValueExW failed\n");
2101 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
2102 "RegSetValueExW failed\n");
2103 ok(SetEnvironmentVariableA("MSITEST", "Four"), "SetEnvironmentVariableA failed %d\n", GetLastError());
2104 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
2105 "RegSetValueExW failed\n");
2106 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
2107 "RegSetValueExW failed\n");
2108 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
2109 "RegSetValueExW failed\n");
2110 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, NULL, 0),
2111 "RegSetValueExW failed\n");
2113 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
2114 "RegSetValueExW failed\n");
2116 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
2118 /* Does our key exist? It should, and make sure we retrieve the correct default value */
2119 bRet = FALSE;
2120 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
2121 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
2122 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
2124 memset(szString, 0, sizeof(szString));
2125 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
2126 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2127 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
2129 /* Ask for the value of a nonexistent key */
2130 memset(szString, 0, sizeof(szString));
2131 hr = Installer_RegistryValueW(curr_user, szKey, szExpand, szString);
2132 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2134 /* Get values of keys */
2135 memset(szString, 0, sizeof(szString));
2136 hr = Installer_RegistryValueW(curr_user, szKey, szOne, szString);
2137 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2138 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
2140 VariantInit(&vararg);
2141 V_VT(&vararg) = VT_BSTR;
2142 V_BSTR(&vararg) = SysAllocString(szTwo);
2143 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_I4);
2144 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
2145 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
2146 VariantClear(&varresult);
2148 memset(szString, 0, sizeof(szString));
2149 hr = Installer_RegistryValueW(curr_user, szKey, szThree, szString);
2150 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2151 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
2153 memset(szString, 0, sizeof(szString));
2154 hr = Installer_RegistryValueW(curr_user, szKey, szFour, szString);
2155 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2156 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
2158 /* Vista does not NULL-terminate this case */
2159 memset(szString, 0, sizeof(szString));
2160 hr = Installer_RegistryValueW(curr_user, szKey, szFive, szString);
2161 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2162 ok_w2n("Registry value \"%s\" does not match expected \"%s\"\n",
2163 szString, szFiveHi, lstrlenW(szFiveHi));
2165 memset(szString, 0, sizeof(szString));
2166 hr = Installer_RegistryValueW(curr_user, szKey, szSix, szString);
2167 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2168 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_);
2170 VariantInit(&vararg);
2171 V_VT(&vararg) = VT_BSTR;
2172 V_BSTR(&vararg) = SysAllocString(szSeven);
2173 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_EMPTY);
2174 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
2176 /* Get string class name for the key */
2177 memset(szString, 0, sizeof(szString));
2178 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
2179 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2180 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank);
2182 /* Get name of a value by positive number (RegEnumValue like), valid index */
2183 memset(szString, 0, sizeof(szString));
2184 hr = Installer_RegistryValueI(curr_user, szKey, 2, szString, VT_BSTR);
2185 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2186 /* RegEnumValue order seems different on wine */
2187 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
2189 /* Get name of a value by positive number (RegEnumValue like), invalid index */
2190 memset(szString, 0, sizeof(szString));
2191 hr = Installer_RegistryValueI(curr_user, szKey, 10, szString, VT_EMPTY);
2192 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2194 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
2195 memset(szString, 0, sizeof(szString));
2196 hr = Installer_RegistryValueI(curr_user, szKey, -1, szString, VT_BSTR);
2197 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2198 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
2200 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
2201 memset(szString, 0, sizeof(szString));
2202 hr = Installer_RegistryValueI(curr_user, szKey, -10, szString, VT_EMPTY);
2203 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2205 /* clean up */
2206 delete_key(hkey);
2209 static void test_Installer_Products(BOOL bProductInstalled)
2211 WCHAR szString[MAX_PATH];
2212 HRESULT hr;
2213 int idx;
2214 IUnknown *pUnk = NULL;
2215 IEnumVARIANT *pEnum = NULL;
2216 VARIANT var;
2217 ULONG celt;
2218 int iCount, iValue;
2219 IDispatch *pStringList = NULL;
2220 BOOL bProductFound = FALSE;
2222 /* Installer::Products */
2223 hr = Installer_Products(&pStringList);
2224 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
2225 if (hr == S_OK)
2227 /* StringList::_NewEnum */
2228 hr = StringList__NewEnum(pStringList, &pUnk);
2229 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
2230 if (hr == S_OK)
2232 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
2233 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2235 if (!pEnum)
2236 skip("IEnumVARIANT tests\n");
2238 /* StringList::Count */
2239 hr = StringList_Count(pStringList, &iCount);
2240 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2242 for (idx=0; idx<iCount; idx++)
2244 /* StringList::Item */
2245 memset(szString, 0, sizeof(szString));
2246 hr = StringList_Item(pStringList, idx, szString);
2247 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2249 if (hr == S_OK)
2251 /* Installer::ProductState */
2252 hr = Installer_ProductState(szString, &iValue);
2253 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2254 if (hr == S_OK)
2255 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
2257 /* Not found our product code yet? Check */
2258 if (!bProductFound && !strcmp_ww(szString, szProductCode))
2259 bProductFound = TRUE;
2261 /* IEnumVARIANT::Next */
2262 if (pEnum)
2264 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2265 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2266 ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
2267 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2268 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2269 VariantClear(&var);
2274 if (bProductInstalled)
2276 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
2277 bProductInstalled ? "be" : "not be",
2278 bProductFound ? "found" : "not found");
2281 if (pEnum)
2283 IEnumVARIANT *pEnum2 = NULL;
2285 if (0) /* Crashes on Windows XP */
2287 /* IEnumVARIANT::Clone, NULL pointer */
2288 hr = IEnumVARIANT_Clone(pEnum, NULL);
2291 /* IEnumVARIANT::Clone */
2292 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
2293 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
2294 if (hr == S_OK)
2296 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
2298 /* IEnumVARIANT::Next of the clone */
2299 if (iCount)
2301 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
2302 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2303 ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
2304 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2305 VariantClear(&var);
2307 else
2308 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
2310 IEnumVARIANT_Release(pEnum2);
2313 /* IEnumVARIANT::Skip should fail */
2314 hr = IEnumVARIANT_Skip(pEnum, 1);
2315 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2317 /* IEnumVARIANT::Next, NULL variant pointer */
2318 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2319 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2320 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2322 /* IEnumVARIANT::Next, should not return any more items */
2323 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2324 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2325 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2326 VariantClear(&var);
2328 /* IEnumVARIANT::Reset */
2329 hr = IEnumVARIANT_Reset(pEnum);
2330 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2332 if (iCount)
2334 /* IEnumVARIANT::Skip to the last product */
2335 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2336 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2338 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2339 * NULL celt pointer. */
2340 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2341 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2342 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2343 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2344 VariantClear(&var);
2346 else
2347 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2350 /* StringList::Item using an invalid index */
2351 memset(szString, 0, sizeof(szString));
2352 hr = StringList_Item(pStringList, iCount, szString);
2353 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2355 if (pEnum) IEnumVARIANT_Release(pEnum);
2356 if (pUnk) IUnknown_Release(pUnk);
2357 IDispatch_Release(pStringList);
2361 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2362 * deleting the subkeys first) */
2363 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey, REGSAM access)
2365 UINT ret;
2366 CHAR *string = NULL;
2367 HKEY hkey;
2368 DWORD dwSize;
2370 ret = RegOpenKeyEx(hkeyParent, subkey, 0, access, &hkey);
2371 if (ret != ERROR_SUCCESS) return ret;
2372 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2373 if (ret != ERROR_SUCCESS) return ret;
2374 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2376 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2377 delete_registry_key(hkey, string, access);
2379 RegCloseKey(hkey);
2380 HeapFree(GetProcessHeap(), 0, string);
2381 delete_key_portable(hkeyParent, subkey, access);
2382 return ERROR_SUCCESS;
2385 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2386 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, REGSAM access, HKEY *phkey)
2388 UINT ret;
2389 CHAR *string = NULL;
2390 int idx = 0;
2391 HKEY hkey;
2392 DWORD dwSize;
2393 BOOL found = FALSE;
2395 *phkey = 0;
2397 ret = RegOpenKeyEx(hkeyParent, subkey, 0, access, &hkey);
2398 if (ret != ERROR_SUCCESS) return ret;
2399 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2400 if (ret != ERROR_SUCCESS) return ret;
2401 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2403 while (!found &&
2404 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2406 if (!strcmp(string, findkey))
2408 *phkey = hkey;
2409 found = TRUE;
2411 else if (find_registry_key(hkey, string, findkey, access, phkey) == ERROR_SUCCESS) found = TRUE;
2414 if (*phkey != hkey) RegCloseKey(hkey);
2415 HeapFree(GetProcessHeap(), 0, string);
2416 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2419 static void test_Installer_InstallProduct(void)
2421 HRESULT hr;
2422 CHAR path[MAX_PATH];
2423 WCHAR szString[MAX_PATH];
2424 LONG res;
2425 HKEY hkey;
2426 DWORD num, size, type;
2427 int iValue, iCount;
2428 IDispatch *pStringList = NULL;
2429 REGSAM access = KEY_ALL_ACCESS;
2430 BOOL wow64;
2432 if (pIsWow64Process && pIsWow64Process(GetCurrentProcess(), &wow64) && wow64)
2433 access |= KEY_WOW64_64KEY;
2435 create_test_files();
2437 /* Avoid an interactive dialog in case of insufficient privileges. */
2438 hr = Installer_UILevelPut(INSTALLUILEVEL_NONE);
2439 ok(hr == S_OK, "Expected UILevel propery put invoke to return S_OK, got 0x%08x\n", hr);
2441 /* Installer::InstallProduct */
2442 hr = Installer_InstallProduct(szMsifile, NULL);
2443 if (hr == DISP_E_EXCEPTION)
2445 skip("InstallProduct failed, insufficient rights?\n");
2446 delete_test_files();
2447 return;
2449 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2451 /* Installer::ProductState for our product code, which has been installed */
2452 hr = Installer_ProductState(szProductCode, &iValue);
2453 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2454 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2456 /* Installer::ProductInfo for our product code */
2458 /* NULL attribute */
2459 memset(szString, 0, sizeof(szString));
2460 hr = Installer_ProductInfo(szProductCode, NULL, szString);
2461 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2462 ok_exception(hr, szProductInfoException);
2464 /* Nonexistent attribute */
2465 memset(szString, 0, sizeof(szString));
2466 hr = Installer_ProductInfo(szProductCode, szMsifile, szString);
2467 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2468 ok_exception(hr, szProductInfoException);
2470 /* Package name */
2471 memset(szString, 0, sizeof(szString));
2472 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szString);
2473 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2474 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile);
2476 /* Product name */
2477 memset(szString, 0, sizeof(szString));
2478 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PRODUCTNAMEW, szString);
2479 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2480 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST);
2482 /* Installer::Products */
2483 test_Installer_Products(TRUE);
2485 /* Installer::RelatedProducts for our upgrade code */
2486 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2487 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2488 if (hr == S_OK)
2490 /* StringList::Count */
2491 hr = StringList_Count(pStringList, &iCount);
2492 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2493 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2495 /* StringList::Item */
2496 memset(szString, 0, sizeof(szString));
2497 hr = StringList_Item(pStringList, 0, szString);
2498 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2499 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
2501 IDispatch_Release(pStringList);
2504 /* Check & clean up installed files & registry keys */
2505 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2506 ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
2507 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2508 ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
2509 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2510 ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
2511 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2512 ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
2513 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2514 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2515 ok(delete_pf("msitest", FALSE), "File not installed\n");
2517 res = RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest", &hkey);
2518 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2520 size = MAX_PATH;
2521 type = REG_SZ;
2522 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2523 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2524 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2526 size = MAX_PATH;
2527 type = REG_SZ;
2528 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2529 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2531 size = sizeof(num);
2532 type = REG_DWORD;
2533 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2534 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2535 ok(num == 314, "Expected 314, got %d\n", num);
2537 size = MAX_PATH;
2538 type = REG_SZ;
2539 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2540 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2541 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2543 RegCloseKey(hkey);
2545 res = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest");
2546 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2548 /* Remove registry keys written by RegisterProduct standard action */
2549 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE,
2550 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F1C3AF50-8B56-4A69-A00C-00773FE42F30}");
2551 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2553 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2554 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656", access);
2555 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2557 res = find_registry_key(HKEY_LOCAL_MACHINE,
2558 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "05FA3C1F65B896A40AC00077F34EF203", access, &hkey);
2559 ok(res == ERROR_SUCCESS ||
2560 broken(res == ERROR_FILE_NOT_FOUND), /* win9x */
2561 "Expected ERROR_SUCCESS, got %d\n", res);
2562 if (res == ERROR_SUCCESS)
2564 res = delete_registry_key(hkey, "05FA3C1F65B896A40AC00077F34EF203", access);
2565 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2566 RegCloseKey(hkey);
2568 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2569 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203", access);
2570 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2572 else
2574 /* win9x defaults to a per-machine install. */
2575 delete_key_portable(HKEY_LOCAL_MACHINE,
2576 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203", access);
2579 /* Remove registry keys written by PublishProduct standard action */
2580 res = RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2581 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2583 res = delete_registry_key(hkey, "Products\\05FA3C1F65B896A40AC00077F34EF203", KEY_ALL_ACCESS);
2584 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2586 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2587 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2589 RegCloseKey(hkey);
2591 /* Delete installation files we installed */
2592 delete_test_files();
2595 static void test_Installer(void)
2597 static WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
2598 static WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
2599 WCHAR szPath[MAX_PATH];
2600 HRESULT hr;
2601 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL;
2602 int iValue, iCount;
2604 if (!pInstaller) return;
2606 /* Installer::CreateRecord */
2608 /* Test for error */
2609 hr = Installer_CreateRecord(-1, &pRecord);
2610 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2611 ok_exception(hr, szCreateRecordException);
2613 /* Test for success */
2614 hr = Installer_CreateRecord(1, &pRecord);
2615 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2616 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2617 if (pRecord)
2619 /* Record::FieldCountGet */
2620 hr = Record_FieldCountGet(pRecord, &iValue);
2621 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2622 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2624 /* Record::IntegerDataGet */
2625 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2626 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2627 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2629 /* Record::IntegerDataGet, bad index */
2630 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2631 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2632 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2634 /* Record::IntegerDataPut */
2635 hr = Record_IntegerDataPut(pRecord, 1, 100);
2636 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2638 /* Record::IntegerDataPut, bad index */
2639 hr = Record_IntegerDataPut(pRecord, 10, 100);
2640 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2641 ok_exception(hr, szIntegerDataException);
2643 /* Record::IntegerDataGet */
2644 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2645 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2646 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2648 IDispatch_Release(pRecord);
2651 create_package(szPath);
2653 /* Installer::OpenPackage */
2654 hr = Installer_OpenPackage(szPath, 0, &pSession);
2655 if (hr == DISP_E_EXCEPTION)
2657 skip("OpenPackage failed, insufficient rights?\n");
2658 DeleteFileW(szPath);
2659 return;
2661 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2662 if (hr == S_OK)
2664 test_Session(pSession);
2665 IDispatch_Release(pSession);
2668 /* Installer::OpenDatabase */
2669 hr = Installer_OpenDatabase(szPath, (INT_PTR)MSIDBOPEN_TRANSACT, &pDatabase);
2670 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2671 if (hr == S_OK)
2673 test_Database(pDatabase, FALSE);
2674 IDispatch_Release(pDatabase);
2677 /* Installer::RegistryValue */
2678 test_Installer_RegistryValue();
2680 /* Installer::ProductState for our product code, which should not be installed */
2681 hr = Installer_ProductState(szProductCode, &iValue);
2682 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2683 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2685 /* Installer::ProductInfo for our product code, which should not be installed */
2687 /* Package name */
2688 memset(szPath, 0, sizeof(szPath));
2689 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szPath);
2690 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2691 ok_exception(hr, szProductInfoException);
2693 /* NULL attribute and NULL product code */
2694 memset(szPath, 0, sizeof(szPath));
2695 hr = Installer_ProductInfo(NULL, NULL, szPath);
2696 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2697 ok_exception(hr, szProductInfoException);
2699 /* Installer::Products */
2700 test_Installer_Products(FALSE);
2702 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2703 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2704 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2705 if (hr == S_OK)
2707 /* StringList::Count */
2708 hr = StringList_Count(pStringList, &iCount);
2709 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2710 ok(!iCount, "Expected no related products but found %d\n", iCount);
2712 IDispatch_Release(pStringList);
2715 /* Installer::Version */
2716 memset(szPath, 0, sizeof(szPath));
2717 hr = Installer_VersionGet(szPath);
2718 ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr);
2720 /* Installer::InstallProduct and other tests that depend on our product being installed */
2721 test_Installer_InstallProduct();
2724 START_TEST(automation)
2726 DWORD len;
2727 char temp_path[MAX_PATH], prev_path[MAX_PATH];
2728 HRESULT hr;
2729 CLSID clsid;
2730 IUnknown *pUnk;
2732 init_functionpointers();
2733 GetSystemTimeAsFileTime(&systemtime);
2735 GetCurrentDirectoryA(MAX_PATH, prev_path);
2736 GetTempPath(MAX_PATH, temp_path);
2737 SetCurrentDirectoryA(temp_path);
2739 lstrcpyA(CURR_DIR, temp_path);
2740 len = lstrlenA(CURR_DIR);
2742 if(len && (CURR_DIR[len - 1] == '\\'))
2743 CURR_DIR[len - 1] = 0;
2745 get_program_files_dir(PROG_FILES_DIR);
2747 hr = OleInitialize(NULL);
2748 ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr);
2749 hr = CLSIDFromProgID(szProgId, &clsid);
2750 ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr);
2751 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2752 ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr);
2754 if (pUnk)
2756 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2757 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2759 test_dispid();
2760 test_dispatch();
2761 test_Installer();
2763 IDispatch_Release(pInstaller);
2764 IUnknown_Release(pUnk);
2767 OleUninitialize();
2769 SetCurrentDirectoryA(prev_path);