msi/tests: Check that we have enough privileges to run the automation tests.
[wine.git] / dlls / msi / tests / automation.c
blob242ec63d957832307bc753ca7af9d0ab0431f3e2
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;
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,
241 0, 0, 0, 0, 0, 0, &Group) ||
242 !pCheckTokenMembership(NULL, Group, &IsInGroup))
244 trace("Could not check if the current user is an administrator\n");
245 return FALSE;
247 if (!IsInGroup)
249 /* Only administrators have enough privileges for these tests */
250 return TRUE;
253 if (pOpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
255 BOOL ret;
256 TOKEN_ELEVATION_TYPE type = TokenElevationTypeDefault;
257 DWORD size;
259 ret = GetTokenInformation(token, TokenElevationType, &type, sizeof(type), &size);
260 CloseHandle(token);
261 return (ret && type == TokenElevationTypeLimited);
263 return FALSE;
266 static LONG delete_key_portable( HKEY key, LPCSTR subkey, REGSAM access )
268 if (pRegDeleteKeyExA)
269 return pRegDeleteKeyExA( key, subkey, access, 0 );
270 return RegDeleteKeyA( key, subkey );
274 * Database Helpers
277 static void write_file(const CHAR *filename, const char *data, int data_size)
279 DWORD size;
281 HANDLE hf = CreateFileA(filename, GENERIC_WRITE, 0, NULL,
282 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
283 WriteFile(hf, data, data_size, &size, NULL);
284 CloseHandle(hf);
287 static void write_msi_summary_info(MSIHANDLE db, const msi_summary_info *info, int num_info)
289 MSIHANDLE summary;
290 UINT r;
291 int j;
293 r = MsiGetSummaryInformationA(db, NULL, num_info, &summary);
294 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
296 /* import summary information into the stream */
297 for (j = 0; j < num_info; j++)
299 const msi_summary_info *entry = &info[j];
301 r = MsiSummaryInfoSetPropertyA(summary, entry->property, entry->datatype,
302 entry->iValue, entry->pftValue, entry->szValue);
303 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
306 /* write the summary changes back to the stream */
307 r = MsiSummaryInfoPersist(summary);
308 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
310 MsiCloseHandle(summary);
313 static void create_database(const CHAR *name, const msi_table *tables, int num_tables,
314 const msi_summary_info *info, int num_info)
316 MSIHANDLE db;
317 UINT r;
318 WCHAR *nameW;
319 int j, len;
321 len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
322 if (!(nameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return;
323 MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, len );
325 r = MsiOpenDatabaseW(nameW, MSIDBOPEN_CREATE, &db);
326 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
328 /* import the tables into the database */
329 for (j = 0; j < num_tables; j++)
331 const msi_table *table = &tables[j];
333 write_file(table->filename, table->data, (table->size - 1) * sizeof(char));
335 r = MsiDatabaseImportA(db, CURR_DIR, table->filename);
336 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
338 DeleteFileA(table->filename);
341 write_msi_summary_info(db, info, num_info);
343 r = MsiDatabaseCommit(db);
344 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
346 MsiCloseHandle(db);
347 HeapFree( GetProcessHeap(), 0, nameW );
350 static BOOL create_package(LPWSTR path)
352 static const WCHAR slashW[] = {'\\',0};
353 DWORD len;
355 /* Prepare package */
356 create_database(msifile, tables,
357 sizeof(tables) / sizeof(msi_table), summary_info,
358 sizeof(summary_info) / sizeof(msi_summary_info));
360 len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
361 CURR_DIR, -1, path, MAX_PATH);
362 ok(len, "MultiByteToWideChar returned error %d\n", GetLastError());
363 if (!len)
364 return FALSE;
366 lstrcatW(path, slashW);
367 lstrcatW(path, szMsifile);
368 return TRUE;
372 * Installation helpers
375 static char PROG_FILES_DIR[MAX_PATH];
377 static BOOL get_program_files_dir(LPSTR buf)
379 HKEY hkey;
380 DWORD type = REG_EXPAND_SZ, size;
382 if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &hkey))
383 return FALSE;
385 size = MAX_PATH;
386 if (RegQueryValueExA(hkey, "ProgramFilesDir (x86)", 0, &type, (LPBYTE)buf, &size) &&
387 RegQueryValueExA(hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size))
388 return FALSE;
390 RegCloseKey(hkey);
391 return TRUE;
394 static void create_file(const CHAR *name, DWORD size)
396 HANDLE file;
397 DWORD written, left;
399 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
400 ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
401 WriteFile(file, name, strlen(name), &written, NULL);
402 WriteFile(file, "\n", strlen("\n"), &written, NULL);
404 left = size - lstrlenA(name) - 1;
406 SetFilePointer(file, left, NULL, FILE_CURRENT);
407 SetEndOfFile(file);
409 CloseHandle(file);
412 static void create_test_files(void)
414 CreateDirectoryA("msitest", NULL);
415 create_file("msitest\\one.txt", 100);
416 CreateDirectoryA("msitest\\first", NULL);
417 create_file("msitest\\first\\two.txt", 100);
418 CreateDirectoryA("msitest\\second", NULL);
419 create_file("msitest\\second\\three.txt", 100);
420 CreateDirectoryA("msitest\\cabout",NULL);
421 create_file("msitest\\cabout\\four.txt", 100);
422 CreateDirectoryA("msitest\\cabout\\new",NULL);
423 create_file("msitest\\cabout\\new\\five.txt", 100);
424 create_file("msitest\\filename", 100);
427 static BOOL delete_pf(const CHAR *rel_path, BOOL is_file)
429 CHAR path[MAX_PATH];
431 lstrcpyA(path, PROG_FILES_DIR);
432 lstrcatA(path, "\\");
433 lstrcatA(path, rel_path);
435 if (is_file)
436 return DeleteFileA(path);
437 else
438 return RemoveDirectoryA(path);
441 static void delete_test_files(void)
443 DeleteFileA(msifile);
444 DeleteFileA("msitest\\cabout\\new\\five.txt");
445 DeleteFileA("msitest\\cabout\\four.txt");
446 DeleteFileA("msitest\\second\\three.txt");
447 DeleteFileA("msitest\\first\\two.txt");
448 DeleteFileA("msitest\\one.txt");
449 DeleteFileA("msitest\\filename");
450 RemoveDirectoryA("msitest\\cabout\\new");
451 RemoveDirectoryA("msitest\\cabout");
452 RemoveDirectoryA("msitest\\second");
453 RemoveDirectoryA("msitest\\first");
454 RemoveDirectoryA("msitest");
458 * Automation helpers and tests
461 /* ok-like statement which takes two unicode strings or one unicode and one ANSI string as arguments */
462 static CHAR string1[MAX_PATH], string2[MAX_PATH];
464 #define ok_w2(format, szString1, szString2) \
466 do { \
467 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
468 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
469 if (lstrcmpA(string1, string2) != 0) \
470 ok(0, format, string1, string2); \
471 } while(0);
473 #define ok_w2n(format, szString1, szString2, len) \
475 if (memcmp(szString1, szString2, len * sizeof(WCHAR)) != 0) \
477 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
478 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
479 ok(0, format, string1, string2); \
482 #define ok_aw(format, aString, wString) \
484 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
485 if (lstrcmpA(string1, aString) != 0) \
486 ok(0, format, string1, aString); \
488 #define ok_awplus(format, extra, aString, wString) \
490 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
491 if (lstrcmpA(string1, aString) != 0) \
492 ok(0, format, extra, string1, aString); \
494 /* exception checker */
495 static const WCHAR szSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
497 #define ok_exception(hr, szDescription) \
498 if (hr == DISP_E_EXCEPTION) \
500 /* Compare wtype, source, and destination */ \
501 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
503 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
504 if (excepinfo.bstrSource) \
505 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, szSource); \
507 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
508 if (excepinfo.bstrDescription) \
509 ok_w2("Exception description was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrDescription, szDescription); \
511 SysFreeString(excepinfo.bstrSource); \
512 SysFreeString(excepinfo.bstrDescription); \
513 SysFreeString(excepinfo.bstrHelpFile); \
516 static DISPID get_dispid( IDispatch *disp, const char *name )
518 LPOLESTR str;
519 UINT len;
520 DISPID id = -1;
521 HRESULT r;
523 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
524 str = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
525 if (str)
527 MultiByteToWideChar(CP_ACP, 0, name, -1, str, len );
528 r = IDispatch_GetIDsOfNames( disp, &IID_NULL, &str, 1, 0, &id );
529 HeapFree(GetProcessHeap(), 0, str);
530 if (r != S_OK)
531 return -1;
534 return id;
537 typedef struct {
538 DISPID did;
539 const char *name;
540 BOOL todo;
541 } get_did_t;
543 static const get_did_t get_did_data[] = {
544 { 1, "CreateRecord" },
545 { 2, "OpenPackage" },
546 { 3, "OpenProduct" },
547 { 4, "OpenDatabase" },
548 { 5, "SummaryInformation" },
549 { 6, "UILevel" },
550 { 7, "EnableLog" },
551 { 8, "InstallProduct" },
552 { 9, "Version" },
553 { 10, "LastErrorRecord" },
554 { 11, "RegistryValue" },
555 { 12, "Environment" },
556 { 13, "FileAttributes" },
557 { 15, "FileSize" },
558 { 16, "FileVersion" },
559 { 17, "ProductState" },
560 { 18, "ProductInfo" },
561 { 19, "ConfigureProduct", TRUE },
562 { 20, "ReinstallProduct", TRUE },
563 { 21, "CollectUserInfo", TRUE },
564 { 22, "ApplyPatch", TRUE },
565 { 23, "FeatureParent", TRUE },
566 { 24, "FeatureState", TRUE },
567 { 25, "UseFeature", TRUE },
568 { 26, "FeatureUsageCount", TRUE },
569 { 27, "FeatureUsageDate", TRUE },
570 { 28, "ConfigureFeature", TRUE },
571 { 29, "ReinstallFeature", TRUE },
572 { 30, "ProvideComponent", TRUE },
573 { 31, "ComponentPath", TRUE },
574 { 32, "ProvideQualifiedComponent", TRUE },
575 { 33, "QualifierDescription", TRUE },
576 { 34, "ComponentQualifiers", TRUE },
577 { 35, "Products" },
578 { 36, "Features", TRUE },
579 { 37, "Components", TRUE },
580 { 38, "ComponentClients", TRUE },
581 { 39, "Patches", TRUE },
582 { 40, "RelatedProducts" },
583 { 41, "PatchInfo", TRUE },
584 { 42, "PatchTransforms", TRUE },
585 { 43, "AddSource", TRUE },
586 { 44, "ClearSourceList", TRUE },
587 { 45, "ForceSourceListResolution", TRUE },
588 { 46, "ShortcutTarget", TRUE },
589 { 47, "FileHash", TRUE },
590 { 48, "FileSignatureInfo", TRUE },
591 { 0 }
594 static void test_dispid(void)
596 const get_did_t *ptr = get_did_data;
597 DISPID dispid;
599 while (ptr->name)
601 dispid = get_dispid(pInstaller, ptr->name);
602 if (ptr->todo)
603 todo_wine
604 ok(dispid == ptr->did, "%s: expected %d, got %d\n", ptr->name, ptr->did, dispid);
605 else
606 ok(dispid == ptr->did, "%s: expected %d, got %d\n", ptr->name, ptr->did, dispid);
607 ptr++;
610 dispid = get_dispid(pInstaller, "RemovePatches");
611 ok(dispid == 49 || dispid == -1, "Expected 49 or -1, got %d\n", dispid);
612 dispid = get_dispid(pInstaller, "ApplyMultiplePatches");
613 ok(dispid == 51 || dispid == -1, "Expected 51 or -1, got %d\n", dispid);
614 dispid = get_dispid(pInstaller, "ProductsEx");
615 ok(dispid == 52 || dispid == -1, "Expected 52 or -1, got %d\n", dispid);
616 dispid = get_dispid(pInstaller, "PatchesEx");
617 ok(dispid == 55 || dispid == -1, "Expected 55 or -1, got %d\n", dispid);
618 dispid = get_dispid(pInstaller, "ExtractPatchXMLData");
619 ok(dispid == 57 || dispid == -1, "Expected 57 or -1, got %d\n", dispid);
620 dispid = get_dispid( pInstaller, "ProductElevated" );
621 ok(dispid == 59 || dispid == -1, "Expected 59 or -1, got %d\n", dispid);
622 dispid = get_dispid( pInstaller, "ProvideAssembly" );
623 ok(dispid == 60 || dispid == -1, "Expected 60 or -1, got %d\n", dispid);
624 dispid = get_dispid( pInstaller, "ProductInfoFromScript" );
625 ok(dispid == 61 || dispid == -1, "Expected 61 or -1, got %d\n", dispid);
626 dispid = get_dispid( pInstaller, "AdvertiseProduct" );
627 ok(dispid == 62 || dispid == -1, "Expected 62 or -1, got %d\n", dispid);
628 dispid = get_dispid( pInstaller, "CreateAdvertiseScript" );
629 ok(dispid == 63 || dispid == -1, "Expected 63 or -1, got %d\n", dispid);
630 dispid = get_dispid( pInstaller, "PatchFiles" );
631 ok(dispid == 65 || dispid == -1, "Expected 65 or -1, got %d\n", dispid);
634 /* Test basic IDispatch functions */
635 static void test_dispatch(void)
637 static WCHAR szOpenPackage[] = { 'O','p','e','n','P','a','c','k','a','g','e',0 };
638 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};
639 static WCHAR szProductState[] = { 'P','r','o','d','u','c','t','S','t','a','t','e',0 };
640 HRESULT hr;
641 DISPID dispid;
642 OLECHAR *name;
643 VARIANT varresult;
644 VARIANTARG vararg[3];
645 WCHAR path[MAX_PATH];
646 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
648 /* Test getting ID of a function name that does not exist */
649 name = (WCHAR *)szMsifile;
650 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
651 ok(hr == DISP_E_UNKNOWNNAME, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
653 /* Test invoking this function */
654 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
655 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
657 /* Test getting ID of a function name that does exist */
658 name = szOpenPackage;
659 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
660 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
662 /* Test invoking this function (without parameters passed) */
663 if (0) /* All of these crash MSI on Windows XP */
665 IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
666 IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL);
667 VariantInit(&varresult);
668 IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, &varresult, &excepinfo, NULL);
671 /* Try with NULL params */
672 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
673 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
675 /* Try one empty parameter */
676 dispparams.rgvarg = vararg;
677 dispparams.cArgs = 1;
678 VariantInit(&vararg[0]);
679 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
680 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
682 /* Try two empty parameters */
683 dispparams.cArgs = 2;
684 VariantInit(&vararg[0]);
685 VariantInit(&vararg[1]);
686 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
687 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
689 /* Try one parameter, the required BSTR. Second parameter is optional.
690 * NOTE: The specified package does not exist, which is why the call fails.
692 dispparams.cArgs = 1;
693 VariantInit(&vararg[0]);
694 V_VT(&vararg[0]) = VT_BSTR;
695 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
696 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
697 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
698 ok_exception(hr, szOpenPackageException);
699 VariantClear(&vararg[0]);
701 /* Provide the required BSTR and an empty second parameter.
702 * NOTE: The specified package does not exist, which is why the call fails.
704 dispparams.cArgs = 2;
705 VariantInit(&vararg[1]);
706 V_VT(&vararg[1]) = VT_BSTR;
707 V_BSTR(&vararg[1]) = SysAllocString(szMsifile);
708 VariantInit(&vararg[0]);
709 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
710 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
711 ok_exception(hr, szOpenPackageException);
712 VariantClear(&vararg[1]);
714 /* Provide the required BSTR and two empty parameters.
715 * NOTE: The specified package does not exist, which is why the call fails.
717 dispparams.cArgs = 3;
718 VariantInit(&vararg[2]);
719 V_VT(&vararg[2]) = VT_BSTR;
720 V_BSTR(&vararg[2]) = SysAllocString(szMsifile);
721 VariantInit(&vararg[1]);
722 VariantInit(&vararg[0]);
723 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
724 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
725 ok_exception(hr, szOpenPackageException);
726 VariantClear(&vararg[2]);
728 /* Provide the required BSTR and a second parameter with the wrong type. */
729 dispparams.cArgs = 2;
730 VariantInit(&vararg[1]);
731 V_VT(&vararg[1]) = VT_BSTR;
732 V_BSTR(&vararg[1]) = SysAllocString(szMsifile);
733 VariantInit(&vararg[0]);
734 V_VT(&vararg[0]) = VT_BSTR;
735 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
736 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
737 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
738 VariantClear(&vararg[0]);
739 VariantClear(&vararg[1]);
741 /* Create a proper installer package. */
742 create_package(path);
744 /* Try one parameter, the required BSTR. Second parameter is optional.
745 * Proper installer package exists. Path to the package is relative.
747 dispparams.cArgs = 1;
748 VariantInit(&vararg[0]);
749 V_VT(&vararg[0]) = VT_BSTR;
750 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
751 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
752 todo_wine ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
753 ok_exception(hr, szOpenPackageException);
754 VariantClear(&vararg[0]);
755 if (hr != DISP_E_EXCEPTION)
756 VariantClear(&varresult);
758 /* Try one parameter, the required BSTR. Second parameter is optional.
759 * Proper installer package exists. Path to the package is absolute.
761 dispparams.cArgs = 1;
762 VariantInit(&vararg[0]);
763 V_VT(&vararg[0]) = VT_BSTR;
764 V_BSTR(&vararg[0]) = SysAllocString(path);
765 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
766 if (hr == DISP_E_EXCEPTION)
768 skip("OpenPackage failed, insufficient rights?\n");
769 DeleteFileW(path);
770 return;
772 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
773 VariantClear(&vararg[0]);
774 VariantClear(&varresult);
776 /* Provide the required BSTR and an empty second parameter. Proper
777 * installation package exists.
779 dispparams.cArgs = 2;
780 VariantInit(&vararg[1]);
781 V_VT(&vararg[1]) = VT_BSTR;
782 V_BSTR(&vararg[1]) = SysAllocString(path);
783 VariantInit(&vararg[0]);
784 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
785 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
786 VariantClear(&vararg[1]);
787 VariantClear(&varresult);
789 /* Provide the required BSTR and two empty parameters. Proper
790 * installation package exists.
792 dispparams.cArgs = 3;
793 VariantInit(&vararg[2]);
794 V_VT(&vararg[2]) = VT_BSTR;
795 V_BSTR(&vararg[2]) = SysAllocString(path);
796 VariantInit(&vararg[1]);
797 VariantInit(&vararg[0]);
798 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
799 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
800 VariantClear(&vararg[2]);
801 VariantClear(&varresult);
803 /* Provide the required BSTR and a second parameter with the wrong type. */
804 dispparams.cArgs = 2;
805 VariantInit(&vararg[1]);
806 V_VT(&vararg[1]) = VT_BSTR;
807 V_BSTR(&vararg[1]) = SysAllocString(path);
808 VariantInit(&vararg[0]);
809 V_VT(&vararg[0]) = VT_BSTR;
810 V_BSTR(&vararg[0]) = SysAllocString(path);
811 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
812 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
813 VariantClear(&vararg[0]);
814 VariantClear(&vararg[1]);
816 /* Provide the required BSTR and a second parameter that can be coerced to
817 * VT_I4.
819 dispparams.cArgs = 2;
820 VariantInit(&vararg[1]);
821 V_VT(&vararg[1]) = VT_BSTR;
822 V_BSTR(&vararg[1]) = SysAllocString(path);
823 VariantInit(&vararg[0]);
824 V_VT(&vararg[0]) = VT_I2;
825 V_BSTR(&vararg[0]) = 0;
826 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
827 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
828 VariantClear(&vararg[1]);
829 VariantClear(&varresult);
831 DeleteFileW(path);
833 /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
834 VariantInit(&vararg[0]);
835 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
836 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
838 VariantInit(&vararg[0]);
839 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
840 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
842 /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
843 name = szProductState;
844 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
845 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
847 dispparams.rgvarg = NULL;
848 dispparams.cArgs = 0;
849 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
850 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
852 dispparams.rgvarg = NULL;
853 dispparams.cArgs = 0;
854 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
855 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
858 /* invocation helper function */
859 static int _invoke_todo_vtResult = 0;
861 static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult)
863 OLECHAR *name = NULL;
864 DISPID dispid;
865 HRESULT hr;
866 UINT i;
867 UINT len;
869 memset(pVarResult, 0, sizeof(VARIANT));
870 VariantInit(pVarResult);
872 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 );
873 name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
874 if (!name) return E_FAIL;
875 MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len );
876 hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
877 HeapFree(GetProcessHeap(), 0, name);
878 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
879 if (!hr == S_OK) return hr;
881 memset(&excepinfo, 0, sizeof(excepinfo));
882 hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL);
884 if (hr == S_OK)
886 if (_invoke_todo_vtResult) todo_wine
887 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
888 else
889 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
890 if (vtResult != VT_EMPTY)
892 hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult);
893 ok(hr == S_OK, "VariantChangeTypeEx returned 0x%08x\n", hr);
897 for (i=0; i<pDispParams->cArgs; i++)
898 VariantClear(&pDispParams->rgvarg[i]);
900 return hr;
903 /* Object_Property helper functions */
905 static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord)
907 VARIANT varresult;
908 VARIANTARG vararg[1];
909 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
910 HRESULT hr;
912 VariantInit(&vararg[0]);
913 V_VT(&vararg[0]) = VT_I4;
914 V_I4(&vararg[0]) = count;
916 hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
917 *pRecord = V_DISPATCH(&varresult);
918 return hr;
921 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
923 VARIANTARG vararg[3];
924 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
926 VariantInit(&vararg[2]);
927 V_VT(&vararg[2]) = VT_I4;
928 V_I4(&vararg[2]) = (INT_PTR)hkey;
929 VariantInit(&vararg[1]);
930 V_VT(&vararg[1]) = VT_BSTR;
931 V_BSTR(&vararg[1]) = SysAllocString(szKey);
932 VariantInit(&vararg[0]);
933 VariantCopy(&vararg[0], &vValue);
934 VariantClear(&vValue);
936 return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect);
939 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
941 VARIANT varresult;
942 VARIANTARG vararg;
943 HRESULT hr;
945 VariantInit(&vararg);
946 V_VT(&vararg) = VT_EMPTY;
947 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL);
948 *pBool = V_BOOL(&varresult);
949 VariantClear(&varresult);
950 return hr;
953 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
955 VARIANT varresult;
956 VARIANTARG vararg;
957 HRESULT hr;
959 VariantInit(&vararg);
960 V_VT(&vararg) = VT_BSTR;
961 V_BSTR(&vararg) = SysAllocString(szValue);
963 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR);
964 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
965 VariantClear(&varresult);
966 return hr;
969 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
971 VARIANT varresult;
972 VARIANTARG vararg;
973 HRESULT hr;
975 VariantInit(&vararg);
976 V_VT(&vararg) = VT_I4;
977 V_I4(&vararg) = iValue;
979 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult);
980 if (SUCCEEDED(hr) && vtResult == VT_BSTR) lstrcpyW(szString, V_BSTR(&varresult));
981 VariantClear(&varresult);
982 return hr;
985 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
987 VARIANT varresult;
988 VARIANTARG vararg[2];
989 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
990 HRESULT hr;
992 VariantInit(&vararg[1]);
993 V_VT(&vararg[1]) = VT_BSTR;
994 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
995 VariantInit(&vararg[0]);
996 V_VT(&vararg[0]) = VT_I4;
997 V_I4(&vararg[0]) = options;
999 hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1000 *pSession = V_DISPATCH(&varresult);
1001 return hr;
1004 static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase)
1006 VARIANT varresult;
1007 VARIANTARG vararg[2];
1008 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1009 HRESULT hr;
1011 VariantInit(&vararg[1]);
1012 V_VT(&vararg[1]) = VT_BSTR;
1013 V_BSTR(&vararg[1]) = SysAllocString(szDatabasePath);
1014 VariantInit(&vararg[0]);
1015 V_VT(&vararg[0]) = VT_I4;
1016 V_I4(&vararg[0]) = openmode;
1018 hr = invoke(pInstaller, "OpenDatabase", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1019 *pDatabase = V_DISPATCH(&varresult);
1020 return hr;
1023 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
1025 VARIANT varresult;
1026 VARIANTARG vararg[2];
1027 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1029 VariantInit(&vararg[1]);
1030 V_VT(&vararg[1]) = VT_BSTR;
1031 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
1032 VariantInit(&vararg[0]);
1033 V_VT(&vararg[0]) = VT_BSTR;
1034 V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues);
1036 return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1039 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
1041 VARIANT varresult;
1042 VARIANTARG vararg[1];
1043 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1044 HRESULT hr;
1046 VariantInit(&vararg[0]);
1047 V_VT(&vararg[0]) = VT_BSTR;
1048 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
1050 hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1051 *pInstallState = V_I4(&varresult);
1052 VariantClear(&varresult);
1053 return hr;
1056 static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szString)
1058 VARIANT varresult;
1059 VARIANTARG vararg[2];
1060 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1061 HRESULT hr;
1063 VariantInit(&vararg[1]);
1064 V_VT(&vararg[1]) = VT_BSTR;
1065 V_BSTR(&vararg[1]) = SysAllocString(szProduct);
1066 VariantInit(&vararg[0]);
1067 V_VT(&vararg[0]) = VT_BSTR;
1068 V_BSTR(&vararg[0]) = SysAllocString(szAttribute);
1070 hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1071 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1072 VariantClear(&varresult);
1073 return hr;
1076 static HRESULT Installer_Products(IDispatch **pStringList)
1078 VARIANT varresult;
1079 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1080 HRESULT hr;
1082 hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1083 *pStringList = V_DISPATCH(&varresult);
1084 return hr;
1087 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
1089 VARIANT varresult;
1090 VARIANTARG vararg[1];
1091 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1092 HRESULT hr;
1094 VariantInit(&vararg[0]);
1095 V_VT(&vararg[0]) = VT_BSTR;
1096 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
1098 hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1099 *pStringList = V_DISPATCH(&varresult);
1100 return hr;
1103 static HRESULT Installer_VersionGet(LPWSTR szVersion)
1105 VARIANT varresult;
1106 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1107 HRESULT hr;
1109 hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1110 if (V_BSTR(&varresult)) lstrcpyW(szVersion, V_BSTR(&varresult));
1111 VariantClear(&varresult);
1112 return hr;
1115 static HRESULT Installer_UILevelPut(int level)
1117 VARIANT varresult;
1118 VARIANTARG vararg;
1119 DISPID dispid = DISPID_PROPERTYPUT;
1120 DISPPARAMS dispparams = {&vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1122 VariantInit(&vararg);
1123 V_VT(&vararg) = VT_I4;
1124 V_I4(&vararg) = level;
1126 return invoke(pInstaller, "UILevel", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1129 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
1131 VARIANT varresult;
1132 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1133 HRESULT hr;
1135 hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1136 *pInst = V_DISPATCH(&varresult);
1137 return hr;
1140 static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn)
1142 VARIANT varresult;
1143 VARIANTARG vararg[1];
1144 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1145 HRESULT hr;
1147 VariantInit(&vararg[0]);
1148 V_VT(&vararg[0]) = VT_BSTR;
1149 V_BSTR(&vararg[0]) = SysAllocString(szName);
1151 hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1152 if (V_BSTR(&varresult)) lstrcpyW(szReturn, V_BSTR(&varresult));
1153 VariantClear(&varresult);
1154 return hr;
1157 static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue)
1159 VARIANT varresult;
1160 VARIANTARG vararg[2];
1161 DISPID dispid = DISPID_PROPERTYPUT;
1162 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1164 VariantInit(&vararg[1]);
1165 V_VT(&vararg[1]) = VT_BSTR;
1166 V_BSTR(&vararg[1]) = SysAllocString(szName);
1167 VariantInit(&vararg[0]);
1168 V_VT(&vararg[0]) = VT_BSTR;
1169 V_BSTR(&vararg[0]) = SysAllocString(szValue);
1171 return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1174 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
1176 VARIANT varresult;
1177 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1178 HRESULT hr;
1180 hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1181 *pLangId = V_I4(&varresult);
1182 VariantClear(&varresult);
1183 return hr;
1186 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, BOOL *pMode)
1188 VARIANT varresult;
1189 VARIANTARG vararg[1];
1190 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1191 HRESULT hr;
1193 VariantInit(&vararg[0]);
1194 V_VT(&vararg[0]) = VT_I4;
1195 V_I4(&vararg[0]) = iFlag;
1197 hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL);
1198 *pMode = V_BOOL(&varresult);
1199 VariantClear(&varresult);
1200 return hr;
1203 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, BOOL bMode)
1205 VARIANT varresult;
1206 VARIANTARG vararg[2];
1207 DISPID dispid = DISPID_PROPERTYPUT;
1208 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1210 VariantInit(&vararg[1]);
1211 V_VT(&vararg[1]) = VT_I4;
1212 V_I4(&vararg[1]) = iFlag;
1213 VariantInit(&vararg[0]);
1214 V_VT(&vararg[0]) = VT_BOOL;
1215 V_BOOL(&vararg[0]) = bMode;
1217 return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1220 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
1222 VARIANT varresult;
1223 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1224 HRESULT hr;
1226 hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1227 *pDatabase = V_DISPATCH(&varresult);
1228 return hr;
1231 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn)
1233 VARIANT varresult;
1234 VARIANTARG vararg[1];
1235 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1236 HRESULT hr;
1238 VariantInit(&vararg[0]);
1239 V_VT(&vararg[0]) = VT_BSTR;
1240 V_BSTR(&vararg[0]) = SysAllocString(szAction);
1242 hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1243 *iReturn = V_I4(&varresult);
1244 VariantClear(&varresult);
1245 return hr;
1248 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
1250 VARIANT varresult;
1251 VARIANTARG vararg[1];
1252 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1253 HRESULT hr;
1255 VariantInit(&vararg[0]);
1256 V_VT(&vararg[0]) = VT_BSTR;
1257 V_BSTR(&vararg[0]) = SysAllocString(szCondition);
1259 hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1260 *iReturn = V_I4(&varresult);
1261 VariantClear(&varresult);
1262 return hr;
1265 static HRESULT Session_Message(IDispatch *pSession, LONG kind, IDispatch *record, int *ret)
1267 VARIANT varresult;
1268 VARIANTARG vararg[2];
1269 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1270 HRESULT hr;
1272 VariantInit(&varresult);
1273 V_VT(vararg) = VT_DISPATCH;
1274 V_DISPATCH(vararg) = record;
1275 V_VT(vararg+1) = VT_I4;
1276 V_I4(vararg+1) = kind;
1278 hr = invoke(pSession, "Message", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1280 ok(V_VT(&varresult) == VT_I4, "V_VT(varresult) = %d\n", V_VT(&varresult));
1281 *ret = V_I4(&varresult);
1283 return hr;
1286 static HRESULT Session_SetInstallLevel(IDispatch *pSession, LONG iInstallLevel)
1288 VARIANT varresult;
1289 VARIANTARG vararg[1];
1290 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1292 VariantInit(&vararg[0]);
1293 V_VT(&vararg[0]) = VT_I4;
1294 V_I4(&vararg[0]) = iInstallLevel;
1296 return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1299 static HRESULT Session_FeatureCurrentState(IDispatch *pSession, LPCWSTR szName, int *pState)
1301 VARIANT varresult;
1302 VARIANTARG vararg[1];
1303 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1304 HRESULT hr;
1306 VariantInit(&vararg[0]);
1307 V_VT(&vararg[0]) = VT_BSTR;
1308 V_BSTR(&vararg[0]) = SysAllocString(szName);
1310 hr = invoke(pSession, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1311 *pState = V_I4(&varresult);
1312 VariantClear(&varresult);
1313 return hr;
1316 static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState)
1318 VARIANT varresult;
1319 VARIANTARG vararg[1];
1320 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1321 HRESULT hr;
1323 VariantInit(&vararg[0]);
1324 V_VT(&vararg[0]) = VT_BSTR;
1325 V_BSTR(&vararg[0]) = SysAllocString(szName);
1327 hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1328 *pState = V_I4(&varresult);
1329 VariantClear(&varresult);
1330 return hr;
1333 static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState)
1335 VARIANT varresult;
1336 VARIANTARG vararg[2];
1337 DISPID dispid = DISPID_PROPERTYPUT;
1338 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1340 VariantInit(&vararg[1]);
1341 V_VT(&vararg[1]) = VT_BSTR;
1342 V_BSTR(&vararg[1]) = SysAllocString(szName);
1343 VariantInit(&vararg[0]);
1344 V_VT(&vararg[0]) = VT_I4;
1345 V_I4(&vararg[0]) = iState;
1347 return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1350 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
1352 VARIANT varresult;
1353 VARIANTARG vararg[1];
1354 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1355 HRESULT hr;
1357 VariantInit(&vararg[0]);
1358 V_VT(&vararg[0]) = VT_BSTR;
1359 V_BSTR(&vararg[0]) = SysAllocString(szSql);
1361 hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1362 *pView = V_DISPATCH(&varresult);
1363 return hr;
1366 static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo)
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_I4;
1375 V_I4(&vararg[0]) = iUpdateCount;
1377 hr = invoke(pDatabase, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1378 *pSummaryInfo = V_DISPATCH(&varresult);
1379 return hr;
1382 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
1384 VARIANT varresult;
1385 VARIANTARG vararg[1];
1386 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1388 VariantInit(&vararg[0]);
1389 V_VT(&vararg[0]) = VT_DISPATCH;
1390 V_DISPATCH(&vararg[0]) = pRecord;
1392 return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1395 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
1397 VARIANT varresult;
1398 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1399 HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1400 *ppRecord = V_DISPATCH(&varresult);
1401 return hr;
1404 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
1406 VARIANT varresult;
1407 VARIANTARG vararg[2];
1408 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1410 VariantInit(&vararg[1]);
1411 V_VT(&vararg[1]) = VT_I4;
1412 V_I4(&vararg[1]) = iMode;
1413 VariantInit(&vararg[0]);
1414 V_VT(&vararg[0]) = VT_DISPATCH;
1415 V_DISPATCH(&vararg[0]) = pRecord;
1416 if (pRecord)
1417 IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */
1419 return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1422 static HRESULT View_Close(IDispatch *pView)
1424 VARIANT varresult;
1425 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1426 return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1429 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
1431 VARIANT varresult;
1432 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1433 HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1434 *pFieldCount = V_I4(&varresult);
1435 VariantClear(&varresult);
1436 return hr;
1439 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString)
1441 VARIANT varresult;
1442 VARIANTARG vararg[1];
1443 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1444 HRESULT hr;
1446 VariantInit(&vararg[0]);
1447 V_VT(&vararg[0]) = VT_I4;
1448 V_I4(&vararg[0]) = iField;
1450 hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1451 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1452 VariantClear(&varresult);
1453 return hr;
1456 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
1458 VARIANT varresult;
1459 VARIANTARG vararg[2];
1460 DISPID dispid = DISPID_PROPERTYPUT;
1461 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1463 VariantInit(&vararg[1]);
1464 V_VT(&vararg[1]) = VT_I4;
1465 V_I4(&vararg[1]) = iField;
1466 VariantInit(&vararg[0]);
1467 V_VT(&vararg[0]) = VT_BSTR;
1468 V_BSTR(&vararg[0]) = SysAllocString(szString);
1470 return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1473 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
1475 VARIANT varresult;
1476 VARIANTARG vararg[1];
1477 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1478 HRESULT hr;
1480 VariantInit(&vararg[0]);
1481 V_VT(&vararg[0]) = VT_I4;
1482 V_I4(&vararg[0]) = iField;
1484 hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1485 *pValue = V_I4(&varresult);
1486 VariantClear(&varresult);
1487 return hr;
1490 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
1492 VARIANT varresult;
1493 VARIANTARG vararg[2];
1494 DISPID dispid = DISPID_PROPERTYPUT;
1495 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1497 VariantInit(&vararg[1]);
1498 V_VT(&vararg[1]) = VT_I4;
1499 V_I4(&vararg[1]) = iField;
1500 VariantInit(&vararg[0]);
1501 V_VT(&vararg[0]) = VT_I4;
1502 V_I4(&vararg[0]) = iValue;
1504 return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1507 static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT)
1509 VARIANT varresult;
1510 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1511 HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN);
1512 *ppEnumVARIANT = V_UNKNOWN(&varresult);
1513 return hr;
1516 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
1518 VARIANT varresult;
1519 VARIANTARG vararg[1];
1520 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1521 HRESULT hr;
1523 VariantInit(&vararg[0]);
1524 V_VT(&vararg[0]) = VT_I4;
1525 V_I4(&vararg[0]) = iIndex;
1527 hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1528 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1529 VariantClear(&varresult);
1530 return hr;
1533 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
1535 VARIANT varresult;
1536 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1537 HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1538 *pCount = V_I4(&varresult);
1539 VariantClear(&varresult);
1540 return hr;
1543 static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect)
1545 VARIANTARG vararg[1];
1546 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1548 VariantInit(&vararg[0]);
1549 V_VT(&vararg[0]) = VT_I4;
1550 V_I4(&vararg[0]) = pid;
1551 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYGET, &dispparams, pVarResult, vtExpect);
1554 static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant)
1556 VARIANT varresult;
1557 VARIANTARG vararg[2];
1558 DISPID dispid = DISPID_PROPERTYPUT;
1559 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1561 VariantInit(&vararg[1]);
1562 V_VT(&vararg[1]) = VT_I4;
1563 V_I4(&vararg[1]) = pid;
1564 VariantInit(&vararg[0]);
1565 VariantCopyInd(vararg, pVariant);
1567 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1570 static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount)
1572 VARIANT varresult;
1573 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1574 HRESULT hr;
1576 hr = invoke(pSummaryInfo, "PropertyCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1577 *pCount = V_I4(&varresult);
1578 VariantClear(&varresult);
1579 return hr;
1582 /* Test the various objects */
1584 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4
1586 static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly)
1588 static const WCHAR szPropertyException[] = { 'P','r','o','p','e','r','t','y',',','P','i','d',0 };
1589 static const WCHAR szTitle[] = { 'T','i','t','l','e',0 };
1590 VARIANT varresult, var;
1591 SYSTEMTIME st;
1592 HRESULT hr;
1593 int j;
1595 /* SummaryInfo::PropertyCount */
1596 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1597 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1598 ok(j == num_info, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1600 /* SummaryInfo::Property, get for properties we have set */
1601 for (j = 0; j < num_info; j++)
1603 const msi_summary_info *entry = &info[j];
1605 int vt = entry->datatype;
1606 if (vt == VT_LPSTR) vt = VT_BSTR;
1607 else if (vt == VT_FILETIME) vt = VT_DATE;
1608 else if (vt == VT_I2) vt = VT_I4;
1610 hr = SummaryInfo_PropertyGet(pSummaryInfo, entry->property, &varresult, vt);
1611 ok(hr == S_OK, "SummaryInfo_Property (pid %d) failed, hresult 0x%08x\n", entry->property, hr);
1612 if (V_VT(&varresult) != vt)
1613 skip("Skipping property tests due to type mismatch\n");
1614 else if (vt == VT_I4)
1615 ok(V_I4(&varresult) == entry->iValue, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %d\n",
1616 entry->property, entry->iValue, V_I4(&varresult));
1617 else if (vt == VT_DATE)
1619 FILETIME ft;
1620 DATE d;
1622 FileTimeToLocalFileTime(entry->pftValue, &ft);
1623 FileTimeToSystemTime(&ft, &st);
1624 SystemTimeToVariantTime(&st, &d);
1625 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));
1627 else if (vt == VT_BSTR)
1629 ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry->property, entry->szValue, V_BSTR(&varresult));
1631 else
1632 skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry->property, vt);
1634 VariantClear(&varresult);
1637 /* SummaryInfo::Property, get; invalid arguments */
1639 /* Invalid pids */
1640 hr = SummaryInfo_PropertyGet(pSummaryInfo, -1, &varresult, VT_EMPTY);
1641 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1642 ok_exception(hr, szPropertyException);
1644 hr = SummaryInfo_PropertyGet(pSummaryInfo, 1000, &varresult, VT_EMPTY);
1645 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1646 ok_exception(hr, szPropertyException);
1648 /* Unsupported pids */
1649 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_DICTIONARY, &varresult, VT_EMPTY);
1650 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1652 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY);
1653 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1655 /* Pids we have not set, one for each type */
1656 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_EMPTY);
1657 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1659 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY);
1660 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1662 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY);
1663 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1665 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY);
1666 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1668 if (!readonly)
1670 /* SummaryInfo::Property, put; one for each type */
1672 /* VT_I2 */
1673 VariantInit(&var);
1674 V_VT(&var) = VT_I2;
1675 V_I2(&var) = 1;
1676 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CODEPAGE, &var);
1677 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1679 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */);
1680 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1681 ok(V_I2(&var) == V_I2(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var), V_I2(&varresult));
1682 VariantClear(&varresult);
1683 VariantClear(&var);
1685 /* VT_BSTR */
1686 V_VT(&var) = VT_BSTR;
1687 V_BSTR(&var) = SysAllocString(szTitle);
1688 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_TITLE, &var);
1689 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1691 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var));
1692 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1693 ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var), V_BSTR(&varresult));
1694 VariantClear(&varresult);
1695 VariantClear(&var);
1697 /* VT_DATE */
1698 V_VT(&var) = VT_DATE;
1699 FileTimeToSystemTime(&systemtime, &st);
1700 SystemTimeToVariantTime(&st, &V_DATE(&var));
1701 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_LASTSAVE_DTM, &var);
1702 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1704 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var));
1705 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1706 ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1707 VariantClear(&varresult);
1708 VariantClear(&var);
1710 /* VT_I4 */
1711 V_VT(&var) = VT_I4;
1712 V_I4(&var) = 1000;
1713 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1714 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1716 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1717 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1718 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult));
1719 VariantClear(&varresult);
1720 VariantClear(&var);
1722 /* SummaryInfo::PropertyCount */
1723 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1724 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1725 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1729 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1731 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 };
1732 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
1733 static const WCHAR szTwo[] = { 'T','w','o',0 };
1734 static const WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
1735 static const WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 };
1736 IDispatch *pView = NULL, *pSummaryInfo = NULL;
1737 HRESULT hr;
1739 hr = Database_OpenView(pDatabase, szSql, &pView);
1740 ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr);
1741 if (hr == S_OK)
1743 IDispatch *pRecord = NULL;
1744 WCHAR szString[MAX_PATH];
1746 /* View::Execute */
1747 hr = View_Execute(pView, NULL);
1748 ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr);
1750 /* View::Fetch */
1751 hr = View_Fetch(pView, &pRecord);
1752 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1753 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1754 if (pRecord)
1756 /* Record::StringDataGet */
1757 memset(szString, 0, sizeof(szString));
1758 hr = Record_StringDataGet(pRecord, 1, szString);
1759 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1760 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1762 /* Record::StringDataPut with correct index */
1763 hr = Record_StringDataPut(pRecord, 1, szTwo);
1764 ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1766 /* Record::StringDataGet */
1767 memset(szString, 0, sizeof(szString));
1768 hr = Record_StringDataGet(pRecord, 1, szString);
1769 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1770 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1772 /* Record::StringDataPut with incorrect index */
1773 hr = Record_StringDataPut(pRecord, -1, szString);
1774 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1775 ok_exception(hr, szStringDataField);
1777 /* View::Modify with incorrect parameters */
1778 hr = View_Modify(pView, -5, NULL);
1779 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1780 ok_exception(hr, szModifyModeRecord);
1782 hr = View_Modify(pView, -5, pRecord);
1783 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1784 ok_exception(hr, szModifyModeRecord);
1786 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1787 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1788 ok_exception(hr, szModifyModeRecord);
1790 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1791 ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr);
1793 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1794 memset(szString, 0, sizeof(szString));
1795 hr = Record_StringDataGet(pRecord, 1, szString);
1796 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1797 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1799 IDispatch_Release(pRecord);
1802 /* View::Fetch */
1803 hr = View_Fetch(pView, &pRecord);
1804 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1805 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1806 if (pRecord)
1808 /* Record::StringDataGet */
1809 memset(szString, 0, sizeof(szString));
1810 hr = Record_StringDataGet(pRecord, 1, szString);
1811 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1812 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1814 IDispatch_Release(pRecord);
1817 /* View::Fetch */
1818 hr = View_Fetch(pView, &pRecord);
1819 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1820 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1821 if (pRecord)
1822 IDispatch_Release(pRecord);
1824 /* View::Close */
1825 hr = View_Close(pView);
1826 ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr);
1828 IDispatch_Release(pView);
1831 /* Database::SummaryInformation */
1832 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo);
1833 ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr);
1834 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1835 if (pSummaryInfo)
1837 test_SummaryInfo(pSummaryInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), readonly);
1838 IDispatch_Release(pSummaryInfo);
1842 static void test_Session(IDispatch *pSession)
1844 static const WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
1845 static const WCHAR szOne[] = { 'O','n','e',0 };
1846 static const WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 };
1847 static const WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 };
1848 static const WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 };
1849 static const WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 };
1850 static const WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1851 static const WCHAR szEmpty[] = { 0 };
1852 static const WCHAR szEquals[] = { '=',0 };
1853 static const WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
1854 static const WCHAR szModeFlag[] = { 'M','o','d','e',',','F','l','a','g',0 };
1855 WCHAR stringw[MAX_PATH];
1856 CHAR string[MAX_PATH];
1857 UINT len;
1858 BOOL bool;
1859 int myint;
1860 IDispatch *pDatabase = NULL, *pInst = NULL, *record = NULL;
1861 ULONG refs_before, refs_after;
1862 HRESULT hr;
1864 /* Session::Installer */
1865 hr = Session_Installer(pSession, &pInst);
1866 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1867 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1868 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1869 refs_before = IDispatch_AddRef(pInst);
1871 hr = Session_Installer(pSession, &pInst);
1872 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1873 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1874 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1875 refs_after = IDispatch_Release(pInst);
1876 ok(refs_before == refs_after, "got %u and %u\n", refs_before, refs_after);
1878 /* Session::Property, get */
1879 memset(stringw, 0, sizeof(stringw));
1880 hr = Session_PropertyGet(pSession, szProductName, stringw);
1881 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1882 if (lstrcmpW(stringw, szMSITEST) != 0)
1884 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1885 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1886 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1889 /* Session::Property, put */
1890 hr = Session_PropertyPut(pSession, szProductName, szProductName);
1891 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1892 memset(stringw, 0, sizeof(stringw));
1893 hr = Session_PropertyGet(pSession, szProductName, stringw);
1894 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1895 if (lstrcmpW(stringw, szProductName) != 0)
1897 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1898 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1899 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1902 /* Try putting a property using empty property identifier */
1903 hr = Session_PropertyPut(pSession, szEmpty, szProductName);
1904 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1905 ok_exception(hr, szPropertyName);
1907 /* Try putting a property using illegal property identifier */
1908 hr = Session_PropertyPut(pSession, szEquals, szProductName);
1909 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1911 /* Session::Language, get */
1912 hr = Session_LanguageGet(pSession, &len);
1913 ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1914 /* Not sure how to check the language is correct */
1916 /* Session::Mode, get */
1917 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1918 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1919 ok(!bool, "Reboot at end session mode is %d\n", bool);
1921 hr = Session_ModeGet(pSession, MSIRUNMODE_MAINTENANCE, &bool);
1922 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1923 ok(!bool, "Maintenance mode is %d\n", bool);
1925 /* Session::Mode, put */
1926 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE);
1927 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1928 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1929 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1930 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1931 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE); /* set it again so we don't reboot */
1932 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1934 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, TRUE);
1935 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1936 if (hr == DISP_E_EXCEPTION) ok_exception(hr, szModeFlag);
1938 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTNOW, &bool);
1939 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1940 ok(bool, "Reboot now mode is %d, expected 1\n", bool);
1942 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, FALSE); /* set it again so we don't reboot */
1943 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1944 if (hr == DISP_E_EXCEPTION) ok_exception(hr, szModeFlag);
1946 hr = Session_ModePut(pSession, MSIRUNMODE_MAINTENANCE, TRUE);
1947 ok(hr == DISP_E_EXCEPTION, "Session_ModePut failed, hresult 0x%08x\n", hr);
1948 ok_exception(hr, szModeFlag);
1950 /* Session::Database, get */
1951 hr = Session_Database(pSession, &pDatabase);
1952 ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr);
1953 if (hr == S_OK)
1955 test_Database(pDatabase, TRUE);
1956 IDispatch_Release(pDatabase);
1959 /* Session::EvaluateCondition */
1960 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1961 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1962 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1964 hr = Session_EvaluateCondition(pSession, szEmpty, &myint);
1965 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1966 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1968 hr = Session_EvaluateCondition(pSession, szEquals, &myint);
1969 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1970 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1972 /* Session::DoAction(CostInitialize) must occur before the next statements */
1973 hr = Session_DoAction(pSession, szCostInitialize, &myint);
1974 ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr);
1975 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1977 /* Session::SetInstallLevel */
1978 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1979 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
1981 /* Session::FeatureCurrentState, get */
1982 hr = Session_FeatureCurrentState(pSession, szOne, &myint);
1983 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
1984 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1986 /* Session::Message */
1987 hr = Installer_CreateRecord(0, &record);
1988 ok(hr == S_OK, "Installer_CreateRecord failed: %08x\n", hr);
1989 hr = Session_Message(pSession, INSTALLMESSAGE_INFO, record, &myint);
1990 ok(hr == S_OK, "Session_Message failed: %08x\n", hr);
1991 ok(myint == 0, "Session_Message returned %x\n", myint);
1993 /* Session::EvaluateCondition */
1994 hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint);
1995 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1996 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1998 hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint);
1999 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
2000 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
2002 /* Session::FeatureRequestState, put */
2003 hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED);
2004 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
2005 hr = Session_FeatureRequestStateGet(pSession, szOne, &myint);
2006 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
2007 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
2009 /* Session::EvaluateCondition */
2010 hr = Session_EvaluateCondition(pSession, szOneActionFalse, &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, szOneActionTrue, &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);
2019 /* delete key and all its subkeys */
2020 static DWORD delete_key( HKEY hkey )
2022 char name[MAX_PATH];
2023 DWORD ret;
2025 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
2027 HKEY tmp;
2028 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
2030 ret = delete_key( tmp );
2031 RegCloseKey( tmp );
2033 if (ret) break;
2035 if (ret != ERROR_NO_MORE_ITEMS) return ret;
2036 RegDeleteKeyA( hkey, "" );
2037 return 0;
2040 static void test_Installer_RegistryValue(void)
2042 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
2043 static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 };
2044 static const WCHAR szOne[] = { 'O','n','e',0 };
2045 static const WCHAR szTwo[] = { 'T','w','o',0 };
2046 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
2047 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
2048 static const WCHAR szFour[] = { 'F','o','u','r',0 };
2049 static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 };
2050 static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 };
2051 static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 };
2052 static const WCHAR szSix[] = { 'S','i','x',0 };
2053 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
2054 static const WCHAR szREG_2[] = { '(','R','E','G','_','?','?',')',0 };
2055 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
2056 static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
2057 static const WCHAR szBlank[] = { 0 };
2058 VARIANT varresult;
2059 VARIANTARG vararg;
2060 WCHAR szString[MAX_PATH];
2061 HKEY hkey, hkey_sub;
2062 HKEY curr_user = (HKEY)1;
2063 HRESULT hr;
2064 BOOL bRet;
2065 LONG lRet;
2067 /* Delete keys */
2068 SetLastError(0xdeadbeef);
2069 lRet = RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey );
2070 if (!lRet && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2072 win_skip("Needed W-functions are not implemented\n");
2073 return;
2075 if (!lRet)
2076 delete_key( hkey );
2078 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
2079 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
2080 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
2081 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
2083 memset(szString, 0, sizeof(szString));
2084 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
2085 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2087 memset(szString, 0, sizeof(szString));
2088 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
2089 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2091 /* Create key */
2092 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
2094 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
2095 "RegSetValueExW failed\n");
2096 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
2097 "RegSetValueExW failed\n");
2098 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
2099 "RegSetValueExW failed\n");
2100 bRet = SetEnvironmentVariableA("MSITEST", "Four");
2101 ok(bRet, "SetEnvironmentVariableA failed %d\n", GetLastError());
2102 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
2103 "RegSetValueExW failed\n");
2104 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
2105 "RegSetValueExW failed\n");
2106 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
2107 "RegSetValueExW failed\n");
2108 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, NULL, 0),
2109 "RegSetValueExW failed\n");
2111 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
2112 "RegSetValueExW failed\n");
2114 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
2116 /* Does our key exist? It should, and make sure we retrieve the correct default value */
2117 bRet = FALSE;
2118 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
2119 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
2120 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
2122 memset(szString, 0, sizeof(szString));
2123 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
2124 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2125 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
2127 /* Ask for the value of a nonexistent key */
2128 memset(szString, 0, sizeof(szString));
2129 hr = Installer_RegistryValueW(curr_user, szKey, szExpand, szString);
2130 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2132 /* Get values of keys */
2133 memset(szString, 0, sizeof(szString));
2134 hr = Installer_RegistryValueW(curr_user, szKey, szOne, szString);
2135 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2136 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
2138 VariantInit(&vararg);
2139 V_VT(&vararg) = VT_BSTR;
2140 V_BSTR(&vararg) = SysAllocString(szTwo);
2141 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_I4);
2142 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
2143 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
2144 VariantClear(&varresult);
2146 memset(szString, 0, sizeof(szString));
2147 hr = Installer_RegistryValueW(curr_user, szKey, szThree, szString);
2148 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2149 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
2151 memset(szString, 0, sizeof(szString));
2152 hr = Installer_RegistryValueW(curr_user, szKey, szFour, szString);
2153 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2154 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
2156 /* Vista does not NULL-terminate this case */
2157 memset(szString, 0, sizeof(szString));
2158 hr = Installer_RegistryValueW(curr_user, szKey, szFive, szString);
2159 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2160 ok_w2n("Registry value \"%s\" does not match expected \"%s\"\n",
2161 szString, szFiveHi, lstrlenW(szFiveHi));
2163 memset(szString, 0, sizeof(szString));
2164 hr = Installer_RegistryValueW(curr_user, szKey, szSix, szString);
2165 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2166 ok(!lstrcmpW(szString, szREG_2) || broken(!lstrcmpW(szString, szREG_)),
2167 "Registry value does not match\n");
2169 VariantInit(&vararg);
2170 V_VT(&vararg) = VT_BSTR;
2171 V_BSTR(&vararg) = SysAllocString(szSeven);
2172 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_EMPTY);
2173 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
2175 /* Get string class name for the key */
2176 memset(szString, 0, sizeof(szString));
2177 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
2178 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2179 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank);
2181 /* Get name of a value by positive number (RegEnumValue like), valid index */
2182 memset(szString, 0, sizeof(szString));
2183 hr = Installer_RegistryValueI(curr_user, szKey, 2, szString, VT_BSTR);
2184 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2185 /* RegEnumValue order seems different on wine */
2186 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
2188 /* Get name of a value by positive number (RegEnumValue like), invalid index */
2189 memset(szString, 0, sizeof(szString));
2190 hr = Installer_RegistryValueI(curr_user, szKey, 10, szString, VT_EMPTY);
2191 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2193 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
2194 memset(szString, 0, sizeof(szString));
2195 hr = Installer_RegistryValueI(curr_user, szKey, -1, szString, VT_BSTR);
2196 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2197 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
2199 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
2200 memset(szString, 0, sizeof(szString));
2201 hr = Installer_RegistryValueI(curr_user, szKey, -10, szString, VT_EMPTY);
2202 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2204 /* clean up */
2205 delete_key(hkey);
2208 static void test_Installer_Products(BOOL bProductInstalled)
2210 WCHAR szString[MAX_PATH];
2211 HRESULT hr;
2212 int idx;
2213 IUnknown *pUnk = NULL;
2214 IEnumVARIANT *pEnum = NULL;
2215 VARIANT var;
2216 ULONG celt;
2217 int iCount, iValue;
2218 IDispatch *pStringList = NULL;
2219 BOOL bProductFound = FALSE;
2221 /* Installer::Products */
2222 hr = Installer_Products(&pStringList);
2223 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
2224 if (hr == S_OK)
2226 /* StringList::_NewEnum */
2227 hr = StringList__NewEnum(pStringList, &pUnk);
2228 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
2229 if (hr == S_OK)
2231 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
2232 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2234 if (!pEnum)
2235 skip("IEnumVARIANT tests\n");
2237 /* StringList::Count */
2238 hr = StringList_Count(pStringList, &iCount);
2239 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2241 for (idx=0; idx<iCount; idx++)
2243 /* StringList::Item */
2244 memset(szString, 0, sizeof(szString));
2245 hr = StringList_Item(pStringList, idx, szString);
2246 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2248 if (hr == S_OK)
2250 /* Installer::ProductState */
2251 hr = Installer_ProductState(szString, &iValue);
2252 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2253 if (hr == S_OK)
2254 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
2256 /* Not found our product code yet? Check */
2257 if (!bProductFound && !lstrcmpW(szString, szProductCode))
2258 bProductFound = TRUE;
2260 /* IEnumVARIANT::Next */
2261 if (pEnum)
2263 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2264 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2265 ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
2266 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2267 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2268 VariantClear(&var);
2273 if (bProductInstalled)
2275 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
2276 bProductInstalled ? "be" : "not be",
2277 bProductFound ? "found" : "not found");
2280 if (pEnum)
2282 IEnumVARIANT *pEnum2 = NULL;
2284 if (0) /* Crashes on Windows XP */
2286 /* IEnumVARIANT::Clone, NULL pointer */
2287 IEnumVARIANT_Clone(pEnum, NULL);
2290 /* IEnumVARIANT::Clone */
2291 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
2292 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
2293 if (hr == S_OK)
2295 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
2297 /* IEnumVARIANT::Next of the clone */
2298 if (iCount)
2300 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
2301 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2302 ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
2303 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2304 VariantClear(&var);
2306 else
2307 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
2309 IEnumVARIANT_Release(pEnum2);
2312 /* IEnumVARIANT::Skip should fail */
2313 hr = IEnumVARIANT_Skip(pEnum, 1);
2314 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2316 /* IEnumVARIANT::Next, NULL variant pointer */
2317 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2318 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2319 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2321 /* IEnumVARIANT::Next, should not return any more items */
2322 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2323 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2324 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2325 VariantClear(&var);
2327 /* IEnumVARIANT::Reset */
2328 hr = IEnumVARIANT_Reset(pEnum);
2329 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2331 if (iCount)
2333 /* IEnumVARIANT::Skip to the last product */
2334 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2335 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2337 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2338 * NULL celt pointer. */
2339 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2340 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2341 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2342 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2343 VariantClear(&var);
2345 else
2346 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2349 /* StringList::Item using an invalid index */
2350 memset(szString, 0, sizeof(szString));
2351 hr = StringList_Item(pStringList, iCount, szString);
2352 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2354 if (pEnum) IEnumVARIANT_Release(pEnum);
2355 if (pUnk) IUnknown_Release(pUnk);
2356 IDispatch_Release(pStringList);
2360 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2361 * deleting the subkeys first) */
2362 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey, REGSAM access)
2364 UINT ret;
2365 CHAR *string = NULL;
2366 HKEY hkey;
2367 DWORD dwSize;
2369 ret = RegOpenKeyExA(hkeyParent, subkey, 0, access, &hkey);
2370 if (ret != ERROR_SUCCESS) return ret;
2371 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2372 if (ret != ERROR_SUCCESS) return ret;
2373 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2375 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2376 delete_registry_key(hkey, string, access);
2378 RegCloseKey(hkey);
2379 HeapFree(GetProcessHeap(), 0, string);
2380 delete_key_portable(hkeyParent, subkey, access);
2381 return ERROR_SUCCESS;
2384 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2385 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, REGSAM access, HKEY *phkey)
2387 UINT ret;
2388 CHAR *string = NULL;
2389 int idx = 0;
2390 HKEY hkey;
2391 DWORD dwSize;
2392 BOOL found = FALSE;
2394 *phkey = 0;
2396 ret = RegOpenKeyExA(hkeyParent, subkey, 0, access, &hkey);
2397 if (ret != ERROR_SUCCESS) return ret;
2398 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2399 if (ret != ERROR_SUCCESS) return ret;
2400 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2402 while (!found &&
2403 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2405 if (!strcmp(string, findkey))
2407 *phkey = hkey;
2408 found = TRUE;
2410 else if (find_registry_key(hkey, string, findkey, access, phkey) == ERROR_SUCCESS) found = TRUE;
2413 if (*phkey != hkey) RegCloseKey(hkey);
2414 HeapFree(GetProcessHeap(), 0, string);
2415 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2418 static void test_Installer_InstallProduct(void)
2420 HRESULT hr;
2421 CHAR path[MAX_PATH];
2422 WCHAR szString[MAX_PATH];
2423 LONG res;
2424 HKEY hkey;
2425 DWORD num, size, type;
2426 int iValue, iCount;
2427 IDispatch *pStringList = NULL;
2428 REGSAM access = KEY_ALL_ACCESS;
2430 if (is_process_limited())
2432 /* In fact InstallProduct would succeed but then Windows XP
2433 * would not allow us to clean up the registry!
2435 skip("Installer_InstallProduct (insufficient privileges)\n");
2436 return;
2439 if (is_wow64)
2440 access |= KEY_WOW64_64KEY;
2442 create_test_files();
2444 /* Avoid an interactive dialog in case of insufficient privileges. */
2445 hr = Installer_UILevelPut(INSTALLUILEVEL_NONE);
2446 ok(hr == S_OK, "Expected UILevel property put invoke to return S_OK, got 0x%08x\n", hr);
2448 /* Installer::InstallProduct */
2449 hr = Installer_InstallProduct(szMsifile, NULL);
2450 if (hr == DISP_E_EXCEPTION)
2452 skip("InstallProduct failed, insufficient rights?\n");
2453 delete_test_files();
2454 return;
2456 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2458 /* Installer::ProductState for our product code, which has been installed */
2459 hr = Installer_ProductState(szProductCode, &iValue);
2460 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2461 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2463 /* Installer::ProductInfo for our product code */
2465 /* NULL attribute */
2466 memset(szString, 0, sizeof(szString));
2467 hr = Installer_ProductInfo(szProductCode, NULL, szString);
2468 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2469 ok_exception(hr, szProductInfoException);
2471 /* Nonexistent attribute */
2472 memset(szString, 0, sizeof(szString));
2473 hr = Installer_ProductInfo(szProductCode, szMsifile, szString);
2474 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2475 ok_exception(hr, szProductInfoException);
2477 /* Package name */
2478 memset(szString, 0, sizeof(szString));
2479 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szString);
2480 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2481 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile);
2483 /* Product name */
2484 memset(szString, 0, sizeof(szString));
2485 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PRODUCTNAMEW, szString);
2486 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2487 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST);
2489 /* Installer::Products */
2490 test_Installer_Products(TRUE);
2492 /* Installer::RelatedProducts for our upgrade code */
2493 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2494 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2495 if (hr == S_OK)
2497 /* StringList::Count */
2498 hr = StringList_Count(pStringList, &iCount);
2499 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2500 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2502 /* StringList::Item */
2503 memset(szString, 0, sizeof(szString));
2504 hr = StringList_Item(pStringList, 0, szString);
2505 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2506 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
2508 IDispatch_Release(pStringList);
2511 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_LOCALPACKAGEW, szString);
2512 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2513 DeleteFileW( szString );
2515 /* Check & clean up installed files & registry keys */
2516 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2517 ok(delete_pf("msitest\\cabout\\new", FALSE), "Directory not created\n");
2518 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2519 ok(delete_pf("msitest\\cabout", FALSE), "Directory not created\n");
2520 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2521 ok(delete_pf("msitest\\changed", FALSE), "Directory not created\n");
2522 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2523 ok(delete_pf("msitest\\first", FALSE), "Directory not created\n");
2524 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2525 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2526 ok(delete_pf("msitest", FALSE), "Directory not created\n");
2528 res = RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest", &hkey);
2529 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2531 size = MAX_PATH;
2532 type = REG_SZ;
2533 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2534 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2535 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2537 size = MAX_PATH;
2538 type = REG_SZ;
2539 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2540 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2542 size = sizeof(num);
2543 type = REG_DWORD;
2544 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2545 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2546 ok(num == 314, "Expected 314, got %d\n", num);
2548 size = MAX_PATH;
2549 type = REG_SZ;
2550 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2551 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2552 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2554 RegCloseKey(hkey);
2556 res = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest");
2557 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2559 /* Remove registry keys written by RegisterProduct standard action */
2560 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2561 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{837450fa-a39b-4bc8-b321-08b393f784b3}",
2562 KEY_WOW64_32KEY);
2563 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2565 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2566 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656", access);
2567 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2569 res = find_registry_key(HKEY_LOCAL_MACHINE,
2570 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "af054738b93a8cb43b12803b397f483b", access, &hkey);
2571 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2573 res = delete_registry_key(hkey, "af054738b93a8cb43b12803b397f483b", access);
2574 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2575 RegCloseKey(hkey);
2577 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2578 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\af054738b93a8cb43b12803b397f483b", access);
2579 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2581 /* Remove registry keys written by PublishProduct standard action */
2582 res = RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2583 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2585 res = delete_registry_key(hkey, "Products\\af054738b93a8cb43b12803b397f483b", KEY_ALL_ACCESS);
2586 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2588 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2589 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2591 RegCloseKey(hkey);
2593 /* Delete installation files we created */
2594 delete_test_files();
2597 static void test_Installer(void)
2599 static const WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
2600 static const WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
2601 WCHAR szPath[MAX_PATH];
2602 HRESULT hr;
2603 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL;
2604 int iValue, iCount;
2606 if (!pInstaller) return;
2608 /* Installer::CreateRecord */
2610 /* Test for error */
2611 hr = Installer_CreateRecord(-1, &pRecord);
2612 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2613 ok_exception(hr, szCreateRecordException);
2615 /* Test for success */
2616 hr = Installer_CreateRecord(1, &pRecord);
2617 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2618 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2619 if (pRecord)
2621 /* Record::FieldCountGet */
2622 hr = Record_FieldCountGet(pRecord, &iValue);
2623 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2624 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2626 /* Record::IntegerDataGet */
2627 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2628 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2629 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2631 /* Record::IntegerDataGet, bad index */
2632 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2633 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2634 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2636 /* Record::IntegerDataPut */
2637 hr = Record_IntegerDataPut(pRecord, 1, 100);
2638 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2640 /* Record::IntegerDataPut, bad index */
2641 hr = Record_IntegerDataPut(pRecord, 10, 100);
2642 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2643 ok_exception(hr, szIntegerDataException);
2645 /* Record::IntegerDataGet */
2646 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2647 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2648 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2650 IDispatch_Release(pRecord);
2653 create_package(szPath);
2655 /* Installer::OpenPackage */
2656 hr = Installer_OpenPackage(szPath, 0, &pSession);
2657 if (hr == DISP_E_EXCEPTION)
2659 skip("OpenPackage failed, insufficient rights?\n");
2660 DeleteFileW(szPath);
2661 return;
2663 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2664 if (hr == S_OK)
2666 test_Session(pSession);
2667 IDispatch_Release(pSession);
2670 /* Installer::OpenDatabase */
2671 hr = Installer_OpenDatabase(szPath, (INT_PTR)MSIDBOPEN_TRANSACT, &pDatabase);
2672 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2673 if (hr == S_OK)
2675 test_Database(pDatabase, FALSE);
2676 IDispatch_Release(pDatabase);
2679 /* Installer::RegistryValue */
2680 test_Installer_RegistryValue();
2682 /* Installer::ProductState for our product code, which should not be installed */
2683 hr = Installer_ProductState(szProductCode, &iValue);
2684 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2685 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2687 /* Installer::ProductInfo for our product code, which should not be installed */
2689 /* Package name */
2690 memset(szPath, 0, sizeof(szPath));
2691 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szPath);
2692 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2693 ok_exception(hr, szProductInfoException);
2695 /* NULL attribute and NULL product code */
2696 memset(szPath, 0, sizeof(szPath));
2697 hr = Installer_ProductInfo(NULL, NULL, szPath);
2698 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2699 ok_exception(hr, szProductInfoException);
2701 /* Installer::Products */
2702 test_Installer_Products(FALSE);
2704 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2705 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2706 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2707 if (hr == S_OK)
2709 /* StringList::Count */
2710 hr = StringList_Count(pStringList, &iCount);
2711 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2712 ok(!iCount, "Expected no related products but found %d\n", iCount);
2714 IDispatch_Release(pStringList);
2717 /* Installer::Version */
2718 memset(szPath, 0, sizeof(szPath));
2719 hr = Installer_VersionGet(szPath);
2720 ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr);
2722 /* Installer::InstallProduct and other tests that depend on our product being installed */
2723 test_Installer_InstallProduct();
2726 START_TEST(automation)
2728 DWORD len;
2729 char temp_path[MAX_PATH], prev_path[MAX_PATH];
2730 HRESULT hr;
2731 CLSID clsid;
2732 IUnknown *pUnk;
2734 init_functionpointers();
2736 if (pIsWow64Process)
2737 pIsWow64Process(GetCurrentProcess(), &is_wow64);
2739 GetSystemTimeAsFileTime(&systemtime);
2741 GetCurrentDirectoryA(MAX_PATH, prev_path);
2742 GetTempPathA(MAX_PATH, temp_path);
2743 SetCurrentDirectoryA(temp_path);
2745 lstrcpyA(CURR_DIR, temp_path);
2746 len = lstrlenA(CURR_DIR);
2748 if(len && (CURR_DIR[len - 1] == '\\'))
2749 CURR_DIR[len - 1] = 0;
2751 get_program_files_dir(PROG_FILES_DIR);
2753 hr = OleInitialize(NULL);
2754 ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr);
2755 hr = CLSIDFromProgID(szProgId, &clsid);
2756 ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr);
2757 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2758 ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr);
2760 if (pUnk)
2762 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2763 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2765 test_dispid();
2766 test_dispatch();
2767 test_Installer();
2769 IDispatch_Release(pInstaller);
2770 IUnknown_Release(pUnk);
2773 OleUninitialize();
2775 SetCurrentDirectoryA(prev_path);