regedit: Display data for all values in the GUI.
[wine.git] / dlls / msi / tests / automation.c
blobe4d2faad5c3529a2f01f26716be3dfb9eb163239
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>
32 #include <oaidl.h>
34 #include "wine/test.h"
36 static BOOL is_wow64;
38 static BOOL (WINAPI *pCheckTokenMembership)(HANDLE,PSID,PBOOL);
39 static BOOL (WINAPI *pOpenProcessToken)(HANDLE, DWORD, PHANDLE);
40 static LONG (WINAPI *pRegDeleteKeyExA)(HKEY, LPCSTR, REGSAM, DWORD);
41 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
43 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
45 static const char *msifile = "winetest-automation.msi";
46 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};
47 static const WCHAR szMSITEST[] = { 'M','S','I','T','E','S','T',0 };
48 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 };
49 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 };
50 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 };
51 static const WCHAR WINE_INSTALLPROPERTY_PACKAGENAMEW[] = {'P','a','c','k','a','g','e','N','a','m','e',0};
52 static const WCHAR WINE_INSTALLPROPERTY_PRODUCTNAMEW[] = {'P','r','o','d','u','c','t','N','a','m','e',0};
53 static const WCHAR WINE_INSTALLPROPERTY_LOCALPACKAGEW[] = {'L','o','c','a','l','P','a','c','k','a','g','e',0};
54 static FILETIME systemtime;
55 static CHAR CURR_DIR[MAX_PATH];
56 static EXCEPINFO excepinfo;
59 * OLE automation data
60 **/
61 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 };
62 static IDispatch *pInstaller;
64 /* msi database data */
66 static const CHAR component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
67 "s72\tS38\ts72\ti2\tS255\tS72\n"
68 "Component\tComponent\n"
69 "Five\t{8CC92E9D-14B2-4CA4-B2AA-B11D02078087}\tNEWDIR\t2\t\tfive.txt\n"
70 "Four\t{FD37B4EA-7209-45C0-8917-535F35A2F080}\tCABOUTDIR\t2\t\tfour.txt\n"
71 "One\t{783B242E-E185-4A56-AF86-C09815EC053C}\tMSITESTDIR\t2\t\tone.txt\n"
72 "Three\t{010B6ADD-B27D-4EDD-9B3D-34C4F7D61684}\tCHANGEDDIR\t2\t\tthree.txt\n"
73 "Two\t{BF03D1A6-20DA-4A65-82F3-6CAC995915CE}\tFIRSTDIR\t2\t\ttwo.txt\n"
74 "dangler\t{6091DF25-EF96-45F1-B8E9-A9B1420C7A3C}\tTARGETDIR\t4\t\tregdata\n"
75 "component\t\tMSITESTDIR\t0\t1\tfile\n";
77 static const CHAR directory_dat[] = "Directory\tDirectory_Parent\tDefaultDir\n"
78 "s72\tS72\tl255\n"
79 "Directory\tDirectory\n"
80 "CABOUTDIR\tMSITESTDIR\tcabout\n"
81 "CHANGEDDIR\tMSITESTDIR\tchanged:second\n"
82 "FIRSTDIR\tMSITESTDIR\tfirst\n"
83 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
84 "NEWDIR\tCABOUTDIR\tnew\n"
85 "ProgramFilesFolder\tTARGETDIR\t.\n"
86 "TARGETDIR\t\tSourceDir\n";
88 static const CHAR feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
89 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
90 "Feature\tFeature\n"
91 "Five\t\tFive\tThe Five Feature\t5\t3\tNEWDIR\t0\n"
92 "Four\t\tFour\tThe Four Feature\t4\t3\tCABOUTDIR\t0\n"
93 "One\t\tOne\tThe One Feature\t1\t3\tMSITESTDIR\t0\n"
94 "Three\tOne\tThree\tThe Three Feature\t3\t3\tCHANGEDDIR\t0\n"
95 "Two\tOne\tTwo\tThe Two Feature\t2\t3\tFIRSTDIR\t0\n"
96 "feature\t\t\t\t2\t1\tTARGETDIR\t0\n";
98 static const CHAR feature_comp_dat[] = "Feature_\tComponent_\n"
99 "s38\ts72\n"
100 "FeatureComponents\tFeature_\tComponent_\n"
101 "Five\tFive\n"
102 "Four\tFour\n"
103 "One\tOne\n"
104 "Three\tThree\n"
105 "Two\tTwo\n"
106 "feature\tcomponent\n";
108 static const CHAR file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
109 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
110 "File\tFile\n"
111 "five.txt\tFive\tfive.txt\t1000\t\t\t0\t5\n"
112 "four.txt\tFour\tfour.txt\t1000\t\t\t0\t4\n"
113 "one.txt\tOne\tone.txt\t1000\t\t\t0\t1\n"
114 "three.txt\tThree\tthree.txt\t1000\t\t\t0\t3\n"
115 "two.txt\tTwo\ttwo.txt\t1000\t\t\t0\t2\n"
116 "file\tcomponent\tfilename\t100\t\t\t8192\t1\n";
118 static const CHAR install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
119 "s72\tS255\tI2\n"
120 "InstallExecuteSequence\tAction\n"
121 "AllocateRegistrySpace\tNOT Installed\t1550\n"
122 "CostFinalize\t\t1000\n"
123 "CostInitialize\t\t800\n"
124 "FileCost\t\t900\n"
125 "InstallFiles\t\t4000\n"
126 "RegisterProduct\t\t6100\n"
127 "PublishProduct\t\t6400\n"
128 "InstallFinalize\t\t6600\n"
129 "InstallInitialize\t\t1500\n"
130 "InstallValidate\t\t1400\n"
131 "LaunchConditions\t\t100\n"
132 "WriteRegistryValues\tSourceDir And SOURCEDIR\t5000\n";
134 static const CHAR media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
135 "i2\ti4\tL64\tS255\tS32\tS72\n"
136 "Media\tDiskId\n"
137 "1\t5\t\t\tDISK1\t\n";
139 static const CHAR property_dat[] = "Property\tValue\n"
140 "s72\tl0\n"
141 "Property\tProperty\n"
142 "DefaultUIFont\tDlgFont8\n"
143 "HASUIRUN\t0\n"
144 "INSTALLLEVEL\t3\n"
145 "InstallMode\tTypical\n"
146 "Manufacturer\tWine\n"
147 "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n"
148 "ProductCode\t{837450fa-a39b-4bc8-b321-08b393f784b3}\n"
149 "ProductID\tnone\n"
150 "ProductLanguage\t1033\n"
151 "ProductName\tMSITEST\n"
152 "ProductVersion\t1.1.1\n"
153 "PROMPTROLLBACKCOST\tP\n"
154 "Setup\tSetup\n"
155 "UpgradeCode\t{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}\n"
156 "MSIFASTINSTALL\t1\n";
158 static const CHAR registry_dat[] = "Registry\tRoot\tKey\tName\tValue\tComponent_\n"
159 "s72\ti2\tl255\tL255\tL0\ts72\n"
160 "Registry\tRegistry\n"
161 "Apples\t1\tSOFTWARE\\Wine\\msitest\tName\timaname\tOne\n"
162 "Oranges\t1\tSOFTWARE\\Wine\\msitest\tnumber\t#314\tTwo\n"
163 "regdata\t1\tSOFTWARE\\Wine\\msitest\tblah\tbad\tdangler\n"
164 "OrderTest\t1\tSOFTWARE\\Wine\\msitest\tOrderTestName\tOrderTestValue\tcomponent\n";
166 typedef struct _msi_table
168 const CHAR *filename;
169 const CHAR *data;
170 int size;
171 } msi_table;
173 #define ADD_TABLE(x) {#x".idt", x##_dat, sizeof(x##_dat)}
175 static const msi_table tables[] =
177 ADD_TABLE(component),
178 ADD_TABLE(directory),
179 ADD_TABLE(feature),
180 ADD_TABLE(feature_comp),
181 ADD_TABLE(file),
182 ADD_TABLE(install_exec_seq),
183 ADD_TABLE(media),
184 ADD_TABLE(property),
185 ADD_TABLE(registry)
188 typedef struct _msi_summary_info
190 UINT property;
191 UINT datatype;
192 INT iValue;
193 FILETIME *pftValue;
194 const CHAR *szValue;
195 } msi_summary_info;
197 #define ADD_INFO_I2(property, iValue) {property, VT_I2, iValue, NULL, NULL}
198 #define ADD_INFO_I4(property, iValue) {property, VT_I4, iValue, NULL, NULL}
199 #define ADD_INFO_LPSTR(property, szValue) {property, VT_LPSTR, 0, NULL, szValue}
200 #define ADD_INFO_FILETIME(property, pftValue) {property, VT_FILETIME, 0, pftValue, NULL}
202 static const msi_summary_info summary_info[] =
204 ADD_INFO_LPSTR(PID_TEMPLATE, ";1033"),
205 ADD_INFO_LPSTR(PID_REVNUMBER, "{004757CA-5092-49C2-AD20-28E1CE0DF5F2}"),
206 ADD_INFO_I4(PID_PAGECOUNT, 100),
207 ADD_INFO_I4(PID_WORDCOUNT, 0),
208 ADD_INFO_FILETIME(PID_CREATE_DTM, &systemtime),
209 ADD_INFO_FILETIME(PID_LASTPRINTED, &systemtime)
212 static void init_functionpointers(void)
214 HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll");
215 HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
217 #define GET_PROC(dll, func) \
218 p ## func = (void *)GetProcAddress(dll, #func); \
219 if(!p ## func) \
220 trace("GetProcAddress(%s) failed\n", #func);
222 GET_PROC(hadvapi32, CheckTokenMembership);
223 GET_PROC(hadvapi32, OpenProcessToken);
224 GET_PROC(hadvapi32, RegDeleteKeyExA)
225 GET_PROC(hkernel32, IsWow64Process)
227 #undef GET_PROC
230 static BOOL is_process_limited(void)
232 SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
233 PSID Group = NULL;
234 BOOL IsInGroup;
235 HANDLE token;
237 if (!pCheckTokenMembership || !pOpenProcessToken) return FALSE;
239 if (!AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
240 DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &Group) ||
241 !pCheckTokenMembership(NULL, Group, &IsInGroup))
243 trace("Could not check if the current user is an administrator\n");
244 FreeSid(Group);
245 return FALSE;
247 FreeSid(Group);
249 if (!IsInGroup)
251 /* Only administrators have enough privileges for these tests */
252 return TRUE;
255 if (pOpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
257 BOOL ret;
258 TOKEN_ELEVATION_TYPE type = TokenElevationTypeDefault;
259 DWORD size;
261 ret = GetTokenInformation(token, TokenElevationType, &type, sizeof(type), &size);
262 CloseHandle(token);
263 return (ret && type == TokenElevationTypeLimited);
265 return FALSE;
268 static LONG delete_key_portable( HKEY key, LPCSTR subkey, REGSAM access )
270 if (pRegDeleteKeyExA)
271 return pRegDeleteKeyExA( key, subkey, access, 0 );
272 return RegDeleteKeyA( key, subkey );
276 * Database Helpers
279 static void write_file(const CHAR *filename, const char *data, int data_size)
281 DWORD size;
283 HANDLE hf = CreateFileA(filename, GENERIC_WRITE, 0, NULL,
284 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
285 WriteFile(hf, data, data_size, &size, NULL);
286 CloseHandle(hf);
289 static void write_msi_summary_info(MSIHANDLE db, const msi_summary_info *info, int num_info)
291 MSIHANDLE summary;
292 UINT r;
293 int j;
295 r = MsiGetSummaryInformationA(db, NULL, num_info, &summary);
296 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
298 /* import summary information into the stream */
299 for (j = 0; j < num_info; j++)
301 const msi_summary_info *entry = &info[j];
303 r = MsiSummaryInfoSetPropertyA(summary, entry->property, entry->datatype,
304 entry->iValue, entry->pftValue, entry->szValue);
305 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
308 /* write the summary changes back to the stream */
309 r = MsiSummaryInfoPersist(summary);
310 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
312 MsiCloseHandle(summary);
315 static void create_database(const CHAR *name, const msi_table *tables, int num_tables,
316 const msi_summary_info *info, int num_info)
318 MSIHANDLE db;
319 UINT r;
320 WCHAR *nameW;
321 int j, len;
323 len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
324 if (!(nameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return;
325 MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, len );
327 r = MsiOpenDatabaseW(nameW, MSIDBOPEN_CREATE, &db);
328 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
330 /* import the tables into the database */
331 for (j = 0; j < num_tables; j++)
333 const msi_table *table = &tables[j];
335 write_file(table->filename, table->data, (table->size - 1) * sizeof(char));
337 r = MsiDatabaseImportA(db, CURR_DIR, table->filename);
338 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
340 DeleteFileA(table->filename);
343 write_msi_summary_info(db, info, num_info);
345 r = MsiDatabaseCommit(db);
346 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
348 MsiCloseHandle(db);
349 HeapFree( GetProcessHeap(), 0, nameW );
352 static BOOL create_package(LPWSTR path)
354 static const WCHAR slashW[] = {'\\',0};
355 DWORD len;
357 /* Prepare package */
358 create_database(msifile, tables,
359 sizeof(tables) / sizeof(msi_table), summary_info,
360 sizeof(summary_info) / sizeof(msi_summary_info));
362 len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
363 CURR_DIR, -1, path, MAX_PATH);
364 ok(len, "MultiByteToWideChar returned error %d\n", GetLastError());
365 if (!len)
366 return FALSE;
368 lstrcatW(path, slashW);
369 lstrcatW(path, szMsifile);
370 return TRUE;
374 * Installation helpers
377 static char PROG_FILES_DIR[MAX_PATH];
379 static BOOL get_program_files_dir(LPSTR buf)
381 HKEY hkey;
382 DWORD type = REG_EXPAND_SZ, size;
384 if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &hkey))
385 return FALSE;
387 size = MAX_PATH;
388 if (RegQueryValueExA(hkey, "ProgramFilesDir (x86)", 0, &type, (LPBYTE)buf, &size) &&
389 RegQueryValueExA(hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size))
390 return FALSE;
392 RegCloseKey(hkey);
393 return TRUE;
396 static void create_file(const CHAR *name, DWORD size)
398 HANDLE file;
399 DWORD written, left;
401 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
402 ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
403 WriteFile(file, name, strlen(name), &written, NULL);
404 WriteFile(file, "\n", strlen("\n"), &written, NULL);
406 left = size - lstrlenA(name) - 1;
408 SetFilePointer(file, left, NULL, FILE_CURRENT);
409 SetEndOfFile(file);
411 CloseHandle(file);
414 static void create_test_files(void)
416 CreateDirectoryA("msitest", NULL);
417 create_file("msitest\\one.txt", 100);
418 CreateDirectoryA("msitest\\first", NULL);
419 create_file("msitest\\first\\two.txt", 100);
420 CreateDirectoryA("msitest\\second", NULL);
421 create_file("msitest\\second\\three.txt", 100);
422 CreateDirectoryA("msitest\\cabout",NULL);
423 create_file("msitest\\cabout\\four.txt", 100);
424 CreateDirectoryA("msitest\\cabout\\new",NULL);
425 create_file("msitest\\cabout\\new\\five.txt", 100);
426 create_file("msitest\\filename", 100);
429 static BOOL delete_pf(const CHAR *rel_path, BOOL is_file)
431 CHAR path[MAX_PATH];
433 lstrcpyA(path, PROG_FILES_DIR);
434 lstrcatA(path, "\\");
435 lstrcatA(path, rel_path);
437 if (is_file)
438 return DeleteFileA(path);
439 else
440 return RemoveDirectoryA(path);
443 static void delete_test_files(void)
445 DeleteFileA(msifile);
446 DeleteFileA("msitest\\cabout\\new\\five.txt");
447 DeleteFileA("msitest\\cabout\\four.txt");
448 DeleteFileA("msitest\\second\\three.txt");
449 DeleteFileA("msitest\\first\\two.txt");
450 DeleteFileA("msitest\\one.txt");
451 DeleteFileA("msitest\\filename");
452 RemoveDirectoryA("msitest\\cabout\\new");
453 RemoveDirectoryA("msitest\\cabout");
454 RemoveDirectoryA("msitest\\second");
455 RemoveDirectoryA("msitest\\first");
456 RemoveDirectoryA("msitest");
460 * Automation helpers and tests
463 /* ok-like statement which takes two unicode strings or one unicode and one ANSI string as arguments */
464 static CHAR string1[MAX_PATH], string2[MAX_PATH];
466 #define ok_w2(format, szString1, szString2) \
468 do { \
469 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
470 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
471 if (lstrcmpA(string1, string2) != 0) \
472 ok(0, format, string1, string2); \
473 } while(0);
475 #define ok_w2n(format, szString1, szString2, len) \
477 if (memcmp(szString1, szString2, len * sizeof(WCHAR)) != 0) \
479 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
480 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
481 ok(0, format, string1, string2); \
484 #define ok_aw(format, aString, wString) \
486 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
487 if (lstrcmpA(string1, aString) != 0) \
488 ok(0, format, string1, aString); \
490 #define ok_awplus(format, extra, aString, wString) \
492 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
493 if (lstrcmpA(string1, aString) != 0) \
494 ok(0, format, extra, string1, aString); \
496 /* exception checker */
497 static const WCHAR szSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
499 #define ok_exception(hr, szDescription) \
500 if (hr == DISP_E_EXCEPTION) \
502 /* Compare wtype, source, and destination */ \
503 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
505 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
506 if (excepinfo.bstrSource) \
507 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, szSource); \
509 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
510 if (excepinfo.bstrDescription) \
511 ok_w2("Exception description was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrDescription, szDescription); \
513 SysFreeString(excepinfo.bstrSource); \
514 SysFreeString(excepinfo.bstrDescription); \
515 SysFreeString(excepinfo.bstrHelpFile); \
518 static DISPID get_dispid( IDispatch *disp, const char *name )
520 LPOLESTR str;
521 UINT len;
522 DISPID id = -1;
523 HRESULT r;
525 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
526 str = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
527 if (str)
529 MultiByteToWideChar(CP_ACP, 0, name, -1, str, len );
530 r = IDispatch_GetIDsOfNames( disp, &IID_NULL, &str, 1, 0, &id );
531 HeapFree(GetProcessHeap(), 0, str);
532 if (r != S_OK)
533 return -1;
536 return id;
539 typedef struct {
540 DISPID did;
541 const char *name;
542 BOOL todo;
543 } get_did_t;
545 static const get_did_t get_did_data[] = {
546 { 1, "CreateRecord" },
547 { 2, "OpenPackage" },
548 { 3, "OpenProduct" },
549 { 4, "OpenDatabase" },
550 { 5, "SummaryInformation" },
551 { 6, "UILevel" },
552 { 7, "EnableLog" },
553 { 8, "InstallProduct" },
554 { 9, "Version" },
555 { 10, "LastErrorRecord" },
556 { 11, "RegistryValue" },
557 { 12, "Environment" },
558 { 13, "FileAttributes" },
559 { 15, "FileSize" },
560 { 16, "FileVersion" },
561 { 17, "ProductState" },
562 { 18, "ProductInfo" },
563 { 19, "ConfigureProduct", TRUE },
564 { 20, "ReinstallProduct", TRUE },
565 { 21, "CollectUserInfo", TRUE },
566 { 22, "ApplyPatch", TRUE },
567 { 23, "FeatureParent", TRUE },
568 { 24, "FeatureState", TRUE },
569 { 25, "UseFeature", TRUE },
570 { 26, "FeatureUsageCount", TRUE },
571 { 27, "FeatureUsageDate", TRUE },
572 { 28, "ConfigureFeature", TRUE },
573 { 29, "ReinstallFeature", TRUE },
574 { 30, "ProvideComponent", TRUE },
575 { 31, "ComponentPath", TRUE },
576 { 32, "ProvideQualifiedComponent", TRUE },
577 { 33, "QualifierDescription", TRUE },
578 { 34, "ComponentQualifiers", TRUE },
579 { 35, "Products" },
580 { 36, "Features", TRUE },
581 { 37, "Components", TRUE },
582 { 38, "ComponentClients", TRUE },
583 { 39, "Patches", TRUE },
584 { 40, "RelatedProducts" },
585 { 41, "PatchInfo", TRUE },
586 { 42, "PatchTransforms", TRUE },
587 { 43, "AddSource", TRUE },
588 { 44, "ClearSourceList", TRUE },
589 { 45, "ForceSourceListResolution", TRUE },
590 { 46, "ShortcutTarget", TRUE },
591 { 47, "FileHash", TRUE },
592 { 48, "FileSignatureInfo", TRUE },
593 { 0 }
596 static void test_dispid(void)
598 const get_did_t *ptr = get_did_data;
599 DISPID dispid;
601 while (ptr->name)
603 dispid = get_dispid(pInstaller, ptr->name);
604 todo_wine_if (ptr->todo)
605 ok(dispid == ptr->did, "%s: expected %d, got %d\n", ptr->name, ptr->did, dispid);
606 ptr++;
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 const 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 IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
665 IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL);
666 VariantInit(&varresult);
667 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 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 todo_wine_if (_invoke_todo_vtResult)
886 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
887 if (vtResult != VT_EMPTY)
889 hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult);
890 ok(hr == S_OK, "VariantChangeTypeEx returned 0x%08x\n", hr);
894 for (i=0; i<pDispParams->cArgs; i++)
895 VariantClear(&pDispParams->rgvarg[i]);
897 return hr;
900 /* Object_Property helper functions */
902 static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord)
904 VARIANT varresult;
905 VARIANTARG vararg[1];
906 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
907 HRESULT hr;
909 VariantInit(&vararg[0]);
910 V_VT(&vararg[0]) = VT_I4;
911 V_I4(&vararg[0]) = count;
913 hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
914 *pRecord = V_DISPATCH(&varresult);
915 return hr;
918 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
920 VARIANTARG vararg[3];
921 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
923 VariantInit(&vararg[2]);
924 V_VT(&vararg[2]) = VT_I4;
925 V_I4(&vararg[2]) = (INT_PTR)hkey;
926 VariantInit(&vararg[1]);
927 V_VT(&vararg[1]) = VT_BSTR;
928 V_BSTR(&vararg[1]) = SysAllocString(szKey);
929 VariantInit(&vararg[0]);
930 VariantCopy(&vararg[0], &vValue);
931 VariantClear(&vValue);
933 return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect);
936 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
938 VARIANT varresult;
939 VARIANTARG vararg;
940 HRESULT hr;
942 VariantInit(&vararg);
943 V_VT(&vararg) = VT_EMPTY;
944 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL);
945 *pBool = V_BOOL(&varresult);
946 VariantClear(&varresult);
947 return hr;
950 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
952 VARIANT varresult;
953 VARIANTARG vararg;
954 HRESULT hr;
956 VariantInit(&vararg);
957 V_VT(&vararg) = VT_BSTR;
958 V_BSTR(&vararg) = SysAllocString(szValue);
960 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR);
961 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
962 VariantClear(&varresult);
963 return hr;
966 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
968 VARIANT varresult;
969 VARIANTARG vararg;
970 HRESULT hr;
972 VariantInit(&vararg);
973 V_VT(&vararg) = VT_I4;
974 V_I4(&vararg) = iValue;
976 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult);
977 if (SUCCEEDED(hr) && vtResult == VT_BSTR) lstrcpyW(szString, V_BSTR(&varresult));
978 VariantClear(&varresult);
979 return hr;
982 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
984 VARIANT varresult;
985 VARIANTARG vararg[2];
986 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
987 HRESULT hr;
989 VariantInit(&vararg[1]);
990 V_VT(&vararg[1]) = VT_BSTR;
991 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
992 VariantInit(&vararg[0]);
993 V_VT(&vararg[0]) = VT_I4;
994 V_I4(&vararg[0]) = options;
996 hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
997 *pSession = V_DISPATCH(&varresult);
998 return hr;
1001 static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase)
1003 VARIANT varresult;
1004 VARIANTARG vararg[2];
1005 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1006 HRESULT hr;
1008 VariantInit(&vararg[1]);
1009 V_VT(&vararg[1]) = VT_BSTR;
1010 V_BSTR(&vararg[1]) = SysAllocString(szDatabasePath);
1011 VariantInit(&vararg[0]);
1012 V_VT(&vararg[0]) = VT_I4;
1013 V_I4(&vararg[0]) = openmode;
1015 hr = invoke(pInstaller, "OpenDatabase", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1016 *pDatabase = V_DISPATCH(&varresult);
1017 return hr;
1020 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
1022 VARIANT varresult;
1023 VARIANTARG vararg[2];
1024 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1026 VariantInit(&vararg[1]);
1027 V_VT(&vararg[1]) = VT_BSTR;
1028 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
1029 VariantInit(&vararg[0]);
1030 V_VT(&vararg[0]) = VT_BSTR;
1031 V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues);
1033 return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1036 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
1038 VARIANT varresult;
1039 VARIANTARG vararg[1];
1040 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1041 HRESULT hr;
1043 VariantInit(&vararg[0]);
1044 V_VT(&vararg[0]) = VT_BSTR;
1045 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
1047 hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1048 *pInstallState = V_I4(&varresult);
1049 VariantClear(&varresult);
1050 return hr;
1053 static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szString)
1055 VARIANT varresult;
1056 VARIANTARG vararg[2];
1057 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1058 HRESULT hr;
1060 VariantInit(&vararg[1]);
1061 V_VT(&vararg[1]) = VT_BSTR;
1062 V_BSTR(&vararg[1]) = SysAllocString(szProduct);
1063 VariantInit(&vararg[0]);
1064 V_VT(&vararg[0]) = VT_BSTR;
1065 V_BSTR(&vararg[0]) = SysAllocString(szAttribute);
1067 hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1068 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1069 VariantClear(&varresult);
1070 return hr;
1073 static HRESULT Installer_Products(IDispatch **pStringList)
1075 VARIANT varresult;
1076 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1077 HRESULT hr;
1079 hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1080 *pStringList = V_DISPATCH(&varresult);
1081 return hr;
1084 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
1086 VARIANT varresult;
1087 VARIANTARG vararg[1];
1088 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1089 HRESULT hr;
1091 VariantInit(&vararg[0]);
1092 V_VT(&vararg[0]) = VT_BSTR;
1093 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
1095 hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1096 *pStringList = V_DISPATCH(&varresult);
1097 return hr;
1100 static HRESULT Installer_VersionGet(LPWSTR szVersion)
1102 VARIANT varresult;
1103 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1104 HRESULT hr;
1106 hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1107 if (V_BSTR(&varresult)) lstrcpyW(szVersion, V_BSTR(&varresult));
1108 VariantClear(&varresult);
1109 return hr;
1112 static HRESULT Installer_UILevelPut(int level)
1114 VARIANT varresult;
1115 VARIANTARG vararg;
1116 DISPID dispid = DISPID_PROPERTYPUT;
1117 DISPPARAMS dispparams = {&vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1119 VariantInit(&vararg);
1120 V_VT(&vararg) = VT_I4;
1121 V_I4(&vararg) = level;
1123 return invoke(pInstaller, "UILevel", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1126 static HRESULT Installer_SummaryInformation(BSTR PackagePath, int UpdateCount, IDispatch **pSumInfo)
1128 VARIANT varresult;
1129 VARIANTARG vararg[2];
1130 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1131 HRESULT hr;
1133 VariantInit(&vararg[1]);
1134 V_VT(&vararg[1]) = VT_BSTR;
1135 V_BSTR(&vararg[1]) = SysAllocString(PackagePath);
1136 VariantInit(&vararg[0]);
1137 V_VT(&vararg[0]) = VT_I4;
1138 V_I4(&vararg[0]) = UpdateCount;
1140 hr = invoke(pInstaller, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1141 *pSumInfo = V_DISPATCH(&varresult);
1142 return hr;
1145 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
1147 VARIANT varresult;
1148 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1149 HRESULT hr;
1151 hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1152 *pInst = V_DISPATCH(&varresult);
1153 return hr;
1156 static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn)
1158 VARIANT varresult;
1159 VARIANTARG vararg[1];
1160 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1161 HRESULT hr;
1163 VariantInit(&vararg[0]);
1164 V_VT(&vararg[0]) = VT_BSTR;
1165 V_BSTR(&vararg[0]) = SysAllocString(szName);
1167 hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1168 if (V_BSTR(&varresult)) lstrcpyW(szReturn, V_BSTR(&varresult));
1169 VariantClear(&varresult);
1170 return hr;
1173 static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue)
1175 VARIANT varresult;
1176 VARIANTARG vararg[2];
1177 DISPID dispid = DISPID_PROPERTYPUT;
1178 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1180 VariantInit(&vararg[1]);
1181 V_VT(&vararg[1]) = VT_BSTR;
1182 V_BSTR(&vararg[1]) = SysAllocString(szName);
1183 VariantInit(&vararg[0]);
1184 V_VT(&vararg[0]) = VT_BSTR;
1185 V_BSTR(&vararg[0]) = SysAllocString(szValue);
1187 return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1190 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
1192 VARIANT varresult;
1193 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1194 HRESULT hr;
1196 hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1197 *pLangId = V_I4(&varresult);
1198 VariantClear(&varresult);
1199 return hr;
1202 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, VARIANT_BOOL *mode)
1204 VARIANT varresult;
1205 VARIANTARG vararg[1];
1206 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1207 HRESULT hr;
1209 VariantInit(&vararg[0]);
1210 V_VT(&vararg[0]) = VT_I4;
1211 V_I4(&vararg[0]) = iFlag;
1213 hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL);
1214 *mode = V_BOOL(&varresult);
1215 VariantClear(&varresult);
1216 return hr;
1219 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, VARIANT_BOOL mode)
1221 VARIANT varresult;
1222 VARIANTARG vararg[2];
1223 DISPID dispid = DISPID_PROPERTYPUT;
1224 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1226 VariantInit(&vararg[1]);
1227 V_VT(&vararg[1]) = VT_I4;
1228 V_I4(&vararg[1]) = iFlag;
1229 VariantInit(&vararg[0]);
1230 V_VT(&vararg[0]) = VT_BOOL;
1231 V_BOOL(&vararg[0]) = mode;
1233 return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1236 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
1238 VARIANT varresult;
1239 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1240 HRESULT hr;
1242 hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1243 *pDatabase = V_DISPATCH(&varresult);
1244 return hr;
1247 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn)
1249 VARIANT varresult;
1250 VARIANTARG vararg[1];
1251 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1252 HRESULT hr;
1254 VariantInit(&vararg[0]);
1255 V_VT(&vararg[0]) = VT_BSTR;
1256 V_BSTR(&vararg[0]) = SysAllocString(szAction);
1258 hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1259 *iReturn = V_I4(&varresult);
1260 VariantClear(&varresult);
1261 return hr;
1264 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
1266 VARIANT varresult;
1267 VARIANTARG vararg[1];
1268 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1269 HRESULT hr;
1271 VariantInit(&vararg[0]);
1272 V_VT(&vararg[0]) = VT_BSTR;
1273 V_BSTR(&vararg[0]) = SysAllocString(szCondition);
1275 hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1276 *iReturn = V_I4(&varresult);
1277 VariantClear(&varresult);
1278 return hr;
1281 static HRESULT Session_Message(IDispatch *pSession, LONG kind, IDispatch *record, int *ret)
1283 VARIANT varresult;
1284 VARIANTARG vararg[2];
1285 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1286 HRESULT hr;
1288 VariantInit(&varresult);
1289 V_VT(vararg) = VT_DISPATCH;
1290 V_DISPATCH(vararg) = record;
1291 V_VT(vararg+1) = VT_I4;
1292 V_I4(vararg+1) = kind;
1294 hr = invoke(pSession, "Message", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1296 ok(V_VT(&varresult) == VT_I4, "V_VT(varresult) = %d\n", V_VT(&varresult));
1297 *ret = V_I4(&varresult);
1299 return hr;
1302 static HRESULT Session_SetInstallLevel(IDispatch *pSession, LONG iInstallLevel)
1304 VARIANT varresult;
1305 VARIANTARG vararg[1];
1306 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1308 VariantInit(&vararg[0]);
1309 V_VT(&vararg[0]) = VT_I4;
1310 V_I4(&vararg[0]) = iInstallLevel;
1312 return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1315 static HRESULT Session_FeatureCurrentState(IDispatch *pSession, LPCWSTR szName, int *pState)
1317 VARIANT varresult;
1318 VARIANTARG vararg[1];
1319 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1320 HRESULT hr;
1322 VariantInit(&vararg[0]);
1323 V_VT(&vararg[0]) = VT_BSTR;
1324 V_BSTR(&vararg[0]) = SysAllocString(szName);
1326 hr = invoke(pSession, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1327 *pState = V_I4(&varresult);
1328 VariantClear(&varresult);
1329 return hr;
1332 static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState)
1334 VARIANT varresult;
1335 VARIANTARG vararg[1];
1336 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1337 HRESULT hr;
1339 VariantInit(&vararg[0]);
1340 V_VT(&vararg[0]) = VT_BSTR;
1341 V_BSTR(&vararg[0]) = SysAllocString(szName);
1343 hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1344 *pState = V_I4(&varresult);
1345 VariantClear(&varresult);
1346 return hr;
1349 static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState)
1351 VARIANT varresult;
1352 VARIANTARG vararg[2];
1353 DISPID dispid = DISPID_PROPERTYPUT;
1354 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1356 VariantInit(&vararg[1]);
1357 V_VT(&vararg[1]) = VT_BSTR;
1358 V_BSTR(&vararg[1]) = SysAllocString(szName);
1359 VariantInit(&vararg[0]);
1360 V_VT(&vararg[0]) = VT_I4;
1361 V_I4(&vararg[0]) = iState;
1363 return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1366 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
1368 VARIANT varresult;
1369 VARIANTARG vararg[1];
1370 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1371 HRESULT hr;
1373 VariantInit(&vararg[0]);
1374 V_VT(&vararg[0]) = VT_BSTR;
1375 V_BSTR(&vararg[0]) = SysAllocString(szSql);
1377 hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1378 *pView = V_DISPATCH(&varresult);
1379 return hr;
1382 static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo)
1384 VARIANT varresult;
1385 VARIANTARG vararg[1];
1386 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1387 HRESULT hr;
1389 VariantInit(&vararg[0]);
1390 V_VT(&vararg[0]) = VT_I4;
1391 V_I4(&vararg[0]) = iUpdateCount;
1393 hr = invoke(pDatabase, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1394 *pSummaryInfo = V_DISPATCH(&varresult);
1395 return hr;
1398 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
1400 VARIANT varresult;
1401 VARIANTARG vararg[1];
1402 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1404 VariantInit(&vararg[0]);
1405 V_VT(&vararg[0]) = VT_DISPATCH;
1406 V_DISPATCH(&vararg[0]) = pRecord;
1408 return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1411 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
1413 VARIANT varresult;
1414 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1415 HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1416 *ppRecord = V_DISPATCH(&varresult);
1417 return hr;
1420 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
1422 VARIANT varresult;
1423 VARIANTARG vararg[2];
1424 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1426 VariantInit(&vararg[1]);
1427 V_VT(&vararg[1]) = VT_I4;
1428 V_I4(&vararg[1]) = iMode;
1429 VariantInit(&vararg[0]);
1430 V_VT(&vararg[0]) = VT_DISPATCH;
1431 V_DISPATCH(&vararg[0]) = pRecord;
1432 if (pRecord)
1433 IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */
1435 return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1438 static HRESULT View_Close(IDispatch *pView)
1440 VARIANT varresult;
1441 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1442 return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1445 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
1447 VARIANT varresult;
1448 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1449 HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1450 *pFieldCount = V_I4(&varresult);
1451 VariantClear(&varresult);
1452 return hr;
1455 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString)
1457 VARIANT varresult;
1458 VARIANTARG vararg[1];
1459 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1460 HRESULT hr;
1462 VariantInit(&vararg[0]);
1463 V_VT(&vararg[0]) = VT_I4;
1464 V_I4(&vararg[0]) = iField;
1466 hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1467 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1468 VariantClear(&varresult);
1469 return hr;
1472 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
1474 VARIANT varresult;
1475 VARIANTARG vararg[2];
1476 DISPID dispid = DISPID_PROPERTYPUT;
1477 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1479 VariantInit(&vararg[1]);
1480 V_VT(&vararg[1]) = VT_I4;
1481 V_I4(&vararg[1]) = iField;
1482 VariantInit(&vararg[0]);
1483 V_VT(&vararg[0]) = VT_BSTR;
1484 V_BSTR(&vararg[0]) = SysAllocString(szString);
1486 return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1489 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
1491 VARIANT varresult;
1492 VARIANTARG vararg[1];
1493 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1494 HRESULT hr;
1496 VariantInit(&vararg[0]);
1497 V_VT(&vararg[0]) = VT_I4;
1498 V_I4(&vararg[0]) = iField;
1500 hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1501 *pValue = V_I4(&varresult);
1502 VariantClear(&varresult);
1503 return hr;
1506 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
1508 VARIANT varresult;
1509 VARIANTARG vararg[2];
1510 DISPID dispid = DISPID_PROPERTYPUT;
1511 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1513 VariantInit(&vararg[1]);
1514 V_VT(&vararg[1]) = VT_I4;
1515 V_I4(&vararg[1]) = iField;
1516 VariantInit(&vararg[0]);
1517 V_VT(&vararg[0]) = VT_I4;
1518 V_I4(&vararg[0]) = iValue;
1520 return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1523 static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT)
1525 VARIANT varresult;
1526 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1527 HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN);
1528 *ppEnumVARIANT = V_UNKNOWN(&varresult);
1529 return hr;
1532 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
1534 VARIANT varresult;
1535 VARIANTARG vararg[1];
1536 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1537 HRESULT hr;
1539 VariantInit(&vararg[0]);
1540 V_VT(&vararg[0]) = VT_I4;
1541 V_I4(&vararg[0]) = iIndex;
1543 hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1544 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1545 VariantClear(&varresult);
1546 return hr;
1549 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
1551 VARIANT varresult;
1552 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1553 HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1554 *pCount = V_I4(&varresult);
1555 VariantClear(&varresult);
1556 return hr;
1559 static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect)
1561 VARIANTARG vararg[1];
1562 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1564 VariantInit(&vararg[0]);
1565 V_VT(&vararg[0]) = VT_I4;
1566 V_I4(&vararg[0]) = pid;
1567 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYGET, &dispparams, pVarResult, vtExpect);
1570 static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant)
1572 VARIANT varresult;
1573 VARIANTARG vararg[2];
1574 DISPID dispid = DISPID_PROPERTYPUT;
1575 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1577 VariantInit(&vararg[1]);
1578 V_VT(&vararg[1]) = VT_I4;
1579 V_I4(&vararg[1]) = pid;
1580 VariantInit(&vararg[0]);
1581 VariantCopyInd(vararg, pVariant);
1583 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1586 static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount)
1588 VARIANT varresult;
1589 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1590 HRESULT hr;
1592 hr = invoke(pSummaryInfo, "PropertyCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1593 *pCount = V_I4(&varresult);
1594 VariantClear(&varresult);
1595 return hr;
1598 /* Test the various objects */
1600 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4
1602 static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly)
1604 static const WCHAR szPropertyException[] = { 'P','r','o','p','e','r','t','y',',','P','i','d',0 };
1605 static const WCHAR szTitle[] = { 'T','i','t','l','e',0 };
1606 VARIANT varresult, var;
1607 SYSTEMTIME st;
1608 HRESULT hr;
1609 int j;
1611 /* SummaryInfo::PropertyCount */
1612 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1613 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1614 ok(j == num_info, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1616 /* SummaryInfo::Property, get for properties we have set */
1617 for (j = 0; j < num_info; j++)
1619 const msi_summary_info *entry = &info[j];
1621 int vt = entry->datatype;
1622 if (vt == VT_LPSTR) vt = VT_BSTR;
1623 else if (vt == VT_FILETIME) vt = VT_DATE;
1624 else if (vt == VT_I2) vt = VT_I4;
1626 hr = SummaryInfo_PropertyGet(pSummaryInfo, entry->property, &varresult, vt);
1627 ok(hr == S_OK, "SummaryInfo_Property (pid %d) failed, hresult 0x%08x\n", entry->property, hr);
1628 if (V_VT(&varresult) != vt)
1629 skip("Skipping property tests due to type mismatch\n");
1630 else if (vt == VT_I4)
1631 ok(V_I4(&varresult) == entry->iValue, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %d\n",
1632 entry->property, entry->iValue, V_I4(&varresult));
1633 else if (vt == VT_DATE)
1635 FILETIME ft;
1636 DATE d;
1638 FileTimeToLocalFileTime(entry->pftValue, &ft);
1639 FileTimeToSystemTime(&ft, &st);
1640 SystemTimeToVariantTime(&st, &d);
1641 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));
1643 else if (vt == VT_BSTR)
1645 ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry->property, entry->szValue, V_BSTR(&varresult));
1647 else
1648 skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry->property, vt);
1650 VariantClear(&varresult);
1653 /* SummaryInfo::Property, get; invalid arguments */
1655 /* Invalid pids */
1656 hr = SummaryInfo_PropertyGet(pSummaryInfo, -1, &varresult, VT_EMPTY);
1657 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1658 ok_exception(hr, szPropertyException);
1660 hr = SummaryInfo_PropertyGet(pSummaryInfo, 1000, &varresult, VT_EMPTY);
1661 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1662 ok_exception(hr, szPropertyException);
1664 /* Unsupported pids */
1665 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_DICTIONARY, &varresult, VT_EMPTY);
1666 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1668 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY);
1669 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1671 /* Pids we have not set, one for each type */
1672 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_EMPTY);
1673 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1675 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY);
1676 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1678 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY);
1679 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1681 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY);
1682 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1684 if (!readonly)
1686 /* SummaryInfo::Property, put; one for each type */
1688 /* VT_I2 */
1689 VariantInit(&var);
1690 V_VT(&var) = VT_I2;
1691 V_I2(&var) = 1;
1692 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CODEPAGE, &var);
1693 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1695 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */);
1696 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1697 ok(V_I2(&var) == V_I2(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var), V_I2(&varresult));
1698 VariantClear(&varresult);
1699 VariantClear(&var);
1701 /* VT_BSTR */
1702 V_VT(&var) = VT_BSTR;
1703 V_BSTR(&var) = SysAllocString(szTitle);
1704 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_TITLE, &var);
1705 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1707 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var));
1708 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1709 ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var), V_BSTR(&varresult));
1710 VariantClear(&varresult);
1711 VariantClear(&var);
1713 /* VT_DATE */
1714 V_VT(&var) = VT_DATE;
1715 FileTimeToSystemTime(&systemtime, &st);
1716 SystemTimeToVariantTime(&st, &V_DATE(&var));
1717 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_LASTSAVE_DTM, &var);
1718 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1720 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var));
1721 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1722 ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1723 VariantClear(&varresult);
1724 VariantClear(&var);
1726 /* VT_I4 */
1727 V_VT(&var) = VT_I4;
1728 V_I4(&var) = 1000;
1729 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1730 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1732 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1733 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1734 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult));
1735 VariantClear(&varresult);
1736 VariantClear(&var);
1738 /* SummaryInfo::PropertyCount */
1739 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1740 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1741 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1745 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1747 static const 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 };
1748 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
1749 static const WCHAR szTwo[] = { 'T','w','o',0 };
1750 static const WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
1751 static const WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 };
1752 IDispatch *pView = NULL, *pSummaryInfo = NULL;
1753 HRESULT hr;
1755 hr = Database_OpenView(pDatabase, szSql, &pView);
1756 ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr);
1757 if (hr == S_OK)
1759 IDispatch *pRecord = NULL;
1760 WCHAR szString[MAX_PATH];
1762 /* View::Execute */
1763 hr = View_Execute(pView, NULL);
1764 ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr);
1766 /* View::Fetch */
1767 hr = View_Fetch(pView, &pRecord);
1768 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1769 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1770 if (pRecord)
1772 /* Record::StringDataGet */
1773 memset(szString, 0, sizeof(szString));
1774 hr = Record_StringDataGet(pRecord, 1, szString);
1775 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1776 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1778 /* Record::StringDataPut with correct index */
1779 hr = Record_StringDataPut(pRecord, 1, szTwo);
1780 ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1782 /* Record::StringDataGet */
1783 memset(szString, 0, sizeof(szString));
1784 hr = Record_StringDataGet(pRecord, 1, szString);
1785 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1786 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1788 /* Record::StringDataPut with incorrect index */
1789 hr = Record_StringDataPut(pRecord, -1, szString);
1790 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1791 ok_exception(hr, szStringDataField);
1793 /* View::Modify with incorrect parameters */
1794 hr = View_Modify(pView, -5, NULL);
1795 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1796 ok_exception(hr, szModifyModeRecord);
1798 hr = View_Modify(pView, -5, pRecord);
1799 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1800 ok_exception(hr, szModifyModeRecord);
1802 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1803 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1804 ok_exception(hr, szModifyModeRecord);
1806 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1807 ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr);
1809 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1810 memset(szString, 0, sizeof(szString));
1811 hr = Record_StringDataGet(pRecord, 1, szString);
1812 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1813 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1815 IDispatch_Release(pRecord);
1818 /* View::Fetch */
1819 hr = View_Fetch(pView, &pRecord);
1820 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1821 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1822 if (pRecord)
1824 /* Record::StringDataGet */
1825 memset(szString, 0, sizeof(szString));
1826 hr = Record_StringDataGet(pRecord, 1, szString);
1827 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1828 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1830 IDispatch_Release(pRecord);
1833 /* View::Fetch */
1834 hr = View_Fetch(pView, &pRecord);
1835 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1836 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1837 if (pRecord)
1838 IDispatch_Release(pRecord);
1840 /* View::Close */
1841 hr = View_Close(pView);
1842 ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr);
1844 IDispatch_Release(pView);
1847 /* Database::SummaryInformation */
1848 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo);
1849 ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr);
1850 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1851 if (pSummaryInfo)
1853 test_SummaryInfo(pSummaryInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), readonly);
1854 IDispatch_Release(pSummaryInfo);
1858 static void test_Session(IDispatch *pSession)
1860 static const WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
1861 static const WCHAR szOne[] = { 'O','n','e',0 };
1862 static const WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 };
1863 static const WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 };
1864 static const WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 };
1865 static const WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 };
1866 static const WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1867 static const WCHAR szEmpty[] = { 0 };
1868 static const WCHAR szEquals[] = { '=',0 };
1869 static const WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
1870 static const WCHAR szModeFlag[] = { 'M','o','d','e',',','F','l','a','g',0 };
1871 WCHAR stringw[MAX_PATH];
1872 CHAR string[MAX_PATH];
1873 UINT len;
1874 VARIANT_BOOL bool;
1875 int myint;
1876 IDispatch *pDatabase = NULL, *pInst = NULL, *record = NULL;
1877 ULONG refs_before, refs_after;
1878 HRESULT hr;
1880 /* Session::Installer */
1881 hr = Session_Installer(pSession, &pInst);
1882 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1883 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1884 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1885 refs_before = IDispatch_AddRef(pInst);
1887 hr = Session_Installer(pSession, &pInst);
1888 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1889 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1890 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1891 refs_after = IDispatch_Release(pInst);
1892 ok(refs_before == refs_after, "got %u and %u\n", refs_before, refs_after);
1894 /* Session::Property, get */
1895 memset(stringw, 0, sizeof(stringw));
1896 hr = Session_PropertyGet(pSession, szProductName, stringw);
1897 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1898 if (lstrcmpW(stringw, szMSITEST) != 0)
1900 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1901 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1902 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1905 /* Session::Property, put */
1906 hr = Session_PropertyPut(pSession, szProductName, szProductName);
1907 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1908 memset(stringw, 0, sizeof(stringw));
1909 hr = Session_PropertyGet(pSession, szProductName, stringw);
1910 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1911 if (lstrcmpW(stringw, szProductName) != 0)
1913 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1914 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1915 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1918 /* Try putting a property using empty property identifier */
1919 hr = Session_PropertyPut(pSession, szEmpty, szProductName);
1920 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1921 ok_exception(hr, szPropertyName);
1923 /* Try putting a property using illegal property identifier */
1924 hr = Session_PropertyPut(pSession, szEquals, szProductName);
1925 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1927 /* Session::Language, get */
1928 hr = Session_LanguageGet(pSession, &len);
1929 ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1930 /* Not sure how to check the language is correct */
1932 /* Session::Mode, get */
1933 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1934 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1935 ok(!bool, "Reboot at end session mode is %d\n", bool);
1937 hr = Session_ModeGet(pSession, MSIRUNMODE_MAINTENANCE, &bool);
1938 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1939 ok(!bool, "Maintenance mode is %d\n", bool);
1941 /* Session::Mode, put */
1942 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, VARIANT_TRUE);
1943 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1944 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1945 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1946 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1947 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, VARIANT_FALSE); /* set it again so we don't reboot */
1948 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1950 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, VARIANT_TRUE);
1951 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1952 ok_exception(hr, szModeFlag);
1954 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTNOW, &bool);
1955 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1956 ok(bool, "Reboot now mode is %d, expected 1\n", bool);
1958 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, VARIANT_FALSE); /* set it again so we don't reboot */
1959 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1960 ok_exception(hr, szModeFlag);
1962 hr = Session_ModePut(pSession, MSIRUNMODE_MAINTENANCE, VARIANT_TRUE);
1963 ok(hr == DISP_E_EXCEPTION, "Session_ModePut failed, hresult 0x%08x\n", hr);
1964 ok_exception(hr, szModeFlag);
1966 /* Session::Database, get */
1967 hr = Session_Database(pSession, &pDatabase);
1968 ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr);
1969 if (hr == S_OK)
1971 test_Database(pDatabase, TRUE);
1972 IDispatch_Release(pDatabase);
1975 /* Session::EvaluateCondition */
1976 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1977 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1978 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1980 hr = Session_EvaluateCondition(pSession, szEmpty, &myint);
1981 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1982 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1984 hr = Session_EvaluateCondition(pSession, szEquals, &myint);
1985 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1986 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1988 /* Session::DoAction(CostInitialize) must occur before the next statements */
1989 hr = Session_DoAction(pSession, szCostInitialize, &myint);
1990 ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr);
1991 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1993 /* Session::SetInstallLevel */
1994 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1995 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
1997 /* Session::FeatureCurrentState, get */
1998 hr = Session_FeatureCurrentState(pSession, szOne, &myint);
1999 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
2000 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2002 /* Session::Message */
2003 hr = Installer_CreateRecord(0, &record);
2004 ok(hr == S_OK, "Installer_CreateRecord failed: %08x\n", hr);
2005 hr = Session_Message(pSession, INSTALLMESSAGE_INFO, record, &myint);
2006 ok(hr == S_OK, "Session_Message failed: %08x\n", hr);
2007 ok(myint == 0, "Session_Message returned %x\n", myint);
2009 /* Session::EvaluateCondition */
2010 hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint);
2011 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2012 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2014 hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint);
2015 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2016 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2018 /* Session::FeatureRequestState, put */
2019 hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED);
2020 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
2021 hr = Session_FeatureRequestStateGet(pSession, szOne, &myint);
2022 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
2023 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
2025 /* Session::EvaluateCondition */
2026 hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint);
2027 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2028 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2030 hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint);
2031 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2032 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2035 /* delete key and all its subkeys */
2036 static DWORD delete_key( HKEY hkey )
2038 char name[MAX_PATH];
2039 DWORD ret;
2041 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
2043 HKEY tmp;
2044 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
2046 ret = delete_key( tmp );
2047 RegCloseKey( tmp );
2049 if (ret) break;
2051 if (ret != ERROR_NO_MORE_ITEMS) return ret;
2052 RegDeleteKeyA( hkey, "" );
2053 return 0;
2056 static void test_Installer_RegistryValue(void)
2058 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
2059 static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 };
2060 static const WCHAR szOne[] = { 'O','n','e',0 };
2061 static const WCHAR szTwo[] = { 'T','w','o',0 };
2062 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
2063 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
2064 static const WCHAR szFour[] = { 'F','o','u','r',0 };
2065 static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 };
2066 static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 };
2067 static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 };
2068 static const WCHAR szSix[] = { 'S','i','x',0 };
2069 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
2070 static const WCHAR szREG_2[] = { '(','R','E','G','_','?','?',')',0 };
2071 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
2072 static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
2073 static const WCHAR szBlank[] = { 0 };
2074 VARIANT varresult;
2075 VARIANTARG vararg;
2076 WCHAR szString[MAX_PATH];
2077 HKEY hkey, hkey_sub;
2078 HKEY curr_user = (HKEY)1;
2079 HRESULT hr;
2080 BOOL bRet;
2081 LONG lRet;
2083 /* Delete keys */
2084 SetLastError(0xdeadbeef);
2085 lRet = RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey );
2086 if (!lRet && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2088 win_skip("Needed W-functions are not implemented\n");
2089 return;
2091 if (!lRet)
2092 delete_key( hkey );
2094 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
2095 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
2096 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
2097 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
2099 memset(szString, 0, sizeof(szString));
2100 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
2101 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2103 memset(szString, 0, sizeof(szString));
2104 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
2105 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2107 /* Create key */
2108 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
2110 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
2111 "RegSetValueExW failed\n");
2112 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
2113 "RegSetValueExW failed\n");
2114 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
2115 "RegSetValueExW failed\n");
2116 bRet = SetEnvironmentVariableA("MSITEST", "Four");
2117 ok(bRet, "SetEnvironmentVariableA failed %d\n", GetLastError());
2118 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
2119 "RegSetValueExW failed\n");
2120 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
2121 "RegSetValueExW failed\n");
2122 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
2123 "RegSetValueExW failed\n");
2124 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, NULL, 0),
2125 "RegSetValueExW failed\n");
2127 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
2128 "RegSetValueExW failed\n");
2130 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
2132 /* Does our key exist? It should, and make sure we retrieve the correct default value */
2133 bRet = FALSE;
2134 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
2135 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
2136 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
2138 memset(szString, 0, sizeof(szString));
2139 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
2140 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2141 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
2143 /* Ask for the value of a nonexistent key */
2144 memset(szString, 0, sizeof(szString));
2145 hr = Installer_RegistryValueW(curr_user, szKey, szExpand, szString);
2146 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2148 /* Get values of keys */
2149 memset(szString, 0, sizeof(szString));
2150 hr = Installer_RegistryValueW(curr_user, szKey, szOne, szString);
2151 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2152 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
2154 VariantInit(&vararg);
2155 V_VT(&vararg) = VT_BSTR;
2156 V_BSTR(&vararg) = SysAllocString(szTwo);
2157 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_I4);
2158 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
2159 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
2160 VariantClear(&varresult);
2162 memset(szString, 0, sizeof(szString));
2163 hr = Installer_RegistryValueW(curr_user, szKey, szThree, szString);
2164 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2165 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
2167 memset(szString, 0, sizeof(szString));
2168 hr = Installer_RegistryValueW(curr_user, szKey, szFour, szString);
2169 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2170 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
2172 /* Vista does not NULL-terminate this case */
2173 memset(szString, 0, sizeof(szString));
2174 hr = Installer_RegistryValueW(curr_user, szKey, szFive, szString);
2175 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2176 ok_w2n("Registry value \"%s\" does not match expected \"%s\"\n",
2177 szString, szFiveHi, lstrlenW(szFiveHi));
2179 memset(szString, 0, sizeof(szString));
2180 hr = Installer_RegistryValueW(curr_user, szKey, szSix, szString);
2181 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2182 ok(!lstrcmpW(szString, szREG_2) || broken(!lstrcmpW(szString, szREG_)),
2183 "Registry value does not match\n");
2185 VariantInit(&vararg);
2186 V_VT(&vararg) = VT_BSTR;
2187 V_BSTR(&vararg) = SysAllocString(szSeven);
2188 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_EMPTY);
2189 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
2191 /* Get string class name for the key */
2192 memset(szString, 0, sizeof(szString));
2193 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
2194 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2195 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank);
2197 /* Get name of a value by positive number (RegEnumValue like), valid index */
2198 memset(szString, 0, sizeof(szString));
2199 hr = Installer_RegistryValueI(curr_user, szKey, 2, szString, VT_BSTR);
2200 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2201 /* RegEnumValue order seems different on wine */
2202 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
2204 /* Get name of a value by positive number (RegEnumValue like), invalid index */
2205 memset(szString, 0, sizeof(szString));
2206 hr = Installer_RegistryValueI(curr_user, szKey, 10, szString, VT_EMPTY);
2207 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2209 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
2210 memset(szString, 0, sizeof(szString));
2211 hr = Installer_RegistryValueI(curr_user, szKey, -1, szString, VT_BSTR);
2212 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2213 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
2215 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
2216 memset(szString, 0, sizeof(szString));
2217 hr = Installer_RegistryValueI(curr_user, szKey, -10, szString, VT_EMPTY);
2218 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2220 /* clean up */
2221 delete_key(hkey);
2224 static void test_Installer_Products(BOOL bProductInstalled)
2226 WCHAR szString[MAX_PATH];
2227 HRESULT hr;
2228 int idx;
2229 IUnknown *pUnk = NULL;
2230 IEnumVARIANT *pEnum = NULL;
2231 VARIANT var;
2232 ULONG celt;
2233 int iCount, iValue;
2234 IDispatch *pStringList = NULL;
2235 BOOL bProductFound = FALSE;
2237 /* Installer::Products */
2238 hr = Installer_Products(&pStringList);
2239 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
2240 if (hr == S_OK)
2242 /* StringList::_NewEnum */
2243 hr = StringList__NewEnum(pStringList, &pUnk);
2244 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
2245 if (hr == S_OK)
2247 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
2248 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2250 if (!pEnum)
2251 skip("IEnumVARIANT tests\n");
2253 /* StringList::Count */
2254 hr = StringList_Count(pStringList, &iCount);
2255 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2257 for (idx=0; idx<iCount; idx++)
2259 /* StringList::Item */
2260 memset(szString, 0, sizeof(szString));
2261 hr = StringList_Item(pStringList, idx, szString);
2262 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2264 if (hr == S_OK)
2266 /* Installer::ProductState */
2267 hr = Installer_ProductState(szString, &iValue);
2268 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2269 if (hr == S_OK)
2270 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
2272 /* Not found our product code yet? Check */
2273 if (!bProductFound && !lstrcmpW(szString, szProductCode))
2274 bProductFound = TRUE;
2276 /* IEnumVARIANT::Next */
2277 if (pEnum)
2279 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2280 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2281 ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
2282 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2283 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2284 VariantClear(&var);
2289 if (bProductInstalled)
2291 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
2292 bProductInstalled ? "be" : "not be",
2293 bProductFound ? "found" : "not found");
2296 if (pEnum)
2298 IEnumVARIANT *pEnum2 = NULL;
2300 if (0) /* Crashes on Windows XP */
2302 /* IEnumVARIANT::Clone, NULL pointer */
2303 IEnumVARIANT_Clone(pEnum, NULL);
2306 /* IEnumVARIANT::Clone */
2307 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
2308 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
2309 if (hr == S_OK)
2311 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
2313 /* IEnumVARIANT::Next of the clone */
2314 if (iCount)
2316 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
2317 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2318 ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
2319 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2320 VariantClear(&var);
2322 else
2323 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
2325 IEnumVARIANT_Release(pEnum2);
2328 /* IEnumVARIANT::Skip should fail */
2329 hr = IEnumVARIANT_Skip(pEnum, 1);
2330 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2332 /* IEnumVARIANT::Next, NULL variant pointer */
2333 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2334 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2335 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2337 /* IEnumVARIANT::Next, should not return any more items */
2338 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2339 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2340 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2341 VariantClear(&var);
2343 /* IEnumVARIANT::Reset */
2344 hr = IEnumVARIANT_Reset(pEnum);
2345 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2347 if (iCount)
2349 /* IEnumVARIANT::Skip to the last product */
2350 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2351 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2353 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2354 * NULL celt pointer. */
2355 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2356 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2357 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2358 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2359 VariantClear(&var);
2361 else
2362 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2365 /* StringList::Item using an invalid index */
2366 memset(szString, 0, sizeof(szString));
2367 hr = StringList_Item(pStringList, iCount, szString);
2368 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2370 if (pEnum) IEnumVARIANT_Release(pEnum);
2371 if (pUnk) IUnknown_Release(pUnk);
2372 IDispatch_Release(pStringList);
2376 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2377 * deleting the subkeys first) */
2378 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey, REGSAM access)
2380 UINT ret;
2381 CHAR *string = NULL;
2382 HKEY hkey;
2383 DWORD dwSize;
2385 ret = RegOpenKeyExA(hkeyParent, subkey, 0, access, &hkey);
2386 if (ret != ERROR_SUCCESS) return ret;
2387 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2388 if (ret != ERROR_SUCCESS) return ret;
2389 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2391 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2392 delete_registry_key(hkey, string, access);
2394 RegCloseKey(hkey);
2395 HeapFree(GetProcessHeap(), 0, string);
2396 delete_key_portable(hkeyParent, subkey, access);
2397 return ERROR_SUCCESS;
2400 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2401 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, REGSAM access, HKEY *phkey)
2403 UINT ret;
2404 CHAR *string = NULL;
2405 int idx = 0;
2406 HKEY hkey;
2407 DWORD dwSize;
2408 BOOL found = FALSE;
2410 *phkey = 0;
2412 ret = RegOpenKeyExA(hkeyParent, subkey, 0, access, &hkey);
2413 if (ret != ERROR_SUCCESS) return ret;
2414 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2415 if (ret != ERROR_SUCCESS) return ret;
2416 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2418 while (!found &&
2419 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2421 if (!strcmp(string, findkey))
2423 *phkey = hkey;
2424 found = TRUE;
2426 else if (find_registry_key(hkey, string, findkey, access, phkey) == ERROR_SUCCESS) found = TRUE;
2429 if (*phkey != hkey) RegCloseKey(hkey);
2430 HeapFree(GetProcessHeap(), 0, string);
2431 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2434 static void test_Installer_InstallProduct(void)
2436 HRESULT hr;
2437 CHAR path[MAX_PATH];
2438 WCHAR szString[MAX_PATH];
2439 LONG res;
2440 HKEY hkey;
2441 DWORD num, size, type;
2442 int iValue, iCount;
2443 IDispatch *pStringList = NULL;
2444 REGSAM access = KEY_ALL_ACCESS;
2446 if (is_process_limited())
2448 /* In fact InstallProduct would succeed but then Windows XP
2449 * would not allow us to clean up the registry!
2451 skip("Installer_InstallProduct (insufficient privileges)\n");
2452 return;
2455 if (is_wow64)
2456 access |= KEY_WOW64_64KEY;
2458 create_test_files();
2460 /* Avoid an interactive dialog in case of insufficient privileges. */
2461 hr = Installer_UILevelPut(INSTALLUILEVEL_NONE);
2462 ok(hr == S_OK, "Expected UILevel property put invoke to return S_OK, got 0x%08x\n", hr);
2464 /* Installer::InstallProduct */
2465 hr = Installer_InstallProduct(szMsifile, NULL);
2466 if (hr == DISP_E_EXCEPTION)
2468 skip("InstallProduct failed, insufficient rights?\n");
2469 delete_test_files();
2470 return;
2472 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2474 /* Installer::ProductState for our product code, which has been installed */
2475 hr = Installer_ProductState(szProductCode, &iValue);
2476 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2477 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2479 /* Installer::ProductInfo for our product code */
2481 /* NULL attribute */
2482 memset(szString, 0, sizeof(szString));
2483 hr = Installer_ProductInfo(szProductCode, NULL, szString);
2484 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2485 ok_exception(hr, szProductInfoException);
2487 /* Nonexistent attribute */
2488 memset(szString, 0, sizeof(szString));
2489 hr = Installer_ProductInfo(szProductCode, szMsifile, szString);
2490 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2491 ok_exception(hr, szProductInfoException);
2493 /* Package name */
2494 memset(szString, 0, sizeof(szString));
2495 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szString);
2496 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2497 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile);
2499 /* Product name */
2500 memset(szString, 0, sizeof(szString));
2501 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PRODUCTNAMEW, szString);
2502 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2503 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST);
2505 /* Installer::Products */
2506 test_Installer_Products(TRUE);
2508 /* Installer::RelatedProducts for our upgrade code */
2509 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2510 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2511 if (hr == S_OK)
2513 /* StringList::Count */
2514 hr = StringList_Count(pStringList, &iCount);
2515 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2516 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2518 /* StringList::Item */
2519 memset(szString, 0, sizeof(szString));
2520 hr = StringList_Item(pStringList, 0, szString);
2521 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2522 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
2524 IDispatch_Release(pStringList);
2527 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_LOCALPACKAGEW, szString);
2528 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2529 DeleteFileW( szString );
2531 /* Check & clean up installed files & registry keys */
2532 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2533 ok(delete_pf("msitest\\cabout\\new", FALSE), "Directory not created\n");
2534 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2535 ok(delete_pf("msitest\\cabout", FALSE), "Directory not created\n");
2536 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2537 ok(delete_pf("msitest\\changed", FALSE), "Directory not created\n");
2538 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2539 ok(delete_pf("msitest\\first", FALSE), "Directory not created\n");
2540 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2541 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2542 ok(delete_pf("msitest", FALSE), "Directory not created\n");
2544 res = RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest", &hkey);
2545 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2547 size = MAX_PATH;
2548 type = REG_SZ;
2549 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2550 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2551 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2553 size = MAX_PATH;
2554 type = REG_SZ;
2555 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2556 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2558 size = sizeof(num);
2559 type = REG_DWORD;
2560 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2561 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2562 ok(num == 314, "Expected 314, got %d\n", num);
2564 size = MAX_PATH;
2565 type = REG_SZ;
2566 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2567 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2568 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2570 RegCloseKey(hkey);
2572 res = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest");
2573 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2575 /* Remove registry keys written by RegisterProduct standard action */
2576 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2577 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{837450fa-a39b-4bc8-b321-08b393f784b3}",
2578 KEY_WOW64_32KEY);
2579 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2581 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2582 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656", access);
2583 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2585 res = find_registry_key(HKEY_LOCAL_MACHINE,
2586 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "af054738b93a8cb43b12803b397f483b", access, &hkey);
2587 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2589 res = delete_registry_key(hkey, "af054738b93a8cb43b12803b397f483b", access);
2590 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2591 RegCloseKey(hkey);
2593 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2594 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\af054738b93a8cb43b12803b397f483b", access);
2595 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2597 /* Remove registry keys written by PublishProduct standard action */
2598 res = RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2599 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2601 res = delete_registry_key(hkey, "Products\\af054738b93a8cb43b12803b397f483b", KEY_ALL_ACCESS);
2602 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2604 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2605 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2607 RegCloseKey(hkey);
2609 /* Delete installation files we created */
2610 delete_test_files();
2613 static void test_Installer(void)
2615 static const WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
2616 static const WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
2617 WCHAR szPath[MAX_PATH];
2618 HRESULT hr;
2619 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL, *pSumInfo = NULL;
2620 int iValue, iCount;
2622 if (!pInstaller) return;
2624 /* Installer::CreateRecord */
2626 /* Test for error */
2627 hr = Installer_CreateRecord(-1, &pRecord);
2628 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2629 ok_exception(hr, szCreateRecordException);
2631 /* Test for success */
2632 hr = Installer_CreateRecord(1, &pRecord);
2633 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2634 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2635 if (pRecord)
2637 /* Record::FieldCountGet */
2638 hr = Record_FieldCountGet(pRecord, &iValue);
2639 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2640 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2642 /* Record::IntegerDataGet */
2643 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2644 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2645 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2647 /* Record::IntegerDataGet, bad index */
2648 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2649 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2650 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2652 /* Record::IntegerDataPut */
2653 hr = Record_IntegerDataPut(pRecord, 1, 100);
2654 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2656 /* Record::IntegerDataPut, bad index */
2657 hr = Record_IntegerDataPut(pRecord, 10, 100);
2658 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2659 ok_exception(hr, szIntegerDataException);
2661 /* Record::IntegerDataGet */
2662 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2663 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2664 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2666 IDispatch_Release(pRecord);
2669 create_package(szPath);
2671 /* Installer::OpenPackage */
2672 hr = Installer_OpenPackage(szPath, 0, &pSession);
2673 if (hr == DISP_E_EXCEPTION)
2675 skip("OpenPackage failed, insufficient rights?\n");
2676 DeleteFileW(szPath);
2677 return;
2679 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2680 if (hr == S_OK)
2682 test_Session(pSession);
2683 IDispatch_Release(pSession);
2686 /* Installer::OpenDatabase */
2687 hr = Installer_OpenDatabase(szPath, (INT_PTR)MSIDBOPEN_TRANSACT, &pDatabase);
2688 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2689 if (hr == S_OK)
2691 test_Database(pDatabase, FALSE);
2692 IDispatch_Release(pDatabase);
2695 /* Installer::SummaryInformation */
2696 hr = Installer_SummaryInformation(szPath, 0, &pSumInfo);
2697 ok(hr == S_OK, "Installer_SummaryInformation failed, hresult 0x%08x\n", hr);
2698 if (hr == S_OK)
2700 test_SummaryInfo(pSumInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), TRUE);
2701 IDispatch_Release(pSumInfo);
2704 hr = Installer_SummaryInformation(NULL, 0, &pSumInfo);
2705 ok(hr == DISP_E_EXCEPTION, "Installer_SummaryInformation failed, hresult 0x%08x\n", hr);
2707 /* Installer::RegistryValue */
2708 test_Installer_RegistryValue();
2710 /* Installer::ProductState for our product code, which should not be installed */
2711 hr = Installer_ProductState(szProductCode, &iValue);
2712 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2713 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2715 /* Installer::ProductInfo for our product code, which should not be installed */
2717 /* Package name */
2718 memset(szPath, 0, sizeof(szPath));
2719 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szPath);
2720 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2721 ok_exception(hr, szProductInfoException);
2723 /* NULL attribute and NULL product code */
2724 memset(szPath, 0, sizeof(szPath));
2725 hr = Installer_ProductInfo(NULL, NULL, szPath);
2726 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2727 ok_exception(hr, szProductInfoException);
2729 /* Installer::Products */
2730 test_Installer_Products(FALSE);
2732 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2733 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2734 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2735 if (hr == S_OK)
2737 /* StringList::Count */
2738 hr = StringList_Count(pStringList, &iCount);
2739 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2740 ok(!iCount, "Expected no related products but found %d\n", iCount);
2742 IDispatch_Release(pStringList);
2745 /* Installer::Version */
2746 memset(szPath, 0, sizeof(szPath));
2747 hr = Installer_VersionGet(szPath);
2748 ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr);
2750 /* Installer::InstallProduct and other tests that depend on our product being installed */
2751 test_Installer_InstallProduct();
2754 START_TEST(automation)
2756 DWORD len;
2757 char temp_path[MAX_PATH], prev_path[MAX_PATH];
2758 HRESULT hr;
2759 CLSID clsid;
2760 IUnknown *pUnk;
2762 init_functionpointers();
2764 if (pIsWow64Process)
2765 pIsWow64Process(GetCurrentProcess(), &is_wow64);
2767 GetSystemTimeAsFileTime(&systemtime);
2769 GetCurrentDirectoryA(MAX_PATH, prev_path);
2770 GetTempPathA(MAX_PATH, temp_path);
2771 SetCurrentDirectoryA(temp_path);
2773 lstrcpyA(CURR_DIR, temp_path);
2774 len = lstrlenA(CURR_DIR);
2776 if(len && (CURR_DIR[len - 1] == '\\'))
2777 CURR_DIR[len - 1] = 0;
2779 get_program_files_dir(PROG_FILES_DIR);
2781 hr = OleInitialize(NULL);
2782 ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr);
2783 hr = CLSIDFromProgID(szProgId, &clsid);
2784 ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr);
2785 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2786 ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr);
2788 if (pUnk)
2790 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2791 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2793 test_dispid();
2794 test_dispatch();
2795 test_Installer();
2797 IDispatch_Release(pInstaller);
2798 IUnknown_Release(pUnk);
2801 OleUninitialize();
2803 SetCurrentDirectoryA(prev_path);