msi/tests: Delete the temp .msi file in all failure cases.
[wine.git] / dlls / msi / tests / automation.c
blobd61ee82b1a228004cdcb40d818410ccf8a94797f
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("msitest\\cabout\\new\\five.txt");
427 DeleteFileA("msitest\\cabout\\four.txt");
428 DeleteFileA("msitest\\second\\three.txt");
429 DeleteFileA("msitest\\first\\two.txt");
430 DeleteFileA("msitest\\one.txt");
431 DeleteFileA("msitest\\filename");
432 RemoveDirectoryA("msitest\\cabout\\new");
433 RemoveDirectoryA("msitest\\cabout");
434 RemoveDirectoryA("msitest\\second");
435 RemoveDirectoryA("msitest\\first");
436 RemoveDirectoryA("msitest");
440 * Automation helpers and tests
443 /* ok-like statement which takes two unicode strings or one unicode and one ANSI string as arguments */
444 static CHAR string1[MAX_PATH], string2[MAX_PATH];
446 #define ok_w2(format, szString1, szString2) \
448 do { \
449 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
450 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
451 if (lstrcmpA(string1, string2) != 0) \
452 ok(0, format, string1, string2); \
453 } while(0);
455 #define ok_w2n(format, szString1, szString2, len) \
457 if (memcmp(szString1, szString2, len * sizeof(WCHAR)) != 0) \
459 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
460 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
461 ok(0, format, string1, string2); \
464 #define ok_aw(format, aString, wString) \
466 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
467 if (lstrcmpA(string1, aString) != 0) \
468 ok(0, format, string1, aString); \
470 #define ok_awplus(format, extra, aString, wString) \
472 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
473 if (lstrcmpA(string1, aString) != 0) \
474 ok(0, format, extra, string1, aString); \
476 /* exception checker */
477 #define ok_exception(hr, szDescription) \
478 if (hr == DISP_E_EXCEPTION) \
480 /* Compare wtype, source, and destination */ \
481 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
483 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
484 if (excepinfo.bstrSource) \
485 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, L"Msi API Error"); \
487 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
488 if (excepinfo.bstrDescription) \
489 ok_w2("Exception description was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrDescription, szDescription); \
491 SysFreeString(excepinfo.bstrSource); \
492 SysFreeString(excepinfo.bstrDescription); \
493 SysFreeString(excepinfo.bstrHelpFile); \
496 static DISPID get_dispid( IDispatch *disp, const char *name )
498 LPOLESTR str;
499 UINT len;
500 DISPID id = -1;
501 HRESULT r;
503 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
504 str = malloc( len * sizeof(WCHAR) );
505 if (str)
507 MultiByteToWideChar(CP_ACP, 0, name, -1, str, len );
508 r = IDispatch_GetIDsOfNames( disp, &IID_NULL, &str, 1, 0, &id );
509 free( str );
510 if (r != S_OK)
511 return -1;
514 return id;
517 typedef struct {
518 DISPID did;
519 const char *name;
520 BOOL todo;
521 } get_did_t;
523 static const get_did_t get_did_data[] = {
524 { 1, "CreateRecord" },
525 { 2, "OpenPackage" },
526 { 3, "OpenProduct" },
527 { 4, "OpenDatabase" },
528 { 5, "SummaryInformation" },
529 { 6, "UILevel" },
530 { 7, "EnableLog" },
531 { 8, "InstallProduct" },
532 { 9, "Version" },
533 { 10, "LastErrorRecord" },
534 { 11, "RegistryValue" },
535 { 12, "Environment" },
536 { 13, "FileAttributes" },
537 { 15, "FileSize" },
538 { 16, "FileVersion" },
539 { 17, "ProductState" },
540 { 18, "ProductInfo" },
541 { 19, "ConfigureProduct", TRUE },
542 { 20, "ReinstallProduct", TRUE },
543 { 21, "CollectUserInfo", TRUE },
544 { 22, "ApplyPatch", TRUE },
545 { 23, "FeatureParent", TRUE },
546 { 24, "FeatureState", TRUE },
547 { 25, "UseFeature", TRUE },
548 { 26, "FeatureUsageCount", TRUE },
549 { 27, "FeatureUsageDate", TRUE },
550 { 28, "ConfigureFeature", TRUE },
551 { 29, "ReinstallFeature", TRUE },
552 { 30, "ProvideComponent", TRUE },
553 { 31, "ComponentPath", TRUE },
554 { 32, "ProvideQualifiedComponent", TRUE },
555 { 33, "QualifierDescription", TRUE },
556 { 34, "ComponentQualifiers", TRUE },
557 { 35, "Products" },
558 { 36, "Features", TRUE },
559 { 37, "Components", TRUE },
560 { 38, "ComponentClients", TRUE },
561 { 39, "Patches", TRUE },
562 { 40, "RelatedProducts" },
563 { 41, "PatchInfo", TRUE },
564 { 42, "PatchTransforms", TRUE },
565 { 43, "AddSource", TRUE },
566 { 44, "ClearSourceList", TRUE },
567 { 45, "ForceSourceListResolution", TRUE },
568 { 46, "ShortcutTarget", TRUE },
569 { 47, "FileHash", TRUE },
570 { 48, "FileSignatureInfo", TRUE },
571 { 0 }
574 static void test_dispid(void)
576 const get_did_t *ptr = get_did_data;
577 DISPID dispid;
579 while (ptr->name)
581 dispid = get_dispid(pInstaller, ptr->name);
582 todo_wine_if (ptr->todo)
583 ok(dispid == ptr->did, "%s: expected %ld, got %ld\n", ptr->name, ptr->did, dispid);
584 ptr++;
587 dispid = get_dispid(pInstaller, "RemovePatches");
588 ok(dispid == 49 || dispid == -1, "Expected 49 or -1, got %ld\n", dispid);
589 dispid = get_dispid(pInstaller, "ApplyMultiplePatches");
590 ok(dispid == 51 || dispid == -1, "Expected 51 or -1, got %ld\n", dispid);
591 dispid = get_dispid(pInstaller, "ProductsEx");
592 ok(dispid == 52 || dispid == -1, "Expected 52 or -1, got %ld\n", dispid);
593 dispid = get_dispid(pInstaller, "PatchesEx");
594 ok(dispid == 55 || dispid == -1, "Expected 55 or -1, got %ld\n", dispid);
595 dispid = get_dispid(pInstaller, "ExtractPatchXMLData");
596 ok(dispid == 57 || dispid == -1, "Expected 57 or -1, got %ld\n", dispid);
597 dispid = get_dispid( pInstaller, "ProductElevated" );
598 ok(dispid == 59 || dispid == -1, "Expected 59 or -1, got %ld\n", dispid);
599 dispid = get_dispid( pInstaller, "ProvideAssembly" );
600 ok(dispid == 60 || dispid == -1, "Expected 60 or -1, got %ld\n", dispid);
601 dispid = get_dispid( pInstaller, "ProductInfoFromScript" );
602 ok(dispid == 61 || dispid == -1, "Expected 61 or -1, got %ld\n", dispid);
603 dispid = get_dispid( pInstaller, "AdvertiseProduct" );
604 ok(dispid == 62 || dispid == -1, "Expected 62 or -1, got %ld\n", dispid);
605 dispid = get_dispid( pInstaller, "CreateAdvertiseScript" );
606 ok(dispid == 63 || dispid == -1, "Expected 63 or -1, got %ld\n", dispid);
607 dispid = get_dispid( pInstaller, "PatchFiles" );
608 ok(dispid == 65 || dispid == -1, "Expected 65 or -1, got %ld\n", dispid);
611 /* Test basic IDispatch functions */
612 static void test_dispatch(void)
614 HRESULT hr;
615 DISPID dispid;
616 OLECHAR *name;
617 VARIANT varresult;
618 VARIANTARG vararg[3];
619 WCHAR path[MAX_PATH];
620 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
622 /* Test getting ID of a function name that does not exist */
623 name = (WCHAR *)L"winetest-automation.msi";
624 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
625 ok(hr == DISP_E_UNKNOWNNAME, "IDispatch::GetIDsOfNames returned %#lx\n", hr);
627 /* Test invoking this function */
628 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
629 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned %#lx\n", hr);
631 /* Test getting ID of a function name that does exist */
632 name = (WCHAR *)L"OpenPackage";
633 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
634 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned %#lx\n", hr);
636 /* Test invoking this function (without parameters passed) */
637 if (0) /* All of these crash MSI on Windows XP */
639 IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
640 IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL);
641 VariantInit(&varresult);
642 IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, &varresult, &excepinfo, NULL);
645 /* Try with NULL params */
646 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
647 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned %#lx\n", hr);
649 /* Try one empty parameter */
650 dispparams.rgvarg = vararg;
651 dispparams.cArgs = 1;
652 VariantInit(&vararg[0]);
653 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
654 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned %#lx\n", hr);
656 /* Try two empty parameters */
657 dispparams.cArgs = 2;
658 VariantInit(&vararg[0]);
659 VariantInit(&vararg[1]);
660 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
661 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned %#lx\n", hr);
663 /* Try one parameter, the required BSTR. Second parameter is optional.
664 * NOTE: The specified package does not exist, which is why the call fails.
666 dispparams.cArgs = 1;
667 VariantInit(&vararg[0]);
668 V_VT(&vararg[0]) = VT_BSTR;
669 V_BSTR(&vararg[0]) = SysAllocString(L"winetest-automation.msi");
670 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
671 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned %#lx\n", hr);
672 ok_exception(hr, L"OpenPackage,PackagePath,Options");
673 VariantClear(&vararg[0]);
675 /* Provide the required BSTR and an empty second parameter.
676 * NOTE: The specified package does not exist, which is why the call fails.
678 dispparams.cArgs = 2;
679 VariantInit(&vararg[1]);
680 V_VT(&vararg[1]) = VT_BSTR;
681 V_BSTR(&vararg[1]) = SysAllocString(L"winetest-automation.msi");
682 VariantInit(&vararg[0]);
683 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
684 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned %#lx\n", hr);
685 ok_exception(hr, L"OpenPackage,PackagePath,Options");
686 VariantClear(&vararg[1]);
688 /* Provide the required BSTR and two empty parameters.
689 * NOTE: The specified package does not exist, which is why the call fails.
691 dispparams.cArgs = 3;
692 VariantInit(&vararg[2]);
693 V_VT(&vararg[2]) = VT_BSTR;
694 V_BSTR(&vararg[2]) = SysAllocString(L"winetest-automation.msi");
695 VariantInit(&vararg[1]);
696 VariantInit(&vararg[0]);
697 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
698 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned %#lx\n", hr);
699 ok_exception(hr, L"OpenPackage,PackagePath,Options");
700 VariantClear(&vararg[2]);
702 /* Provide the required BSTR and a second parameter with the wrong type. */
703 dispparams.cArgs = 2;
704 VariantInit(&vararg[1]);
705 V_VT(&vararg[1]) = VT_BSTR;
706 V_BSTR(&vararg[1]) = SysAllocString(L"winetest-automation.msi");
707 VariantInit(&vararg[0]);
708 V_VT(&vararg[0]) = VT_BSTR;
709 V_BSTR(&vararg[0]) = SysAllocString(L"winetest-automation.msi");
710 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
711 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned %#lx\n", hr);
712 VariantClear(&vararg[0]);
713 VariantClear(&vararg[1]);
715 /* Create a proper installer package. */
716 create_package(path);
718 /* Try one parameter, the required BSTR. Second parameter is optional.
719 * Proper installer package exists. Path to the package is relative.
721 dispparams.cArgs = 1;
722 VariantInit(&vararg[0]);
723 V_VT(&vararg[0]) = VT_BSTR;
724 V_BSTR(&vararg[0]) = SysAllocString(L"winetest-automation.msi");
725 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
726 todo_wine ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned %#lx\n", hr);
727 ok_exception(hr, L"OpenPackage,PackagePath,Options");
728 VariantClear(&vararg[0]);
729 if (hr != DISP_E_EXCEPTION)
730 VariantClear(&varresult);
732 /* Try one parameter, the required BSTR. Second parameter is optional.
733 * Proper installer package exists. Path to the package is absolute.
735 dispparams.cArgs = 1;
736 VariantInit(&vararg[0]);
737 V_VT(&vararg[0]) = VT_BSTR;
738 V_BSTR(&vararg[0]) = SysAllocString(path);
739 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
740 if (hr == DISP_E_EXCEPTION)
742 skip("OpenPackage failed, insufficient rights?\n");
743 DeleteFileW(path);
744 return;
746 ok(hr == S_OK, "IDispatch::Invoke returned %#lx\n", hr);
747 VariantClear(&vararg[0]);
748 VariantClear(&varresult);
750 /* Provide the required BSTR and an empty second parameter. Proper
751 * installation package exists.
753 dispparams.cArgs = 2;
754 VariantInit(&vararg[1]);
755 V_VT(&vararg[1]) = VT_BSTR;
756 V_BSTR(&vararg[1]) = SysAllocString(path);
757 VariantInit(&vararg[0]);
758 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
759 ok(hr == S_OK, "IDispatch::Invoke returned %#lx\n", hr);
760 VariantClear(&vararg[1]);
761 VariantClear(&varresult);
763 /* Provide the required BSTR and two empty parameters. Proper
764 * installation package exists.
766 dispparams.cArgs = 3;
767 VariantInit(&vararg[2]);
768 V_VT(&vararg[2]) = VT_BSTR;
769 V_BSTR(&vararg[2]) = SysAllocString(path);
770 VariantInit(&vararg[1]);
771 VariantInit(&vararg[0]);
772 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
773 ok(hr == S_OK, "IDispatch::Invoke returned %#lx\n", hr);
774 VariantClear(&vararg[2]);
775 VariantClear(&varresult);
777 /* Provide the required BSTR and a second parameter with the wrong type. */
778 dispparams.cArgs = 2;
779 VariantInit(&vararg[1]);
780 V_VT(&vararg[1]) = VT_BSTR;
781 V_BSTR(&vararg[1]) = SysAllocString(path);
782 VariantInit(&vararg[0]);
783 V_VT(&vararg[0]) = VT_BSTR;
784 V_BSTR(&vararg[0]) = SysAllocString(path);
785 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
786 ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned %#lx\n", hr);
787 VariantClear(&vararg[0]);
788 VariantClear(&vararg[1]);
790 /* Provide the required BSTR and a second parameter that can be coerced to
791 * VT_I4.
793 dispparams.cArgs = 2;
794 VariantInit(&vararg[1]);
795 V_VT(&vararg[1]) = VT_BSTR;
796 V_BSTR(&vararg[1]) = SysAllocString(path);
797 VariantInit(&vararg[0]);
798 V_VT(&vararg[0]) = VT_I2;
799 V_BSTR(&vararg[0]) = 0;
800 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
801 ok(hr == S_OK, "IDispatch::Invoke returned %#lx\n", hr);
802 VariantClear(&vararg[1]);
803 VariantClear(&varresult);
805 DeleteFileW(path);
807 /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
808 VariantInit(&vararg[0]);
809 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
810 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned %#lx\n", hr);
812 VariantInit(&vararg[0]);
813 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
814 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned %#lx\n", hr);
816 /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
817 name = (WCHAR *)L"ProductState";
818 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
819 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned %#lx\n", hr);
821 dispparams.rgvarg = NULL;
822 dispparams.cArgs = 0;
823 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
824 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned %#lx\n", hr);
826 dispparams.rgvarg = NULL;
827 dispparams.cArgs = 0;
828 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
829 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned %#lx\n", hr);
832 /* invocation helper function */
833 static int _invoke_todo_vtResult = 0;
835 static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult)
837 OLECHAR *name = NULL;
838 DISPID dispid;
839 HRESULT hr;
840 UINT i;
841 UINT len;
843 memset(pVarResult, 0, sizeof(VARIANT));
844 VariantInit(pVarResult);
846 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 );
847 name = malloc(len * sizeof(WCHAR));
848 if (!name) return E_FAIL;
849 MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len );
850 hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
851 free(name);
852 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned %#lx\n", hr);
853 if (hr != S_OK) return hr;
855 memset(&excepinfo, 0, sizeof(excepinfo));
856 hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL);
858 if (hr == S_OK)
860 todo_wine_if (_invoke_todo_vtResult)
861 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
862 if (vtResult != VT_EMPTY)
864 hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult);
865 ok(hr == S_OK, "VariantChangeTypeEx returned %#lx\n", hr);
869 for (i=0; i<pDispParams->cArgs; i++)
870 VariantClear(&pDispParams->rgvarg[i]);
872 return hr;
875 /* Object_Property helper functions */
877 static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord)
879 VARIANT varresult;
880 VARIANTARG vararg[1];
881 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
882 HRESULT hr;
884 VariantInit(&vararg[0]);
885 V_VT(&vararg[0]) = VT_I4;
886 V_I4(&vararg[0]) = count;
888 hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
889 *pRecord = V_DISPATCH(&varresult);
890 return hr;
893 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
895 VARIANTARG vararg[3];
896 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
898 VariantInit(&vararg[2]);
899 V_VT(&vararg[2]) = VT_I4;
900 V_I4(&vararg[2]) = (INT_PTR)hkey;
901 VariantInit(&vararg[1]);
902 V_VT(&vararg[1]) = VT_BSTR;
903 V_BSTR(&vararg[1]) = SysAllocString(szKey);
904 VariantInit(&vararg[0]);
905 VariantCopy(&vararg[0], &vValue);
906 VariantClear(&vValue);
908 return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect);
911 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
913 VARIANT varresult;
914 VARIANTARG vararg;
915 HRESULT hr;
917 VariantInit(&vararg);
918 V_VT(&vararg) = VT_EMPTY;
919 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL);
920 *pBool = V_BOOL(&varresult);
921 VariantClear(&varresult);
922 return hr;
925 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
927 VARIANT varresult;
928 VARIANTARG vararg;
929 HRESULT hr;
931 VariantInit(&vararg);
932 V_VT(&vararg) = VT_BSTR;
933 V_BSTR(&vararg) = SysAllocString(szValue);
935 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR);
936 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
937 VariantClear(&varresult);
938 return hr;
941 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
943 VARIANT varresult;
944 VARIANTARG vararg;
945 HRESULT hr;
947 VariantInit(&vararg);
948 V_VT(&vararg) = VT_I4;
949 V_I4(&vararg) = iValue;
951 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult);
952 if (SUCCEEDED(hr) && vtResult == VT_BSTR) lstrcpyW(szString, V_BSTR(&varresult));
953 VariantClear(&varresult);
954 return hr;
957 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
959 VARIANT varresult;
960 VARIANTARG vararg[2];
961 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
962 HRESULT hr;
964 VariantInit(&vararg[1]);
965 V_VT(&vararg[1]) = VT_BSTR;
966 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
967 VariantInit(&vararg[0]);
968 V_VT(&vararg[0]) = VT_I4;
969 V_I4(&vararg[0]) = options;
971 hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
972 *pSession = V_DISPATCH(&varresult);
973 return hr;
976 static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase)
978 VARIANT varresult;
979 VARIANTARG vararg[2];
980 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
981 HRESULT hr;
983 VariantInit(&vararg[1]);
984 V_VT(&vararg[1]) = VT_BSTR;
985 V_BSTR(&vararg[1]) = SysAllocString(szDatabasePath);
986 VariantInit(&vararg[0]);
987 V_VT(&vararg[0]) = VT_I4;
988 V_I4(&vararg[0]) = openmode;
990 hr = invoke(pInstaller, "OpenDatabase", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
991 *pDatabase = V_DISPATCH(&varresult);
992 return hr;
995 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
997 VARIANT varresult;
998 VARIANTARG vararg[2];
999 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1001 VariantInit(&vararg[1]);
1002 V_VT(&vararg[1]) = VT_BSTR;
1003 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
1004 VariantInit(&vararg[0]);
1005 V_VT(&vararg[0]) = VT_BSTR;
1006 V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues);
1008 return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1011 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
1013 VARIANT varresult;
1014 VARIANTARG vararg[1];
1015 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1016 HRESULT hr;
1018 VariantInit(&vararg[0]);
1019 V_VT(&vararg[0]) = VT_BSTR;
1020 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
1022 hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1023 *pInstallState = V_I4(&varresult);
1024 VariantClear(&varresult);
1025 return hr;
1028 static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szString)
1030 VARIANT varresult;
1031 VARIANTARG vararg[2];
1032 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1033 HRESULT hr;
1035 VariantInit(&vararg[1]);
1036 V_VT(&vararg[1]) = VT_BSTR;
1037 V_BSTR(&vararg[1]) = SysAllocString(szProduct);
1038 VariantInit(&vararg[0]);
1039 V_VT(&vararg[0]) = VT_BSTR;
1040 V_BSTR(&vararg[0]) = SysAllocString(szAttribute);
1042 hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1043 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1044 VariantClear(&varresult);
1045 return hr;
1048 static HRESULT Installer_Products(IDispatch **pStringList)
1050 VARIANT varresult;
1051 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1052 HRESULT hr;
1054 hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1055 *pStringList = V_DISPATCH(&varresult);
1056 return hr;
1059 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
1061 VARIANT varresult;
1062 VARIANTARG vararg[1];
1063 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1064 HRESULT hr;
1066 VariantInit(&vararg[0]);
1067 V_VT(&vararg[0]) = VT_BSTR;
1068 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
1070 hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1071 *pStringList = V_DISPATCH(&varresult);
1072 return hr;
1075 static HRESULT Installer_VersionGet(LPWSTR szVersion)
1077 VARIANT varresult;
1078 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1079 HRESULT hr;
1081 hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1082 if (V_BSTR(&varresult)) lstrcpyW(szVersion, V_BSTR(&varresult));
1083 VariantClear(&varresult);
1084 return hr;
1087 static HRESULT Installer_UILevelPut(int level)
1089 VARIANT varresult;
1090 VARIANTARG vararg;
1091 DISPID dispid = DISPID_PROPERTYPUT;
1092 DISPPARAMS dispparams = {&vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1094 VariantInit(&vararg);
1095 V_VT(&vararg) = VT_I4;
1096 V_I4(&vararg) = level;
1098 return invoke(pInstaller, "UILevel", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1101 static HRESULT Installer_SummaryInformation(BSTR PackagePath, int UpdateCount, IDispatch **pSumInfo)
1103 VARIANT varresult;
1104 VARIANTARG vararg[2];
1105 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1106 HRESULT hr;
1108 VariantInit(&vararg[1]);
1109 V_VT(&vararg[1]) = VT_BSTR;
1110 V_BSTR(&vararg[1]) = SysAllocString(PackagePath);
1111 VariantInit(&vararg[0]);
1112 V_VT(&vararg[0]) = VT_I4;
1113 V_I4(&vararg[0]) = UpdateCount;
1115 hr = invoke(pInstaller, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1116 *pSumInfo = V_DISPATCH(&varresult);
1117 return hr;
1120 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
1122 VARIANT varresult;
1123 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1124 HRESULT hr;
1126 hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1127 *pInst = V_DISPATCH(&varresult);
1128 return hr;
1131 static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn)
1133 VARIANT varresult;
1134 VARIANTARG vararg[1];
1135 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1136 HRESULT hr;
1138 VariantInit(&vararg[0]);
1139 V_VT(&vararg[0]) = VT_BSTR;
1140 V_BSTR(&vararg[0]) = SysAllocString(szName);
1142 hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1143 if (V_BSTR(&varresult)) lstrcpyW(szReturn, V_BSTR(&varresult));
1144 VariantClear(&varresult);
1145 return hr;
1148 static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue)
1150 VARIANT varresult;
1151 VARIANTARG vararg[2];
1152 DISPID dispid = DISPID_PROPERTYPUT;
1153 DISPPARAMS dispparams = {vararg, &dispid, ARRAY_SIZE(vararg), 1};
1155 VariantInit(&vararg[1]);
1156 V_VT(&vararg[1]) = VT_BSTR;
1157 V_BSTR(&vararg[1]) = SysAllocString(szName);
1158 VariantInit(&vararg[0]);
1159 V_VT(&vararg[0]) = VT_BSTR;
1160 V_BSTR(&vararg[0]) = SysAllocString(szValue);
1162 return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1165 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
1167 VARIANT varresult;
1168 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1169 HRESULT hr;
1171 hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1172 *pLangId = V_I4(&varresult);
1173 VariantClear(&varresult);
1174 return hr;
1177 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, VARIANT_BOOL *mode)
1179 VARIANT varresult;
1180 VARIANTARG vararg[1];
1181 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1182 HRESULT hr;
1184 VariantInit(&vararg[0]);
1185 V_VT(&vararg[0]) = VT_I4;
1186 V_I4(&vararg[0]) = iFlag;
1188 hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL);
1189 *mode = V_BOOL(&varresult);
1190 VariantClear(&varresult);
1191 return hr;
1194 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, VARIANT_BOOL mode)
1196 VARIANT varresult;
1197 VARIANTARG vararg[2];
1198 DISPID dispid = DISPID_PROPERTYPUT;
1199 DISPPARAMS dispparams = {vararg, &dispid, ARRAY_SIZE(vararg), 1};
1201 VariantInit(&vararg[1]);
1202 V_VT(&vararg[1]) = VT_I4;
1203 V_I4(&vararg[1]) = iFlag;
1204 VariantInit(&vararg[0]);
1205 V_VT(&vararg[0]) = VT_BOOL;
1206 V_BOOL(&vararg[0]) = mode;
1208 return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1211 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
1213 VARIANT varresult;
1214 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1215 HRESULT hr;
1217 hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1218 *pDatabase = V_DISPATCH(&varresult);
1219 return hr;
1222 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn)
1224 VARIANT varresult;
1225 VARIANTARG vararg[1];
1226 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1227 HRESULT hr;
1229 VariantInit(&vararg[0]);
1230 V_VT(&vararg[0]) = VT_BSTR;
1231 V_BSTR(&vararg[0]) = SysAllocString(szAction);
1233 hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1234 *iReturn = V_I4(&varresult);
1235 VariantClear(&varresult);
1236 return hr;
1239 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
1241 VARIANT varresult;
1242 VARIANTARG vararg[1];
1243 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1244 HRESULT hr;
1246 VariantInit(&vararg[0]);
1247 V_VT(&vararg[0]) = VT_BSTR;
1248 V_BSTR(&vararg[0]) = SysAllocString(szCondition);
1250 hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1251 *iReturn = V_I4(&varresult);
1252 VariantClear(&varresult);
1253 return hr;
1256 static HRESULT Session_Message(IDispatch *pSession, LONG kind, IDispatch *record, int *ret)
1258 VARIANT varresult;
1259 VARIANTARG vararg[2];
1260 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1261 HRESULT hr;
1263 VariantInit(&varresult);
1264 V_VT(vararg) = VT_DISPATCH;
1265 V_DISPATCH(vararg) = record;
1266 V_VT(vararg+1) = VT_I4;
1267 V_I4(vararg+1) = kind;
1269 hr = invoke(pSession, "Message", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1271 ok(V_VT(&varresult) == VT_I4, "V_VT(varresult) = %d\n", V_VT(&varresult));
1272 *ret = V_I4(&varresult);
1274 return hr;
1277 static HRESULT Session_SetInstallLevel(IDispatch *pSession, LONG iInstallLevel)
1279 VARIANT varresult;
1280 VARIANTARG vararg[1];
1281 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1283 VariantInit(&vararg[0]);
1284 V_VT(&vararg[0]) = VT_I4;
1285 V_I4(&vararg[0]) = iInstallLevel;
1287 return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1290 static HRESULT Session_FeatureCurrentState(IDispatch *pSession, LPCWSTR szName, int *pState)
1292 VARIANT varresult;
1293 VARIANTARG vararg[1];
1294 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1295 HRESULT hr;
1297 VariantInit(&vararg[0]);
1298 V_VT(&vararg[0]) = VT_BSTR;
1299 V_BSTR(&vararg[0]) = SysAllocString(szName);
1301 hr = invoke(pSession, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1302 *pState = V_I4(&varresult);
1303 VariantClear(&varresult);
1304 return hr;
1307 static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState)
1309 VARIANT varresult;
1310 VARIANTARG vararg[1];
1311 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1312 HRESULT hr;
1314 VariantInit(&vararg[0]);
1315 V_VT(&vararg[0]) = VT_BSTR;
1316 V_BSTR(&vararg[0]) = SysAllocString(szName);
1318 hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1319 *pState = V_I4(&varresult);
1320 VariantClear(&varresult);
1321 return hr;
1324 static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState)
1326 VARIANT varresult;
1327 VARIANTARG vararg[2];
1328 DISPID dispid = DISPID_PROPERTYPUT;
1329 DISPPARAMS dispparams = {vararg, &dispid, ARRAY_SIZE(vararg), 1};
1331 VariantInit(&vararg[1]);
1332 V_VT(&vararg[1]) = VT_BSTR;
1333 V_BSTR(&vararg[1]) = SysAllocString(szName);
1334 VariantInit(&vararg[0]);
1335 V_VT(&vararg[0]) = VT_I4;
1336 V_I4(&vararg[0]) = iState;
1338 return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1341 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
1343 VARIANT varresult;
1344 VARIANTARG vararg[1];
1345 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1346 HRESULT hr;
1348 VariantInit(&vararg[0]);
1349 V_VT(&vararg[0]) = VT_BSTR;
1350 V_BSTR(&vararg[0]) = SysAllocString(szSql);
1352 hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1353 *pView = V_DISPATCH(&varresult);
1354 return hr;
1357 static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo)
1359 VARIANT varresult;
1360 VARIANTARG vararg[1];
1361 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1362 HRESULT hr;
1364 VariantInit(&vararg[0]);
1365 V_VT(&vararg[0]) = VT_I4;
1366 V_I4(&vararg[0]) = iUpdateCount;
1368 hr = invoke(pDatabase, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1369 *pSummaryInfo = V_DISPATCH(&varresult);
1370 return hr;
1373 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
1375 VARIANT varresult;
1376 VARIANTARG vararg[1];
1377 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1379 VariantInit(&vararg[0]);
1380 V_VT(&vararg[0]) = VT_DISPATCH;
1381 V_DISPATCH(&vararg[0]) = pRecord;
1383 return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1386 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
1388 VARIANT varresult;
1389 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1390 HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1391 *ppRecord = V_DISPATCH(&varresult);
1392 return hr;
1395 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
1397 VARIANT varresult;
1398 VARIANTARG vararg[2];
1399 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1401 VariantInit(&vararg[1]);
1402 V_VT(&vararg[1]) = VT_I4;
1403 V_I4(&vararg[1]) = iMode;
1404 VariantInit(&vararg[0]);
1405 V_VT(&vararg[0]) = VT_DISPATCH;
1406 V_DISPATCH(&vararg[0]) = pRecord;
1407 if (pRecord)
1408 IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */
1410 return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1413 static HRESULT View_Close(IDispatch *pView)
1415 VARIANT varresult;
1416 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1417 return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1420 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
1422 VARIANT varresult;
1423 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1424 HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1425 *pFieldCount = V_I4(&varresult);
1426 VariantClear(&varresult);
1427 return hr;
1430 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString)
1432 VARIANT varresult;
1433 VARIANTARG vararg[1];
1434 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1435 HRESULT hr;
1437 VariantInit(&vararg[0]);
1438 V_VT(&vararg[0]) = VT_I4;
1439 V_I4(&vararg[0]) = iField;
1441 hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1442 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1443 VariantClear(&varresult);
1444 return hr;
1447 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
1449 VARIANT varresult;
1450 VARIANTARG vararg[2];
1451 DISPID dispid = DISPID_PROPERTYPUT;
1452 DISPPARAMS dispparams = {vararg, &dispid, ARRAY_SIZE(vararg), 1};
1454 VariantInit(&vararg[1]);
1455 V_VT(&vararg[1]) = VT_I4;
1456 V_I4(&vararg[1]) = iField;
1457 VariantInit(&vararg[0]);
1458 V_VT(&vararg[0]) = VT_BSTR;
1459 V_BSTR(&vararg[0]) = SysAllocString(szString);
1461 return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1464 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
1466 VARIANT varresult;
1467 VARIANTARG vararg[1];
1468 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1469 HRESULT hr;
1471 VariantInit(&vararg[0]);
1472 V_VT(&vararg[0]) = VT_I4;
1473 V_I4(&vararg[0]) = iField;
1475 hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1476 *pValue = V_I4(&varresult);
1477 VariantClear(&varresult);
1478 return hr;
1481 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
1483 VARIANT varresult;
1484 VARIANTARG vararg[2];
1485 DISPID dispid = DISPID_PROPERTYPUT;
1486 DISPPARAMS dispparams = {vararg, &dispid, ARRAY_SIZE(vararg), 1};
1488 VariantInit(&vararg[1]);
1489 V_VT(&vararg[1]) = VT_I4;
1490 V_I4(&vararg[1]) = iField;
1491 VariantInit(&vararg[0]);
1492 V_VT(&vararg[0]) = VT_I4;
1493 V_I4(&vararg[0]) = iValue;
1495 return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1498 static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT)
1500 VARIANT varresult;
1501 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1502 HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN);
1503 *ppEnumVARIANT = V_UNKNOWN(&varresult);
1504 return hr;
1507 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
1509 VARIANT varresult;
1510 VARIANTARG vararg[1];
1511 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1512 HRESULT hr;
1514 VariantInit(&vararg[0]);
1515 V_VT(&vararg[0]) = VT_I4;
1516 V_I4(&vararg[0]) = iIndex;
1518 hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1519 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1520 VariantClear(&varresult);
1521 return hr;
1524 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
1526 VARIANT varresult;
1527 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1528 HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1529 *pCount = V_I4(&varresult);
1530 VariantClear(&varresult);
1531 return hr;
1534 static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect)
1536 VARIANTARG vararg[1];
1537 DISPPARAMS dispparams = {vararg, NULL, ARRAY_SIZE(vararg), 0};
1539 VariantInit(&vararg[0]);
1540 V_VT(&vararg[0]) = VT_I4;
1541 V_I4(&vararg[0]) = pid;
1542 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYGET, &dispparams, pVarResult, vtExpect);
1545 static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant)
1547 VARIANT varresult;
1548 VARIANTARG vararg[2];
1549 DISPID dispid = DISPID_PROPERTYPUT;
1550 DISPPARAMS dispparams = {vararg, &dispid, ARRAY_SIZE(vararg), 1};
1552 VariantInit(&vararg[1]);
1553 V_VT(&vararg[1]) = VT_I4;
1554 V_I4(&vararg[1]) = pid;
1555 VariantInit(&vararg[0]);
1556 VariantCopyInd(vararg, pVariant);
1558 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1561 static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount)
1563 VARIANT varresult;
1564 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1565 HRESULT hr;
1567 hr = invoke(pSummaryInfo, "PropertyCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1568 *pCount = V_I4(&varresult);
1569 VariantClear(&varresult);
1570 return hr;
1573 /* Test the various objects */
1575 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4
1577 static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly)
1579 VARIANT varresult, var;
1580 SYSTEMTIME st;
1581 HRESULT hr;
1582 int j;
1584 /* SummaryInfo::PropertyCount */
1585 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1586 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult %#lx\n", hr);
1587 ok(j == num_info, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1589 /* SummaryInfo::Property, get for properties we have set */
1590 for (j = 0; j < num_info; j++)
1592 const msi_summary_info *entry = &info[j];
1594 int vt = entry->datatype;
1595 if (vt == VT_LPSTR) vt = VT_BSTR;
1596 else if (vt == VT_FILETIME) vt = VT_DATE;
1597 else if (vt == VT_I2) vt = VT_I4;
1599 hr = SummaryInfo_PropertyGet(pSummaryInfo, entry->property, &varresult, vt);
1600 ok(hr == S_OK, "SummaryInfo_Property (pid %d) failed, hresult %#lx\n", entry->property, hr);
1601 if (V_VT(&varresult) != vt)
1602 skip("Skipping property tests due to type mismatch\n");
1603 else if (vt == VT_I4)
1604 ok(V_I4(&varresult) == entry->iValue, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %ld\n",
1605 entry->property, entry->iValue, V_I4(&varresult));
1606 else if (vt == VT_DATE)
1608 FILETIME ft;
1609 DATE d;
1611 FileTimeToLocalFileTime(entry->pftValue, &ft);
1612 FileTimeToSystemTime(&ft, &st);
1613 SystemTimeToVariantTime(&st, &d);
1614 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));
1616 else if (vt == VT_BSTR)
1618 ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry->property, entry->szValue, V_BSTR(&varresult));
1620 else
1621 skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry->property, vt);
1623 VariantClear(&varresult);
1626 /* SummaryInfo::Property, get; invalid arguments */
1628 /* Invalid pids */
1629 hr = SummaryInfo_PropertyGet(pSummaryInfo, -1, &varresult, VT_EMPTY);
1630 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr);
1631 ok_exception(hr, L"Property,Pid");
1633 hr = SummaryInfo_PropertyGet(pSummaryInfo, 1000, &varresult, VT_EMPTY);
1634 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr);
1635 ok_exception(hr, L"Property,Pid");
1637 /* Unsupported pids */
1638 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_DICTIONARY, &varresult, VT_EMPTY);
1639 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr);
1641 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY);
1642 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr);
1644 /* Pids we have not set, one for each type */
1645 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_EMPTY);
1646 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr);
1648 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY);
1649 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr);
1651 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY);
1652 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr);
1654 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY);
1655 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr);
1657 if (!readonly)
1659 /* SummaryInfo::Property, put; one for each type */
1661 /* VT_I2 */
1662 VariantInit(&var);
1663 V_VT(&var) = VT_I2;
1664 V_I2(&var) = 1;
1665 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CODEPAGE, &var);
1666 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult %#lx\n", hr);
1668 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */);
1669 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr);
1670 ok(V_I2(&var) == V_I2(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var), V_I2(&varresult));
1671 VariantClear(&varresult);
1672 VariantClear(&var);
1674 /* VT_BSTR */
1675 V_VT(&var) = VT_BSTR;
1676 V_BSTR(&var) = SysAllocString(L"Title");
1677 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_TITLE, &var);
1678 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult %#lx\n", hr);
1680 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var));
1681 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr);
1682 ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var), V_BSTR(&varresult));
1683 VariantClear(&varresult);
1684 VariantClear(&var);
1686 /* VT_DATE */
1687 V_VT(&var) = VT_DATE;
1688 FileTimeToSystemTime(&systemtime, &st);
1689 SystemTimeToVariantTime(&st, &V_DATE(&var));
1690 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_LASTSAVE_DTM, &var);
1691 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult %#lx\n", hr);
1693 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var));
1694 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr);
1695 ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1696 VariantClear(&varresult);
1697 VariantClear(&var);
1699 /* VT_I4 */
1700 V_VT(&var) = VT_I4;
1701 V_I4(&var) = 1000;
1702 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1703 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult %#lx\n", hr);
1705 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1706 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult %#lx\n", hr);
1707 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %ld, but returned %ld\n", V_I4(&var), V_I4(&varresult));
1708 VariantClear(&varresult);
1709 VariantClear(&var);
1711 /* SummaryInfo::PropertyCount */
1712 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1713 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult %#lx\n", hr);
1714 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1718 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1720 IDispatch *pView = NULL, *pSummaryInfo = NULL;
1721 HRESULT hr;
1723 hr = Database_OpenView(pDatabase, L"SELECT `Feature` FROM `Feature` WHERE `Feature_Parent`='One'", &pView);
1724 ok(hr == S_OK, "Database_OpenView failed, hresult %#lx\n", hr);
1725 if (hr == S_OK)
1727 IDispatch *pRecord = NULL;
1728 WCHAR szString[MAX_PATH];
1730 /* View::Execute */
1731 hr = View_Execute(pView, NULL);
1732 ok(hr == S_OK, "View_Execute failed, hresult %#lx\n", hr);
1734 /* View::Fetch */
1735 hr = View_Fetch(pView, &pRecord);
1736 ok(hr == S_OK, "View_Fetch failed, hresult %#lx\n", hr);
1737 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1738 if (pRecord)
1740 /* Record::StringDataGet */
1741 memset(szString, 0, sizeof(szString));
1742 hr = Record_StringDataGet(pRecord, 1, szString);
1743 ok(hr == S_OK, "Record_StringDataGet failed, hresult %#lx\n", hr);
1744 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, L"Three");
1746 /* Record::StringDataPut with correct index */
1747 hr = Record_StringDataPut(pRecord, 1, L"Two");
1748 ok(hr == S_OK, "Record_StringDataPut failed, hresult %#lx\n", hr);
1750 /* Record::StringDataGet */
1751 memset(szString, 0, sizeof(szString));
1752 hr = Record_StringDataGet(pRecord, 1, szString);
1753 ok(hr == S_OK, "Record_StringDataGet failed, hresult %#lx\n", hr);
1754 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, L"Two");
1756 /* Record::StringDataPut with incorrect index */
1757 hr = Record_StringDataPut(pRecord, -1, szString);
1758 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult %#lx\n", hr);
1759 ok_exception(hr, L"StringData,Field");
1761 /* View::Modify with incorrect parameters */
1762 hr = View_Modify(pView, -5, NULL);
1763 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult %#lx\n", hr);
1764 ok_exception(hr, L"Modify,Mode,Record");
1766 hr = View_Modify(pView, -5, pRecord);
1767 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult %#lx\n", hr);
1768 ok_exception(hr, L"Modify,Mode,Record");
1770 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1771 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult %#lx\n", hr);
1772 ok_exception(hr, L"Modify,Mode,Record");
1774 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1775 ok(hr == S_OK, "View_Modify failed, hresult %#lx\n", hr);
1777 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1778 memset(szString, 0, sizeof(szString));
1779 hr = Record_StringDataGet(pRecord, 1, szString);
1780 ok(hr == S_OK, "Record_StringDataGet failed, hresult %#lx\n", hr);
1781 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, L"Three");
1783 IDispatch_Release(pRecord);
1786 /* View::Fetch */
1787 hr = View_Fetch(pView, &pRecord);
1788 ok(hr == S_OK, "View_Fetch failed, hresult %#lx\n", hr);
1789 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1790 if (pRecord)
1792 /* Record::StringDataGet */
1793 memset(szString, 0, sizeof(szString));
1794 hr = Record_StringDataGet(pRecord, 1, szString);
1795 ok(hr == S_OK, "Record_StringDataGet failed, hresult %#lx\n", hr);
1796 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, L"Two");
1798 IDispatch_Release(pRecord);
1801 /* View::Fetch */
1802 hr = View_Fetch(pView, &pRecord);
1803 ok(hr == S_OK, "View_Fetch failed, hresult %#lx\n", hr);
1804 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1805 if (pRecord)
1806 IDispatch_Release(pRecord);
1808 /* View::Close */
1809 hr = View_Close(pView);
1810 ok(hr == S_OK, "View_Close failed, hresult %#lx\n", hr);
1812 IDispatch_Release(pView);
1815 /* Database::SummaryInformation */
1816 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo);
1817 ok(hr == S_OK, "Database_SummaryInformation failed, hresult %#lx\n", hr);
1818 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1819 if (pSummaryInfo)
1821 test_SummaryInfo(pSummaryInfo, summary_info, ARRAY_SIZE(summary_info), readonly);
1822 IDispatch_Release(pSummaryInfo);
1826 static void test_Session(IDispatch *pSession)
1828 WCHAR stringw[MAX_PATH];
1829 CHAR string[MAX_PATH];
1830 UINT len;
1831 VARIANT_BOOL bool;
1832 int myint;
1833 IDispatch *pDatabase = NULL, *pInst = NULL, *record = NULL;
1834 ULONG refs_before, refs_after;
1835 HRESULT hr;
1837 /* Session::Installer */
1838 hr = Session_Installer(pSession, &pInst);
1839 ok(hr == S_OK, "Session_Installer failed, hresult %#lx\n", hr);
1840 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1841 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1842 refs_before = IDispatch_AddRef(pInst);
1844 hr = Session_Installer(pSession, &pInst);
1845 ok(hr == S_OK, "Session_Installer failed, hresult %#lx\n", hr);
1846 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1847 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1848 refs_after = IDispatch_Release(pInst);
1849 ok(refs_before == refs_after, "got %lu and %lu\n", refs_before, refs_after);
1851 /* Session::Property, get */
1852 memset(stringw, 0, sizeof(stringw));
1853 hr = Session_PropertyGet(pSession, L"ProductName", stringw);
1854 ok(hr == S_OK, "Session_PropertyGet failed, hresult %#lx\n", hr);
1855 if (lstrcmpW(stringw, L"MSITEST") != 0)
1857 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1858 ok(len, "WideCharToMultiByteChar returned error %lu\n", GetLastError());
1859 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1862 /* Session::Property, put */
1863 hr = Session_PropertyPut(pSession, L"ProductName", L"ProductName");
1864 ok(hr == S_OK, "Session_PropertyPut failed, hresult %#lx\n", hr);
1865 memset(stringw, 0, sizeof(stringw));
1866 hr = Session_PropertyGet(pSession, L"ProductName", stringw);
1867 ok(hr == S_OK, "Session_PropertyGet failed, hresult %#lx\n", hr);
1868 if (lstrcmpW(stringw, L"ProductName") != 0)
1870 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1871 ok(len, "WideCharToMultiByteChar returned error %lu\n", GetLastError());
1872 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1875 /* Try putting a property using empty property identifier */
1876 hr = Session_PropertyPut(pSession, L"", L"ProductName");
1877 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult %#lx\n", hr);
1878 ok_exception(hr, L"Property,Name");
1880 /* Try putting a property using illegal property identifier */
1881 hr = Session_PropertyPut(pSession, L"=", L"ProductName");
1882 ok(hr == S_OK, "Session_PropertyPut failed, hresult %#lx\n", hr);
1884 /* Session::Language, get */
1885 hr = Session_LanguageGet(pSession, &len);
1886 ok(hr == S_OK, "Session_LanguageGet failed, hresult %#lx\n", hr);
1887 /* Not sure how to check the language is correct */
1889 /* Session::Mode, get */
1890 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1891 ok(hr == S_OK, "Session_ModeGet failed, hresult %#lx\n", hr);
1892 ok(!bool, "Reboot at end session mode is %d\n", bool);
1894 hr = Session_ModeGet(pSession, MSIRUNMODE_MAINTENANCE, &bool);
1895 ok(hr == S_OK, "Session_ModeGet failed, hresult %#lx\n", hr);
1896 ok(!bool, "Maintenance mode is %d\n", bool);
1898 /* Session::Mode, put */
1899 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, VARIANT_TRUE);
1900 ok(hr == S_OK, "Session_ModePut failed, hresult %#lx\n", hr);
1901 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1902 ok(hr == S_OK, "Session_ModeGet failed, hresult %#lx\n", hr);
1903 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1904 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, VARIANT_FALSE); /* set it again so we don't reboot */
1905 ok(hr == S_OK, "Session_ModePut failed, hresult %#lx\n", hr);
1907 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, VARIANT_TRUE);
1908 ok(hr == S_OK, "Session_ModePut failed, hresult %#lx\n", hr);
1909 ok_exception(hr, L"Mode,Flag");
1911 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTNOW, &bool);
1912 ok(hr == S_OK, "Session_ModeGet failed, hresult %#lx\n", hr);
1913 ok(bool, "Reboot now mode is %d, expected 1\n", bool);
1915 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTNOW, VARIANT_FALSE); /* set it again so we don't reboot */
1916 ok(hr == S_OK, "Session_ModePut failed, hresult %#lx\n", hr);
1917 ok_exception(hr, L"Mode,Flag");
1919 hr = Session_ModePut(pSession, MSIRUNMODE_MAINTENANCE, VARIANT_TRUE);
1920 ok(hr == DISP_E_EXCEPTION, "Session_ModePut failed, hresult %#lx\n", hr);
1921 ok_exception(hr, L"Mode,Flag");
1923 /* Session::Database, get */
1924 hr = Session_Database(pSession, &pDatabase);
1925 ok(hr == S_OK, "Session_Database failed, hresult %#lx\n", hr);
1926 if (hr == S_OK)
1928 test_Database(pDatabase, TRUE);
1929 IDispatch_Release(pDatabase);
1932 /* Session::EvaluateCondition */
1933 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1934 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult %#lx\n", hr);
1935 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1937 hr = Session_EvaluateCondition(pSession, L"", &myint);
1938 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult %#lx\n", hr);
1939 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1941 hr = Session_EvaluateCondition(pSession, L"=", &myint);
1942 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult %#lx\n", hr);
1943 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1945 /* Session::DoAction(CostInitialize) must occur before the next statements */
1946 hr = Session_DoAction(pSession, L"CostInitialize", &myint);
1947 ok(hr == S_OK, "Session_DoAction failed, hresult %#lx\n", hr);
1948 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1950 /* Session::SetInstallLevel */
1951 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1952 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult %#lx\n", hr);
1954 /* Session::FeatureCurrentState, get */
1955 hr = Session_FeatureCurrentState(pSession, L"One", &myint);
1956 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult %#lx\n", hr);
1957 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1959 /* Session::Message */
1960 hr = Installer_CreateRecord(0, &record);
1961 ok(hr == S_OK, "Installer_CreateRecord failed: %#lx\n", hr);
1962 hr = Session_Message(pSession, INSTALLMESSAGE_INFO, record, &myint);
1963 ok(hr == S_OK, "Session_Message failed: %#lx\n", hr);
1964 ok(myint == 0, "Session_Message returned %x\n", myint);
1966 /* Session::EvaluateCondition */
1967 hr = Session_EvaluateCondition(pSession, L"!One>0", &myint);
1968 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult %#lx\n", hr);
1969 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1971 hr = Session_EvaluateCondition(pSession, L"!One=-1", &myint);
1972 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult %#lx\n", hr);
1973 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1975 /* Session::FeatureRequestState, put */
1976 hr = Session_FeatureRequestStatePut(pSession, L"One", INSTALLSTATE_ADVERTISED);
1977 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult %#lx\n", hr);
1978 hr = Session_FeatureRequestStateGet(pSession, L"One", &myint);
1979 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult %#lx\n", hr);
1980 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
1982 /* Session::EvaluateCondition */
1983 hr = Session_EvaluateCondition(pSession, L"$One=-1", &myint);
1984 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult %#lx\n", hr);
1985 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1987 hr = Session_EvaluateCondition(pSession, L"$One>0", &myint);
1988 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult %#lx\n", hr);
1989 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1992 /* delete key and all its subkeys */
1993 static DWORD delete_key( HKEY hkey )
1995 char name[MAX_PATH];
1996 DWORD ret;
1998 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
2000 HKEY tmp;
2001 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
2003 ret = delete_key( tmp );
2004 RegCloseKey( tmp );
2006 if (ret) break;
2008 if (ret != ERROR_NO_MORE_ITEMS) return ret;
2009 RegDeleteKeyA( hkey, "" );
2010 return 0;
2013 static void test_Installer_RegistryValue(void)
2015 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
2016 VARIANT varresult;
2017 VARIANTARG vararg;
2018 WCHAR szString[MAX_PATH];
2019 HKEY hkey, hkey_sub;
2020 HKEY curr_user = (HKEY)1;
2021 HRESULT hr;
2022 BOOL bRet;
2023 LONG lRet;
2025 /* Delete keys */
2026 SetLastError(0xdeadbeef);
2027 lRet = RegOpenKeyW( HKEY_CURRENT_USER, L"Software\\Wine\\Test", &hkey );
2028 if (!lRet && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2030 win_skip("Needed W-functions are not implemented\n");
2031 return;
2033 if (!lRet)
2034 delete_key( hkey );
2036 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
2037 hr = Installer_RegistryValueE(curr_user, L"Software\\Wine\\Test", &bRet);
2038 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult %#lx\n", hr);
2039 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
2041 memset(szString, 0, sizeof(szString));
2042 hr = Installer_RegistryValueW(curr_user, L"Software\\Wine\\Test", NULL, szString);
2043 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult %#lx\n", hr);
2045 memset(szString, 0, sizeof(szString));
2046 hr = Installer_RegistryValueI(curr_user, L"Software\\Wine\\Test", 0, szString, VT_BSTR);
2047 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult %#lx\n", hr);
2049 /* Create key */
2050 ok(!RegCreateKeyW( HKEY_CURRENT_USER, L"Software\\Wine\\Test", &hkey ), "RegCreateKeyW failed\n");
2052 ok(!RegSetValueExW(hkey, L"One", 0, REG_SZ, (const BYTE *)L"One", sizeof(L"one")),
2053 "RegSetValueExW failed\n");
2054 ok(!RegSetValueExW(hkey, L"Two", 0, REG_DWORD, (const BYTE *)qw, 4),
2055 "RegSetValueExW failed\n");
2056 ok(!RegSetValueExW(hkey, L"Three", 0, REG_BINARY, (const BYTE *)qw, 4),
2057 "RegSetValueExW failed\n");
2058 bRet = SetEnvironmentVariableA("MSITEST", "Four");
2059 ok(bRet, "SetEnvironmentVariableA failed %lu\n", GetLastError());
2060 ok(!RegSetValueExW(hkey, L"Four", 0, REG_EXPAND_SZ, (const BYTE *)L"%MSITEST%", sizeof(L"%MSITEST%")),
2061 "RegSetValueExW failed\n");
2062 ok(!RegSetValueExW(hkey, L"Five\0Hi\0", 0, REG_MULTI_SZ, (const BYTE *)L"Five\0Hi\0", sizeof(L"Five\0Hi\0")),
2063 "RegSetValueExW failed\n");
2064 ok(!RegSetValueExW(hkey, L"Six", 0, REG_QWORD, (const BYTE *)qw, 8),
2065 "RegSetValueExW failed\n");
2066 ok(!RegSetValueExW(hkey, L"Seven", 0, REG_NONE, NULL, 0),
2067 "RegSetValueExW failed\n");
2069 ok(!RegSetValueExW(hkey, NULL, 0, REG_SZ, (const BYTE *)L"One", sizeof(L"One")),
2070 "RegSetValueExW failed\n");
2072 ok(!RegCreateKeyW( hkey, L"Eight", &hkey_sub ), "RegCreateKeyW failed\n");
2074 /* Does our key exist? It should, and make sure we retrieve the correct default value */
2075 bRet = FALSE;
2076 hr = Installer_RegistryValueE(curr_user, L"Software\\Wine\\Test", &bRet);
2077 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult %#lx\n", hr);
2078 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
2080 memset(szString, 0, sizeof(szString));
2081 hr = Installer_RegistryValueW(curr_user, L"Software\\Wine\\Test", NULL, szString);
2082 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult %#lx\n", hr);
2083 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, L"One");
2085 /* Ask for the value of a nonexistent key */
2086 memset(szString, 0, sizeof(szString));
2087 hr = Installer_RegistryValueW(curr_user, L"Software\\Wine\\Test", L"%MSITEST%", szString);
2088 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult %#lx\n", hr);
2090 /* Get values of keys */
2091 memset(szString, 0, sizeof(szString));
2092 hr = Installer_RegistryValueW(curr_user, L"Software\\Wine\\Test", L"One", szString);
2093 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult %#lx\n", hr);
2094 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, L"One");
2096 VariantInit(&vararg);
2097 V_VT(&vararg) = VT_BSTR;
2098 V_BSTR(&vararg) = SysAllocString(L"Two");
2099 hr = Installer_RegistryValue(curr_user, L"Software\\Wine\\Test", vararg, &varresult, VT_I4);
2100 ok(hr == S_OK, "Installer_RegistryValue failed, hresult %#lx\n", hr);
2101 ok(V_I4(&varresult) == 305419896, "Registry value %ld does not match expected value\n", V_I4(&varresult));
2102 VariantClear(&varresult);
2104 memset(szString, 0, sizeof(szString));
2105 hr = Installer_RegistryValueW(curr_user, L"Software\\Wine\\Test", L"Three", szString);
2106 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult %#lx\n", hr);
2107 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, L"(REG_BINARY)");
2109 memset(szString, 0, sizeof(szString));
2110 hr = Installer_RegistryValueW(curr_user, L"Software\\Wine\\Test", L"Four", szString);
2111 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult %#lx\n", hr);
2112 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, L"Four");
2114 /* Vista does not NULL-terminate this case */
2115 memset(szString, 0, sizeof(szString));
2116 hr = Installer_RegistryValueW(curr_user, L"Software\\Wine\\Test", L"Five\0Hi\0", szString);
2117 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult %#lx\n", hr);
2118 ok_w2n("Registry value \"%s\" does not match expected \"%s\"\n",
2119 szString, L"Five\nHi", lstrlenW(L"Five\nHi"));
2121 memset(szString, 0, sizeof(szString));
2122 hr = Installer_RegistryValueW(curr_user, L"Software\\Wine\\Test", L"Six", szString);
2123 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult %#lx\n", hr);
2124 ok(!lstrcmpW(szString, L"(REG_\?\?)") || broken(!lstrcmpW(szString, L"(REG_]")),
2125 "Registry value does not match\n");
2127 VariantInit(&vararg);
2128 V_VT(&vararg) = VT_BSTR;
2129 V_BSTR(&vararg) = SysAllocString(L"Seven");
2130 hr = Installer_RegistryValue(curr_user, L"Software\\Wine\\Test", vararg, &varresult, VT_EMPTY);
2131 ok(hr == S_OK, "Installer_RegistryValue failed, hresult %#lx\n", hr);
2133 /* Get string class name for the key */
2134 memset(szString, 0, sizeof(szString));
2135 hr = Installer_RegistryValueI(curr_user, L"Software\\Wine\\Test", 0, szString, VT_BSTR);
2136 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult %#lx\n", hr);
2137 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, L"");
2139 /* Get name of a value by positive number (RegEnumValue like), valid index */
2140 memset(szString, 0, sizeof(szString));
2141 hr = Installer_RegistryValueI(curr_user, L"Software\\Wine\\Test", 2, szString, VT_BSTR);
2142 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult %#lx\n", hr);
2143 /* RegEnumValue order seems different on wine */
2144 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, L"Two");
2146 /* Get name of a value by positive number (RegEnumValue like), invalid index */
2147 memset(szString, 0, sizeof(szString));
2148 hr = Installer_RegistryValueI(curr_user, L"Software\\Wine\\Test", 10, szString, VT_EMPTY);
2149 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult %#lx\n", hr);
2151 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
2152 memset(szString, 0, sizeof(szString));
2153 hr = Installer_RegistryValueI(curr_user, L"Software\\Wine\\Test", -1, szString, VT_BSTR);
2154 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult %#lx\n", hr);
2155 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, L"Eight");
2157 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
2158 memset(szString, 0, sizeof(szString));
2159 hr = Installer_RegistryValueI(curr_user, L"Software\\Wine\\Test", -10, szString, VT_EMPTY);
2160 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult %#lx\n", hr);
2162 /* clean up */
2163 delete_key(hkey);
2166 static void test_Installer_Products(BOOL bProductInstalled)
2168 WCHAR szString[MAX_PATH];
2169 HRESULT hr;
2170 int idx;
2171 IUnknown *pUnk = NULL;
2172 IEnumVARIANT *pEnum = NULL;
2173 VARIANT var;
2174 ULONG celt;
2175 int iCount, iValue;
2176 IDispatch *pStringList = NULL;
2177 BOOL bProductFound = FALSE;
2179 /* Installer::Products */
2180 hr = Installer_Products(&pStringList);
2181 ok(hr == S_OK, "Installer_Products failed, hresult %#lx\n", hr);
2182 if (hr == S_OK)
2184 /* StringList::_NewEnum */
2185 hr = StringList__NewEnum(pStringList, &pUnk);
2186 ok(hr == S_OK, "StringList_NewEnum failed, hresult %#lx\n", hr);
2187 if (hr == S_OK)
2189 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
2190 ok (hr == S_OK, "IUnknown::QueryInterface returned %#lx\n", hr);
2192 if (!pEnum)
2193 skip("IEnumVARIANT tests\n");
2195 /* StringList::Count */
2196 hr = StringList_Count(pStringList, &iCount);
2197 ok(hr == S_OK, "StringList_Count failed, hresult %#lx\n", hr);
2199 for (idx=0; idx<iCount; idx++)
2201 /* StringList::Item */
2202 memset(szString, 0, sizeof(szString));
2203 hr = StringList_Item(pStringList, idx, szString);
2204 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult %#lx\n", idx, iCount, hr);
2206 if (hr == S_OK)
2208 /* Installer::ProductState */
2209 hr = Installer_ProductState(szString, &iValue);
2210 ok(hr == S_OK, "Installer_ProductState failed, hresult %#lx\n", hr);
2211 if (hr == S_OK)
2212 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED,
2213 "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
2215 /* Not found our product code yet? Check */
2216 if (!bProductFound && !lstrcmpW(szString, L"{837450fa-a39b-4bc8-b321-08b393f784b3}"))
2217 bProductFound = TRUE;
2219 /* IEnumVARIANT::Next */
2220 if (pEnum)
2222 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2223 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult %#lx\n", idx, iCount, hr);
2224 ok(celt == 1, "%lu items were retrieved, expected 1\n", celt);
2225 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2226 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2227 VariantClear(&var);
2232 if (bProductInstalled)
2234 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
2235 bProductInstalled ? "be" : "not be",
2236 bProductFound ? "found" : "not found");
2239 if (pEnum)
2241 IEnumVARIANT *pEnum2 = NULL;
2243 if (0) /* Crashes on Windows XP */
2245 /* IEnumVARIANT::Clone, NULL pointer */
2246 IEnumVARIANT_Clone(pEnum, NULL);
2249 /* IEnumVARIANT::Clone */
2250 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
2251 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult %#lx\n", hr);
2252 if (hr == S_OK)
2254 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
2256 /* IEnumVARIANT::Next of the clone */
2257 if (iCount)
2259 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
2260 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult %#lx\n", hr);
2261 ok(celt == 1, "%lu items were retrieved, expected 0\n", celt);
2262 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2263 VariantClear(&var);
2265 else
2266 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
2268 IEnumVARIANT_Release(pEnum2);
2271 /* IEnumVARIANT::Skip should fail */
2272 hr = IEnumVARIANT_Skip(pEnum, 1);
2273 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult %#lx\n", hr);
2275 /* IEnumVARIANT::Next, NULL variant pointer */
2276 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2277 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult %#lx\n", hr);
2278 ok(celt == 0, "%lu items were retrieved, expected 0\n", celt);
2280 /* IEnumVARIANT::Next, should not return any more items */
2281 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2282 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult %#lx\n", hr);
2283 ok(celt == 0, "%lu items were retrieved, expected 0\n", celt);
2284 VariantClear(&var);
2286 /* IEnumVARIANT::Reset */
2287 hr = IEnumVARIANT_Reset(pEnum);
2288 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult %#lx\n", hr);
2290 if (iCount)
2292 /* IEnumVARIANT::Skip to the last product */
2293 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2294 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult %#lx\n", hr);
2296 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2297 * NULL celt pointer. */
2298 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2299 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult %#lx\n", idx, iCount, hr);
2300 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2301 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2302 VariantClear(&var);
2304 else
2305 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2308 /* StringList::Item using an invalid index */
2309 memset(szString, 0, sizeof(szString));
2310 hr = StringList_Item(pStringList, iCount, szString);
2311 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult %#lx\n", hr);
2313 if (pEnum) IEnumVARIANT_Release(pEnum);
2314 if (pUnk) IUnknown_Release(pUnk);
2315 IDispatch_Release(pStringList);
2319 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2320 * deleting the subkeys first) */
2321 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey, REGSAM access)
2323 UINT ret;
2324 CHAR *string = NULL;
2325 HKEY hkey;
2326 DWORD dwSize;
2328 ret = RegOpenKeyExA(hkeyParent, subkey, 0, access, &hkey);
2329 if (ret != ERROR_SUCCESS) return ret;
2330 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2331 if (ret != ERROR_SUCCESS) return ret;
2332 if (!(string = malloc(++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2334 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2335 delete_registry_key(hkey, string, access);
2337 RegCloseKey(hkey);
2338 free(string);
2339 delete_key_portable(hkeyParent, subkey, access);
2340 return ERROR_SUCCESS;
2343 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2344 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, REGSAM access, HKEY *phkey)
2346 UINT ret;
2347 CHAR *string = NULL;
2348 int idx = 0;
2349 HKEY hkey;
2350 DWORD dwSize;
2351 BOOL found = FALSE;
2353 *phkey = 0;
2355 ret = RegOpenKeyExA(hkeyParent, subkey, 0, access, &hkey);
2356 if (ret != ERROR_SUCCESS) return ret;
2357 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2358 if (ret != ERROR_SUCCESS) return ret;
2359 if (!(string = malloc(++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2361 while (!found &&
2362 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2364 if (!strcmp(string, findkey))
2366 *phkey = hkey;
2367 found = TRUE;
2369 else if (find_registry_key(hkey, string, findkey, access, phkey) == ERROR_SUCCESS) found = TRUE;
2372 if (*phkey != hkey) RegCloseKey(hkey);
2373 free(string);
2374 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2377 static void test_Installer_InstallProduct(void)
2379 HRESULT hr;
2380 CHAR path[MAX_PATH];
2381 WCHAR szString[MAX_PATH];
2382 LONG res;
2383 HKEY hkey;
2384 DWORD num, size, type;
2385 int iValue, iCount;
2386 IDispatch *pStringList = NULL;
2387 REGSAM access = KEY_ALL_ACCESS;
2389 if (is_process_limited())
2391 /* In fact InstallProduct would succeed but then Windows XP
2392 * would not allow us to clean up the registry!
2394 skip("Installer_InstallProduct (insufficient privileges)\n");
2395 return;
2398 if (is_wow64)
2399 access |= KEY_WOW64_64KEY;
2401 create_test_files();
2403 /* Avoid an interactive dialog in case of insufficient privileges. */
2404 hr = Installer_UILevelPut(INSTALLUILEVEL_NONE);
2405 ok(hr == S_OK, "Expected UILevel property put invoke to return S_OK, got %#lx\n", hr);
2407 /* Installer::InstallProduct */
2408 hr = Installer_InstallProduct(L"winetest-automation.msi", NULL);
2409 if (hr == DISP_E_EXCEPTION)
2411 skip("InstallProduct failed, insufficient rights?\n");
2412 delete_test_files();
2413 return;
2415 ok(hr == S_OK, "Installer_InstallProduct failed, hresult %#lx\n", hr);
2417 /* Installer::ProductState for our product code, which has been installed */
2418 hr = Installer_ProductState(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", &iValue);
2419 ok(hr == S_OK, "Installer_ProductState failed, hresult %#lx\n", hr);
2420 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2422 /* Installer::ProductInfo for our product code */
2424 /* NULL attribute */
2425 memset(szString, 0, sizeof(szString));
2426 hr = Installer_ProductInfo(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", NULL, szString);
2427 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult %#lx\n", hr);
2428 ok_exception(hr, L"ProductInfo,Product,Attribute");
2430 /* Nonexistent attribute */
2431 memset(szString, 0, sizeof(szString));
2432 hr = Installer_ProductInfo(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", L"winetest-automation.msi", szString);
2433 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult %#lx\n", hr);
2434 ok_exception(hr, L"ProductInfo,Product,Attribute");
2436 /* Package name */
2437 memset(szString, 0, sizeof(szString));
2438 hr = Installer_ProductInfo(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", L"PackageName", szString);
2439 ok(hr == S_OK, "Installer_ProductInfo failed, hresult %#lx\n", hr);
2440 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, L"winetest-automation.msi");
2442 /* Product name */
2443 memset(szString, 0, sizeof(szString));
2444 hr = Installer_ProductInfo(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", L"ProductName", szString);
2445 ok(hr == S_OK, "Installer_ProductInfo failed, hresult %#lx\n", hr);
2446 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, L"MSITEST");
2448 /* Installer::Products */
2449 test_Installer_Products(TRUE);
2451 /* Installer::RelatedProducts for our upgrade code */
2452 hr = Installer_RelatedProducts(L"{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}", &pStringList);
2453 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult %#lx\n", hr);
2454 if (hr == S_OK)
2456 /* StringList::Count */
2457 hr = StringList_Count(pStringList, &iCount);
2458 ok(hr == S_OK, "StringList_Count failed, hresult %#lx\n", hr);
2459 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2461 /* StringList::Item */
2462 memset(szString, 0, sizeof(szString));
2463 hr = StringList_Item(pStringList, 0, szString);
2464 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult %#lx\n", iCount, hr);
2465 ok_w2("StringList_Item returned %s but expected %s\n", szString, L"{837450fa-a39b-4bc8-b321-08b393f784b3}");
2467 IDispatch_Release(pStringList);
2470 hr = Installer_ProductInfo(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", L"LocalPackage", szString);
2471 ok(hr == S_OK, "Installer_ProductInfo failed, hresult %#lx\n", hr);
2472 DeleteFileW( szString );
2474 /* Check & clean up installed files & registry keys */
2475 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2476 ok(delete_pf("msitest\\cabout\\new", FALSE), "Directory not created\n");
2477 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2478 ok(delete_pf("msitest\\cabout", FALSE), "Directory not created\n");
2479 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2480 ok(delete_pf("msitest\\changed", FALSE), "Directory not created\n");
2481 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2482 ok(delete_pf("msitest\\first", FALSE), "Directory not created\n");
2483 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2484 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2485 ok(delete_pf("msitest", FALSE), "Directory not created\n");
2487 res = RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest", &hkey);
2488 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2490 size = MAX_PATH;
2491 type = REG_SZ;
2492 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2493 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2494 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2496 size = MAX_PATH;
2497 type = REG_SZ;
2498 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2499 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %ld\n", res);
2501 size = sizeof(num);
2502 type = REG_DWORD;
2503 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2504 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2505 ok(num == 314, "Expected 314, got %lu\n", num);
2507 size = MAX_PATH;
2508 type = REG_SZ;
2509 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2510 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2511 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2513 RegCloseKey(hkey);
2515 res = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest");
2516 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2518 /* Remove registry keys written by RegisterProduct standard action */
2519 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2520 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{837450fa-a39b-4bc8-b321-08b393f784b3}",
2521 KEY_WOW64_32KEY);
2522 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2524 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2525 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656", access);
2526 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2528 res = find_registry_key(HKEY_LOCAL_MACHINE,
2529 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "af054738b93a8cb43b12803b397f483b", access, &hkey);
2530 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2532 res = delete_registry_key(hkey, "af054738b93a8cb43b12803b397f483b", access);
2533 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2534 RegCloseKey(hkey);
2536 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2537 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\af054738b93a8cb43b12803b397f483b", access);
2538 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %ld\n", res);
2540 /* Remove registry keys written by PublishProduct standard action */
2541 res = RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2542 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2544 res = delete_registry_key(hkey, "Products\\af054738b93a8cb43b12803b397f483b", KEY_ALL_ACCESS);
2545 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2547 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2548 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %ld\n", res);
2550 RegCloseKey(hkey);
2552 /* Delete installation files we created */
2553 delete_test_files();
2556 static void test_Installer(void)
2558 WCHAR szPath[MAX_PATH];
2559 HRESULT hr;
2560 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL, *pSumInfo = NULL;
2561 int iValue, iCount;
2563 if (!pInstaller) return;
2565 /* Installer::CreateRecord */
2567 /* Test for error */
2568 hr = Installer_CreateRecord(-1, &pRecord);
2569 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult %#lx\n", hr);
2570 ok_exception(hr, L"CreateRecord,Count");
2572 /* Test for success */
2573 hr = Installer_CreateRecord(1, &pRecord);
2574 ok(hr == S_OK, "Installer_CreateRecord failed, hresult %#lx\n", hr);
2575 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2576 if (pRecord)
2578 /* Record::FieldCountGet */
2579 hr = Record_FieldCountGet(pRecord, &iValue);
2580 ok(hr == S_OK, "Record_FiledCountGet failed, hresult %#lx\n", hr);
2581 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2583 /* Record::IntegerDataGet */
2584 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2585 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult %#lx\n", hr);
2586 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2588 /* Record::IntegerDataGet, bad index */
2589 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2590 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult %#lx\n", hr);
2591 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2593 /* Record::IntegerDataPut */
2594 hr = Record_IntegerDataPut(pRecord, 1, 100);
2595 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult %#lx\n", hr);
2597 /* Record::IntegerDataPut, bad index */
2598 hr = Record_IntegerDataPut(pRecord, 10, 100);
2599 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult %#lx\n", hr);
2600 ok_exception(hr, L"IntegerData,Field");
2602 /* Record::IntegerDataGet */
2603 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2604 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult %#lx\n", hr);
2605 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2607 IDispatch_Release(pRecord);
2610 create_package(szPath);
2612 /* Installer::OpenPackage */
2613 hr = Installer_OpenPackage(szPath, 0, &pSession);
2614 if (hr == DISP_E_EXCEPTION)
2616 skip("OpenPackage failed, insufficient rights?\n");
2617 DeleteFileW(szPath);
2618 return;
2620 ok(hr == S_OK, "Installer_OpenPackage failed, hresult %#lx\n", hr);
2621 if (hr == S_OK)
2623 test_Session(pSession);
2624 IDispatch_Release(pSession);
2627 /* Installer::OpenDatabase */
2628 hr = Installer_OpenDatabase(szPath, (INT_PTR)MSIDBOPEN_TRANSACT, &pDatabase);
2629 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult %#lx\n", hr);
2630 if (hr == S_OK)
2632 test_Database(pDatabase, FALSE);
2633 IDispatch_Release(pDatabase);
2636 /* Installer::SummaryInformation */
2637 hr = Installer_SummaryInformation(szPath, 0, &pSumInfo);
2638 ok(hr == S_OK, "Installer_SummaryInformation failed, hresult %#lx\n", hr);
2639 if (hr == S_OK)
2641 test_SummaryInfo(pSumInfo, summary_info, ARRAY_SIZE(summary_info), TRUE);
2642 IDispatch_Release(pSumInfo);
2645 hr = Installer_SummaryInformation(NULL, 0, &pSumInfo);
2646 ok(hr == DISP_E_EXCEPTION, "Installer_SummaryInformation failed, hresult %#lx\n", hr);
2648 /* Installer::RegistryValue */
2649 test_Installer_RegistryValue();
2651 /* Installer::ProductState for our product code, which should not be installed */
2652 hr = Installer_ProductState(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", &iValue);
2653 ok(hr == S_OK, "Installer_ProductState failed, hresult %#lx\n", hr);
2654 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2656 /* Installer::ProductInfo for our product code, which should not be installed */
2658 /* Package name */
2659 memset(szPath, 0, sizeof(szPath));
2660 hr = Installer_ProductInfo(L"{837450fa-a39b-4bc8-b321-08b393f784b3}", L"PackageName", szPath);
2661 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult %#lx\n", hr);
2662 ok_exception(hr, L"ProductInfo,Product,Attribute");
2664 /* NULL attribute and NULL product code */
2665 memset(szPath, 0, sizeof(szPath));
2666 hr = Installer_ProductInfo(NULL, NULL, szPath);
2667 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult %#lx\n", hr);
2668 ok_exception(hr, L"ProductInfo,Product,Attribute");
2670 /* Installer::Products */
2671 test_Installer_Products(FALSE);
2673 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2674 hr = Installer_RelatedProducts(L"{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}", &pStringList);
2675 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult %#lx\n", hr);
2676 if (hr == S_OK)
2678 /* StringList::Count */
2679 hr = StringList_Count(pStringList, &iCount);
2680 ok(hr == S_OK, "StringList_Count failed, hresult %#lx\n", hr);
2681 ok(!iCount, "Expected no related products but found %d\n", iCount);
2683 IDispatch_Release(pStringList);
2686 /* Installer::Version */
2687 memset(szPath, 0, sizeof(szPath));
2688 hr = Installer_VersionGet(szPath);
2689 ok(hr == S_OK, "Installer_VersionGet failed, hresult %#lx\n", hr);
2691 /* Installer::InstallProduct and other tests that depend on our product being installed */
2692 test_Installer_InstallProduct();
2693 DeleteFileA(msifile);
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);