windows.media: Partially implement IClosedCaptionPropertiesStatics_get_FontSize.
[wine.git] / dlls / msi / tests / automation.c
blob45354cc2bb2161f8d056f4d26ff3dd5ea691151d
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 = malloc( 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 free( 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 %lu\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 = malloc( 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 free( 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 %ld, got %ld\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 %ld\n", dispid);
590 dispid = get_dispid(pInstaller, "ApplyMultiplePatches");
591 ok(dispid == 51 || dispid == -1, "Expected 51 or -1, got %ld\n", dispid);
592 dispid = get_dispid(pInstaller, "ProductsEx");
593 ok(dispid == 52 || dispid == -1, "Expected 52 or -1, got %ld\n", dispid);
594 dispid = get_dispid(pInstaller, "PatchesEx");
595 ok(dispid == 55 || dispid == -1, "Expected 55 or -1, got %ld\n", dispid);
596 dispid = get_dispid(pInstaller, "ExtractPatchXMLData");
597 ok(dispid == 57 || dispid == -1, "Expected 57 or -1, got %ld\n", dispid);
598 dispid = get_dispid( pInstaller, "ProductElevated" );
599 ok(dispid == 59 || dispid == -1, "Expected 59 or -1, got %ld\n", dispid);
600 dispid = get_dispid( pInstaller, "ProvideAssembly" );
601 ok(dispid == 60 || dispid == -1, "Expected 60 or -1, got %ld\n", dispid);
602 dispid = get_dispid( pInstaller, "ProductInfoFromScript" );
603 ok(dispid == 61 || dispid == -1, "Expected 61 or -1, got %ld\n", dispid);
604 dispid = get_dispid( pInstaller, "AdvertiseProduct" );
605 ok(dispid == 62 || dispid == -1, "Expected 62 or -1, got %ld\n", dispid);
606 dispid = get_dispid( pInstaller, "CreateAdvertiseScript" );
607 ok(dispid == 63 || dispid == -1, "Expected 63 or -1, got %ld\n", dispid);
608 dispid = get_dispid( pInstaller, "PatchFiles" );
609 ok(dispid == 65 || dispid == -1, "Expected 65 or -1, got %ld\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 = malloc(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 free(name);
853 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned %#lx\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 %#lx\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 %#lx\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 %#lx\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 %ld\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 %#lx\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 %#lx\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 %#lx\n", hr);
1642 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY);
1643 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult %#lx\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 %#lx\n", hr);
1649 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY);
1650 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr);
1652 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY);
1653 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr);
1655 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY);
1656 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult %#lx\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 %#lx\n", hr);
1669 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */);
1670 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult %#lx\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 %#lx\n", hr);
1681 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var));
1682 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult %#lx\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 %#lx\n", hr);
1694 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var));
1695 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult %#lx\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 %#lx\n", hr);
1706 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1707 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr);
1708 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %ld, but returned %ld\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 %#lx\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 %#lx\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 %#lx\n", hr);
1735 /* View::Fetch */
1736 hr = View_Fetch(pView, &pRecord);
1737 ok(hr == S_OK, "View_Fetch failed, hresult %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %lu and %lu\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 %#lx\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 %lu\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 %#lx\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 %#lx\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 %lu\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 %#lx\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 %#lx\n", hr);
1885 /* Session::Language, get */
1886 hr = Session_LanguageGet(pSession, &len);
1887 ok(hr == S_OK, "Session_LanguageGet failed, hresult %#lx\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 %#lx\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 %#lx\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 %#lx\n", hr);
1902 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1903 ok(hr == S_OK, "Session_ModeGet failed, hresult %#lx\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 %#lx\n", hr);
1908 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, VARIANT_TRUE);
1909 ok(hr == S_OK, "Session_ModePut failed, hresult %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\n", hr);
1955 /* Session::FeatureCurrentState, get */
1956 hr = Session_FeatureCurrentState(pSession, L"One", &myint);
1957 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult %#lx\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: %#lx\n", hr);
1963 hr = Session_Message(pSession, INSTALLMESSAGE_INFO, record, &myint);
1964 ok(hr == S_OK, "Session_Message failed: %#lx\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 %#lx\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 %#lx\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 %#lx\n", hr);
1979 hr = Session_FeatureRequestStateGet(pSession, L"One", &myint);
1980 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %lu\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\n", hr);
2102 ok(V_I4(&varresult) == 305419896, "Registry value %ld 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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\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 %#lx\n", hr);
2188 if (hr == S_OK)
2190 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
2191 ok (hr == S_OK, "IUnknown::QueryInterface returned %#lx\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 %#lx\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 %#lx\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 %#lx\n", hr);
2212 if (hr == S_OK)
2213 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED,
2214 "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
2216 /* Not found our product code yet? Check */
2217 if (!bProductFound && !lstrcmpW(szString, L"{837450fa-a39b-4bc8-b321-08b393f784b3}"))
2218 bProductFound = TRUE;
2220 /* IEnumVARIANT::Next */
2221 if (pEnum)
2223 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2224 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult %#lx\n", idx, iCount, hr);
2225 ok(celt == 1, "%lu items were retrieved, expected 1\n", celt);
2226 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2227 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2228 VariantClear(&var);
2233 if (bProductInstalled)
2235 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
2236 bProductInstalled ? "be" : "not be",
2237 bProductFound ? "found" : "not found");
2240 if (pEnum)
2242 IEnumVARIANT *pEnum2 = NULL;
2244 if (0) /* Crashes on Windows XP */
2246 /* IEnumVARIANT::Clone, NULL pointer */
2247 IEnumVARIANT_Clone(pEnum, NULL);
2250 /* IEnumVARIANT::Clone */
2251 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
2252 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult %#lx\n", hr);
2253 if (hr == S_OK)
2255 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
2257 /* IEnumVARIANT::Next of the clone */
2258 if (iCount)
2260 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
2261 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult %#lx\n", hr);
2262 ok(celt == 1, "%lu items were retrieved, expected 0\n", celt);
2263 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2264 VariantClear(&var);
2266 else
2267 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
2269 IEnumVARIANT_Release(pEnum2);
2272 /* IEnumVARIANT::Skip should fail */
2273 hr = IEnumVARIANT_Skip(pEnum, 1);
2274 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult %#lx\n", hr);
2276 /* IEnumVARIANT::Next, NULL variant pointer */
2277 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2278 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult %#lx\n", hr);
2279 ok(celt == 0, "%lu items were retrieved, expected 0\n", celt);
2281 /* IEnumVARIANT::Next, should not return any more items */
2282 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2283 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult %#lx\n", hr);
2284 ok(celt == 0, "%lu items were retrieved, expected 0\n", celt);
2285 VariantClear(&var);
2287 /* IEnumVARIANT::Reset */
2288 hr = IEnumVARIANT_Reset(pEnum);
2289 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult %#lx\n", hr);
2291 if (iCount)
2293 /* IEnumVARIANT::Skip to the last product */
2294 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2295 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult %#lx\n", hr);
2297 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2298 * NULL celt pointer. */
2299 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2300 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult %#lx\n", idx, iCount, hr);
2301 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2302 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2303 VariantClear(&var);
2305 else
2306 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2309 /* StringList::Item using an invalid index */
2310 memset(szString, 0, sizeof(szString));
2311 hr = StringList_Item(pStringList, iCount, szString);
2312 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult %#lx\n", hr);
2314 if (pEnum) IEnumVARIANT_Release(pEnum);
2315 if (pUnk) IUnknown_Release(pUnk);
2316 IDispatch_Release(pStringList);
2320 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2321 * deleting the subkeys first) */
2322 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey, REGSAM access)
2324 UINT ret;
2325 CHAR *string = NULL;
2326 HKEY hkey;
2327 DWORD dwSize;
2329 ret = RegOpenKeyExA(hkeyParent, subkey, 0, access, &hkey);
2330 if (ret != ERROR_SUCCESS) return ret;
2331 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2332 if (ret != ERROR_SUCCESS) return ret;
2333 if (!(string = malloc(++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2335 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2336 delete_registry_key(hkey, string, access);
2338 RegCloseKey(hkey);
2339 free(string);
2340 delete_key_portable(hkeyParent, subkey, access);
2341 return ERROR_SUCCESS;
2344 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2345 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, REGSAM access, HKEY *phkey)
2347 UINT ret;
2348 CHAR *string = NULL;
2349 int idx = 0;
2350 HKEY hkey;
2351 DWORD dwSize;
2352 BOOL found = FALSE;
2354 *phkey = 0;
2356 ret = RegOpenKeyExA(hkeyParent, subkey, 0, access, &hkey);
2357 if (ret != ERROR_SUCCESS) return ret;
2358 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2359 if (ret != ERROR_SUCCESS) return ret;
2360 if (!(string = malloc(++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2362 while (!found &&
2363 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2365 if (!strcmp(string, findkey))
2367 *phkey = hkey;
2368 found = TRUE;
2370 else if (find_registry_key(hkey, string, findkey, access, phkey) == ERROR_SUCCESS) found = TRUE;
2373 if (*phkey != hkey) RegCloseKey(hkey);
2374 free(string);
2375 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2378 static void test_Installer_InstallProduct(void)
2380 HRESULT hr;
2381 CHAR path[MAX_PATH];
2382 WCHAR szString[MAX_PATH];
2383 LONG res;
2384 HKEY hkey;
2385 DWORD num, size, type;
2386 int iValue, iCount;
2387 IDispatch *pStringList = NULL;
2388 REGSAM access = KEY_ALL_ACCESS;
2390 if (is_process_limited())
2392 /* In fact InstallProduct would succeed but then Windows XP
2393 * would not allow us to clean up the registry!
2395 skip("Installer_InstallProduct (insufficient privileges)\n");
2396 return;
2399 if (is_wow64)
2400 access |= KEY_WOW64_64KEY;
2402 create_test_files();
2404 /* Avoid an interactive dialog in case of insufficient privileges. */
2405 hr = Installer_UILevelPut(INSTALLUILEVEL_NONE);
2406 ok(hr == S_OK, "Expected UILevel property put invoke to return S_OK, got %#lx\n", hr);
2408 /* Installer::InstallProduct */
2409 hr = Installer_InstallProduct(L"winetest-automation.msi", NULL);
2410 if (hr == DISP_E_EXCEPTION)
2412 skip("InstallProduct failed, insufficient rights?\n");
2413 delete_test_files();
2414 return;
2416 ok(hr == S_OK, "Installer_InstallProduct failed, hresult %#lx\n", hr);
2418 /* Installer::ProductState for our product code, which has been installed */
2419 hr = Installer_ProductState(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", &iValue);
2420 ok(hr == S_OK, "Installer_ProductState failed, hresult %#lx\n", hr);
2421 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2423 /* Installer::ProductInfo for our product code */
2425 /* NULL attribute */
2426 memset(szString, 0, sizeof(szString));
2427 hr = Installer_ProductInfo(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", NULL, szString);
2428 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult %#lx\n", hr);
2429 ok_exception(hr, L"ProductInfo,Product,Attribute");
2431 /* Nonexistent attribute */
2432 memset(szString, 0, sizeof(szString));
2433 hr = Installer_ProductInfo(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", L"winetest-automation.msi", szString);
2434 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult %#lx\n", hr);
2435 ok_exception(hr, L"ProductInfo,Product,Attribute");
2437 /* Package name */
2438 memset(szString, 0, sizeof(szString));
2439 hr = Installer_ProductInfo(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", L"PackageName", szString);
2440 ok(hr == S_OK, "Installer_ProductInfo failed, hresult %#lx\n", hr);
2441 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, L"winetest-automation.msi");
2443 /* Product name */
2444 memset(szString, 0, sizeof(szString));
2445 hr = Installer_ProductInfo(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", L"ProductName", szString);
2446 ok(hr == S_OK, "Installer_ProductInfo failed, hresult %#lx\n", hr);
2447 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, L"MSITEST");
2449 /* Installer::Products */
2450 test_Installer_Products(TRUE);
2452 /* Installer::RelatedProducts for our upgrade code */
2453 hr = Installer_RelatedProducts(L"{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}", &pStringList);
2454 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult %#lx\n", hr);
2455 if (hr == S_OK)
2457 /* StringList::Count */
2458 hr = StringList_Count(pStringList, &iCount);
2459 ok(hr == S_OK, "StringList_Count failed, hresult %#lx\n", hr);
2460 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2462 /* StringList::Item */
2463 memset(szString, 0, sizeof(szString));
2464 hr = StringList_Item(pStringList, 0, szString);
2465 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult %#lx\n", iCount, hr);
2466 ok_w2("StringList_Item returned %s but expected %s\n", szString, L"{837450fa-a39b-4bc8-b321-08b393f784b3}");
2468 IDispatch_Release(pStringList);
2471 hr = Installer_ProductInfo(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", L"LocalPackage", szString);
2472 ok(hr == S_OK, "Installer_ProductInfo failed, hresult %#lx\n", hr);
2473 DeleteFileW( szString );
2475 /* Check & clean up installed files & registry keys */
2476 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2477 ok(delete_pf("msitest\\cabout\\new", FALSE), "Directory not created\n");
2478 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2479 ok(delete_pf("msitest\\cabout", FALSE), "Directory not created\n");
2480 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2481 ok(delete_pf("msitest\\changed", FALSE), "Directory not created\n");
2482 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2483 ok(delete_pf("msitest\\first", FALSE), "Directory not created\n");
2484 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2485 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2486 ok(delete_pf("msitest", FALSE), "Directory not created\n");
2488 res = RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest", &hkey);
2489 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2491 size = MAX_PATH;
2492 type = REG_SZ;
2493 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2494 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2495 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2497 size = MAX_PATH;
2498 type = REG_SZ;
2499 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2500 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %ld\n", res);
2502 size = sizeof(num);
2503 type = REG_DWORD;
2504 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2505 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2506 ok(num == 314, "Expected 314, got %lu\n", num);
2508 size = MAX_PATH;
2509 type = REG_SZ;
2510 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2511 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2512 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2514 RegCloseKey(hkey);
2516 res = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest");
2517 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2519 /* Remove registry keys written by RegisterProduct standard action */
2520 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2521 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{837450fa-a39b-4bc8-b321-08b393f784b3}",
2522 KEY_WOW64_32KEY);
2523 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2525 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2526 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656", access);
2527 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2529 res = find_registry_key(HKEY_LOCAL_MACHINE,
2530 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "af054738b93a8cb43b12803b397f483b", access, &hkey);
2531 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2533 res = delete_registry_key(hkey, "af054738b93a8cb43b12803b397f483b", access);
2534 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2535 RegCloseKey(hkey);
2537 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2538 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\af054738b93a8cb43b12803b397f483b", access);
2539 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %ld\n", res);
2541 /* Remove registry keys written by PublishProduct standard action */
2542 res = RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2543 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2545 res = delete_registry_key(hkey, "Products\\af054738b93a8cb43b12803b397f483b", KEY_ALL_ACCESS);
2546 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2548 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2549 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2551 RegCloseKey(hkey);
2553 /* Delete installation files we created */
2554 delete_test_files();
2557 static void test_Installer(void)
2559 WCHAR szPath[MAX_PATH];
2560 HRESULT hr;
2561 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL, *pSumInfo = NULL;
2562 int iValue, iCount;
2564 if (!pInstaller) return;
2566 /* Installer::CreateRecord */
2568 /* Test for error */
2569 hr = Installer_CreateRecord(-1, &pRecord);
2570 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult %#lx\n", hr);
2571 ok_exception(hr, L"CreateRecord,Count");
2573 /* Test for success */
2574 hr = Installer_CreateRecord(1, &pRecord);
2575 ok(hr == S_OK, "Installer_CreateRecord failed, hresult %#lx\n", hr);
2576 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2577 if (pRecord)
2579 /* Record::FieldCountGet */
2580 hr = Record_FieldCountGet(pRecord, &iValue);
2581 ok(hr == S_OK, "Record_FiledCountGet failed, hresult %#lx\n", hr);
2582 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2584 /* Record::IntegerDataGet */
2585 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2586 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult %#lx\n", hr);
2587 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2589 /* Record::IntegerDataGet, bad index */
2590 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2591 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult %#lx\n", hr);
2592 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2594 /* Record::IntegerDataPut */
2595 hr = Record_IntegerDataPut(pRecord, 1, 100);
2596 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult %#lx\n", hr);
2598 /* Record::IntegerDataPut, bad index */
2599 hr = Record_IntegerDataPut(pRecord, 10, 100);
2600 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult %#lx\n", hr);
2601 ok_exception(hr, L"IntegerData,Field");
2603 /* Record::IntegerDataGet */
2604 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2605 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult %#lx\n", hr);
2606 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2608 IDispatch_Release(pRecord);
2611 create_package(szPath);
2613 /* Installer::OpenPackage */
2614 hr = Installer_OpenPackage(szPath, 0, &pSession);
2615 if (hr == DISP_E_EXCEPTION)
2617 skip("OpenPackage failed, insufficient rights?\n");
2618 DeleteFileW(szPath);
2619 return;
2621 ok(hr == S_OK, "Installer_OpenPackage failed, hresult %#lx\n", hr);
2622 if (hr == S_OK)
2624 test_Session(pSession);
2625 IDispatch_Release(pSession);
2628 /* Installer::OpenDatabase */
2629 hr = Installer_OpenDatabase(szPath, (INT_PTR)MSIDBOPEN_TRANSACT, &pDatabase);
2630 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult %#lx\n", hr);
2631 if (hr == S_OK)
2633 test_Database(pDatabase, FALSE);
2634 IDispatch_Release(pDatabase);
2637 /* Installer::SummaryInformation */
2638 hr = Installer_SummaryInformation(szPath, 0, &pSumInfo);
2639 ok(hr == S_OK, "Installer_SummaryInformation failed, hresult %#lx\n", hr);
2640 if (hr == S_OK)
2642 test_SummaryInfo(pSumInfo, summary_info, ARRAY_SIZE(summary_info), TRUE);
2643 IDispatch_Release(pSumInfo);
2646 hr = Installer_SummaryInformation(NULL, 0, &pSumInfo);
2647 ok(hr == DISP_E_EXCEPTION, "Installer_SummaryInformation failed, hresult %#lx\n", hr);
2649 /* Installer::RegistryValue */
2650 test_Installer_RegistryValue();
2652 /* Installer::ProductState for our product code, which should not be installed */
2653 hr = Installer_ProductState(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", &iValue);
2654 ok(hr == S_OK, "Installer_ProductState failed, hresult %#lx\n", hr);
2655 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2657 /* Installer::ProductInfo for our product code, which should not be installed */
2659 /* Package name */
2660 memset(szPath, 0, sizeof(szPath));
2661 hr = Installer_ProductInfo(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", L"PackageName", szPath);
2662 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult %#lx\n", hr);
2663 ok_exception(hr, L"ProductInfo,Product,Attribute");
2665 /* NULL attribute and NULL product code */
2666 memset(szPath, 0, sizeof(szPath));
2667 hr = Installer_ProductInfo(NULL, NULL, szPath);
2668 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult %#lx\n", hr);
2669 ok_exception(hr, L"ProductInfo,Product,Attribute");
2671 /* Installer::Products */
2672 test_Installer_Products(FALSE);
2674 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2675 hr = Installer_RelatedProducts(L"{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}", &pStringList);
2676 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult %#lx\n", hr);
2677 if (hr == S_OK)
2679 /* StringList::Count */
2680 hr = StringList_Count(pStringList, &iCount);
2681 ok(hr == S_OK, "StringList_Count failed, hresult %#lx\n", hr);
2682 ok(!iCount, "Expected no related products but found %d\n", iCount);
2684 IDispatch_Release(pStringList);
2687 /* Installer::Version */
2688 memset(szPath, 0, sizeof(szPath));
2689 hr = Installer_VersionGet(szPath);
2690 ok(hr == S_OK, "Installer_VersionGet failed, hresult %#lx\n", hr);
2692 /* Installer::InstallProduct and other tests that depend on our product being installed */
2693 test_Installer_InstallProduct();
2696 START_TEST(automation)
2698 DWORD len;
2699 char temp_path[MAX_PATH], prev_path[MAX_PATH];
2700 HRESULT hr;
2701 CLSID clsid;
2702 IUnknown *pUnk;
2704 init_functionpointers();
2706 if (pIsWow64Process)
2707 pIsWow64Process(GetCurrentProcess(), &is_wow64);
2709 GetSystemTimeAsFileTime(&systemtime);
2711 GetCurrentDirectoryA(MAX_PATH, prev_path);
2712 GetTempPathA(MAX_PATH, temp_path);
2713 SetCurrentDirectoryA(temp_path);
2715 lstrcpyA(CURR_DIR, temp_path);
2716 len = lstrlenA(CURR_DIR);
2718 if(len && (CURR_DIR[len - 1] == '\\'))
2719 CURR_DIR[len - 1] = 0;
2721 get_program_files_dir(PROG_FILES_DIR);
2723 hr = OleInitialize(NULL);
2724 ok (hr == S_OK, "OleInitialize returned %#lx\n", hr);
2725 hr = CLSIDFromProgID(L"WindowsInstaller.Installer", &clsid);
2726 ok (hr == S_OK, "CLSIDFromProgID returned %#lx\n", hr);
2727 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2728 ok(hr == S_OK, "CoCreateInstance returned %#lx\n", hr);
2730 if (pUnk)
2732 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2733 ok (hr == S_OK, "IUnknown::QueryInterface returned %#lx\n", hr);
2735 test_dispid();
2736 test_dispatch();
2737 test_Installer();
2739 IDispatch_Release(pInstaller);
2740 IUnknown_Release(pUnk);
2743 OleUninitialize();
2745 SetCurrentDirectoryA(prev_path);