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