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