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