Release 1.3.7.
[wine/gsoc-2012-control.git] / dlls / msi / tests / automation.c
blob49cdca3bfb3e68e42eedcb6edbbd7fded7058f4b
1 /*
2 * Copyright (C) 2007 Mike McCormack for CodeWeavers
3 * Copyright (C) 2007 Misha Koshelev
5 * A test program for Microsoft Installer OLE automation functionality.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
24 #include <stdio.h>
26 #include <initguid.h>
27 #include <windows.h>
28 #include <msiquery.h>
29 #include <msidefs.h>
30 #include <msi.h>
31 #include <fci.h>
33 #include "wine/test.h"
35 static BOOL is_wow64;
37 static LONG (WINAPI *pRegDeleteKeyExA)(HKEY, LPCSTR, REGSAM, DWORD);
38 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
40 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
42 static const char *msifile = "winetest-automation.msi";
43 static const WCHAR szMsifile[] = {'w','i','n','e','t','e','s','t','-','a','u','t','o','m','a','t','i','o','n','.','m','s','i',0};
44 static const WCHAR szMSITEST[] = { 'M','S','I','T','E','S','T',0 };
45 static const WCHAR szProductCode[] = { '{','8','3','7','4','5','0','f','a','-','a','3','9','b','-','4','b','c','8','-','b','3','2','1','-','0','8','b','3','9','3','f','7','8','4','b','3','}',0 };
46 static const WCHAR szUpgradeCode[] = { '{','C','E','0','6','7','E','8','D','-','2','E','1','A','-','4','3','6','7','-','B','7','3','4','-','4','E','B','2','B','D','A','D','6','5','6','5','}',0 };
47 static const WCHAR szProductInfoException[] = { 'P','r','o','d','u','c','t','I','n','f','o',',','P','r','o','d','u','c','t',',','A','t','t','r','i','b','u','t','e',0 };
48 static const WCHAR WINE_INSTALLPROPERTY_PACKAGENAMEW[] = {'P','a','c','k','a','g','e','N','a','m','e',0};
49 static const WCHAR WINE_INSTALLPROPERTY_PRODUCTNAMEW[] = {'P','r','o','d','u','c','t','N','a','m','e',0};
50 static FILETIME systemtime;
51 static CHAR CURR_DIR[MAX_PATH];
52 static EXCEPINFO excepinfo;
55 * OLE automation data
56 **/
57 static const WCHAR szProgId[] = { 'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r','.','I','n','s','t','a','l','l','e','r',0 };
58 static IDispatch *pInstaller;
60 /* msi database data */
62 static const CHAR component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
63 "s72\tS38\ts72\ti2\tS255\tS72\n"
64 "Component\tComponent\n"
65 "Five\t{8CC92E9D-14B2-4CA4-B2AA-B11D02078087}\tNEWDIR\t2\t\tfive.txt\n"
66 "Four\t{FD37B4EA-7209-45C0-8917-535F35A2F080}\tCABOUTDIR\t2\t\tfour.txt\n"
67 "One\t{783B242E-E185-4A56-AF86-C09815EC053C}\tMSITESTDIR\t2\t\tone.txt\n"
68 "Three\t{010B6ADD-B27D-4EDD-9B3D-34C4F7D61684}\tCHANGEDDIR\t2\t\tthree.txt\n"
69 "Two\t{BF03D1A6-20DA-4A65-82F3-6CAC995915CE}\tFIRSTDIR\t2\t\ttwo.txt\n"
70 "dangler\t{6091DF25-EF96-45F1-B8E9-A9B1420C7A3C}\tTARGETDIR\t4\t\tregdata\n"
71 "component\t\tMSITESTDIR\t0\t1\tfile\n";
73 static const CHAR directory_dat[] = "Directory\tDirectory_Parent\tDefaultDir\n"
74 "s72\tS72\tl255\n"
75 "Directory\tDirectory\n"
76 "CABOUTDIR\tMSITESTDIR\tcabout\n"
77 "CHANGEDDIR\tMSITESTDIR\tchanged:second\n"
78 "FIRSTDIR\tMSITESTDIR\tfirst\n"
79 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
80 "NEWDIR\tCABOUTDIR\tnew\n"
81 "ProgramFilesFolder\tTARGETDIR\t.\n"
82 "TARGETDIR\t\tSourceDir\n";
84 static const CHAR feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
85 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
86 "Feature\tFeature\n"
87 "Five\t\tFive\tThe Five Feature\t5\t3\tNEWDIR\t0\n"
88 "Four\t\tFour\tThe Four Feature\t4\t3\tCABOUTDIR\t0\n"
89 "One\t\tOne\tThe One Feature\t1\t3\tMSITESTDIR\t0\n"
90 "Three\tOne\tThree\tThe Three Feature\t3\t3\tCHANGEDDIR\t0\n"
91 "Two\tOne\tTwo\tThe Two Feature\t2\t3\tFIRSTDIR\t0\n"
92 "feature\t\t\t\t2\t1\tTARGETDIR\t0\n";
94 static const CHAR feature_comp_dat[] = "Feature_\tComponent_\n"
95 "s38\ts72\n"
96 "FeatureComponents\tFeature_\tComponent_\n"
97 "Five\tFive\n"
98 "Four\tFour\n"
99 "One\tOne\n"
100 "Three\tThree\n"
101 "Two\tTwo\n"
102 "feature\tcomponent\n";
104 static const CHAR file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
105 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
106 "File\tFile\n"
107 "five.txt\tFive\tfive.txt\t1000\t\t\t0\t5\n"
108 "four.txt\tFour\tfour.txt\t1000\t\t\t0\t4\n"
109 "one.txt\tOne\tone.txt\t1000\t\t\t0\t1\n"
110 "three.txt\tThree\tthree.txt\t1000\t\t\t0\t3\n"
111 "two.txt\tTwo\ttwo.txt\t1000\t\t\t0\t2\n"
112 "file\tcomponent\tfilename\t100\t\t\t8192\t1\n";
114 static const CHAR install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
115 "s72\tS255\tI2\n"
116 "InstallExecuteSequence\tAction\n"
117 "AllocateRegistrySpace\tNOT Installed\t1550\n"
118 "CostFinalize\t\t1000\n"
119 "CostInitialize\t\t800\n"
120 "FileCost\t\t900\n"
121 "InstallFiles\t\t4000\n"
122 "RegisterProduct\t\t6100\n"
123 "PublishProduct\t\t6400\n"
124 "InstallFinalize\t\t6600\n"
125 "InstallInitialize\t\t1500\n"
126 "InstallValidate\t\t1400\n"
127 "LaunchConditions\t\t100\n"
128 "WriteRegistryValues\tSourceDir And SOURCEDIR\t5000\n";
130 static const CHAR media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
131 "i2\ti4\tL64\tS255\tS32\tS72\n"
132 "Media\tDiskId\n"
133 "1\t5\t\t\tDISK1\t\n";
135 static const CHAR property_dat[] = "Property\tValue\n"
136 "s72\tl0\n"
137 "Property\tProperty\n"
138 "DefaultUIFont\tDlgFont8\n"
139 "HASUIRUN\t0\n"
140 "INSTALLLEVEL\t3\n"
141 "InstallMode\tTypical\n"
142 "Manufacturer\tWine\n"
143 "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n"
144 "ProductCode\t{837450fa-a39b-4bc8-b321-08b393f784b3}\n"
145 "ProductID\tnone\n"
146 "ProductLanguage\t1033\n"
147 "ProductName\tMSITEST\n"
148 "ProductVersion\t1.1.1\n"
149 "PROMPTROLLBACKCOST\tP\n"
150 "Setup\tSetup\n"
151 "UpgradeCode\t{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}\n"
152 "MSIFASTINSTALL\t1\n";
154 static const CHAR registry_dat[] = "Registry\tRoot\tKey\tName\tValue\tComponent_\n"
155 "s72\ti2\tl255\tL255\tL0\ts72\n"
156 "Registry\tRegistry\n"
157 "Apples\t1\tSOFTWARE\\Wine\\msitest\tName\timaname\tOne\n"
158 "Oranges\t1\tSOFTWARE\\Wine\\msitest\tnumber\t#314\tTwo\n"
159 "regdata\t1\tSOFTWARE\\Wine\\msitest\tblah\tbad\tdangler\n"
160 "OrderTest\t1\tSOFTWARE\\Wine\\msitest\tOrderTestName\tOrderTestValue\tcomponent\n";
162 typedef struct _msi_table
164 const CHAR *filename;
165 const CHAR *data;
166 int size;
167 } msi_table;
169 #define ADD_TABLE(x) {#x".idt", x##_dat, sizeof(x##_dat)}
171 static const msi_table tables[] =
173 ADD_TABLE(component),
174 ADD_TABLE(directory),
175 ADD_TABLE(feature),
176 ADD_TABLE(feature_comp),
177 ADD_TABLE(file),
178 ADD_TABLE(install_exec_seq),
179 ADD_TABLE(media),
180 ADD_TABLE(property),
181 ADD_TABLE(registry)
184 typedef struct _msi_summary_info
186 UINT property;
187 UINT datatype;
188 INT iValue;
189 FILETIME *pftValue;
190 const CHAR *szValue;
191 } msi_summary_info;
193 #define ADD_INFO_I2(property, iValue) {property, VT_I2, iValue, NULL, NULL}
194 #define ADD_INFO_I4(property, iValue) {property, VT_I4, iValue, NULL, NULL}
195 #define ADD_INFO_LPSTR(property, szValue) {property, VT_LPSTR, 0, NULL, szValue}
196 #define ADD_INFO_FILETIME(property, pftValue) {property, VT_FILETIME, 0, pftValue, NULL}
198 static const msi_summary_info summary_info[] =
200 ADD_INFO_LPSTR(PID_TEMPLATE, ";1033"),
201 ADD_INFO_LPSTR(PID_REVNUMBER, "{004757CA-5092-49c2-AD20-28E1CE0DF5F2}"),
202 ADD_INFO_I4(PID_PAGECOUNT, 100),
203 ADD_INFO_I4(PID_WORDCOUNT, 0),
204 ADD_INFO_FILETIME(PID_CREATE_DTM, &systemtime),
205 ADD_INFO_FILETIME(PID_LASTPRINTED, &systemtime)
208 static void init_functionpointers(void)
210 HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll");
211 HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
213 #define GET_PROC(dll, func) \
214 p ## func = (void *)GetProcAddress(dll, #func); \
215 if(!p ## func) \
216 trace("GetProcAddress(%s) failed\n", #func);
218 GET_PROC(hadvapi32, RegDeleteKeyExA)
219 GET_PROC(hkernel32, IsWow64Process)
221 #undef GET_PROC
224 static LONG delete_key_portable( HKEY key, LPCSTR subkey, REGSAM access )
226 if (pRegDeleteKeyExA)
227 return pRegDeleteKeyExA( key, subkey, access, 0 );
228 return RegDeleteKeyA( key, subkey );
232 * Database Helpers
235 static void write_file(const CHAR *filename, const char *data, int data_size)
237 DWORD size;
239 HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL,
240 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
242 WriteFile(hf, data, data_size, &size, NULL);
243 CloseHandle(hf);
246 static void write_msi_summary_info(MSIHANDLE db, const msi_summary_info *info, int num_info)
248 MSIHANDLE summary;
249 UINT r;
250 int j;
252 r = MsiGetSummaryInformationA(db, NULL, num_info, &summary);
253 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
255 /* import summary information into the stream */
256 for (j = 0; j < num_info; j++)
258 const msi_summary_info *entry = &info[j];
260 r = MsiSummaryInfoSetPropertyA(summary, entry->property, entry->datatype,
261 entry->iValue, entry->pftValue, entry->szValue);
262 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
265 /* write the summary changes back to the stream */
266 r = MsiSummaryInfoPersist(summary);
267 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
269 MsiCloseHandle(summary);
272 static void create_database(const CHAR *name, const msi_table *tables, int num_tables,
273 const msi_summary_info *info, int num_info)
275 MSIHANDLE db;
276 UINT r;
277 int j;
279 r = MsiOpenDatabaseA(name, MSIDBOPEN_CREATE, &db);
280 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
282 /* import the tables into the database */
283 for (j = 0; j < num_tables; j++)
285 const msi_table *table = &tables[j];
287 write_file(table->filename, table->data, (table->size - 1) * sizeof(char));
289 r = MsiDatabaseImportA(db, CURR_DIR, table->filename);
290 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
292 DeleteFileA(table->filename);
295 write_msi_summary_info(db, info, num_info);
297 r = MsiDatabaseCommit(db);
298 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
300 MsiCloseHandle(db);
303 static BOOL create_package(LPWSTR path)
305 DWORD len;
307 /* Prepare package */
308 create_database(msifile, tables,
309 sizeof(tables) / sizeof(msi_table), summary_info,
310 sizeof(summary_info) / sizeof(msi_summary_info));
312 len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
313 CURR_DIR, -1, path, MAX_PATH);
314 ok(len, "MultiByteToWideChar returned error %d\n", GetLastError());
315 if (!len)
316 return FALSE;
318 /* lstrcatW does not work on win95 */
319 path[len - 1] = '\\';
320 memcpy(&path[len], szMsifile, sizeof(szMsifile));
321 return TRUE;
325 * Installation helpers
328 static char PROG_FILES_DIR[MAX_PATH];
330 static BOOL get_program_files_dir(LPSTR buf)
332 HKEY hkey;
333 DWORD type = REG_EXPAND_SZ, size;
335 if (RegOpenKey(HKEY_LOCAL_MACHINE,
336 "Software\\Microsoft\\Windows\\CurrentVersion", &hkey))
337 return FALSE;
339 size = MAX_PATH;
340 if (RegQueryValueEx(hkey, "ProgramFilesDir (x86)", 0, &type, (LPBYTE)buf, &size) &&
341 RegQueryValueEx(hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size))
342 return FALSE;
344 RegCloseKey(hkey);
345 return TRUE;
348 static void create_file(const CHAR *name, DWORD size)
350 HANDLE file;
351 DWORD written, left;
353 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
354 ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
355 WriteFile(file, name, strlen(name), &written, NULL);
356 WriteFile(file, "\n", strlen("\n"), &written, NULL);
358 left = size - lstrlen(name) - 1;
360 SetFilePointer(file, left, NULL, FILE_CURRENT);
361 SetEndOfFile(file);
363 CloseHandle(file);
366 static void create_test_files(void)
368 CreateDirectoryA("msitest", NULL);
369 create_file("msitest\\one.txt", 100);
370 CreateDirectoryA("msitest\\first", NULL);
371 create_file("msitest\\first\\two.txt", 100);
372 CreateDirectoryA("msitest\\second", NULL);
373 create_file("msitest\\second\\three.txt", 100);
374 CreateDirectoryA("msitest\\cabout",NULL);
375 create_file("msitest\\cabout\\four.txt", 100);
376 CreateDirectoryA("msitest\\cabout\\new",NULL);
377 create_file("msitest\\cabout\\new\\five.txt", 100);
378 create_file("msitest\\filename", 100);
381 static BOOL delete_pf(const CHAR *rel_path, BOOL is_file)
383 CHAR path[MAX_PATH];
385 lstrcpyA(path, PROG_FILES_DIR);
386 lstrcatA(path, "\\");
387 lstrcatA(path, rel_path);
389 if (is_file)
390 return DeleteFileA(path);
391 else
392 return RemoveDirectoryA(path);
395 static void delete_test_files(void)
397 DeleteFileA(msifile);
398 DeleteFileA("msitest\\cabout\\new\\five.txt");
399 DeleteFileA("msitest\\cabout\\four.txt");
400 DeleteFileA("msitest\\second\\three.txt");
401 DeleteFileA("msitest\\first\\two.txt");
402 DeleteFileA("msitest\\one.txt");
403 DeleteFileA("msitest\\filename");
404 RemoveDirectoryA("msitest\\cabout\\new");
405 RemoveDirectoryA("msitest\\cabout");
406 RemoveDirectoryA("msitest\\second");
407 RemoveDirectoryA("msitest\\first");
408 RemoveDirectoryA("msitest");
412 * Automation helpers and tests
415 /* ok-like statement which takes two unicode strings or one unicode and one ANSI string as arguments */
416 static CHAR string1[MAX_PATH], string2[MAX_PATH];
418 /* lstrcmpW is not supported on Win9x */
419 static int strcmp_ww(const WCHAR* str1, const WCHAR* str2)
421 CHAR str1A[MAX_PATH], str2A[MAX_PATH];
423 WideCharToMultiByte(CP_ACP, 0, str1, -1, str1A, MAX_PATH, NULL, NULL);
424 WideCharToMultiByte(CP_ACP, 0, str2, -1, str2A, MAX_PATH, NULL, NULL);
426 return lstrcmpA(str1A, str2A);
429 #define ok_w2(format, szString1, szString2) \
431 do { \
432 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
433 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
434 if (lstrcmpA(string1, string2) != 0) \
435 ok(0, format, string1, string2); \
436 } while(0);
438 #define ok_w2n(format, szString1, szString2, len) \
440 if (memcmp(szString1, szString2, len * sizeof(WCHAR)) != 0) \
442 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
443 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
444 ok(0, format, string1, string2); \
447 #define ok_aw(format, aString, wString) \
449 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
450 if (lstrcmpA(string1, aString) != 0) \
451 ok(0, format, string1, aString); \
453 #define ok_awplus(format, extra, aString, wString) \
455 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
456 if (lstrcmpA(string1, aString) != 0) \
457 ok(0, format, extra, string1, aString); \
459 /* exception checker */
460 static WCHAR szSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
462 #define ok_exception(hr, szDescription) \
463 if (hr == DISP_E_EXCEPTION) \
465 /* Compare wtype, source, and destination */ \
466 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
468 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
469 if (excepinfo.bstrSource) \
470 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, szSource); \
472 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
473 if (excepinfo.bstrDescription) \
474 ok_w2("Exception description was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrDescription, szDescription); \
476 SysFreeString(excepinfo.bstrSource); \
477 SysFreeString(excepinfo.bstrDescription); \
478 SysFreeString(excepinfo.bstrHelpFile); \
481 static DISPID get_dispid( IDispatch *disp, const char *name )
483 LPOLESTR str;
484 UINT len;
485 DISPID id = -1;
486 HRESULT r;
488 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
489 str = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
490 if (str)
492 len = MultiByteToWideChar(CP_ACP, 0, name, -1, str, len );
493 r = IDispatch_GetIDsOfNames( disp, &IID_NULL, &str, 1, 0, &id );
494 HeapFree(GetProcessHeap(), 0, str);
495 if (r != S_OK)
496 return -1;
499 return id;
502 static void test_dispid(void)
504 DISPID dispid;
506 dispid = get_dispid(pInstaller, "CreateRecord");
507 ok(dispid == 1, "Expected 1, got %d\n", dispid);
508 dispid = get_dispid(pInstaller, "OpenPackage");
509 ok(dispid == 2, "Expected 2, got %d\n", dispid);
510 dispid = get_dispid(pInstaller, "OpenProduct");
511 ok(dispid == 3, "Expected 3, got %d\n", dispid);
512 dispid = get_dispid(pInstaller, "OpenDatabase");
513 ok(dispid == 4, "Expected 4, got %d\n", dispid);
514 dispid = get_dispid(pInstaller, "SummaryInformation");
515 ok(dispid == 5, "Expected 5, got %d\n", dispid);
516 dispid = get_dispid( pInstaller, "UILevel" );
517 ok(dispid == 6, "Expected 6, got %d\n", dispid);
518 dispid = get_dispid(pInstaller, "EnableLog");
519 ok(dispid == 7, "Expected 7, got %d\n", dispid);
520 dispid = get_dispid(pInstaller, "InstallProduct");
521 ok(dispid == 8, "Expected 8, got %d\n", dispid);
522 dispid = get_dispid(pInstaller, "Version");
523 ok(dispid == 9, "Expected 9, got %d\n", dispid);
524 dispid = get_dispid(pInstaller, "LastErrorRecord");
525 ok(dispid == 10, "Expected 10, got %d\n", dispid);
526 dispid = get_dispid(pInstaller, "RegistryValue");
527 ok(dispid == 11, "Expected 11, got %d\n", dispid);
528 dispid = get_dispid(pInstaller, "Environment");
529 ok(dispid == 12, "Expected 12, got %d\n", dispid);
530 dispid = get_dispid(pInstaller, "FileAttributes");
531 ok(dispid == 13, "Expected 13, got %d\n", dispid);
532 dispid = get_dispid(pInstaller, "FileSize");
533 ok(dispid == 15, "Expected 15, got %d\n", dispid);
534 dispid = get_dispid(pInstaller, "FileVersion");
535 ok(dispid == 16, "Expected 16, got %d\n", dispid);
536 dispid = get_dispid(pInstaller, "ProductState");
537 ok(dispid == 17, "Expected 17, got %d\n", dispid);
538 dispid = get_dispid(pInstaller, "ProductInfo");
539 ok(dispid == 18, "Expected 18, got %d\n", dispid);
540 todo_wine
542 dispid = get_dispid(pInstaller, "ConfigureProduct");
543 ok(dispid == 19, "Expected 19, got %d\n", dispid);
544 dispid = get_dispid(pInstaller, "ReinstallProduct");
545 ok(dispid == 20 , "Expected 20, got %d\n", dispid);
546 dispid = get_dispid(pInstaller, "CollectUserInfo");
547 ok(dispid == 21, "Expected 21, got %d\n", dispid);
548 dispid = get_dispid(pInstaller, "ApplyPatch");
549 ok(dispid == 22, "Expected 22, got %d\n", dispid);
550 dispid = get_dispid(pInstaller, "FeatureParent");
551 ok(dispid == 23, "Expected 23, got %d\n", dispid);
552 dispid = get_dispid(pInstaller, "FeatureState");
553 ok(dispid == 24, "Expected 24, got %d\n", dispid);
554 dispid = get_dispid(pInstaller, "UseFeature");
555 ok(dispid == 25, "Expected 25, got %d\n", dispid);
556 dispid = get_dispid(pInstaller, "FeatureUsageCount");
557 ok(dispid == 26, "Expected 26, got %d\n", dispid);
558 dispid = get_dispid(pInstaller, "FeatureUsageDate");
559 ok(dispid == 27, "Expected 27, got %d\n", dispid);
560 dispid = get_dispid(pInstaller, "ConfigureFeature");
561 ok(dispid == 28, "Expected 28, got %d\n", dispid);
562 dispid = get_dispid(pInstaller, "ReinstallFeature");
563 ok(dispid == 29, "Expected 29, got %d\n", dispid);
564 dispid = get_dispid(pInstaller, "ProvideComponent");
565 ok(dispid == 30, "Expected 30, got %d\n", dispid);
566 dispid = get_dispid(pInstaller, "ComponentPath");
567 ok(dispid == 31, "Expected 31, got %d\n", dispid);
568 dispid = get_dispid(pInstaller, "ProvideQualifiedComponent");
569 ok(dispid == 32, "Expected 32, got %d\n", dispid);
570 dispid = get_dispid(pInstaller, "QualifierDescription");
571 ok(dispid == 33, "Expected 33, got %d\n", dispid);
572 dispid = get_dispid(pInstaller, "ComponentQualifiers");
573 ok(dispid == 34, "Expected 34, got %d\n", dispid);
575 dispid = get_dispid(pInstaller, "Products");
576 ok(dispid == 35, "Expected 35, got %d\n", dispid);
577 todo_wine
579 dispid = get_dispid(pInstaller, "Features");
580 ok(dispid == 36, "Expected 36, got %d\n", dispid);
581 dispid = get_dispid(pInstaller, "Components");
582 ok(dispid == 37, "Expected 37, got %d\n", dispid);
583 dispid = get_dispid(pInstaller, "ComponentClients");
584 ok(dispid == 38, "Expected 38, got %d\n", dispid);
585 dispid = get_dispid(pInstaller, "Patches");
586 ok(dispid == 39, "Expected 39, got %d\n", dispid);
588 dispid = get_dispid(pInstaller, "RelatedProducts");
589 ok(dispid == 40, "Expected 40, got %d\n", dispid);
590 todo_wine
592 dispid = get_dispid(pInstaller, "PatchInfo");
593 ok(dispid == 41, "Expected 41, got %d\n", dispid);
594 dispid = get_dispid(pInstaller, "PatchTransforms");
595 ok(dispid == 42, "Expected 42, got %d\n", dispid);
596 dispid = get_dispid(pInstaller, "AddSource");
597 ok(dispid == 43, "Expected 43, got %d\n", dispid);
598 dispid = get_dispid(pInstaller, "ClearSourceList");
599 ok(dispid == 44, "Expected 44, got %d\n", dispid);
600 dispid = get_dispid(pInstaller, "ForceSourceListResolution");
601 ok(dispid == 45, "Expected 45, got %d\n", dispid);
602 dispid = get_dispid(pInstaller, "ShortcutTarget");
603 ok(dispid == 46, "Expected 46, got %d\n", dispid);
604 dispid = get_dispid(pInstaller, "FileHash");
605 ok(dispid == 47, "Expected 47, got %d\n", dispid);
606 dispid = get_dispid(pInstaller, "FileSignatureInfo");
607 ok(dispid == 48, "Expected 48, got %d\n", dispid);
609 dispid = get_dispid(pInstaller, "RemovePatches");
610 ok(dispid == 49 || dispid == -1, "Expected 49 or -1, got %d\n", dispid);
611 dispid = get_dispid(pInstaller, "ApplyMultiplePatches");
612 ok(dispid == 51 || dispid == -1, "Expected 51 or -1, got %d\n", dispid);
613 dispid = get_dispid(pInstaller, "ProductsEx");
614 ok(dispid == 52 || dispid == -1, "Expected 52 or -1, got %d\n", dispid);
615 dispid = get_dispid(pInstaller, "PatchesEx");
616 ok(dispid == 55 || dispid == -1, "Expected 55 or -1, got %d\n", dispid);
617 dispid = get_dispid(pInstaller, "ExtractPatchXMLData");
618 ok(dispid == 57 || dispid == -1, "Expected 57 or -1, got %d\n", dispid);
619 dispid = get_dispid( pInstaller, "ProductElevated" );
620 ok(dispid == 59 || dispid == -1, "Expected 59 or -1, got %d\n", dispid);
621 dispid = get_dispid( pInstaller, "ProvideAssembly" );
622 ok(dispid == 60 || dispid == -1, "Expected 60 or -1, got %d\n", dispid);
623 dispid = get_dispid( pInstaller, "ProductInfoFromScript" );
624 ok(dispid == 61 || dispid == -1, "Expected 61 or -1, got %d\n", dispid);
625 dispid = get_dispid( pInstaller, "AdvertiseProduct" );
626 ok(dispid == 62 || dispid == -1, "Expected 62 or -1, got %d\n", dispid);
627 dispid = get_dispid( pInstaller, "CreateAdvertiseScript" );
628 ok(dispid == 63 || dispid == -1, "Expected 63 or -1, got %d\n", dispid);
629 dispid = get_dispid( pInstaller, "PatchFiles" );
630 ok(dispid == 65 || dispid == -1, "Expected 65 or -1, got %d\n", dispid);
633 /* Test basic IDispatch functions */
634 static void test_dispatch(void)
636 static WCHAR szOpenPackage[] = { 'O','p','e','n','P','a','c','k','a','g','e',0 };
637 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};
638 static WCHAR szProductState[] = { 'P','r','o','d','u','c','t','S','t','a','t','e',0 };
639 HRESULT hr;
640 DISPID dispid;
641 OLECHAR *name;
642 VARIANT varresult;
643 VARIANTARG vararg[3];
644 WCHAR path[MAX_PATH];
645 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
647 /* Test getting ID of a function name that does not exist */
648 name = (WCHAR *)szMsifile;
649 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
650 ok(hr == DISP_E_UNKNOWNNAME, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
652 /* Test invoking this function */
653 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
654 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
656 /* Test getting ID of a function name that does exist */
657 name = szOpenPackage;
658 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
659 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
661 /* Test invoking this function (without parameters passed) */
662 if (0) /* All of these crash MSI on Windows XP */
664 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
665 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL);
666 VariantInit(&varresult);
667 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, &varresult, &excepinfo, NULL);
670 /* Try with NULL params */
671 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
672 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
674 /* Try one empty parameter */
675 dispparams.rgvarg = vararg;
676 dispparams.cArgs = 1;
677 VariantInit(&vararg[0]);
678 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
679 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
681 /* Try two empty parameters */
682 dispparams.cArgs = 2;
683 VariantInit(&vararg[0]);
684 VariantInit(&vararg[1]);
685 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
686 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
688 /* Try one parameter, the required BSTR. Second parameter is optional.
689 * NOTE: The specified package does not exist, which is why the call fails.
691 dispparams.cArgs = 1;
692 VariantInit(&vararg[0]);
693 V_VT(&vararg[0]) = VT_BSTR;
694 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
695 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
696 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
697 ok_exception(hr, szOpenPackageException);
698 VariantClear(&vararg[0]);
700 /* Provide the required BSTR and an empty second parameter.
701 * NOTE: The specified package does not exist, which is why the call fails.
703 dispparams.cArgs = 2;
704 VariantInit(&vararg[1]);
705 V_VT(&vararg[1]) = VT_BSTR;
706 V_BSTR(&vararg[1]) = SysAllocString(szMsifile);
707 VariantInit(&vararg[0]);
708 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
709 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
710 ok_exception(hr, szOpenPackageException);
711 VariantClear(&vararg[1]);
713 /* Provide the required BSTR and two empty parameters.
714 * NOTE: The specified package does not exist, which is why the call fails.
716 dispparams.cArgs = 3;
717 VariantInit(&vararg[2]);
718 V_VT(&vararg[2]) = VT_BSTR;
719 V_BSTR(&vararg[2]) = SysAllocString(szMsifile);
720 VariantInit(&vararg[1]);
721 VariantInit(&vararg[0]);
722 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
723 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
724 ok_exception(hr, szOpenPackageException);
725 VariantClear(&vararg[2]);
727 /* Provide the required BSTR and a second parameter with the wrong type. */
728 dispparams.cArgs = 2;
729 VariantInit(&vararg[1]);
730 V_VT(&vararg[1]) = VT_BSTR;
731 V_BSTR(&vararg[1]) = SysAllocString(szMsifile);
732 VariantInit(&vararg[0]);
733 V_VT(&vararg[0]) = VT_BSTR;
734 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
735 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
736 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
737 VariantClear(&vararg[0]);
738 VariantClear(&vararg[1]);
740 /* Create a proper installer package. */
741 create_package(path);
743 /* Try one parameter, the required BSTR. Second parameter is optional.
744 * Proper installer package exists. Path to the package is relative.
746 dispparams.cArgs = 1;
747 VariantInit(&vararg[0]);
748 V_VT(&vararg[0]) = VT_BSTR;
749 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
750 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
751 todo_wine ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
752 ok_exception(hr, szOpenPackageException);
753 VariantClear(&vararg[0]);
754 if (hr != DISP_E_EXCEPTION)
755 VariantClear(&varresult);
757 /* Try one parameter, the required BSTR. Second parameter is optional.
758 * Proper installer package exists. Path to the package is absolute.
760 dispparams.cArgs = 1;
761 VariantInit(&vararg[0]);
762 V_VT(&vararg[0]) = VT_BSTR;
763 V_BSTR(&vararg[0]) = SysAllocString(path);
764 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
765 if (hr == DISP_E_EXCEPTION)
767 skip("OpenPackage failed, insufficient rights?\n");
768 DeleteFileW(path);
769 return;
771 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
772 VariantClear(&vararg[0]);
773 VariantClear(&varresult);
775 /* Provide the required BSTR and an empty second parameter. Proper
776 * installation package exists.
778 dispparams.cArgs = 2;
779 VariantInit(&vararg[1]);
780 V_VT(&vararg[1]) = VT_BSTR;
781 V_BSTR(&vararg[1]) = SysAllocString(path);
782 VariantInit(&vararg[0]);
783 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
784 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
785 VariantClear(&vararg[1]);
786 VariantClear(&varresult);
788 /* Provide the required BSTR and two empty parameters. Proper
789 * installation package exists.
791 dispparams.cArgs = 3;
792 VariantInit(&vararg[2]);
793 V_VT(&vararg[2]) = VT_BSTR;
794 V_BSTR(&vararg[2]) = SysAllocString(path);
795 VariantInit(&vararg[1]);
796 VariantInit(&vararg[0]);
797 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
798 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
799 VariantClear(&vararg[2]);
800 VariantClear(&varresult);
802 /* Provide the required BSTR and a second parameter with the wrong type. */
803 dispparams.cArgs = 2;
804 VariantInit(&vararg[1]);
805 V_VT(&vararg[1]) = VT_BSTR;
806 V_BSTR(&vararg[1]) = SysAllocString(path);
807 VariantInit(&vararg[0]);
808 V_VT(&vararg[0]) = VT_BSTR;
809 V_BSTR(&vararg[0]) = SysAllocString(path);
810 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
811 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
812 VariantClear(&vararg[0]);
813 VariantClear(&vararg[1]);
815 /* Provide the required BSTR and a second parameter that can be coerced to
816 * VT_I4.
818 dispparams.cArgs = 2;
819 VariantInit(&vararg[1]);
820 V_VT(&vararg[1]) = VT_BSTR;
821 V_BSTR(&vararg[1]) = SysAllocString(path);
822 VariantInit(&vararg[0]);
823 V_VT(&vararg[0]) = VT_I2;
824 V_BSTR(&vararg[0]) = 0;
825 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
826 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
827 VariantClear(&vararg[1]);
828 VariantClear(&varresult);
830 DeleteFileW(path);
832 /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
833 VariantInit(&vararg[0]);
834 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
835 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
837 VariantInit(&vararg[0]);
838 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
839 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
841 /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
842 name = szProductState;
843 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
844 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
846 dispparams.rgvarg = NULL;
847 dispparams.cArgs = 0;
848 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
849 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
851 dispparams.rgvarg = NULL;
852 dispparams.cArgs = 0;
853 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
854 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
857 /* invocation helper function */
858 static int _invoke_todo_vtResult = 0;
860 static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult)
862 OLECHAR *name = NULL;
863 DISPID dispid;
864 HRESULT hr;
865 UINT i;
866 UINT len;
868 memset(pVarResult, 0, sizeof(VARIANT));
869 VariantInit(pVarResult);
871 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 );
872 name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
873 if (!name) return E_FAIL;
874 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len );
875 hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
876 HeapFree(GetProcessHeap(), 0, name);
877 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
878 if (!hr == S_OK) return hr;
880 memset(&excepinfo, 0, sizeof(excepinfo));
881 hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL);
883 if (hr == S_OK)
885 if (_invoke_todo_vtResult) todo_wine
886 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
887 else
888 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
889 if (vtResult != VT_EMPTY)
891 hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult);
892 ok(hr == S_OK, "VariantChangeTypeEx returned 0x%08x\n", hr);
896 for (i=0; i<pDispParams->cArgs; i++)
897 VariantClear(&pDispParams->rgvarg[i]);
899 return hr;
902 /* Object_Property helper functions */
904 static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord)
906 VARIANT varresult;
907 VARIANTARG vararg[1];
908 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
909 HRESULT hr;
911 VariantInit(&vararg[0]);
912 V_VT(&vararg[0]) = VT_I4;
913 V_I4(&vararg[0]) = count;
915 hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
916 *pRecord = V_DISPATCH(&varresult);
917 return hr;
920 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
922 VARIANTARG vararg[3];
923 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
925 VariantInit(&vararg[2]);
926 V_VT(&vararg[2]) = VT_I4;
927 V_I4(&vararg[2]) = (INT_PTR)hkey;
928 VariantInit(&vararg[1]);
929 V_VT(&vararg[1]) = VT_BSTR;
930 V_BSTR(&vararg[1]) = SysAllocString(szKey);
931 VariantInit(&vararg[0]);
932 VariantCopy(&vararg[0], &vValue);
933 VariantClear(&vValue);
935 return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect);
938 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
940 VARIANT varresult;
941 VARIANTARG vararg;
942 HRESULT hr;
944 VariantInit(&vararg);
945 V_VT(&vararg) = VT_EMPTY;
946 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL);
947 *pBool = V_BOOL(&varresult);
948 VariantClear(&varresult);
949 return hr;
952 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
954 VARIANT varresult;
955 VARIANTARG vararg;
956 HRESULT hr;
958 VariantInit(&vararg);
959 V_VT(&vararg) = VT_BSTR;
960 V_BSTR(&vararg) = SysAllocString(szValue);
962 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR);
963 if (V_BSTR(&varresult))
964 /* lstrcpyW is not implemented on Win95 (lstrlenW is though) */
965 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
966 VariantClear(&varresult);
967 return hr;
970 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
972 VARIANT varresult;
973 VARIANTARG vararg;
974 HRESULT hr;
976 VariantInit(&vararg);
977 V_VT(&vararg) = VT_I4;
978 V_I4(&vararg) = iValue;
980 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult);
981 if (SUCCEEDED(hr) && vtResult == VT_BSTR)
982 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
983 VariantClear(&varresult);
984 return hr;
987 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
989 VARIANT varresult;
990 VARIANTARG vararg[2];
991 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
992 HRESULT hr;
994 VariantInit(&vararg[1]);
995 V_VT(&vararg[1]) = VT_BSTR;
996 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
997 VariantInit(&vararg[0]);
998 V_VT(&vararg[0]) = VT_I4;
999 V_I4(&vararg[0]) = options;
1001 hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1002 *pSession = V_DISPATCH(&varresult);
1003 return hr;
1006 static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase)
1008 VARIANT varresult;
1009 VARIANTARG vararg[2];
1010 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1011 HRESULT hr;
1013 VariantInit(&vararg[1]);
1014 V_VT(&vararg[1]) = VT_BSTR;
1015 V_BSTR(&vararg[1]) = SysAllocString(szDatabasePath);
1016 VariantInit(&vararg[0]);
1017 V_VT(&vararg[0]) = VT_I4;
1018 V_I4(&vararg[0]) = openmode;
1020 hr = invoke(pInstaller, "OpenDatabase", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1021 *pDatabase = V_DISPATCH(&varresult);
1022 return hr;
1025 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
1027 VARIANT varresult;
1028 VARIANTARG vararg[2];
1029 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1031 VariantInit(&vararg[1]);
1032 V_VT(&vararg[1]) = VT_BSTR;
1033 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
1034 VariantInit(&vararg[0]);
1035 V_VT(&vararg[0]) = VT_BSTR;
1036 V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues);
1038 return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1041 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
1043 VARIANT varresult;
1044 VARIANTARG vararg[1];
1045 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1046 HRESULT hr;
1048 VariantInit(&vararg[0]);
1049 V_VT(&vararg[0]) = VT_BSTR;
1050 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
1052 hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1053 *pInstallState = V_I4(&varresult);
1054 VariantClear(&varresult);
1055 return hr;
1058 static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szString)
1060 VARIANT varresult;
1061 VARIANTARG vararg[2];
1062 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1063 HRESULT hr;
1065 VariantInit(&vararg[1]);
1066 V_VT(&vararg[1]) = VT_BSTR;
1067 V_BSTR(&vararg[1]) = SysAllocString(szProduct);
1068 VariantInit(&vararg[0]);
1069 V_VT(&vararg[0]) = VT_BSTR;
1070 V_BSTR(&vararg[0]) = SysAllocString(szAttribute);
1072 hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1073 if (V_BSTR(&varresult))
1074 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
1075 VariantClear(&varresult);
1076 return hr;
1079 static HRESULT Installer_Products(IDispatch **pStringList)
1081 VARIANT varresult;
1082 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1083 HRESULT hr;
1085 hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1086 *pStringList = V_DISPATCH(&varresult);
1087 return hr;
1090 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
1092 VARIANT varresult;
1093 VARIANTARG vararg[1];
1094 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1095 HRESULT hr;
1097 VariantInit(&vararg[0]);
1098 V_VT(&vararg[0]) = VT_BSTR;
1099 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
1101 hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1102 *pStringList = V_DISPATCH(&varresult);
1103 return hr;
1106 static HRESULT Installer_VersionGet(LPWSTR szVersion)
1108 VARIANT varresult;
1109 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1110 HRESULT hr;
1112 hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1113 if (V_BSTR(&varresult))
1114 memcpy(szVersion, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
1115 VariantClear(&varresult);
1116 return hr;
1119 static HRESULT Installer_UILevelPut(int level)
1121 VARIANT varresult;
1122 VARIANTARG vararg;
1123 DISPID dispid = DISPID_PROPERTYPUT;
1124 DISPPARAMS dispparams = {&vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1126 VariantInit(&vararg);
1127 V_VT(&vararg) = VT_I4;
1128 V_I4(&vararg) = level;
1130 return invoke(pInstaller, "UILevel", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1133 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
1135 VARIANT varresult;
1136 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1137 HRESULT hr;
1139 hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1140 *pInst = V_DISPATCH(&varresult);
1141 return hr;
1144 static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn)
1146 VARIANT varresult;
1147 VARIANTARG vararg[1];
1148 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1149 HRESULT hr;
1151 VariantInit(&vararg[0]);
1152 V_VT(&vararg[0]) = VT_BSTR;
1153 V_BSTR(&vararg[0]) = SysAllocString(szName);
1155 hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1156 if (V_BSTR(&varresult))
1157 memcpy(szReturn, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
1158 VariantClear(&varresult);
1159 return hr;
1162 static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue)
1164 VARIANT varresult;
1165 VARIANTARG vararg[2];
1166 DISPID dispid = DISPID_PROPERTYPUT;
1167 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1169 VariantInit(&vararg[1]);
1170 V_VT(&vararg[1]) = VT_BSTR;
1171 V_BSTR(&vararg[1]) = SysAllocString(szName);
1172 VariantInit(&vararg[0]);
1173 V_VT(&vararg[0]) = VT_BSTR;
1174 V_BSTR(&vararg[0]) = SysAllocString(szValue);
1176 return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1179 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
1181 VARIANT varresult;
1182 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1183 HRESULT hr;
1185 hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1186 *pLangId = V_I4(&varresult);
1187 VariantClear(&varresult);
1188 return hr;
1191 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, BOOL *pMode)
1193 VARIANT varresult;
1194 VARIANTARG vararg[1];
1195 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1196 HRESULT hr;
1198 VariantInit(&vararg[0]);
1199 V_VT(&vararg[0]) = VT_I4;
1200 V_I4(&vararg[0]) = iFlag;
1202 hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL);
1203 *pMode = V_BOOL(&varresult);
1204 VariantClear(&varresult);
1205 return hr;
1208 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, BOOL bMode)
1210 VARIANT varresult;
1211 VARIANTARG vararg[2];
1212 DISPID dispid = DISPID_PROPERTYPUT;
1213 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1215 VariantInit(&vararg[1]);
1216 V_VT(&vararg[1]) = VT_I4;
1217 V_I4(&vararg[1]) = iFlag;
1218 VariantInit(&vararg[0]);
1219 V_VT(&vararg[0]) = VT_BOOL;
1220 V_BOOL(&vararg[0]) = bMode;
1222 return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1225 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
1227 VARIANT varresult;
1228 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1229 HRESULT hr;
1231 hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1232 *pDatabase = V_DISPATCH(&varresult);
1233 return hr;
1236 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn)
1238 VARIANT varresult;
1239 VARIANTARG vararg[1];
1240 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1241 HRESULT hr;
1243 VariantInit(&vararg[0]);
1244 V_VT(&vararg[0]) = VT_BSTR;
1245 V_BSTR(&vararg[0]) = SysAllocString(szAction);
1247 hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1248 *iReturn = V_I4(&varresult);
1249 VariantClear(&varresult);
1250 return hr;
1253 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
1255 VARIANT varresult;
1256 VARIANTARG vararg[1];
1257 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1258 HRESULT hr;
1260 VariantInit(&vararg[0]);
1261 V_VT(&vararg[0]) = VT_BSTR;
1262 V_BSTR(&vararg[0]) = SysAllocString(szCondition);
1264 hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1265 *iReturn = V_I4(&varresult);
1266 VariantClear(&varresult);
1267 return hr;
1270 static HRESULT Session_Message(IDispatch *pSession, LONG kind, IDispatch *record, int *ret)
1272 VARIANT varresult;
1273 VARIANTARG vararg[2];
1274 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1275 HRESULT hr;
1277 VariantInit(&varresult);
1278 V_VT(vararg) = VT_DISPATCH;
1279 V_DISPATCH(vararg) = record;
1280 V_VT(vararg+1) = VT_I4;
1281 V_I4(vararg+1) = kind;
1283 hr = invoke(pSession, "Message", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1285 ok(V_VT(&varresult) == VT_I4, "V_VT(varresult) = %d\n", V_VT(&varresult));
1286 *ret = V_I4(&varresult);
1288 return hr;
1291 static HRESULT Session_SetInstallLevel(IDispatch *pSession, LONG iInstallLevel)
1293 VARIANT varresult;
1294 VARIANTARG vararg[1];
1295 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1297 VariantInit(&vararg[0]);
1298 V_VT(&vararg[0]) = VT_I4;
1299 V_I4(&vararg[0]) = iInstallLevel;
1301 return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1304 static HRESULT Session_FeatureCurrentState(IDispatch *pSession, LPCWSTR szName, int *pState)
1306 VARIANT varresult;
1307 VARIANTARG vararg[1];
1308 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1309 HRESULT hr;
1311 VariantInit(&vararg[0]);
1312 V_VT(&vararg[0]) = VT_BSTR;
1313 V_BSTR(&vararg[0]) = SysAllocString(szName);
1315 hr = invoke(pSession, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1316 *pState = V_I4(&varresult);
1317 VariantClear(&varresult);
1318 return hr;
1321 static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState)
1323 VARIANT varresult;
1324 VARIANTARG vararg[1];
1325 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1326 HRESULT hr;
1328 VariantInit(&vararg[0]);
1329 V_VT(&vararg[0]) = VT_BSTR;
1330 V_BSTR(&vararg[0]) = SysAllocString(szName);
1332 hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1333 *pState = V_I4(&varresult);
1334 VariantClear(&varresult);
1335 return hr;
1338 static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState)
1340 VARIANT varresult;
1341 VARIANTARG vararg[2];
1342 DISPID dispid = DISPID_PROPERTYPUT;
1343 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1345 VariantInit(&vararg[1]);
1346 V_VT(&vararg[1]) = VT_BSTR;
1347 V_BSTR(&vararg[1]) = SysAllocString(szName);
1348 VariantInit(&vararg[0]);
1349 V_VT(&vararg[0]) = VT_I4;
1350 V_I4(&vararg[0]) = iState;
1352 return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1355 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
1357 VARIANT varresult;
1358 VARIANTARG vararg[1];
1359 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1360 HRESULT hr;
1362 VariantInit(&vararg[0]);
1363 V_VT(&vararg[0]) = VT_BSTR;
1364 V_BSTR(&vararg[0]) = SysAllocString(szSql);
1366 hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1367 *pView = V_DISPATCH(&varresult);
1368 return hr;
1371 static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo)
1373 VARIANT varresult;
1374 VARIANTARG vararg[1];
1375 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1376 HRESULT hr;
1378 VariantInit(&vararg[0]);
1379 V_VT(&vararg[0]) = VT_I4;
1380 V_I4(&vararg[0]) = iUpdateCount;
1382 hr = invoke(pDatabase, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1383 *pSummaryInfo = V_DISPATCH(&varresult);
1384 return hr;
1387 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
1389 VARIANT varresult;
1390 VARIANTARG vararg[1];
1391 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1393 VariantInit(&vararg[0]);
1394 V_VT(&vararg[0]) = VT_DISPATCH;
1395 V_DISPATCH(&vararg[0]) = pRecord;
1397 return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1400 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
1402 VARIANT varresult;
1403 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1404 HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1405 *ppRecord = V_DISPATCH(&varresult);
1406 return hr;
1409 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
1411 VARIANT varresult;
1412 VARIANTARG vararg[2];
1413 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1415 VariantInit(&vararg[1]);
1416 V_VT(&vararg[1]) = VT_I4;
1417 V_I4(&vararg[1]) = iMode;
1418 VariantInit(&vararg[0]);
1419 V_VT(&vararg[0]) = VT_DISPATCH;
1420 V_DISPATCH(&vararg[0]) = pRecord;
1421 if (pRecord)
1422 IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */
1424 return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1427 static HRESULT View_Close(IDispatch *pView)
1429 VARIANT varresult;
1430 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1431 return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1434 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
1436 VARIANT varresult;
1437 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1438 HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1439 *pFieldCount = V_I4(&varresult);
1440 VariantClear(&varresult);
1441 return hr;
1444 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString)
1446 VARIANT varresult;
1447 VARIANTARG vararg[1];
1448 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1449 HRESULT hr;
1451 VariantInit(&vararg[0]);
1452 V_VT(&vararg[0]) = VT_I4;
1453 V_I4(&vararg[0]) = iField;
1455 hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1456 if (V_BSTR(&varresult))
1457 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
1458 VariantClear(&varresult);
1459 return hr;
1462 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
1464 VARIANT varresult;
1465 VARIANTARG vararg[2];
1466 DISPID dispid = DISPID_PROPERTYPUT;
1467 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1469 VariantInit(&vararg[1]);
1470 V_VT(&vararg[1]) = VT_I4;
1471 V_I4(&vararg[1]) = iField;
1472 VariantInit(&vararg[0]);
1473 V_VT(&vararg[0]) = VT_BSTR;
1474 V_BSTR(&vararg[0]) = SysAllocString(szString);
1476 return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1479 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
1481 VARIANT varresult;
1482 VARIANTARG vararg[1];
1483 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1484 HRESULT hr;
1486 VariantInit(&vararg[0]);
1487 V_VT(&vararg[0]) = VT_I4;
1488 V_I4(&vararg[0]) = iField;
1490 hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1491 *pValue = V_I4(&varresult);
1492 VariantClear(&varresult);
1493 return hr;
1496 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
1498 VARIANT varresult;
1499 VARIANTARG vararg[2];
1500 DISPID dispid = DISPID_PROPERTYPUT;
1501 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1503 VariantInit(&vararg[1]);
1504 V_VT(&vararg[1]) = VT_I4;
1505 V_I4(&vararg[1]) = iField;
1506 VariantInit(&vararg[0]);
1507 V_VT(&vararg[0]) = VT_I4;
1508 V_I4(&vararg[0]) = iValue;
1510 return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1513 static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT)
1515 VARIANT varresult;
1516 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1517 HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN);
1518 *ppEnumVARIANT = V_UNKNOWN(&varresult);
1519 return hr;
1522 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
1524 VARIANT varresult;
1525 VARIANTARG vararg[1];
1526 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1527 HRESULT hr;
1529 VariantInit(&vararg[0]);
1530 V_VT(&vararg[0]) = VT_I4;
1531 V_I4(&vararg[0]) = iIndex;
1533 hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1534 if (V_BSTR(&varresult))
1535 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
1536 VariantClear(&varresult);
1537 return hr;
1540 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
1542 VARIANT varresult;
1543 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1544 HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1545 *pCount = V_I4(&varresult);
1546 VariantClear(&varresult);
1547 return hr;
1550 static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect)
1552 VARIANTARG vararg[1];
1553 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1555 VariantInit(&vararg[0]);
1556 V_VT(&vararg[0]) = VT_I4;
1557 V_I4(&vararg[0]) = pid;
1558 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYGET, &dispparams, pVarResult, vtExpect);
1561 static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant)
1563 VARIANT varresult;
1564 VARIANTARG vararg[2];
1565 DISPID dispid = DISPID_PROPERTYPUT;
1566 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1568 VariantInit(&vararg[1]);
1569 V_VT(&vararg[1]) = VT_I4;
1570 V_I4(&vararg[1]) = pid;
1571 VariantInit(&vararg[0]);
1572 VariantCopyInd(vararg, pVariant);
1574 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1577 static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount)
1579 VARIANT varresult;
1580 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1581 HRESULT hr;
1583 hr = invoke(pSummaryInfo, "PropertyCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1584 *pCount = V_I4(&varresult);
1585 VariantClear(&varresult);
1586 return hr;
1589 /* Test the various objects */
1591 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4
1593 static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly)
1595 static const WCHAR szPropertyException[] = { 'P','r','o','p','e','r','t','y',',','P','i','d',0 };
1596 static const WCHAR szTitle[] = { 'T','i','t','l','e',0 };
1597 VARIANT varresult, var;
1598 SYSTEMTIME st;
1599 HRESULT hr;
1600 int j;
1602 /* SummaryInfo::PropertyCount */
1603 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1604 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1605 ok(j == num_info, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1607 /* SummaryInfo::Property, get for properties we have set */
1608 for (j = 0; j < num_info; j++)
1610 const msi_summary_info *entry = &info[j];
1612 int vt = entry->datatype;
1613 if (vt == VT_LPSTR) vt = VT_BSTR;
1614 else if (vt == VT_FILETIME) vt = VT_DATE;
1615 else if (vt == VT_I2) vt = VT_I4;
1617 hr = SummaryInfo_PropertyGet(pSummaryInfo, entry->property, &varresult, vt);
1618 ok(hr == S_OK, "SummaryInfo_Property (pid %d) failed, hresult 0x%08x\n", entry->property, hr);
1619 if (V_VT(&varresult) != vt)
1620 skip("Skipping property tests due to type mismatch\n");
1621 else if (vt == VT_I4)
1622 ok(V_I4(&varresult) == entry->iValue, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %d\n",
1623 entry->property, entry->iValue, V_I4(&varresult));
1624 else if (vt == VT_DATE)
1626 FILETIME ft;
1627 DATE d;
1629 FileTimeToLocalFileTime(entry->pftValue, &ft);
1630 FileTimeToSystemTime(&ft, &st);
1631 SystemTimeToVariantTime(&st, &d);
1632 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));
1634 else if (vt == VT_BSTR)
1636 ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry->property, entry->szValue, V_BSTR(&varresult));
1638 else
1639 skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry->property, vt);
1641 VariantClear(&varresult);
1644 /* SummaryInfo::Property, get; invalid arguments */
1646 /* Invalid pids */
1647 hr = SummaryInfo_PropertyGet(pSummaryInfo, -1, &varresult, VT_EMPTY);
1648 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1649 ok_exception(hr, szPropertyException);
1651 hr = SummaryInfo_PropertyGet(pSummaryInfo, 1000, &varresult, VT_EMPTY);
1652 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1653 ok_exception(hr, szPropertyException);
1655 /* Unsupported pids */
1656 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_DICTIONARY, &varresult, VT_EMPTY);
1657 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1659 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY);
1660 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1662 /* Pids we have not set, one for each type */
1663 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_EMPTY);
1664 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1666 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY);
1667 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1669 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY);
1670 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1672 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY);
1673 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1675 if (!readonly)
1677 /* SummaryInfo::Property, put; one for each type */
1679 /* VT_I2 */
1680 VariantInit(&var);
1681 V_VT(&var) = VT_I2;
1682 V_I2(&var) = 1;
1683 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CODEPAGE, &var);
1684 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1686 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */);
1687 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1688 ok(V_I2(&var) == V_I2(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var), V_I2(&varresult));
1689 VariantClear(&varresult);
1690 VariantClear(&var);
1692 /* VT_BSTR */
1693 V_VT(&var) = VT_BSTR;
1694 V_BSTR(&var) = SysAllocString(szTitle);
1695 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_TITLE, &var);
1696 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1698 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var));
1699 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1700 ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var), V_BSTR(&varresult));
1701 VariantClear(&varresult);
1702 VariantClear(&var);
1704 /* VT_DATE */
1705 V_VT(&var) = VT_DATE;
1706 FileTimeToSystemTime(&systemtime, &st);
1707 SystemTimeToVariantTime(&st, &V_DATE(&var));
1708 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_LASTSAVE_DTM, &var);
1709 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1711 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var));
1712 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1713 ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1714 VariantClear(&varresult);
1715 VariantClear(&var);
1717 /* VT_I4 */
1718 V_VT(&var) = VT_I4;
1719 V_I4(&var) = 1000;
1720 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1721 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1723 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1724 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1725 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult));
1726 VariantClear(&varresult);
1727 VariantClear(&var);
1729 /* SummaryInfo::PropertyCount */
1730 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1731 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1732 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1736 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1738 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 };
1739 static WCHAR szThree[] = { 'T','h','r','e','e',0 };
1740 static WCHAR szTwo[] = { 'T','w','o',0 };
1741 static WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
1742 static WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 };
1743 IDispatch *pView = NULL, *pSummaryInfo = NULL;
1744 HRESULT hr;
1746 hr = Database_OpenView(pDatabase, szSql, &pView);
1747 ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr);
1748 if (hr == S_OK)
1750 IDispatch *pRecord = NULL;
1751 WCHAR szString[MAX_PATH];
1753 /* View::Execute */
1754 hr = View_Execute(pView, NULL);
1755 ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr);
1757 /* View::Fetch */
1758 hr = View_Fetch(pView, &pRecord);
1759 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1760 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1761 if (pRecord)
1763 /* Record::StringDataGet */
1764 memset(szString, 0, sizeof(szString));
1765 hr = Record_StringDataGet(pRecord, 1, szString);
1766 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1767 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1769 /* Record::StringDataPut with correct index */
1770 hr = Record_StringDataPut(pRecord, 1, szTwo);
1771 ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1773 /* Record::StringDataGet */
1774 memset(szString, 0, sizeof(szString));
1775 hr = Record_StringDataGet(pRecord, 1, szString);
1776 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1777 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1779 /* Record::StringDataPut with incorrect index */
1780 hr = Record_StringDataPut(pRecord, -1, szString);
1781 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1782 ok_exception(hr, szStringDataField);
1784 /* View::Modify with incorrect parameters */
1785 hr = View_Modify(pView, -5, NULL);
1786 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1787 ok_exception(hr, szModifyModeRecord);
1789 hr = View_Modify(pView, -5, pRecord);
1790 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1791 ok_exception(hr, szModifyModeRecord);
1793 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1794 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1795 ok_exception(hr, szModifyModeRecord);
1797 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1798 ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr);
1800 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1801 memset(szString, 0, sizeof(szString));
1802 hr = Record_StringDataGet(pRecord, 1, szString);
1803 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1804 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1806 IDispatch_Release(pRecord);
1809 /* View::Fetch */
1810 hr = View_Fetch(pView, &pRecord);
1811 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1812 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1813 if (pRecord)
1815 /* Record::StringDataGet */
1816 memset(szString, 0, sizeof(szString));
1817 hr = Record_StringDataGet(pRecord, 1, szString);
1818 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1819 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1821 IDispatch_Release(pRecord);
1824 /* View::Fetch */
1825 hr = View_Fetch(pView, &pRecord);
1826 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1827 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1828 if (pRecord)
1829 IDispatch_Release(pRecord);
1831 /* View::Close */
1832 hr = View_Close(pView);
1833 ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr);
1835 IDispatch_Release(pView);
1838 /* Database::SummaryInformation */
1839 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo);
1840 ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr);
1841 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1842 if (pSummaryInfo)
1844 test_SummaryInfo(pSummaryInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), readonly);
1845 IDispatch_Release(pSummaryInfo);
1849 static void test_Session(IDispatch *pSession)
1851 static WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
1852 static WCHAR szOne[] = { 'O','n','e',0 };
1853 static WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 };
1854 static WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 };
1855 static WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 };
1856 static WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 };
1857 static WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1858 static WCHAR szEmpty[] = { 0 };
1859 static WCHAR szEquals[] = { '=',0 };
1860 static WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
1861 static WCHAR szModeFlag[] = { 'M','o','d','e',',','F','l','a','g',0 };
1862 WCHAR stringw[MAX_PATH];
1863 CHAR string[MAX_PATH];
1864 UINT len;
1865 BOOL bool;
1866 int myint;
1867 IDispatch *pDatabase = NULL, *pInst = NULL, *record = NULL;
1868 ULONG refs_before, refs_after;
1869 HRESULT hr;
1871 /* Session::Installer */
1872 hr = Session_Installer(pSession, &pInst);
1873 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1874 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1875 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1876 refs_before = IDispatch_AddRef(pInst);
1878 hr = Session_Installer(pSession, &pInst);
1879 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1880 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1881 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1882 refs_after = IDispatch_Release(pInst);
1883 ok(refs_before == refs_after, "got %u and %u\n", refs_before, refs_after);
1885 /* Session::Property, get */
1886 memset(stringw, 0, sizeof(stringw));
1887 hr = Session_PropertyGet(pSession, szProductName, stringw);
1888 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1889 if (strcmp_ww(stringw, szMSITEST) != 0)
1891 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1892 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1893 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1896 /* Session::Property, put */
1897 hr = Session_PropertyPut(pSession, szProductName, szProductName);
1898 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1899 memset(stringw, 0, sizeof(stringw));
1900 hr = Session_PropertyGet(pSession, szProductName, stringw);
1901 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1902 if (strcmp_ww(stringw, szProductName) != 0)
1904 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1905 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1906 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1909 /* Try putting a property using empty property identifier */
1910 hr = Session_PropertyPut(pSession, szEmpty, szProductName);
1911 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1912 ok_exception(hr, szPropertyName);
1914 /* Try putting a property using illegal property identifier */
1915 hr = Session_PropertyPut(pSession, szEquals, szProductName);
1916 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1918 /* Session::Language, get */
1919 hr = Session_LanguageGet(pSession, &len);
1920 ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1921 /* Not sure how to check the language is correct */
1923 /* Session::Mode, get */
1924 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1925 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1926 ok(!bool, "Reboot at end session mode is %d\n", bool);
1928 hr = Session_ModeGet(pSession, MSIRUNMODE_MAINTENANCE, &bool);
1929 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1930 ok(!bool, "Maintenance mode is %d\n", bool);
1932 /* Session::Mode, put */
1933 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE);
1934 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1935 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1936 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1937 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1938 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE); /* set it again so we don't reboot */
1939 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1941 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, TRUE);
1942 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1943 if (hr == DISP_E_EXCEPTION) ok_exception(hr, szModeFlag);
1945 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTNOW, &bool);
1946 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1947 ok(bool, "Reboot now mode is %d, expected 1\n", bool);
1949 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, FALSE); /* set it again so we don't reboot */
1950 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1951 if (hr == DISP_E_EXCEPTION) ok_exception(hr, szModeFlag);
1953 hr = Session_ModePut(pSession, MSIRUNMODE_MAINTENANCE, TRUE);
1954 ok(hr == DISP_E_EXCEPTION, "Session_ModePut failed, hresult 0x%08x\n", hr);
1955 ok_exception(hr, szModeFlag);
1957 /* Session::Database, get */
1958 hr = Session_Database(pSession, &pDatabase);
1959 ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr);
1960 if (hr == S_OK)
1962 test_Database(pDatabase, TRUE);
1963 IDispatch_Release(pDatabase);
1966 /* Session::EvaluateCondition */
1967 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1968 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1969 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1971 hr = Session_EvaluateCondition(pSession, szEmpty, &myint);
1972 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1973 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1975 hr = Session_EvaluateCondition(pSession, szEquals, &myint);
1976 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1977 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1979 /* Session::DoAction(CostInitialize) must occur before the next statements */
1980 hr = Session_DoAction(pSession, szCostInitialize, &myint);
1981 ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr);
1982 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1984 /* Session::SetInstallLevel */
1985 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1986 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
1988 /* Session::FeatureCurrentState, get */
1989 hr = Session_FeatureCurrentState(pSession, szOne, &myint);
1990 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
1991 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1993 /* Session::Message */
1994 hr = Installer_CreateRecord(0, &record);
1995 ok(hr == S_OK, "Installer_CreateRecord failed: %08x\n", hr);
1996 hr = Session_Message(pSession, INSTALLMESSAGE_INFO, record, &myint);
1997 ok(hr == S_OK, "Session_Message failed: %08x\n", hr);
1998 ok(myint == 0, "Session_Message returned %x\n", myint);
2000 /* Session::EvaluateCondition */
2001 hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint);
2002 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2003 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2005 hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint);
2006 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2007 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2009 /* Session::FeatureRequestState, put */
2010 hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED);
2011 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
2012 hr = Session_FeatureRequestStateGet(pSession, szOne, &myint);
2013 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
2014 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
2016 /* Session::EvaluateCondition */
2017 hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint);
2018 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2019 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2021 hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint);
2022 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2023 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2026 /* delete key and all its subkeys */
2027 static DWORD delete_key( HKEY hkey )
2029 char name[MAX_PATH];
2030 DWORD ret;
2032 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
2034 HKEY tmp;
2035 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
2037 ret = delete_key( tmp );
2038 RegCloseKey( tmp );
2040 if (ret) break;
2042 if (ret != ERROR_NO_MORE_ITEMS) return ret;
2043 RegDeleteKeyA( hkey, "" );
2044 return 0;
2047 static void test_Installer_RegistryValue(void)
2049 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
2050 static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 };
2051 static const WCHAR szOne[] = { 'O','n','e',0 };
2052 static const WCHAR szTwo[] = { 'T','w','o',0 };
2053 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
2054 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
2055 static const WCHAR szFour[] = { 'F','o','u','r',0 };
2056 static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 };
2057 static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 };
2058 static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 };
2059 static const WCHAR szSix[] = { 'S','i','x',0 };
2060 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
2061 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
2062 static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
2063 static const WCHAR szBlank[] = { 0 };
2064 VARIANT varresult;
2065 VARIANTARG vararg;
2066 WCHAR szString[MAX_PATH];
2067 HKEY hkey, hkey_sub;
2068 HKEY curr_user = (HKEY)1;
2069 HRESULT hr;
2070 BOOL bRet;
2071 LONG lRet;
2073 /* Delete keys */
2074 SetLastError(0xdeadbeef);
2075 lRet = RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey );
2076 if (!lRet && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2078 win_skip("Needed W-functions are not implemented\n");
2079 return;
2081 if (!lRet)
2082 delete_key( hkey );
2084 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
2085 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
2086 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
2087 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
2089 memset(szString, 0, sizeof(szString));
2090 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
2091 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2093 memset(szString, 0, sizeof(szString));
2094 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
2095 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2097 /* Create key */
2098 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
2100 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
2101 "RegSetValueExW failed\n");
2102 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
2103 "RegSetValueExW failed\n");
2104 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
2105 "RegSetValueExW failed\n");
2106 ok(SetEnvironmentVariableA("MSITEST", "Four"), "SetEnvironmentVariableA failed %d\n", GetLastError());
2107 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
2108 "RegSetValueExW failed\n");
2109 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
2110 "RegSetValueExW failed\n");
2111 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
2112 "RegSetValueExW failed\n");
2113 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, NULL, 0),
2114 "RegSetValueExW failed\n");
2116 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
2117 "RegSetValueExW failed\n");
2119 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
2121 /* Does our key exist? It should, and make sure we retrieve the correct default value */
2122 bRet = FALSE;
2123 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
2124 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
2125 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
2127 memset(szString, 0, sizeof(szString));
2128 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
2129 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2130 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
2132 /* Ask for the value of a nonexistent key */
2133 memset(szString, 0, sizeof(szString));
2134 hr = Installer_RegistryValueW(curr_user, szKey, szExpand, szString);
2135 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2137 /* Get values of keys */
2138 memset(szString, 0, sizeof(szString));
2139 hr = Installer_RegistryValueW(curr_user, szKey, szOne, szString);
2140 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2141 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
2143 VariantInit(&vararg);
2144 V_VT(&vararg) = VT_BSTR;
2145 V_BSTR(&vararg) = SysAllocString(szTwo);
2146 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_I4);
2147 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
2148 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
2149 VariantClear(&varresult);
2151 memset(szString, 0, sizeof(szString));
2152 hr = Installer_RegistryValueW(curr_user, szKey, szThree, szString);
2153 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2154 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
2156 memset(szString, 0, sizeof(szString));
2157 hr = Installer_RegistryValueW(curr_user, szKey, szFour, szString);
2158 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2159 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
2161 /* Vista does not NULL-terminate this case */
2162 memset(szString, 0, sizeof(szString));
2163 hr = Installer_RegistryValueW(curr_user, szKey, szFive, szString);
2164 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2165 ok_w2n("Registry value \"%s\" does not match expected \"%s\"\n",
2166 szString, szFiveHi, lstrlenW(szFiveHi));
2168 memset(szString, 0, sizeof(szString));
2169 hr = Installer_RegistryValueW(curr_user, szKey, szSix, szString);
2170 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2171 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_);
2173 VariantInit(&vararg);
2174 V_VT(&vararg) = VT_BSTR;
2175 V_BSTR(&vararg) = SysAllocString(szSeven);
2176 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_EMPTY);
2177 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
2179 /* Get string class name for the key */
2180 memset(szString, 0, sizeof(szString));
2181 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
2182 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2183 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank);
2185 /* Get name of a value by positive number (RegEnumValue like), valid index */
2186 memset(szString, 0, sizeof(szString));
2187 hr = Installer_RegistryValueI(curr_user, szKey, 2, szString, VT_BSTR);
2188 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2189 /* RegEnumValue order seems different on wine */
2190 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
2192 /* Get name of a value by positive number (RegEnumValue like), invalid index */
2193 memset(szString, 0, sizeof(szString));
2194 hr = Installer_RegistryValueI(curr_user, szKey, 10, szString, VT_EMPTY);
2195 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2197 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
2198 memset(szString, 0, sizeof(szString));
2199 hr = Installer_RegistryValueI(curr_user, szKey, -1, szString, VT_BSTR);
2200 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2201 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
2203 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
2204 memset(szString, 0, sizeof(szString));
2205 hr = Installer_RegistryValueI(curr_user, szKey, -10, szString, VT_EMPTY);
2206 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2208 /* clean up */
2209 delete_key(hkey);
2212 static void test_Installer_Products(BOOL bProductInstalled)
2214 WCHAR szString[MAX_PATH];
2215 HRESULT hr;
2216 int idx;
2217 IUnknown *pUnk = NULL;
2218 IEnumVARIANT *pEnum = NULL;
2219 VARIANT var;
2220 ULONG celt;
2221 int iCount, iValue;
2222 IDispatch *pStringList = NULL;
2223 BOOL bProductFound = FALSE;
2225 /* Installer::Products */
2226 hr = Installer_Products(&pStringList);
2227 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
2228 if (hr == S_OK)
2230 /* StringList::_NewEnum */
2231 hr = StringList__NewEnum(pStringList, &pUnk);
2232 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
2233 if (hr == S_OK)
2235 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
2236 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2238 if (!pEnum)
2239 skip("IEnumVARIANT tests\n");
2241 /* StringList::Count */
2242 hr = StringList_Count(pStringList, &iCount);
2243 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2245 for (idx=0; idx<iCount; idx++)
2247 /* StringList::Item */
2248 memset(szString, 0, sizeof(szString));
2249 hr = StringList_Item(pStringList, idx, szString);
2250 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2252 if (hr == S_OK)
2254 /* Installer::ProductState */
2255 hr = Installer_ProductState(szString, &iValue);
2256 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2257 if (hr == S_OK)
2258 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
2260 /* Not found our product code yet? Check */
2261 if (!bProductFound && !strcmp_ww(szString, szProductCode))
2262 bProductFound = TRUE;
2264 /* IEnumVARIANT::Next */
2265 if (pEnum)
2267 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2268 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2269 ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
2270 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2271 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2272 VariantClear(&var);
2277 if (bProductInstalled)
2279 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
2280 bProductInstalled ? "be" : "not be",
2281 bProductFound ? "found" : "not found");
2284 if (pEnum)
2286 IEnumVARIANT *pEnum2 = NULL;
2288 if (0) /* Crashes on Windows XP */
2290 /* IEnumVARIANT::Clone, NULL pointer */
2291 hr = IEnumVARIANT_Clone(pEnum, NULL);
2294 /* IEnumVARIANT::Clone */
2295 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
2296 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
2297 if (hr == S_OK)
2299 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
2301 /* IEnumVARIANT::Next of the clone */
2302 if (iCount)
2304 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
2305 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2306 ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
2307 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2308 VariantClear(&var);
2310 else
2311 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
2313 IEnumVARIANT_Release(pEnum2);
2316 /* IEnumVARIANT::Skip should fail */
2317 hr = IEnumVARIANT_Skip(pEnum, 1);
2318 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2320 /* IEnumVARIANT::Next, NULL variant pointer */
2321 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2322 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2323 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2325 /* IEnumVARIANT::Next, should not return any more items */
2326 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2327 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2328 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2329 VariantClear(&var);
2331 /* IEnumVARIANT::Reset */
2332 hr = IEnumVARIANT_Reset(pEnum);
2333 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2335 if (iCount)
2337 /* IEnumVARIANT::Skip to the last product */
2338 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2339 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2341 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2342 * NULL celt pointer. */
2343 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2344 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2345 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2346 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2347 VariantClear(&var);
2349 else
2350 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2353 /* StringList::Item using an invalid index */
2354 memset(szString, 0, sizeof(szString));
2355 hr = StringList_Item(pStringList, iCount, szString);
2356 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2358 if (pEnum) IEnumVARIANT_Release(pEnum);
2359 if (pUnk) IUnknown_Release(pUnk);
2360 IDispatch_Release(pStringList);
2364 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2365 * deleting the subkeys first) */
2366 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey, REGSAM access)
2368 UINT ret;
2369 CHAR *string = NULL;
2370 HKEY hkey;
2371 DWORD dwSize;
2373 ret = RegOpenKeyEx(hkeyParent, subkey, 0, access, &hkey);
2374 if (ret != ERROR_SUCCESS) return ret;
2375 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2376 if (ret != ERROR_SUCCESS) return ret;
2377 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2379 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2380 delete_registry_key(hkey, string, access);
2382 RegCloseKey(hkey);
2383 HeapFree(GetProcessHeap(), 0, string);
2384 delete_key_portable(hkeyParent, subkey, access);
2385 return ERROR_SUCCESS;
2388 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2389 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, REGSAM access, HKEY *phkey)
2391 UINT ret;
2392 CHAR *string = NULL;
2393 int idx = 0;
2394 HKEY hkey;
2395 DWORD dwSize;
2396 BOOL found = FALSE;
2398 *phkey = 0;
2400 ret = RegOpenKeyEx(hkeyParent, subkey, 0, access, &hkey);
2401 if (ret != ERROR_SUCCESS) return ret;
2402 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2403 if (ret != ERROR_SUCCESS) return ret;
2404 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2406 while (!found &&
2407 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2409 if (!strcmp(string, findkey))
2411 *phkey = hkey;
2412 found = TRUE;
2414 else if (find_registry_key(hkey, string, findkey, access, phkey) == ERROR_SUCCESS) found = TRUE;
2417 if (*phkey != hkey) RegCloseKey(hkey);
2418 HeapFree(GetProcessHeap(), 0, string);
2419 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2422 static void test_Installer_InstallProduct(void)
2424 HRESULT hr;
2425 CHAR path[MAX_PATH];
2426 WCHAR szString[MAX_PATH];
2427 LONG res;
2428 HKEY hkey;
2429 DWORD num, size, type;
2430 int iValue, iCount;
2431 IDispatch *pStringList = NULL;
2432 REGSAM access = KEY_ALL_ACCESS;
2434 if (is_wow64)
2435 access |= KEY_WOW64_64KEY;
2437 create_test_files();
2439 /* Avoid an interactive dialog in case of insufficient privileges. */
2440 hr = Installer_UILevelPut(INSTALLUILEVEL_NONE);
2441 ok(hr == S_OK, "Expected UILevel propery put invoke to return S_OK, got 0x%08x\n", hr);
2443 /* Installer::InstallProduct */
2444 hr = Installer_InstallProduct(szMsifile, NULL);
2445 if (hr == DISP_E_EXCEPTION)
2447 skip("InstallProduct failed, insufficient rights?\n");
2448 delete_test_files();
2449 return;
2451 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2453 /* Installer::ProductState for our product code, which has been installed */
2454 hr = Installer_ProductState(szProductCode, &iValue);
2455 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2456 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2458 /* Installer::ProductInfo for our product code */
2460 /* NULL attribute */
2461 memset(szString, 0, sizeof(szString));
2462 hr = Installer_ProductInfo(szProductCode, NULL, szString);
2463 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2464 ok_exception(hr, szProductInfoException);
2466 /* Nonexistent attribute */
2467 memset(szString, 0, sizeof(szString));
2468 hr = Installer_ProductInfo(szProductCode, szMsifile, szString);
2469 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2470 ok_exception(hr, szProductInfoException);
2472 /* Package name */
2473 memset(szString, 0, sizeof(szString));
2474 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szString);
2475 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2476 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile);
2478 /* Product name */
2479 memset(szString, 0, sizeof(szString));
2480 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PRODUCTNAMEW, szString);
2481 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2482 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST);
2484 /* Installer::Products */
2485 test_Installer_Products(TRUE);
2487 /* Installer::RelatedProducts for our upgrade code */
2488 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2489 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2490 if (hr == S_OK)
2492 /* StringList::Count */
2493 hr = StringList_Count(pStringList, &iCount);
2494 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2495 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2497 /* StringList::Item */
2498 memset(szString, 0, sizeof(szString));
2499 hr = StringList_Item(pStringList, 0, szString);
2500 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2501 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
2503 IDispatch_Release(pStringList);
2506 /* Check & clean up installed files & registry keys */
2507 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2508 ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
2509 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2510 ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
2511 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2512 ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
2513 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2514 ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
2515 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2516 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2517 ok(delete_pf("msitest", FALSE), "File not installed\n");
2519 res = RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest", &hkey);
2520 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2522 size = MAX_PATH;
2523 type = REG_SZ;
2524 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2525 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2526 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2528 size = MAX_PATH;
2529 type = REG_SZ;
2530 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2531 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2533 size = sizeof(num);
2534 type = REG_DWORD;
2535 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2536 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2537 ok(num == 314, "Expected 314, got %d\n", num);
2539 size = MAX_PATH;
2540 type = REG_SZ;
2541 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2542 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2543 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2545 RegCloseKey(hkey);
2547 res = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest");
2548 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2550 /* Remove registry keys written by RegisterProduct standard action */
2551 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2552 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{837450fa-a39b-4bc8-b321-08b393f784b3}",
2553 KEY_WOW64_32KEY);
2554 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2556 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2557 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656", access);
2558 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2560 res = find_registry_key(HKEY_LOCAL_MACHINE,
2561 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "af054738b93a8cb43b12803b397f483b", access, &hkey);
2562 ok(res == ERROR_SUCCESS ||
2563 broken(res == ERROR_FILE_NOT_FOUND), /* win9x */
2564 "Expected ERROR_SUCCESS, got %d\n", res);
2565 if (res == ERROR_SUCCESS)
2567 res = delete_registry_key(hkey, "af054738b93a8cb43b12803b397f483b", access);
2568 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2569 RegCloseKey(hkey);
2571 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2572 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\af054738b93a8cb43b12803b397f483b", access);
2573 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2575 else
2577 /* win9x defaults to a per-machine install. */
2578 delete_key_portable(HKEY_LOCAL_MACHINE,
2579 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\af054738b93a8cb43b12803b397f483b", access);
2582 /* Remove registry keys written by PublishProduct standard action */
2583 res = RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2584 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2586 res = delete_registry_key(hkey, "Products\\af054738b93a8cb43b12803b397f483b", KEY_ALL_ACCESS);
2587 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2589 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2590 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2592 RegCloseKey(hkey);
2594 /* Delete installation files we installed */
2595 delete_test_files();
2598 static void test_Installer(void)
2600 static WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
2601 static WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
2602 WCHAR szPath[MAX_PATH];
2603 HRESULT hr;
2604 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL;
2605 int iValue, iCount;
2607 if (!pInstaller) return;
2609 /* Installer::CreateRecord */
2611 /* Test for error */
2612 hr = Installer_CreateRecord(-1, &pRecord);
2613 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2614 ok_exception(hr, szCreateRecordException);
2616 /* Test for success */
2617 hr = Installer_CreateRecord(1, &pRecord);
2618 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2619 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2620 if (pRecord)
2622 /* Record::FieldCountGet */
2623 hr = Record_FieldCountGet(pRecord, &iValue);
2624 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2625 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2627 /* Record::IntegerDataGet */
2628 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2629 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2630 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2632 /* Record::IntegerDataGet, bad index */
2633 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2634 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2635 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2637 /* Record::IntegerDataPut */
2638 hr = Record_IntegerDataPut(pRecord, 1, 100);
2639 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2641 /* Record::IntegerDataPut, bad index */
2642 hr = Record_IntegerDataPut(pRecord, 10, 100);
2643 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2644 ok_exception(hr, szIntegerDataException);
2646 /* Record::IntegerDataGet */
2647 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2648 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2649 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2651 IDispatch_Release(pRecord);
2654 create_package(szPath);
2656 /* Installer::OpenPackage */
2657 hr = Installer_OpenPackage(szPath, 0, &pSession);
2658 if (hr == DISP_E_EXCEPTION)
2660 skip("OpenPackage failed, insufficient rights?\n");
2661 DeleteFileW(szPath);
2662 return;
2664 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2665 if (hr == S_OK)
2667 test_Session(pSession);
2668 IDispatch_Release(pSession);
2671 /* Installer::OpenDatabase */
2672 hr = Installer_OpenDatabase(szPath, (INT_PTR)MSIDBOPEN_TRANSACT, &pDatabase);
2673 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2674 if (hr == S_OK)
2676 test_Database(pDatabase, FALSE);
2677 IDispatch_Release(pDatabase);
2680 /* Installer::RegistryValue */
2681 test_Installer_RegistryValue();
2683 /* Installer::ProductState for our product code, which should not be installed */
2684 hr = Installer_ProductState(szProductCode, &iValue);
2685 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2686 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2688 /* Installer::ProductInfo for our product code, which should not be installed */
2690 /* Package name */
2691 memset(szPath, 0, sizeof(szPath));
2692 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szPath);
2693 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2694 ok_exception(hr, szProductInfoException);
2696 /* NULL attribute and NULL product code */
2697 memset(szPath, 0, sizeof(szPath));
2698 hr = Installer_ProductInfo(NULL, NULL, szPath);
2699 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2700 ok_exception(hr, szProductInfoException);
2702 /* Installer::Products */
2703 test_Installer_Products(FALSE);
2705 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2706 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2707 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2708 if (hr == S_OK)
2710 /* StringList::Count */
2711 hr = StringList_Count(pStringList, &iCount);
2712 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2713 ok(!iCount, "Expected no related products but found %d\n", iCount);
2715 IDispatch_Release(pStringList);
2718 /* Installer::Version */
2719 memset(szPath, 0, sizeof(szPath));
2720 hr = Installer_VersionGet(szPath);
2721 ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr);
2723 /* Installer::InstallProduct and other tests that depend on our product being installed */
2724 test_Installer_InstallProduct();
2727 START_TEST(automation)
2729 DWORD len;
2730 char temp_path[MAX_PATH], prev_path[MAX_PATH];
2731 HRESULT hr;
2732 CLSID clsid;
2733 IUnknown *pUnk;
2735 init_functionpointers();
2737 if (pIsWow64Process)
2738 pIsWow64Process(GetCurrentProcess(), &is_wow64);
2740 GetSystemTimeAsFileTime(&systemtime);
2742 GetCurrentDirectoryA(MAX_PATH, prev_path);
2743 GetTempPath(MAX_PATH, temp_path);
2744 SetCurrentDirectoryA(temp_path);
2746 lstrcpyA(CURR_DIR, temp_path);
2747 len = lstrlenA(CURR_DIR);
2749 if(len && (CURR_DIR[len - 1] == '\\'))
2750 CURR_DIR[len - 1] = 0;
2752 get_program_files_dir(PROG_FILES_DIR);
2754 hr = OleInitialize(NULL);
2755 ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr);
2756 hr = CLSIDFromProgID(szProgId, &clsid);
2757 ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr);
2758 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2759 ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr);
2761 if (pUnk)
2763 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2764 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2766 test_dispid();
2767 test_dispatch();
2768 test_Installer();
2770 IDispatch_Release(pInstaller);
2771 IUnknown_Release(pUnk);
2774 OleUninitialize();
2776 SetCurrentDirectoryA(prev_path);