mf/session: Forward more events to the application.
[wine/zf.git] / dlls / msi / tests / automation.c
blob42c41dcd731feb1917ebd7557204f0b194d4a9c7
1 /*
2 * Copyright (C) 2007 Mike McCormack for CodeWeavers
3 * Copyright (C) 2007 Misha Koshelev
5 * A test program for Microsoft Installer OLE automation functionality.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
24 #include <stdio.h>
26 #include <initguid.h>
27 #include <windows.h>
28 #include <msiquery.h>
29 #include <msidefs.h>
30 #include <msi.h>
31 #include <fci.h>
32 #include <oaidl.h>
34 #include "wine/test.h"
36 static BOOL is_wow64;
38 static LONG (WINAPI *pRegDeleteKeyExA)(HKEY, LPCSTR, REGSAM, DWORD);
39 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
41 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
43 static const char *msifile = "winetest-automation.msi";
44 static FILETIME systemtime;
45 static CHAR CURR_DIR[MAX_PATH];
46 static EXCEPINFO excepinfo;
49 * OLE automation data
50 **/
51 static IDispatch *pInstaller;
53 /* msi database data */
55 static const CHAR component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
56 "s72\tS38\ts72\ti2\tS255\tS72\n"
57 "Component\tComponent\n"
58 "Five\t{8CC92E9D-14B2-4CA4-B2AA-B11D02078087}\tNEWDIR\t2\t\tfive.txt\n"
59 "Four\t{FD37B4EA-7209-45C0-8917-535F35A2F080}\tCABOUTDIR\t2\t\tfour.txt\n"
60 "One\t{783B242E-E185-4A56-AF86-C09815EC053C}\tMSITESTDIR\t2\t\tone.txt\n"
61 "Three\t{010B6ADD-B27D-4EDD-9B3D-34C4F7D61684}\tCHANGEDDIR\t2\t\tthree.txt\n"
62 "Two\t{BF03D1A6-20DA-4A65-82F3-6CAC995915CE}\tFIRSTDIR\t2\t\ttwo.txt\n"
63 "dangler\t{6091DF25-EF96-45F1-B8E9-A9B1420C7A3C}\tTARGETDIR\t4\t\tregdata\n"
64 "component\t\tMSITESTDIR\t0\t1\tfile\n";
66 static const CHAR directory_dat[] = "Directory\tDirectory_Parent\tDefaultDir\n"
67 "s72\tS72\tl255\n"
68 "Directory\tDirectory\n"
69 "CABOUTDIR\tMSITESTDIR\tcabout\n"
70 "CHANGEDDIR\tMSITESTDIR\tchanged:second\n"
71 "FIRSTDIR\tMSITESTDIR\tfirst\n"
72 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
73 "NEWDIR\tCABOUTDIR\tnew\n"
74 "ProgramFilesFolder\tTARGETDIR\t.\n"
75 "TARGETDIR\t\tSourceDir\n";
77 static const CHAR feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
78 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
79 "Feature\tFeature\n"
80 "Five\t\tFive\tThe Five Feature\t5\t3\tNEWDIR\t0\n"
81 "Four\t\tFour\tThe Four Feature\t4\t3\tCABOUTDIR\t0\n"
82 "One\t\tOne\tThe One Feature\t1\t3\tMSITESTDIR\t0\n"
83 "Three\tOne\tThree\tThe Three Feature\t3\t3\tCHANGEDDIR\t0\n"
84 "Two\tOne\tTwo\tThe Two Feature\t2\t3\tFIRSTDIR\t0\n"
85 "feature\t\t\t\t2\t1\tTARGETDIR\t0\n";
87 static const CHAR feature_comp_dat[] = "Feature_\tComponent_\n"
88 "s38\ts72\n"
89 "FeatureComponents\tFeature_\tComponent_\n"
90 "Five\tFive\n"
91 "Four\tFour\n"
92 "One\tOne\n"
93 "Three\tThree\n"
94 "Two\tTwo\n"
95 "feature\tcomponent\n";
97 static const CHAR file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
98 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
99 "File\tFile\n"
100 "five.txt\tFive\tfive.txt\t1000\t\t\t0\t5\n"
101 "four.txt\tFour\tfour.txt\t1000\t\t\t0\t4\n"
102 "one.txt\tOne\tone.txt\t1000\t\t\t0\t1\n"
103 "three.txt\tThree\tthree.txt\t1000\t\t\t0\t3\n"
104 "two.txt\tTwo\ttwo.txt\t1000\t\t\t0\t2\n"
105 "file\tcomponent\tfilename\t100\t\t\t8192\t1\n";
107 static const CHAR install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
108 "s72\tS255\tI2\n"
109 "InstallExecuteSequence\tAction\n"
110 "AllocateRegistrySpace\tNOT Installed\t1550\n"
111 "CostFinalize\t\t1000\n"
112 "CostInitialize\t\t800\n"
113 "FileCost\t\t900\n"
114 "InstallFiles\t\t4000\n"
115 "RegisterProduct\t\t6100\n"
116 "PublishProduct\t\t6400\n"
117 "InstallFinalize\t\t6600\n"
118 "InstallInitialize\t\t1500\n"
119 "InstallValidate\t\t1400\n"
120 "LaunchConditions\t\t100\n"
121 "WriteRegistryValues\tSourceDir And SOURCEDIR\t5000\n";
123 static const CHAR media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
124 "i2\ti4\tL64\tS255\tS32\tS72\n"
125 "Media\tDiskId\n"
126 "1\t5\t\t\tDISK1\t\n";
128 static const CHAR property_dat[] = "Property\tValue\n"
129 "s72\tl0\n"
130 "Property\tProperty\n"
131 "DefaultUIFont\tDlgFont8\n"
132 "HASUIRUN\t0\n"
133 "INSTALLLEVEL\t3\n"
134 "InstallMode\tTypical\n"
135 "Manufacturer\tWine\n"
136 "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n"
137 "ProductCode\t{837450fa-a39b-4bc8-b321-08b393f784b3}\n"
138 "ProductID\tnone\n"
139 "ProductLanguage\t1033\n"
140 "ProductName\tMSITEST\n"
141 "ProductVersion\t1.1.1\n"
142 "PROMPTROLLBACKCOST\tP\n"
143 "Setup\tSetup\n"
144 "UpgradeCode\t{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}\n"
145 "MSIFASTINSTALL\t1\n";
147 static const CHAR registry_dat[] = "Registry\tRoot\tKey\tName\tValue\tComponent_\n"
148 "s72\ti2\tl255\tL255\tL0\ts72\n"
149 "Registry\tRegistry\n"
150 "Apples\t1\tSOFTWARE\\Wine\\msitest\tName\timaname\tOne\n"
151 "Oranges\t1\tSOFTWARE\\Wine\\msitest\tnumber\t#314\tTwo\n"
152 "regdata\t1\tSOFTWARE\\Wine\\msitest\tblah\tbad\tdangler\n"
153 "OrderTest\t1\tSOFTWARE\\Wine\\msitest\tOrderTestName\tOrderTestValue\tcomponent\n";
155 typedef struct _msi_table
157 const CHAR *filename;
158 const CHAR *data;
159 int size;
160 } msi_table;
162 #define ADD_TABLE(x) {#x".idt", x##_dat, sizeof(x##_dat)}
164 static const msi_table tables[] =
166 ADD_TABLE(component),
167 ADD_TABLE(directory),
168 ADD_TABLE(feature),
169 ADD_TABLE(feature_comp),
170 ADD_TABLE(file),
171 ADD_TABLE(install_exec_seq),
172 ADD_TABLE(media),
173 ADD_TABLE(property),
174 ADD_TABLE(registry)
177 typedef struct _msi_summary_info
179 UINT property;
180 UINT datatype;
181 INT iValue;
182 FILETIME *pftValue;
183 const CHAR *szValue;
184 } msi_summary_info;
186 #define ADD_INFO_I2(property, iValue) {property, VT_I2, iValue, NULL, NULL}
187 #define ADD_INFO_I4(property, iValue) {property, VT_I4, iValue, NULL, NULL}
188 #define ADD_INFO_LPSTR(property, szValue) {property, VT_LPSTR, 0, NULL, szValue}
189 #define ADD_INFO_FILETIME(property, pftValue) {property, VT_FILETIME, 0, pftValue, NULL}
191 static const msi_summary_info summary_info[] =
193 ADD_INFO_LPSTR(PID_TEMPLATE, ";1033"),
194 ADD_INFO_LPSTR(PID_REVNUMBER, "{004757CA-5092-49C2-AD20-28E1CE0DF5F2}"),
195 ADD_INFO_I4(PID_PAGECOUNT, 100),
196 ADD_INFO_I4(PID_WORDCOUNT, 0),
197 ADD_INFO_FILETIME(PID_CREATE_DTM, &systemtime),
198 ADD_INFO_FILETIME(PID_LASTPRINTED, &systemtime)
201 static void init_functionpointers(void)
203 HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll");
204 HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
206 #define GET_PROC(dll, func) \
207 p ## func = (void *)GetProcAddress(dll, #func); \
208 if(!p ## func) \
209 trace("GetProcAddress(%s) failed\n", #func);
211 GET_PROC(hadvapi32, RegDeleteKeyExA)
212 GET_PROC(hkernel32, IsWow64Process)
214 #undef GET_PROC
217 static BOOL is_process_limited(void)
219 SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
220 PSID Group = NULL;
221 BOOL IsInGroup;
222 HANDLE token;
224 if (!AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
225 DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &Group) ||
226 !CheckTokenMembership(NULL, Group, &IsInGroup))
228 trace("Could not check if the current user is an administrator\n");
229 FreeSid(Group);
230 return FALSE;
232 FreeSid(Group);
234 if (!IsInGroup)
236 /* Only administrators have enough privileges for these tests */
237 return TRUE;
240 if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
242 BOOL ret;
243 TOKEN_ELEVATION_TYPE type = TokenElevationTypeDefault;
244 DWORD size;
246 ret = GetTokenInformation(token, TokenElevationType, &type, sizeof(type), &size);
247 CloseHandle(token);
248 return (ret && type == TokenElevationTypeLimited);
250 return FALSE;
253 static LONG delete_key_portable( HKEY key, LPCSTR subkey, REGSAM access )
255 if (pRegDeleteKeyExA)
256 return pRegDeleteKeyExA( key, subkey, access, 0 );
257 return RegDeleteKeyA( key, subkey );
261 * Database Helpers
264 static void write_file(const CHAR *filename, const char *data, int data_size)
266 DWORD size;
268 HANDLE hf = CreateFileA(filename, GENERIC_WRITE, 0, NULL,
269 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
270 WriteFile(hf, data, data_size, &size, NULL);
271 CloseHandle(hf);
274 static void write_msi_summary_info(MSIHANDLE db, const msi_summary_info *info, int num_info)
276 MSIHANDLE summary;
277 UINT r;
278 int j;
280 r = MsiGetSummaryInformationA(db, NULL, num_info, &summary);
281 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
283 /* import summary information into the stream */
284 for (j = 0; j < num_info; j++)
286 const msi_summary_info *entry = &info[j];
288 r = MsiSummaryInfoSetPropertyA(summary, entry->property, entry->datatype,
289 entry->iValue, entry->pftValue, entry->szValue);
290 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
293 /* write the summary changes back to the stream */
294 r = MsiSummaryInfoPersist(summary);
295 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
297 MsiCloseHandle(summary);
300 static void create_database(const CHAR *name, const msi_table *tables, int num_tables,
301 const msi_summary_info *info, int num_info)
303 MSIHANDLE db;
304 UINT r;
305 WCHAR *nameW;
306 int j, len;
308 len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
309 if (!(nameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return;
310 MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, len );
312 r = MsiOpenDatabaseW(nameW, MSIDBOPEN_CREATE, &db);
313 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
315 /* import the tables into the database */
316 for (j = 0; j < num_tables; j++)
318 const msi_table *table = &tables[j];
320 write_file(table->filename, table->data, (table->size - 1) * sizeof(char));
322 r = MsiDatabaseImportA(db, CURR_DIR, table->filename);
323 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
325 DeleteFileA(table->filename);
328 write_msi_summary_info(db, info, num_info);
330 r = MsiDatabaseCommit(db);
331 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
333 MsiCloseHandle(db);
334 HeapFree( GetProcessHeap(), 0, nameW );
337 static BOOL create_package(LPWSTR path)
339 DWORD len;
341 /* Prepare package */
342 create_database(msifile, tables, ARRAY_SIZE(tables), summary_info, ARRAY_SIZE(summary_info));
344 len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
345 CURR_DIR, -1, path, MAX_PATH);
346 ok(len, "MultiByteToWideChar returned error %d\n", GetLastError());
347 if (!len)
348 return FALSE;
350 lstrcatW(path, L"\\winetest-automation.msi");
351 return TRUE;
355 * Installation helpers
358 static char PROG_FILES_DIR[MAX_PATH];
360 static BOOL get_program_files_dir(LPSTR buf)
362 HKEY hkey;
363 DWORD type = REG_EXPAND_SZ, size;
365 if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &hkey))
366 return FALSE;
368 size = MAX_PATH;
369 if (RegQueryValueExA(hkey, "ProgramFilesDir (x86)", 0, &type, (LPBYTE)buf, &size) &&
370 RegQueryValueExA(hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size))
371 return FALSE;
373 RegCloseKey(hkey);
374 return TRUE;
377 static void create_file(const CHAR *name, DWORD size)
379 HANDLE file;
380 DWORD written, left;
382 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
383 ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
384 WriteFile(file, name, strlen(name), &written, NULL);
385 WriteFile(file, "\n", strlen("\n"), &written, NULL);
387 left = size - lstrlenA(name) - 1;
389 SetFilePointer(file, left, NULL, FILE_CURRENT);
390 SetEndOfFile(file);
392 CloseHandle(file);
395 static void create_test_files(void)
397 CreateDirectoryA("msitest", NULL);
398 create_file("msitest\\one.txt", 100);
399 CreateDirectoryA("msitest\\first", NULL);
400 create_file("msitest\\first\\two.txt", 100);
401 CreateDirectoryA("msitest\\second", NULL);
402 create_file("msitest\\second\\three.txt", 100);
403 CreateDirectoryA("msitest\\cabout",NULL);
404 create_file("msitest\\cabout\\four.txt", 100);
405 CreateDirectoryA("msitest\\cabout\\new",NULL);
406 create_file("msitest\\cabout\\new\\five.txt", 100);
407 create_file("msitest\\filename", 100);
410 static BOOL delete_pf(const CHAR *rel_path, BOOL is_file)
412 CHAR path[MAX_PATH];
414 lstrcpyA(path, PROG_FILES_DIR);
415 lstrcatA(path, "\\");
416 lstrcatA(path, rel_path);
418 if (is_file)
419 return DeleteFileA(path);
420 else
421 return RemoveDirectoryA(path);
424 static void delete_test_files(void)
426 DeleteFileA(msifile);
427 DeleteFileA("msitest\\cabout\\new\\five.txt");
428 DeleteFileA("msitest\\cabout\\four.txt");
429 DeleteFileA("msitest\\second\\three.txt");
430 DeleteFileA("msitest\\first\\two.txt");
431 DeleteFileA("msitest\\one.txt");
432 DeleteFileA("msitest\\filename");
433 RemoveDirectoryA("msitest\\cabout\\new");
434 RemoveDirectoryA("msitest\\cabout");
435 RemoveDirectoryA("msitest\\second");
436 RemoveDirectoryA("msitest\\first");
437 RemoveDirectoryA("msitest");
441 * Automation helpers and tests
444 /* ok-like statement which takes two unicode strings or one unicode and one ANSI string as arguments */
445 static CHAR string1[MAX_PATH], string2[MAX_PATH];
447 #define ok_w2(format, szString1, szString2) \
449 do { \
450 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
451 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
452 if (lstrcmpA(string1, string2) != 0) \
453 ok(0, format, string1, string2); \
454 } while(0);
456 #define ok_w2n(format, szString1, szString2, len) \
458 if (memcmp(szString1, szString2, len * sizeof(WCHAR)) != 0) \
460 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
461 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
462 ok(0, format, string1, string2); \
465 #define ok_aw(format, aString, wString) \
467 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
468 if (lstrcmpA(string1, aString) != 0) \
469 ok(0, format, string1, aString); \
471 #define ok_awplus(format, extra, aString, wString) \
473 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
474 if (lstrcmpA(string1, aString) != 0) \
475 ok(0, format, extra, string1, aString); \
477 /* exception checker */
478 #define ok_exception(hr, szDescription) \
479 if (hr == DISP_E_EXCEPTION) \
481 /* Compare wtype, source, and destination */ \
482 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
484 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
485 if (excepinfo.bstrSource) \
486 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, L"Msi API Error"); \
488 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
489 if (excepinfo.bstrDescription) \
490 ok_w2("Exception description was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrDescription, szDescription); \
492 SysFreeString(excepinfo.bstrSource); \
493 SysFreeString(excepinfo.bstrDescription); \
494 SysFreeString(excepinfo.bstrHelpFile); \
497 static DISPID get_dispid( IDispatch *disp, const char *name )
499 LPOLESTR str;
500 UINT len;
501 DISPID id = -1;
502 HRESULT r;
504 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
505 str = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
506 if (str)
508 MultiByteToWideChar(CP_ACP, 0, name, -1, str, len );
509 r = IDispatch_GetIDsOfNames( disp, &IID_NULL, &str, 1, 0, &id );
510 HeapFree(GetProcessHeap(), 0, str);
511 if (r != S_OK)
512 return -1;
515 return id;
518 typedef struct {
519 DISPID did;
520 const char *name;
521 BOOL todo;
522 } get_did_t;
524 static const get_did_t get_did_data[] = {
525 { 1, "CreateRecord" },
526 { 2, "OpenPackage" },
527 { 3, "OpenProduct" },
528 { 4, "OpenDatabase" },
529 { 5, "SummaryInformation" },
530 { 6, "UILevel" },
531 { 7, "EnableLog" },
532 { 8, "InstallProduct" },
533 { 9, "Version" },
534 { 10, "LastErrorRecord" },
535 { 11, "RegistryValue" },
536 { 12, "Environment" },
537 { 13, "FileAttributes" },
538 { 15, "FileSize" },
539 { 16, "FileVersion" },
540 { 17, "ProductState" },
541 { 18, "ProductInfo" },
542 { 19, "ConfigureProduct", TRUE },
543 { 20, "ReinstallProduct", TRUE },
544 { 21, "CollectUserInfo", TRUE },
545 { 22, "ApplyPatch", TRUE },
546 { 23, "FeatureParent", TRUE },
547 { 24, "FeatureState", TRUE },
548 { 25, "UseFeature", TRUE },
549 { 26, "FeatureUsageCount", TRUE },
550 { 27, "FeatureUsageDate", TRUE },
551 { 28, "ConfigureFeature", TRUE },
552 { 29, "ReinstallFeature", TRUE },
553 { 30, "ProvideComponent", TRUE },
554 { 31, "ComponentPath", TRUE },
555 { 32, "ProvideQualifiedComponent", TRUE },
556 { 33, "QualifierDescription", TRUE },
557 { 34, "ComponentQualifiers", TRUE },
558 { 35, "Products" },
559 { 36, "Features", TRUE },
560 { 37, "Components", TRUE },
561 { 38, "ComponentClients", TRUE },
562 { 39, "Patches", TRUE },
563 { 40, "RelatedProducts" },
564 { 41, "PatchInfo", TRUE },
565 { 42, "PatchTransforms", TRUE },
566 { 43, "AddSource", TRUE },
567 { 44, "ClearSourceList", TRUE },
568 { 45, "ForceSourceListResolution", TRUE },
569 { 46, "ShortcutTarget", TRUE },
570 { 47, "FileHash", TRUE },
571 { 48, "FileSignatureInfo", TRUE },
572 { 0 }
575 static void test_dispid(void)
577 const get_did_t *ptr = get_did_data;
578 DISPID dispid;
580 while (ptr->name)
582 dispid = get_dispid(pInstaller, ptr->name);
583 todo_wine_if (ptr->todo)
584 ok(dispid == ptr->did, "%s: expected %d, got %d\n", ptr->name, ptr->did, dispid);
585 ptr++;
588 dispid = get_dispid(pInstaller, "RemovePatches");
589 ok(dispid == 49 || dispid == -1, "Expected 49 or -1, got %d\n", dispid);
590 dispid = get_dispid(pInstaller, "ApplyMultiplePatches");
591 ok(dispid == 51 || dispid == -1, "Expected 51 or -1, got %d\n", dispid);
592 dispid = get_dispid(pInstaller, "ProductsEx");
593 ok(dispid == 52 || dispid == -1, "Expected 52 or -1, got %d\n", dispid);
594 dispid = get_dispid(pInstaller, "PatchesEx");
595 ok(dispid == 55 || dispid == -1, "Expected 55 or -1, got %d\n", dispid);
596 dispid = get_dispid(pInstaller, "ExtractPatchXMLData");
597 ok(dispid == 57 || dispid == -1, "Expected 57 or -1, got %d\n", dispid);
598 dispid = get_dispid( pInstaller, "ProductElevated" );
599 ok(dispid == 59 || dispid == -1, "Expected 59 or -1, got %d\n", dispid);
600 dispid = get_dispid( pInstaller, "ProvideAssembly" );
601 ok(dispid == 60 || dispid == -1, "Expected 60 or -1, got %d\n", dispid);
602 dispid = get_dispid( pInstaller, "ProductInfoFromScript" );
603 ok(dispid == 61 || dispid == -1, "Expected 61 or -1, got %d\n", dispid);
604 dispid = get_dispid( pInstaller, "AdvertiseProduct" );
605 ok(dispid == 62 || dispid == -1, "Expected 62 or -1, got %d\n", dispid);
606 dispid = get_dispid( pInstaller, "CreateAdvertiseScript" );
607 ok(dispid == 63 || dispid == -1, "Expected 63 or -1, got %d\n", dispid);
608 dispid = get_dispid( pInstaller, "PatchFiles" );
609 ok(dispid == 65 || dispid == -1, "Expected 65 or -1, got %d\n", dispid);
612 /* Test basic IDispatch functions */
613 static void test_dispatch(void)
615 HRESULT hr;
616 DISPID dispid;
617 OLECHAR *name;
618 VARIANT varresult;
619 VARIANTARG vararg[3];
620 WCHAR path[MAX_PATH];
621 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
623 /* Test getting ID of a function name that does not exist */
624 name = (WCHAR *)L"winetest-automation.msi";
625 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
626 ok(hr == DISP_E_UNKNOWNNAME, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
628 /* Test invoking this function */
629 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
630 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
632 /* Test getting ID of a function name that does exist */
633 name = (WCHAR *)L"OpenPackage";
634 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
635 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
637 /* Test invoking this function (without parameters passed) */
638 if (0) /* All of these crash MSI on Windows XP */
640 IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
641 IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL);
642 VariantInit(&varresult);
643 IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, &varresult, &excepinfo, NULL);
646 /* Try with NULL params */
647 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
648 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
650 /* Try one empty parameter */
651 dispparams.rgvarg = vararg;
652 dispparams.cArgs = 1;
653 VariantInit(&vararg[0]);
654 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
655 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
657 /* Try two empty parameters */
658 dispparams.cArgs = 2;
659 VariantInit(&vararg[0]);
660 VariantInit(&vararg[1]);
661 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
662 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
664 /* Try one parameter, the required BSTR. Second parameter is optional.
665 * NOTE: The specified package does not exist, which is why the call fails.
667 dispparams.cArgs = 1;
668 VariantInit(&vararg[0]);
669 V_VT(&vararg[0]) = VT_BSTR;
670 V_BSTR(&vararg[0]) = SysAllocString(L"winetest-automation.msi");
671 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
672 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
673 ok_exception(hr, L"OpenPackage,PackagePath,Options");
674 VariantClear(&vararg[0]);
676 /* Provide the required BSTR and an empty second parameter.
677 * NOTE: The specified package does not exist, which is why the call fails.
679 dispparams.cArgs = 2;
680 VariantInit(&vararg[1]);
681 V_VT(&vararg[1]) = VT_BSTR;
682 V_BSTR(&vararg[1]) = SysAllocString(L"winetest-automation.msi");
683 VariantInit(&vararg[0]);
684 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
685 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
686 ok_exception(hr, L"OpenPackage,PackagePath,Options");
687 VariantClear(&vararg[1]);
689 /* Provide the required BSTR and two empty parameters.
690 * NOTE: The specified package does not exist, which is why the call fails.
692 dispparams.cArgs = 3;
693 VariantInit(&vararg[2]);
694 V_VT(&vararg[2]) = VT_BSTR;
695 V_BSTR(&vararg[2]) = SysAllocString(L"winetest-automation.msi");
696 VariantInit(&vararg[1]);
697 VariantInit(&vararg[0]);
698 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
699 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
700 ok_exception(hr, L"OpenPackage,PackagePath,Options");
701 VariantClear(&vararg[2]);
703 /* Provide the required BSTR and a second parameter with the wrong type. */
704 dispparams.cArgs = 2;
705 VariantInit(&vararg[1]);
706 V_VT(&vararg[1]) = VT_BSTR;
707 V_BSTR(&vararg[1]) = SysAllocString(L"winetest-automation.msi");
708 VariantInit(&vararg[0]);
709 V_VT(&vararg[0]) = VT_BSTR;
710 V_BSTR(&vararg[0]) = SysAllocString(L"winetest-automation.msi");
711 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
712 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
713 VariantClear(&vararg[0]);
714 VariantClear(&vararg[1]);
716 /* Create a proper installer package. */
717 create_package(path);
719 /* Try one parameter, the required BSTR. Second parameter is optional.
720 * Proper installer package exists. Path to the package is relative.
722 dispparams.cArgs = 1;
723 VariantInit(&vararg[0]);
724 V_VT(&vararg[0]) = VT_BSTR;
725 V_BSTR(&vararg[0]) = SysAllocString(L"winetest-automation.msi");
726 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
727 todo_wine ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
728 ok_exception(hr, L"OpenPackage,PackagePath,Options");
729 VariantClear(&vararg[0]);
730 if (hr != DISP_E_EXCEPTION)
731 VariantClear(&varresult);
733 /* Try one parameter, the required BSTR. Second parameter is optional.
734 * Proper installer package exists. Path to the package is absolute.
736 dispparams.cArgs = 1;
737 VariantInit(&vararg[0]);
738 V_VT(&vararg[0]) = VT_BSTR;
739 V_BSTR(&vararg[0]) = SysAllocString(path);
740 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
741 if (hr == DISP_E_EXCEPTION)
743 skip("OpenPackage failed, insufficient rights?\n");
744 DeleteFileW(path);
745 return;
747 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
748 VariantClear(&vararg[0]);
749 VariantClear(&varresult);
751 /* Provide the required BSTR and an empty second parameter. Proper
752 * installation package exists.
754 dispparams.cArgs = 2;
755 VariantInit(&vararg[1]);
756 V_VT(&vararg[1]) = VT_BSTR;
757 V_BSTR(&vararg[1]) = SysAllocString(path);
758 VariantInit(&vararg[0]);
759 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
760 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
761 VariantClear(&vararg[1]);
762 VariantClear(&varresult);
764 /* Provide the required BSTR and two empty parameters. Proper
765 * installation package exists.
767 dispparams.cArgs = 3;
768 VariantInit(&vararg[2]);
769 V_VT(&vararg[2]) = VT_BSTR;
770 V_BSTR(&vararg[2]) = SysAllocString(path);
771 VariantInit(&vararg[1]);
772 VariantInit(&vararg[0]);
773 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
774 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
775 VariantClear(&vararg[2]);
776 VariantClear(&varresult);
778 /* Provide the required BSTR and a second parameter with the wrong type. */
779 dispparams.cArgs = 2;
780 VariantInit(&vararg[1]);
781 V_VT(&vararg[1]) = VT_BSTR;
782 V_BSTR(&vararg[1]) = SysAllocString(path);
783 VariantInit(&vararg[0]);
784 V_VT(&vararg[0]) = VT_BSTR;
785 V_BSTR(&vararg[0]) = SysAllocString(path);
786 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
787 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
788 VariantClear(&vararg[0]);
789 VariantClear(&vararg[1]);
791 /* Provide the required BSTR and a second parameter that can be coerced to
792 * VT_I4.
794 dispparams.cArgs = 2;
795 VariantInit(&vararg[1]);
796 V_VT(&vararg[1]) = VT_BSTR;
797 V_BSTR(&vararg[1]) = SysAllocString(path);
798 VariantInit(&vararg[0]);
799 V_VT(&vararg[0]) = VT_I2;
800 V_BSTR(&vararg[0]) = 0;
801 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
802 ok(hr == S_OK, "IDispatch::Invoke returned 0x%08x\n", hr);
803 VariantClear(&vararg[1]);
804 VariantClear(&varresult);
806 DeleteFileW(path);
808 /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
809 VariantInit(&vararg[0]);
810 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
811 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
813 VariantInit(&vararg[0]);
814 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
815 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
817 /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
818 name = (WCHAR *)L"ProductState";
819 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
820 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
822 dispparams.rgvarg = NULL;
823 dispparams.cArgs = 0;
824 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
825 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
827 dispparams.rgvarg = NULL;
828 dispparams.cArgs = 0;
829 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
830 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
833 /* invocation helper function */
834 static int _invoke_todo_vtResult = 0;
836 static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult)
838 OLECHAR *name = NULL;
839 DISPID dispid;
840 HRESULT hr;
841 UINT i;
842 UINT len;
844 memset(pVarResult, 0, sizeof(VARIANT));
845 VariantInit(pVarResult);
847 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 );
848 name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
849 if (!name) return E_FAIL;
850 MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len );
851 hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
852 HeapFree(GetProcessHeap(), 0, name);
853 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
854 if (hr != S_OK) return hr;
856 memset(&excepinfo, 0, sizeof(excepinfo));
857 hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL);
859 if (hr == S_OK)
861 todo_wine_if (_invoke_todo_vtResult)
862 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
863 if (vtResult != VT_EMPTY)
865 hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult);
866 ok(hr == S_OK, "VariantChangeTypeEx returned 0x%08x\n", hr);
870 for (i=0; i<pDispParams->cArgs; i++)
871 VariantClear(&pDispParams->rgvarg[i]);
873 return hr;
876 /* Object_Property helper functions */
878 static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord)
880 VARIANT varresult;
881 VARIANTARG vararg[1];
882 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
883 HRESULT hr;
885 VariantInit(&vararg[0]);
886 V_VT(&vararg[0]) = VT_I4;
887 V_I4(&vararg[0]) = count;
889 hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
890 *pRecord = V_DISPATCH(&varresult);
891 return hr;
894 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
896 VARIANTARG vararg[3];
897 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
899 VariantInit(&vararg[2]);
900 V_VT(&vararg[2]) = VT_I4;
901 V_I4(&vararg[2]) = (INT_PTR)hkey;
902 VariantInit(&vararg[1]);
903 V_VT(&vararg[1]) = VT_BSTR;
904 V_BSTR(&vararg[1]) = SysAllocString(szKey);
905 VariantInit(&vararg[0]);
906 VariantCopy(&vararg[0], &vValue);
907 VariantClear(&vValue);
909 return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect);
912 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
914 VARIANT varresult;
915 VARIANTARG vararg;
916 HRESULT hr;
918 VariantInit(&vararg);
919 V_VT(&vararg) = VT_EMPTY;
920 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL);
921 *pBool = V_BOOL(&varresult);
922 VariantClear(&varresult);
923 return hr;
926 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
928 VARIANT varresult;
929 VARIANTARG vararg;
930 HRESULT hr;
932 VariantInit(&vararg);
933 V_VT(&vararg) = VT_BSTR;
934 V_BSTR(&vararg) = SysAllocString(szValue);
936 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR);
937 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
938 VariantClear(&varresult);
939 return hr;
942 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
944 VARIANT varresult;
945 VARIANTARG vararg;
946 HRESULT hr;
948 VariantInit(&vararg);
949 V_VT(&vararg) = VT_I4;
950 V_I4(&vararg) = iValue;
952 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult);
953 if (SUCCEEDED(hr) && vtResult == VT_BSTR) lstrcpyW(szString, V_BSTR(&varresult));
954 VariantClear(&varresult);
955 return hr;
958 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
960 VARIANT varresult;
961 VARIANTARG vararg[2];
962 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
963 HRESULT hr;
965 VariantInit(&vararg[1]);
966 V_VT(&vararg[1]) = VT_BSTR;
967 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
968 VariantInit(&vararg[0]);
969 V_VT(&vararg[0]) = VT_I4;
970 V_I4(&vararg[0]) = options;
972 hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
973 *pSession = V_DISPATCH(&varresult);
974 return hr;
977 static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase)
979 VARIANT varresult;
980 VARIANTARG vararg[2];
981 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
982 HRESULT hr;
984 VariantInit(&vararg[1]);
985 V_VT(&vararg[1]) = VT_BSTR;
986 V_BSTR(&vararg[1]) = SysAllocString(szDatabasePath);
987 VariantInit(&vararg[0]);
988 V_VT(&vararg[0]) = VT_I4;
989 V_I4(&vararg[0]) = openmode;
991 hr = invoke(pInstaller, "OpenDatabase", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
992 *pDatabase = V_DISPATCH(&varresult);
993 return hr;
996 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
998 VARIANT varresult;
999 VARIANTARG vararg[2];
1000 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1002 VariantInit(&vararg[1]);
1003 V_VT(&vararg[1]) = VT_BSTR;
1004 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
1005 VariantInit(&vararg[0]);
1006 V_VT(&vararg[0]) = VT_BSTR;
1007 V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues);
1009 return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1012 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
1014 VARIANT varresult;
1015 VARIANTARG vararg[1];
1016 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1017 HRESULT hr;
1019 VariantInit(&vararg[0]);
1020 V_VT(&vararg[0]) = VT_BSTR;
1021 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
1023 hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1024 *pInstallState = V_I4(&varresult);
1025 VariantClear(&varresult);
1026 return hr;
1029 static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szString)
1031 VARIANT varresult;
1032 VARIANTARG vararg[2];
1033 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1034 HRESULT hr;
1036 VariantInit(&vararg[1]);
1037 V_VT(&vararg[1]) = VT_BSTR;
1038 V_BSTR(&vararg[1]) = SysAllocString(szProduct);
1039 VariantInit(&vararg[0]);
1040 V_VT(&vararg[0]) = VT_BSTR;
1041 V_BSTR(&vararg[0]) = SysAllocString(szAttribute);
1043 hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1044 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1045 VariantClear(&varresult);
1046 return hr;
1049 static HRESULT Installer_Products(IDispatch **pStringList)
1051 VARIANT varresult;
1052 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1053 HRESULT hr;
1055 hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1056 *pStringList = V_DISPATCH(&varresult);
1057 return hr;
1060 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
1062 VARIANT varresult;
1063 VARIANTARG vararg[1];
1064 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1065 HRESULT hr;
1067 VariantInit(&vararg[0]);
1068 V_VT(&vararg[0]) = VT_BSTR;
1069 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
1071 hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1072 *pStringList = V_DISPATCH(&varresult);
1073 return hr;
1076 static HRESULT Installer_VersionGet(LPWSTR szVersion)
1078 VARIANT varresult;
1079 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1080 HRESULT hr;
1082 hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1083 if (V_BSTR(&varresult)) lstrcpyW(szVersion, V_BSTR(&varresult));
1084 VariantClear(&varresult);
1085 return hr;
1088 static HRESULT Installer_UILevelPut(int level)
1090 VARIANT varresult;
1091 VARIANTARG vararg;
1092 DISPID dispid = DISPID_PROPERTYPUT;
1093 DISPPARAMS dispparams = {&vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1095 VariantInit(&vararg);
1096 V_VT(&vararg) = VT_I4;
1097 V_I4(&vararg) = level;
1099 return invoke(pInstaller, "UILevel", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1102 static HRESULT Installer_SummaryInformation(BSTR PackagePath, int UpdateCount, IDispatch **pSumInfo)
1104 VARIANT varresult;
1105 VARIANTARG vararg[2];
1106 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1107 HRESULT hr;
1109 VariantInit(&vararg[1]);
1110 V_VT(&vararg[1]) = VT_BSTR;
1111 V_BSTR(&vararg[1]) = SysAllocString(PackagePath);
1112 VariantInit(&vararg[0]);
1113 V_VT(&vararg[0]) = VT_I4;
1114 V_I4(&vararg[0]) = UpdateCount;
1116 hr = invoke(pInstaller, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1117 *pSumInfo = V_DISPATCH(&varresult);
1118 return hr;
1121 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
1123 VARIANT varresult;
1124 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1125 HRESULT hr;
1127 hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1128 *pInst = V_DISPATCH(&varresult);
1129 return hr;
1132 static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn)
1134 VARIANT varresult;
1135 VARIANTARG vararg[1];
1136 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1137 HRESULT hr;
1139 VariantInit(&vararg[0]);
1140 V_VT(&vararg[0]) = VT_BSTR;
1141 V_BSTR(&vararg[0]) = SysAllocString(szName);
1143 hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1144 if (V_BSTR(&varresult)) lstrcpyW(szReturn, V_BSTR(&varresult));
1145 VariantClear(&varresult);
1146 return hr;
1149 static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue)
1151 VARIANT varresult;
1152 VARIANTARG vararg[2];
1153 DISPID dispid = DISPID_PROPERTYPUT;
1154 DISPPARAMS dispparams = {vararg, &dispid, ARRAY_SIZE(vararg), 1};
1156 VariantInit(&vararg[1]);
1157 V_VT(&vararg[1]) = VT_BSTR;
1158 V_BSTR(&vararg[1]) = SysAllocString(szName);
1159 VariantInit(&vararg[0]);
1160 V_VT(&vararg[0]) = VT_BSTR;
1161 V_BSTR(&vararg[0]) = SysAllocString(szValue);
1163 return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1166 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
1168 VARIANT varresult;
1169 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1170 HRESULT hr;
1172 hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1173 *pLangId = V_I4(&varresult);
1174 VariantClear(&varresult);
1175 return hr;
1178 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, VARIANT_BOOL *mode)
1180 VARIANT varresult;
1181 VARIANTARG vararg[1];
1182 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1183 HRESULT hr;
1185 VariantInit(&vararg[0]);
1186 V_VT(&vararg[0]) = VT_I4;
1187 V_I4(&vararg[0]) = iFlag;
1189 hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL);
1190 *mode = V_BOOL(&varresult);
1191 VariantClear(&varresult);
1192 return hr;
1195 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, VARIANT_BOOL mode)
1197 VARIANT varresult;
1198 VARIANTARG vararg[2];
1199 DISPID dispid = DISPID_PROPERTYPUT;
1200 DISPPARAMS dispparams = {vararg, &dispid, ARRAY_SIZE(vararg), 1};
1202 VariantInit(&vararg[1]);
1203 V_VT(&vararg[1]) = VT_I4;
1204 V_I4(&vararg[1]) = iFlag;
1205 VariantInit(&vararg[0]);
1206 V_VT(&vararg[0]) = VT_BOOL;
1207 V_BOOL(&vararg[0]) = mode;
1209 return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1212 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
1214 VARIANT varresult;
1215 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1216 HRESULT hr;
1218 hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1219 *pDatabase = V_DISPATCH(&varresult);
1220 return hr;
1223 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn)
1225 VARIANT varresult;
1226 VARIANTARG vararg[1];
1227 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1228 HRESULT hr;
1230 VariantInit(&vararg[0]);
1231 V_VT(&vararg[0]) = VT_BSTR;
1232 V_BSTR(&vararg[0]) = SysAllocString(szAction);
1234 hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1235 *iReturn = V_I4(&varresult);
1236 VariantClear(&varresult);
1237 return hr;
1240 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
1242 VARIANT varresult;
1243 VARIANTARG vararg[1];
1244 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1245 HRESULT hr;
1247 VariantInit(&vararg[0]);
1248 V_VT(&vararg[0]) = VT_BSTR;
1249 V_BSTR(&vararg[0]) = SysAllocString(szCondition);
1251 hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1252 *iReturn = V_I4(&varresult);
1253 VariantClear(&varresult);
1254 return hr;
1257 static HRESULT Session_Message(IDispatch *pSession, LONG kind, IDispatch *record, int *ret)
1259 VARIANT varresult;
1260 VARIANTARG vararg[2];
1261 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1262 HRESULT hr;
1264 VariantInit(&varresult);
1265 V_VT(vararg) = VT_DISPATCH;
1266 V_DISPATCH(vararg) = record;
1267 V_VT(vararg+1) = VT_I4;
1268 V_I4(vararg+1) = kind;
1270 hr = invoke(pSession, "Message", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1272 ok(V_VT(&varresult) == VT_I4, "V_VT(varresult) = %d\n", V_VT(&varresult));
1273 *ret = V_I4(&varresult);
1275 return hr;
1278 static HRESULT Session_SetInstallLevel(IDispatch *pSession, LONG iInstallLevel)
1280 VARIANT varresult;
1281 VARIANTARG vararg[1];
1282 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1284 VariantInit(&vararg[0]);
1285 V_VT(&vararg[0]) = VT_I4;
1286 V_I4(&vararg[0]) = iInstallLevel;
1288 return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1291 static HRESULT Session_FeatureCurrentState(IDispatch *pSession, LPCWSTR szName, int *pState)
1293 VARIANT varresult;
1294 VARIANTARG vararg[1];
1295 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1296 HRESULT hr;
1298 VariantInit(&vararg[0]);
1299 V_VT(&vararg[0]) = VT_BSTR;
1300 V_BSTR(&vararg[0]) = SysAllocString(szName);
1302 hr = invoke(pSession, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1303 *pState = V_I4(&varresult);
1304 VariantClear(&varresult);
1305 return hr;
1308 static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState)
1310 VARIANT varresult;
1311 VARIANTARG vararg[1];
1312 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1313 HRESULT hr;
1315 VariantInit(&vararg[0]);
1316 V_VT(&vararg[0]) = VT_BSTR;
1317 V_BSTR(&vararg[0]) = SysAllocString(szName);
1319 hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1320 *pState = V_I4(&varresult);
1321 VariantClear(&varresult);
1322 return hr;
1325 static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState)
1327 VARIANT varresult;
1328 VARIANTARG vararg[2];
1329 DISPID dispid = DISPID_PROPERTYPUT;
1330 DISPPARAMS dispparams = {vararg, &dispid, ARRAY_SIZE(vararg), 1};
1332 VariantInit(&vararg[1]);
1333 V_VT(&vararg[1]) = VT_BSTR;
1334 V_BSTR(&vararg[1]) = SysAllocString(szName);
1335 VariantInit(&vararg[0]);
1336 V_VT(&vararg[0]) = VT_I4;
1337 V_I4(&vararg[0]) = iState;
1339 return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1342 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
1344 VARIANT varresult;
1345 VARIANTARG vararg[1];
1346 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1347 HRESULT hr;
1349 VariantInit(&vararg[0]);
1350 V_VT(&vararg[0]) = VT_BSTR;
1351 V_BSTR(&vararg[0]) = SysAllocString(szSql);
1353 hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1354 *pView = V_DISPATCH(&varresult);
1355 return hr;
1358 static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo)
1360 VARIANT varresult;
1361 VARIANTARG vararg[1];
1362 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1363 HRESULT hr;
1365 VariantInit(&vararg[0]);
1366 V_VT(&vararg[0]) = VT_I4;
1367 V_I4(&vararg[0]) = iUpdateCount;
1369 hr = invoke(pDatabase, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1370 *pSummaryInfo = V_DISPATCH(&varresult);
1371 return hr;
1374 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
1376 VARIANT varresult;
1377 VARIANTARG vararg[1];
1378 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1380 VariantInit(&vararg[0]);
1381 V_VT(&vararg[0]) = VT_DISPATCH;
1382 V_DISPATCH(&vararg[0]) = pRecord;
1384 return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1387 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
1389 VARIANT varresult;
1390 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1391 HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1392 *ppRecord = V_DISPATCH(&varresult);
1393 return hr;
1396 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
1398 VARIANT varresult;
1399 VARIANTARG vararg[2];
1400 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1402 VariantInit(&vararg[1]);
1403 V_VT(&vararg[1]) = VT_I4;
1404 V_I4(&vararg[1]) = iMode;
1405 VariantInit(&vararg[0]);
1406 V_VT(&vararg[0]) = VT_DISPATCH;
1407 V_DISPATCH(&vararg[0]) = pRecord;
1408 if (pRecord)
1409 IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */
1411 return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1414 static HRESULT View_Close(IDispatch *pView)
1416 VARIANT varresult;
1417 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1418 return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1421 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
1423 VARIANT varresult;
1424 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1425 HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1426 *pFieldCount = V_I4(&varresult);
1427 VariantClear(&varresult);
1428 return hr;
1431 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString)
1433 VARIANT varresult;
1434 VARIANTARG vararg[1];
1435 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1436 HRESULT hr;
1438 VariantInit(&vararg[0]);
1439 V_VT(&vararg[0]) = VT_I4;
1440 V_I4(&vararg[0]) = iField;
1442 hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1443 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1444 VariantClear(&varresult);
1445 return hr;
1448 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
1450 VARIANT varresult;
1451 VARIANTARG vararg[2];
1452 DISPID dispid = DISPID_PROPERTYPUT;
1453 DISPPARAMS dispparams = {vararg, &dispid, ARRAY_SIZE(vararg), 1};
1455 VariantInit(&vararg[1]);
1456 V_VT(&vararg[1]) = VT_I4;
1457 V_I4(&vararg[1]) = iField;
1458 VariantInit(&vararg[0]);
1459 V_VT(&vararg[0]) = VT_BSTR;
1460 V_BSTR(&vararg[0]) = SysAllocString(szString);
1462 return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1465 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
1467 VARIANT varresult;
1468 VARIANTARG vararg[1];
1469 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1470 HRESULT hr;
1472 VariantInit(&vararg[0]);
1473 V_VT(&vararg[0]) = VT_I4;
1474 V_I4(&vararg[0]) = iField;
1476 hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1477 *pValue = V_I4(&varresult);
1478 VariantClear(&varresult);
1479 return hr;
1482 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
1484 VARIANT varresult;
1485 VARIANTARG vararg[2];
1486 DISPID dispid = DISPID_PROPERTYPUT;
1487 DISPPARAMS dispparams = {vararg, &dispid, ARRAY_SIZE(vararg), 1};
1489 VariantInit(&vararg[1]);
1490 V_VT(&vararg[1]) = VT_I4;
1491 V_I4(&vararg[1]) = iField;
1492 VariantInit(&vararg[0]);
1493 V_VT(&vararg[0]) = VT_I4;
1494 V_I4(&vararg[0]) = iValue;
1496 return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1499 static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT)
1501 VARIANT varresult;
1502 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1503 HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN);
1504 *ppEnumVARIANT = V_UNKNOWN(&varresult);
1505 return hr;
1508 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
1510 VARIANT varresult;
1511 VARIANTARG vararg[1];
1512 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1513 HRESULT hr;
1515 VariantInit(&vararg[0]);
1516 V_VT(&vararg[0]) = VT_I4;
1517 V_I4(&vararg[0]) = iIndex;
1519 hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1520 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1521 VariantClear(&varresult);
1522 return hr;
1525 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
1527 VARIANT varresult;
1528 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1529 HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1530 *pCount = V_I4(&varresult);
1531 VariantClear(&varresult);
1532 return hr;
1535 static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect)
1537 VARIANTARG vararg[1];
1538 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1540 VariantInit(&vararg[0]);
1541 V_VT(&vararg[0]) = VT_I4;
1542 V_I4(&vararg[0]) = pid;
1543 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYGET, &dispparams, pVarResult, vtExpect);
1546 static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant)
1548 VARIANT varresult;
1549 VARIANTARG vararg[2];
1550 DISPID dispid = DISPID_PROPERTYPUT;
1551 DISPPARAMS dispparams = {vararg, &dispid, ARRAY_SIZE(vararg), 1};
1553 VariantInit(&vararg[1]);
1554 V_VT(&vararg[1]) = VT_I4;
1555 V_I4(&vararg[1]) = pid;
1556 VariantInit(&vararg[0]);
1557 VariantCopyInd(vararg, pVariant);
1559 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1562 static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount)
1564 VARIANT varresult;
1565 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1566 HRESULT hr;
1568 hr = invoke(pSummaryInfo, "PropertyCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1569 *pCount = V_I4(&varresult);
1570 VariantClear(&varresult);
1571 return hr;
1574 /* Test the various objects */
1576 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4
1578 static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly)
1580 VARIANT varresult, var;
1581 SYSTEMTIME st;
1582 HRESULT hr;
1583 int j;
1585 /* SummaryInfo::PropertyCount */
1586 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1587 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1588 ok(j == num_info, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1590 /* SummaryInfo::Property, get for properties we have set */
1591 for (j = 0; j < num_info; j++)
1593 const msi_summary_info *entry = &info[j];
1595 int vt = entry->datatype;
1596 if (vt == VT_LPSTR) vt = VT_BSTR;
1597 else if (vt == VT_FILETIME) vt = VT_DATE;
1598 else if (vt == VT_I2) vt = VT_I4;
1600 hr = SummaryInfo_PropertyGet(pSummaryInfo, entry->property, &varresult, vt);
1601 ok(hr == S_OK, "SummaryInfo_Property (pid %d) failed, hresult 0x%08x\n", entry->property, hr);
1602 if (V_VT(&varresult) != vt)
1603 skip("Skipping property tests due to type mismatch\n");
1604 else if (vt == VT_I4)
1605 ok(V_I4(&varresult) == entry->iValue, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %d\n",
1606 entry->property, entry->iValue, V_I4(&varresult));
1607 else if (vt == VT_DATE)
1609 FILETIME ft;
1610 DATE d;
1612 FileTimeToLocalFileTime(entry->pftValue, &ft);
1613 FileTimeToSystemTime(&ft, &st);
1614 SystemTimeToVariantTime(&st, &d);
1615 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));
1617 else if (vt == VT_BSTR)
1619 ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry->property, entry->szValue, V_BSTR(&varresult));
1621 else
1622 skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry->property, vt);
1624 VariantClear(&varresult);
1627 /* SummaryInfo::Property, get; invalid arguments */
1629 /* Invalid pids */
1630 hr = SummaryInfo_PropertyGet(pSummaryInfo, -1, &varresult, VT_EMPTY);
1631 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1632 ok_exception(hr, L"Property,Pid");
1634 hr = SummaryInfo_PropertyGet(pSummaryInfo, 1000, &varresult, VT_EMPTY);
1635 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1636 ok_exception(hr, L"Property,Pid");
1638 /* Unsupported pids */
1639 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_DICTIONARY, &varresult, VT_EMPTY);
1640 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1642 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY);
1643 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1645 /* Pids we have not set, one for each type */
1646 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_EMPTY);
1647 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1649 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY);
1650 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1652 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY);
1653 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1655 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY);
1656 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1658 if (!readonly)
1660 /* SummaryInfo::Property, put; one for each type */
1662 /* VT_I2 */
1663 VariantInit(&var);
1664 V_VT(&var) = VT_I2;
1665 V_I2(&var) = 1;
1666 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CODEPAGE, &var);
1667 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1669 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */);
1670 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1671 ok(V_I2(&var) == V_I2(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var), V_I2(&varresult));
1672 VariantClear(&varresult);
1673 VariantClear(&var);
1675 /* VT_BSTR */
1676 V_VT(&var) = VT_BSTR;
1677 V_BSTR(&var) = SysAllocString(L"Title");
1678 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_TITLE, &var);
1679 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1681 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var));
1682 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1683 ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var), V_BSTR(&varresult));
1684 VariantClear(&varresult);
1685 VariantClear(&var);
1687 /* VT_DATE */
1688 V_VT(&var) = VT_DATE;
1689 FileTimeToSystemTime(&systemtime, &st);
1690 SystemTimeToVariantTime(&st, &V_DATE(&var));
1691 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_LASTSAVE_DTM, &var);
1692 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1694 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var));
1695 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1696 ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1697 VariantClear(&varresult);
1698 VariantClear(&var);
1700 /* VT_I4 */
1701 V_VT(&var) = VT_I4;
1702 V_I4(&var) = 1000;
1703 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1704 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1706 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1707 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1708 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult));
1709 VariantClear(&varresult);
1710 VariantClear(&var);
1712 /* SummaryInfo::PropertyCount */
1713 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1714 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1715 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1719 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1721 IDispatch *pView = NULL, *pSummaryInfo = NULL;
1722 HRESULT hr;
1724 hr = Database_OpenView(pDatabase, L"SELECT `Feature` FROM `Feature` WHERE `Feature_Parent`='One'", &pView);
1725 ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr);
1726 if (hr == S_OK)
1728 IDispatch *pRecord = NULL;
1729 WCHAR szString[MAX_PATH];
1731 /* View::Execute */
1732 hr = View_Execute(pView, NULL);
1733 ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr);
1735 /* View::Fetch */
1736 hr = View_Fetch(pView, &pRecord);
1737 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1738 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1739 if (pRecord)
1741 /* Record::StringDataGet */
1742 memset(szString, 0, sizeof(szString));
1743 hr = Record_StringDataGet(pRecord, 1, szString);
1744 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1745 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, L"Three");
1747 /* Record::StringDataPut with correct index */
1748 hr = Record_StringDataPut(pRecord, 1, L"Two");
1749 ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1751 /* Record::StringDataGet */
1752 memset(szString, 0, sizeof(szString));
1753 hr = Record_StringDataGet(pRecord, 1, szString);
1754 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1755 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, L"Two");
1757 /* Record::StringDataPut with incorrect index */
1758 hr = Record_StringDataPut(pRecord, -1, szString);
1759 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1760 ok_exception(hr, L"StringData,Field");
1762 /* View::Modify with incorrect parameters */
1763 hr = View_Modify(pView, -5, NULL);
1764 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1765 ok_exception(hr, L"Modify,Mode,Record");
1767 hr = View_Modify(pView, -5, pRecord);
1768 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1769 ok_exception(hr, L"Modify,Mode,Record");
1771 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1772 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1773 ok_exception(hr, L"Modify,Mode,Record");
1775 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1776 ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr);
1778 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1779 memset(szString, 0, sizeof(szString));
1780 hr = Record_StringDataGet(pRecord, 1, szString);
1781 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1782 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, L"Three");
1784 IDispatch_Release(pRecord);
1787 /* View::Fetch */
1788 hr = View_Fetch(pView, &pRecord);
1789 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1790 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1791 if (pRecord)
1793 /* Record::StringDataGet */
1794 memset(szString, 0, sizeof(szString));
1795 hr = Record_StringDataGet(pRecord, 1, szString);
1796 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1797 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, L"Two");
1799 IDispatch_Release(pRecord);
1802 /* View::Fetch */
1803 hr = View_Fetch(pView, &pRecord);
1804 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1805 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1806 if (pRecord)
1807 IDispatch_Release(pRecord);
1809 /* View::Close */
1810 hr = View_Close(pView);
1811 ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr);
1813 IDispatch_Release(pView);
1816 /* Database::SummaryInformation */
1817 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo);
1818 ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr);
1819 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1820 if (pSummaryInfo)
1822 test_SummaryInfo(pSummaryInfo, summary_info, ARRAY_SIZE(summary_info), readonly);
1823 IDispatch_Release(pSummaryInfo);
1827 static void test_Session(IDispatch *pSession)
1829 WCHAR stringw[MAX_PATH];
1830 CHAR string[MAX_PATH];
1831 UINT len;
1832 VARIANT_BOOL bool;
1833 int myint;
1834 IDispatch *pDatabase = NULL, *pInst = NULL, *record = NULL;
1835 ULONG refs_before, refs_after;
1836 HRESULT hr;
1838 /* Session::Installer */
1839 hr = Session_Installer(pSession, &pInst);
1840 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1841 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1842 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1843 refs_before = IDispatch_AddRef(pInst);
1845 hr = Session_Installer(pSession, &pInst);
1846 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1847 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1848 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1849 refs_after = IDispatch_Release(pInst);
1850 ok(refs_before == refs_after, "got %u and %u\n", refs_before, refs_after);
1852 /* Session::Property, get */
1853 memset(stringw, 0, sizeof(stringw));
1854 hr = Session_PropertyGet(pSession, L"ProductName", stringw);
1855 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1856 if (lstrcmpW(stringw, L"MSITEST") != 0)
1858 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1859 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1860 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1863 /* Session::Property, put */
1864 hr = Session_PropertyPut(pSession, L"ProductName", L"ProductName");
1865 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1866 memset(stringw, 0, sizeof(stringw));
1867 hr = Session_PropertyGet(pSession, L"ProductName", stringw);
1868 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1869 if (lstrcmpW(stringw, L"ProductName") != 0)
1871 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1872 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1873 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1876 /* Try putting a property using empty property identifier */
1877 hr = Session_PropertyPut(pSession, L"", L"ProductName");
1878 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1879 ok_exception(hr, L"Property,Name");
1881 /* Try putting a property using illegal property identifier */
1882 hr = Session_PropertyPut(pSession, L"=", L"ProductName");
1883 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1885 /* Session::Language, get */
1886 hr = Session_LanguageGet(pSession, &len);
1887 ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1888 /* Not sure how to check the language is correct */
1890 /* Session::Mode, get */
1891 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1892 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1893 ok(!bool, "Reboot at end session mode is %d\n", bool);
1895 hr = Session_ModeGet(pSession, MSIRUNMODE_MAINTENANCE, &bool);
1896 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1897 ok(!bool, "Maintenance mode is %d\n", bool);
1899 /* Session::Mode, put */
1900 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, VARIANT_TRUE);
1901 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1902 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1903 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1904 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1905 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, VARIANT_FALSE); /* set it again so we don't reboot */
1906 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1908 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, VARIANT_TRUE);
1909 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1910 ok_exception(hr, L"Mode,Flag");
1912 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTNOW, &bool);
1913 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1914 ok(bool, "Reboot now mode is %d, expected 1\n", bool);
1916 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, VARIANT_FALSE); /* set it again so we don't reboot */
1917 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1918 ok_exception(hr, L"Mode,Flag");
1920 hr = Session_ModePut(pSession, MSIRUNMODE_MAINTENANCE, VARIANT_TRUE);
1921 ok(hr == DISP_E_EXCEPTION, "Session_ModePut failed, hresult 0x%08x\n", hr);
1922 ok_exception(hr, L"Mode,Flag");
1924 /* Session::Database, get */
1925 hr = Session_Database(pSession, &pDatabase);
1926 ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr);
1927 if (hr == S_OK)
1929 test_Database(pDatabase, TRUE);
1930 IDispatch_Release(pDatabase);
1933 /* Session::EvaluateCondition */
1934 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1935 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1936 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1938 hr = Session_EvaluateCondition(pSession, L"", &myint);
1939 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1940 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1942 hr = Session_EvaluateCondition(pSession, L"=", &myint);
1943 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1944 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1946 /* Session::DoAction(CostInitialize) must occur before the next statements */
1947 hr = Session_DoAction(pSession, L"CostInitialize", &myint);
1948 ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr);
1949 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1951 /* Session::SetInstallLevel */
1952 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1953 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
1955 /* Session::FeatureCurrentState, get */
1956 hr = Session_FeatureCurrentState(pSession, L"One", &myint);
1957 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
1958 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1960 /* Session::Message */
1961 hr = Installer_CreateRecord(0, &record);
1962 ok(hr == S_OK, "Installer_CreateRecord failed: %08x\n", hr);
1963 hr = Session_Message(pSession, INSTALLMESSAGE_INFO, record, &myint);
1964 ok(hr == S_OK, "Session_Message failed: %08x\n", hr);
1965 ok(myint == 0, "Session_Message returned %x\n", myint);
1967 /* Session::EvaluateCondition */
1968 hr = Session_EvaluateCondition(pSession, L"!One>0", &myint);
1969 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1970 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1972 hr = Session_EvaluateCondition(pSession, L"!One=-1", &myint);
1973 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1974 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1976 /* Session::FeatureRequestState, put */
1977 hr = Session_FeatureRequestStatePut(pSession, L"One", INSTALLSTATE_ADVERTISED);
1978 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
1979 hr = Session_FeatureRequestStateGet(pSession, L"One", &myint);
1980 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
1981 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
1983 /* Session::EvaluateCondition */
1984 hr = Session_EvaluateCondition(pSession, L"$One=-1", &myint);
1985 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1986 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1988 hr = Session_EvaluateCondition(pSession, L"$One>0", &myint);
1989 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1990 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1993 /* delete key and all its subkeys */
1994 static DWORD delete_key( HKEY hkey )
1996 char name[MAX_PATH];
1997 DWORD ret;
1999 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
2001 HKEY tmp;
2002 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
2004 ret = delete_key( tmp );
2005 RegCloseKey( tmp );
2007 if (ret) break;
2009 if (ret != ERROR_NO_MORE_ITEMS) return ret;
2010 RegDeleteKeyA( hkey, "" );
2011 return 0;
2014 static void test_Installer_RegistryValue(void)
2016 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
2017 VARIANT varresult;
2018 VARIANTARG vararg;
2019 WCHAR szString[MAX_PATH];
2020 HKEY hkey, hkey_sub;
2021 HKEY curr_user = (HKEY)1;
2022 HRESULT hr;
2023 BOOL bRet;
2024 LONG lRet;
2026 /* Delete keys */
2027 SetLastError(0xdeadbeef);
2028 lRet = RegOpenKeyW( HKEY_CURRENT_USER, L"Software\\Wine\\Test", &hkey );
2029 if (!lRet && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2031 win_skip("Needed W-functions are not implemented\n");
2032 return;
2034 if (!lRet)
2035 delete_key( hkey );
2037 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
2038 hr = Installer_RegistryValueE(curr_user, L"Software\\Wine\\Test", &bRet);
2039 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
2040 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
2042 memset(szString, 0, sizeof(szString));
2043 hr = Installer_RegistryValueW(curr_user, L"Software\\Wine\\Test", NULL, szString);
2044 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2046 memset(szString, 0, sizeof(szString));
2047 hr = Installer_RegistryValueI(curr_user, L"Software\\Wine\\Test", 0, szString, VT_BSTR);
2048 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2050 /* Create key */
2051 ok(!RegCreateKeyW( HKEY_CURRENT_USER, L"Software\\Wine\\Test", &hkey ), "RegCreateKeyW failed\n");
2053 ok(!RegSetValueExW(hkey, L"One", 0, REG_SZ, (const BYTE *)L"One", sizeof(L"one")),
2054 "RegSetValueExW failed\n");
2055 ok(!RegSetValueExW(hkey, L"Two", 0, REG_DWORD, (const BYTE *)qw, 4),
2056 "RegSetValueExW failed\n");
2057 ok(!RegSetValueExW(hkey, L"Three", 0, REG_BINARY, (const BYTE *)qw, 4),
2058 "RegSetValueExW failed\n");
2059 bRet = SetEnvironmentVariableA("MSITEST", "Four");
2060 ok(bRet, "SetEnvironmentVariableA failed %d\n", GetLastError());
2061 ok(!RegSetValueExW(hkey, L"Four", 0, REG_EXPAND_SZ, (const BYTE *)L"%MSITEST%", sizeof(L"%MSITEST%")),
2062 "RegSetValueExW failed\n");
2063 ok(!RegSetValueExW(hkey, L"Five\0Hi\0", 0, REG_MULTI_SZ, (const BYTE *)L"Five\0Hi\0", sizeof(L"Five\0Hi\0")),
2064 "RegSetValueExW failed\n");
2065 ok(!RegSetValueExW(hkey, L"Six", 0, REG_QWORD, (const BYTE *)qw, 8),
2066 "RegSetValueExW failed\n");
2067 ok(!RegSetValueExW(hkey, L"Seven", 0, REG_NONE, NULL, 0),
2068 "RegSetValueExW failed\n");
2070 ok(!RegSetValueExW(hkey, NULL, 0, REG_SZ, (const BYTE *)L"One", sizeof(L"One")),
2071 "RegSetValueExW failed\n");
2073 ok(!RegCreateKeyW( hkey, L"Eight", &hkey_sub ), "RegCreateKeyW failed\n");
2075 /* Does our key exist? It should, and make sure we retrieve the correct default value */
2076 bRet = FALSE;
2077 hr = Installer_RegistryValueE(curr_user, L"Software\\Wine\\Test", &bRet);
2078 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
2079 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
2081 memset(szString, 0, sizeof(szString));
2082 hr = Installer_RegistryValueW(curr_user, L"Software\\Wine\\Test", NULL, szString);
2083 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2084 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, L"One");
2086 /* Ask for the value of a nonexistent key */
2087 memset(szString, 0, sizeof(szString));
2088 hr = Installer_RegistryValueW(curr_user, L"Software\\Wine\\Test", L"%MSITEST%", szString);
2089 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2091 /* Get values of keys */
2092 memset(szString, 0, sizeof(szString));
2093 hr = Installer_RegistryValueW(curr_user, L"Software\\Wine\\Test", L"One", szString);
2094 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2095 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, L"One");
2097 VariantInit(&vararg);
2098 V_VT(&vararg) = VT_BSTR;
2099 V_BSTR(&vararg) = SysAllocString(L"Two");
2100 hr = Installer_RegistryValue(curr_user, L"Software\\Wine\\Test", vararg, &varresult, VT_I4);
2101 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
2102 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
2103 VariantClear(&varresult);
2105 memset(szString, 0, sizeof(szString));
2106 hr = Installer_RegistryValueW(curr_user, L"Software\\Wine\\Test", L"Three", szString);
2107 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2108 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, L"(REG_BINARY)");
2110 memset(szString, 0, sizeof(szString));
2111 hr = Installer_RegistryValueW(curr_user, L"Software\\Wine\\Test", L"Four", szString);
2112 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2113 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, L"Four");
2115 /* Vista does not NULL-terminate this case */
2116 memset(szString, 0, sizeof(szString));
2117 hr = Installer_RegistryValueW(curr_user, L"Software\\Wine\\Test", L"Five\0Hi\0", szString);
2118 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2119 ok_w2n("Registry value \"%s\" does not match expected \"%s\"\n",
2120 szString, L"Five\nHi", lstrlenW(L"Five\nHi"));
2122 memset(szString, 0, sizeof(szString));
2123 hr = Installer_RegistryValueW(curr_user, L"Software\\Wine\\Test", L"Six", szString);
2124 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2125 ok(!lstrcmpW(szString, L"(REG_\?\?)") || broken(!lstrcmpW(szString, L"(REG_]")),
2126 "Registry value does not match\n");
2128 VariantInit(&vararg);
2129 V_VT(&vararg) = VT_BSTR;
2130 V_BSTR(&vararg) = SysAllocString(L"Seven");
2131 hr = Installer_RegistryValue(curr_user, L"Software\\Wine\\Test", vararg, &varresult, VT_EMPTY);
2132 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
2134 /* Get string class name for the key */
2135 memset(szString, 0, sizeof(szString));
2136 hr = Installer_RegistryValueI(curr_user, L"Software\\Wine\\Test", 0, szString, VT_BSTR);
2137 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2138 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, L"");
2140 /* Get name of a value by positive number (RegEnumValue like), valid index */
2141 memset(szString, 0, sizeof(szString));
2142 hr = Installer_RegistryValueI(curr_user, L"Software\\Wine\\Test", 2, szString, VT_BSTR);
2143 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2144 /* RegEnumValue order seems different on wine */
2145 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, L"Two");
2147 /* Get name of a value by positive number (RegEnumValue like), invalid index */
2148 memset(szString, 0, sizeof(szString));
2149 hr = Installer_RegistryValueI(curr_user, L"Software\\Wine\\Test", 10, szString, VT_EMPTY);
2150 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2152 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
2153 memset(szString, 0, sizeof(szString));
2154 hr = Installer_RegistryValueI(curr_user, L"Software\\Wine\\Test", -1, szString, VT_BSTR);
2155 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2156 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, L"Eight");
2158 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
2159 memset(szString, 0, sizeof(szString));
2160 hr = Installer_RegistryValueI(curr_user, L"Software\\Wine\\Test", -10, szString, VT_EMPTY);
2161 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2163 /* clean up */
2164 delete_key(hkey);
2167 static void test_Installer_Products(BOOL bProductInstalled)
2169 WCHAR szString[MAX_PATH];
2170 HRESULT hr;
2171 int idx;
2172 IUnknown *pUnk = NULL;
2173 IEnumVARIANT *pEnum = NULL;
2174 VARIANT var;
2175 ULONG celt;
2176 int iCount, iValue;
2177 IDispatch *pStringList = NULL;
2178 BOOL bProductFound = FALSE;
2180 /* Installer::Products */
2181 hr = Installer_Products(&pStringList);
2182 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
2183 if (hr == S_OK)
2185 /* StringList::_NewEnum */
2186 hr = StringList__NewEnum(pStringList, &pUnk);
2187 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
2188 if (hr == S_OK)
2190 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
2191 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2193 if (!pEnum)
2194 skip("IEnumVARIANT tests\n");
2196 /* StringList::Count */
2197 hr = StringList_Count(pStringList, &iCount);
2198 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2200 for (idx=0; idx<iCount; idx++)
2202 /* StringList::Item */
2203 memset(szString, 0, sizeof(szString));
2204 hr = StringList_Item(pStringList, idx, szString);
2205 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2207 if (hr == S_OK)
2209 /* Installer::ProductState */
2210 hr = Installer_ProductState(szString, &iValue);
2211 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2212 if (hr == S_OK)
2213 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
2215 /* Not found our product code yet? Check */
2216 if (!bProductFound && !lstrcmpW(szString, L"{837450fa-a39b-4bc8-b321-08b393f784b3}"))
2217 bProductFound = TRUE;
2219 /* IEnumVARIANT::Next */
2220 if (pEnum)
2222 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2223 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2224 ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
2225 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2226 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2227 VariantClear(&var);
2232 if (bProductInstalled)
2234 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
2235 bProductInstalled ? "be" : "not be",
2236 bProductFound ? "found" : "not found");
2239 if (pEnum)
2241 IEnumVARIANT *pEnum2 = NULL;
2243 if (0) /* Crashes on Windows XP */
2245 /* IEnumVARIANT::Clone, NULL pointer */
2246 IEnumVARIANT_Clone(pEnum, NULL);
2249 /* IEnumVARIANT::Clone */
2250 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
2251 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
2252 if (hr == S_OK)
2254 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
2256 /* IEnumVARIANT::Next of the clone */
2257 if (iCount)
2259 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
2260 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2261 ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
2262 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2263 VariantClear(&var);
2265 else
2266 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
2268 IEnumVARIANT_Release(pEnum2);
2271 /* IEnumVARIANT::Skip should fail */
2272 hr = IEnumVARIANT_Skip(pEnum, 1);
2273 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2275 /* IEnumVARIANT::Next, NULL variant pointer */
2276 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2277 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2278 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2280 /* IEnumVARIANT::Next, should not return any more items */
2281 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2282 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2283 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2284 VariantClear(&var);
2286 /* IEnumVARIANT::Reset */
2287 hr = IEnumVARIANT_Reset(pEnum);
2288 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2290 if (iCount)
2292 /* IEnumVARIANT::Skip to the last product */
2293 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2294 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2296 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2297 * NULL celt pointer. */
2298 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2299 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2300 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2301 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2302 VariantClear(&var);
2304 else
2305 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2308 /* StringList::Item using an invalid index */
2309 memset(szString, 0, sizeof(szString));
2310 hr = StringList_Item(pStringList, iCount, szString);
2311 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2313 if (pEnum) IEnumVARIANT_Release(pEnum);
2314 if (pUnk) IUnknown_Release(pUnk);
2315 IDispatch_Release(pStringList);
2319 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2320 * deleting the subkeys first) */
2321 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey, REGSAM access)
2323 UINT ret;
2324 CHAR *string = NULL;
2325 HKEY hkey;
2326 DWORD dwSize;
2328 ret = RegOpenKeyExA(hkeyParent, subkey, 0, access, &hkey);
2329 if (ret != ERROR_SUCCESS) return ret;
2330 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2331 if (ret != ERROR_SUCCESS) return ret;
2332 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2334 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2335 delete_registry_key(hkey, string, access);
2337 RegCloseKey(hkey);
2338 HeapFree(GetProcessHeap(), 0, string);
2339 delete_key_portable(hkeyParent, subkey, access);
2340 return ERROR_SUCCESS;
2343 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2344 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, REGSAM access, HKEY *phkey)
2346 UINT ret;
2347 CHAR *string = NULL;
2348 int idx = 0;
2349 HKEY hkey;
2350 DWORD dwSize;
2351 BOOL found = FALSE;
2353 *phkey = 0;
2355 ret = RegOpenKeyExA(hkeyParent, subkey, 0, access, &hkey);
2356 if (ret != ERROR_SUCCESS) return ret;
2357 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2358 if (ret != ERROR_SUCCESS) return ret;
2359 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2361 while (!found &&
2362 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2364 if (!strcmp(string, findkey))
2366 *phkey = hkey;
2367 found = TRUE;
2369 else if (find_registry_key(hkey, string, findkey, access, phkey) == ERROR_SUCCESS) found = TRUE;
2372 if (*phkey != hkey) RegCloseKey(hkey);
2373 HeapFree(GetProcessHeap(), 0, string);
2374 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2377 static void test_Installer_InstallProduct(void)
2379 HRESULT hr;
2380 CHAR path[MAX_PATH];
2381 WCHAR szString[MAX_PATH];
2382 LONG res;
2383 HKEY hkey;
2384 DWORD num, size, type;
2385 int iValue, iCount;
2386 IDispatch *pStringList = NULL;
2387 REGSAM access = KEY_ALL_ACCESS;
2389 if (is_process_limited())
2391 /* In fact InstallProduct would succeed but then Windows XP
2392 * would not allow us to clean up the registry!
2394 skip("Installer_InstallProduct (insufficient privileges)\n");
2395 return;
2398 if (is_wow64)
2399 access |= KEY_WOW64_64KEY;
2401 create_test_files();
2403 /* Avoid an interactive dialog in case of insufficient privileges. */
2404 hr = Installer_UILevelPut(INSTALLUILEVEL_NONE);
2405 ok(hr == S_OK, "Expected UILevel property put invoke to return S_OK, got 0x%08x\n", hr);
2407 /* Installer::InstallProduct */
2408 hr = Installer_InstallProduct(L"winetest-automation.msi", NULL);
2409 if (hr == DISP_E_EXCEPTION)
2411 skip("InstallProduct failed, insufficient rights?\n");
2412 delete_test_files();
2413 return;
2415 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2417 /* Installer::ProductState for our product code, which has been installed */
2418 hr = Installer_ProductState(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", &iValue);
2419 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2420 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2422 /* Installer::ProductInfo for our product code */
2424 /* NULL attribute */
2425 memset(szString, 0, sizeof(szString));
2426 hr = Installer_ProductInfo(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", NULL, szString);
2427 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2428 ok_exception(hr, L"ProductInfo,Product,Attribute");
2430 /* Nonexistent attribute */
2431 memset(szString, 0, sizeof(szString));
2432 hr = Installer_ProductInfo(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", L"winetest-automation.msi", szString);
2433 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2434 ok_exception(hr, L"ProductInfo,Product,Attribute");
2436 /* Package name */
2437 memset(szString, 0, sizeof(szString));
2438 hr = Installer_ProductInfo(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", L"PackageName", szString);
2439 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2440 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, L"winetest-automation.msi");
2442 /* Product name */
2443 memset(szString, 0, sizeof(szString));
2444 hr = Installer_ProductInfo(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", L"ProductName", szString);
2445 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2446 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, L"MSITEST");
2448 /* Installer::Products */
2449 test_Installer_Products(TRUE);
2451 /* Installer::RelatedProducts for our upgrade code */
2452 hr = Installer_RelatedProducts(L"{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}", &pStringList);
2453 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2454 if (hr == S_OK)
2456 /* StringList::Count */
2457 hr = StringList_Count(pStringList, &iCount);
2458 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2459 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2461 /* StringList::Item */
2462 memset(szString, 0, sizeof(szString));
2463 hr = StringList_Item(pStringList, 0, szString);
2464 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2465 ok_w2("StringList_Item returned %s but expected %s\n", szString, L"{837450fa-a39b-4bc8-b321-08b393f784b3}");
2467 IDispatch_Release(pStringList);
2470 hr = Installer_ProductInfo(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", L"LocalPackage", szString);
2471 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2472 DeleteFileW( szString );
2474 /* Check & clean up installed files & registry keys */
2475 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2476 ok(delete_pf("msitest\\cabout\\new", FALSE), "Directory not created\n");
2477 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2478 ok(delete_pf("msitest\\cabout", FALSE), "Directory not created\n");
2479 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2480 ok(delete_pf("msitest\\changed", FALSE), "Directory not created\n");
2481 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2482 ok(delete_pf("msitest\\first", FALSE), "Directory not created\n");
2483 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2484 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2485 ok(delete_pf("msitest", FALSE), "Directory not created\n");
2487 res = RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest", &hkey);
2488 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2490 size = MAX_PATH;
2491 type = REG_SZ;
2492 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2493 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2494 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2496 size = MAX_PATH;
2497 type = REG_SZ;
2498 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2499 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2501 size = sizeof(num);
2502 type = REG_DWORD;
2503 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2504 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2505 ok(num == 314, "Expected 314, got %d\n", num);
2507 size = MAX_PATH;
2508 type = REG_SZ;
2509 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2510 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2511 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2513 RegCloseKey(hkey);
2515 res = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest");
2516 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2518 /* Remove registry keys written by RegisterProduct standard action */
2519 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2520 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{837450fa-a39b-4bc8-b321-08b393f784b3}",
2521 KEY_WOW64_32KEY);
2522 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2524 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2525 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656", access);
2526 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2528 res = find_registry_key(HKEY_LOCAL_MACHINE,
2529 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "af054738b93a8cb43b12803b397f483b", access, &hkey);
2530 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2532 res = delete_registry_key(hkey, "af054738b93a8cb43b12803b397f483b", access);
2533 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2534 RegCloseKey(hkey);
2536 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2537 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\af054738b93a8cb43b12803b397f483b", access);
2538 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2540 /* Remove registry keys written by PublishProduct standard action */
2541 res = RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2542 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2544 res = delete_registry_key(hkey, "Products\\af054738b93a8cb43b12803b397f483b", KEY_ALL_ACCESS);
2545 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2547 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2548 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2550 RegCloseKey(hkey);
2552 /* Delete installation files we created */
2553 delete_test_files();
2556 static void test_Installer(void)
2558 WCHAR szPath[MAX_PATH];
2559 HRESULT hr;
2560 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL, *pSumInfo = NULL;
2561 int iValue, iCount;
2563 if (!pInstaller) return;
2565 /* Installer::CreateRecord */
2567 /* Test for error */
2568 hr = Installer_CreateRecord(-1, &pRecord);
2569 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2570 ok_exception(hr, L"CreateRecord,Count");
2572 /* Test for success */
2573 hr = Installer_CreateRecord(1, &pRecord);
2574 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2575 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2576 if (pRecord)
2578 /* Record::FieldCountGet */
2579 hr = Record_FieldCountGet(pRecord, &iValue);
2580 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2581 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2583 /* Record::IntegerDataGet */
2584 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2585 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2586 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2588 /* Record::IntegerDataGet, bad index */
2589 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2590 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2591 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2593 /* Record::IntegerDataPut */
2594 hr = Record_IntegerDataPut(pRecord, 1, 100);
2595 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2597 /* Record::IntegerDataPut, bad index */
2598 hr = Record_IntegerDataPut(pRecord, 10, 100);
2599 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2600 ok_exception(hr, L"IntegerData,Field");
2602 /* Record::IntegerDataGet */
2603 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2604 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2605 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2607 IDispatch_Release(pRecord);
2610 create_package(szPath);
2612 /* Installer::OpenPackage */
2613 hr = Installer_OpenPackage(szPath, 0, &pSession);
2614 if (hr == DISP_E_EXCEPTION)
2616 skip("OpenPackage failed, insufficient rights?\n");
2617 DeleteFileW(szPath);
2618 return;
2620 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2621 if (hr == S_OK)
2623 test_Session(pSession);
2624 IDispatch_Release(pSession);
2627 /* Installer::OpenDatabase */
2628 hr = Installer_OpenDatabase(szPath, (INT_PTR)MSIDBOPEN_TRANSACT, &pDatabase);
2629 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2630 if (hr == S_OK)
2632 test_Database(pDatabase, FALSE);
2633 IDispatch_Release(pDatabase);
2636 /* Installer::SummaryInformation */
2637 hr = Installer_SummaryInformation(szPath, 0, &pSumInfo);
2638 ok(hr == S_OK, "Installer_SummaryInformation failed, hresult 0x%08x\n", hr);
2639 if (hr == S_OK)
2641 test_SummaryInfo(pSumInfo, summary_info, ARRAY_SIZE(summary_info), TRUE);
2642 IDispatch_Release(pSumInfo);
2645 hr = Installer_SummaryInformation(NULL, 0, &pSumInfo);
2646 ok(hr == DISP_E_EXCEPTION, "Installer_SummaryInformation failed, hresult 0x%08x\n", hr);
2648 /* Installer::RegistryValue */
2649 test_Installer_RegistryValue();
2651 /* Installer::ProductState for our product code, which should not be installed */
2652 hr = Installer_ProductState(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", &iValue);
2653 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2654 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2656 /* Installer::ProductInfo for our product code, which should not be installed */
2658 /* Package name */
2659 memset(szPath, 0, sizeof(szPath));
2660 hr = Installer_ProductInfo(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", L"PackageName", szPath);
2661 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2662 ok_exception(hr, L"ProductInfo,Product,Attribute");
2664 /* NULL attribute and NULL product code */
2665 memset(szPath, 0, sizeof(szPath));
2666 hr = Installer_ProductInfo(NULL, NULL, szPath);
2667 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2668 ok_exception(hr, L"ProductInfo,Product,Attribute");
2670 /* Installer::Products */
2671 test_Installer_Products(FALSE);
2673 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2674 hr = Installer_RelatedProducts(L"{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}", &pStringList);
2675 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2676 if (hr == S_OK)
2678 /* StringList::Count */
2679 hr = StringList_Count(pStringList, &iCount);
2680 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2681 ok(!iCount, "Expected no related products but found %d\n", iCount);
2683 IDispatch_Release(pStringList);
2686 /* Installer::Version */
2687 memset(szPath, 0, sizeof(szPath));
2688 hr = Installer_VersionGet(szPath);
2689 ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr);
2691 /* Installer::InstallProduct and other tests that depend on our product being installed */
2692 test_Installer_InstallProduct();
2695 START_TEST(automation)
2697 DWORD len;
2698 char temp_path[MAX_PATH], prev_path[MAX_PATH];
2699 HRESULT hr;
2700 CLSID clsid;
2701 IUnknown *pUnk;
2703 init_functionpointers();
2705 if (pIsWow64Process)
2706 pIsWow64Process(GetCurrentProcess(), &is_wow64);
2708 GetSystemTimeAsFileTime(&systemtime);
2710 GetCurrentDirectoryA(MAX_PATH, prev_path);
2711 GetTempPathA(MAX_PATH, temp_path);
2712 SetCurrentDirectoryA(temp_path);
2714 lstrcpyA(CURR_DIR, temp_path);
2715 len = lstrlenA(CURR_DIR);
2717 if(len && (CURR_DIR[len - 1] == '\\'))
2718 CURR_DIR[len - 1] = 0;
2720 get_program_files_dir(PROG_FILES_DIR);
2722 hr = OleInitialize(NULL);
2723 ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr);
2724 hr = CLSIDFromProgID(L"WindowsInstaller.Installer", &clsid);
2725 ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr);
2726 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2727 ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr);
2729 if (pUnk)
2731 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2732 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2734 test_dispid();
2735 test_dispatch();
2736 test_Installer();
2738 IDispatch_Release(pInstaller);
2739 IUnknown_Release(pUnk);
2742 OleUninitialize();
2744 SetCurrentDirectoryA(prev_path);