Release 1.6-rc2.
[wine/testsucceed.git] / dlls / msi / tests / automation.c
blobc1c1d4ab4097d224749694ef8b19fe3367cc175a
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 szREG_2[] = { '(','R','E','G','_','?','?',')',0 };
2010 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
2011 static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
2012 static const WCHAR szBlank[] = { 0 };
2013 VARIANT varresult;
2014 VARIANTARG vararg;
2015 WCHAR szString[MAX_PATH];
2016 HKEY hkey, hkey_sub;
2017 HKEY curr_user = (HKEY)1;
2018 HRESULT hr;
2019 BOOL bRet;
2020 LONG lRet;
2022 /* Delete keys */
2023 SetLastError(0xdeadbeef);
2024 lRet = RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey );
2025 if (!lRet && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2027 win_skip("Needed W-functions are not implemented\n");
2028 return;
2030 if (!lRet)
2031 delete_key( hkey );
2033 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
2034 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
2035 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
2036 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
2038 memset(szString, 0, sizeof(szString));
2039 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
2040 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2042 memset(szString, 0, sizeof(szString));
2043 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
2044 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2046 /* Create key */
2047 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
2049 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
2050 "RegSetValueExW failed\n");
2051 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
2052 "RegSetValueExW failed\n");
2053 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
2054 "RegSetValueExW failed\n");
2055 bRet = SetEnvironmentVariableA("MSITEST", "Four");
2056 ok(bRet, "SetEnvironmentVariableA failed %d\n", GetLastError());
2057 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
2058 "RegSetValueExW failed\n");
2059 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
2060 "RegSetValueExW failed\n");
2061 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
2062 "RegSetValueExW failed\n");
2063 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, NULL, 0),
2064 "RegSetValueExW failed\n");
2066 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
2067 "RegSetValueExW failed\n");
2069 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
2071 /* Does our key exist? It should, and make sure we retrieve the correct default value */
2072 bRet = FALSE;
2073 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
2074 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
2075 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
2077 memset(szString, 0, sizeof(szString));
2078 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
2079 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2080 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
2082 /* Ask for the value of a nonexistent key */
2083 memset(szString, 0, sizeof(szString));
2084 hr = Installer_RegistryValueW(curr_user, szKey, szExpand, szString);
2085 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2087 /* Get values of keys */
2088 memset(szString, 0, sizeof(szString));
2089 hr = Installer_RegistryValueW(curr_user, szKey, szOne, szString);
2090 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2091 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
2093 VariantInit(&vararg);
2094 V_VT(&vararg) = VT_BSTR;
2095 V_BSTR(&vararg) = SysAllocString(szTwo);
2096 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_I4);
2097 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
2098 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
2099 VariantClear(&varresult);
2101 memset(szString, 0, sizeof(szString));
2102 hr = Installer_RegistryValueW(curr_user, szKey, szThree, szString);
2103 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2104 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
2106 memset(szString, 0, sizeof(szString));
2107 hr = Installer_RegistryValueW(curr_user, szKey, szFour, szString);
2108 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2109 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
2111 /* Vista does not NULL-terminate this case */
2112 memset(szString, 0, sizeof(szString));
2113 hr = Installer_RegistryValueW(curr_user, szKey, szFive, szString);
2114 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2115 ok_w2n("Registry value \"%s\" does not match expected \"%s\"\n",
2116 szString, szFiveHi, lstrlenW(szFiveHi));
2118 memset(szString, 0, sizeof(szString));
2119 hr = Installer_RegistryValueW(curr_user, szKey, szSix, szString);
2120 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
2121 ok(!lstrcmpW(szString, szREG_2) || broken(!lstrcmpW(szString, szREG_)),
2122 "Registry value does not match\n");
2124 VariantInit(&vararg);
2125 V_VT(&vararg) = VT_BSTR;
2126 V_BSTR(&vararg) = SysAllocString(szSeven);
2127 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_EMPTY);
2128 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
2130 /* Get string class name for the key */
2131 memset(szString, 0, sizeof(szString));
2132 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
2133 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2134 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank);
2136 /* Get name of a value by positive number (RegEnumValue like), valid index */
2137 memset(szString, 0, sizeof(szString));
2138 hr = Installer_RegistryValueI(curr_user, szKey, 2, szString, VT_BSTR);
2139 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2140 /* RegEnumValue order seems different on wine */
2141 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
2143 /* Get name of a value by positive number (RegEnumValue like), invalid index */
2144 memset(szString, 0, sizeof(szString));
2145 hr = Installer_RegistryValueI(curr_user, szKey, 10, szString, VT_EMPTY);
2146 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2148 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
2149 memset(szString, 0, sizeof(szString));
2150 hr = Installer_RegistryValueI(curr_user, szKey, -1, szString, VT_BSTR);
2151 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2152 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
2154 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
2155 memset(szString, 0, sizeof(szString));
2156 hr = Installer_RegistryValueI(curr_user, szKey, -10, szString, VT_EMPTY);
2157 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
2159 /* clean up */
2160 delete_key(hkey);
2163 static void test_Installer_Products(BOOL bProductInstalled)
2165 WCHAR szString[MAX_PATH];
2166 HRESULT hr;
2167 int idx;
2168 IUnknown *pUnk = NULL;
2169 IEnumVARIANT *pEnum = NULL;
2170 VARIANT var;
2171 ULONG celt;
2172 int iCount, iValue;
2173 IDispatch *pStringList = NULL;
2174 BOOL bProductFound = FALSE;
2176 /* Installer::Products */
2177 hr = Installer_Products(&pStringList);
2178 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
2179 if (hr == S_OK)
2181 /* StringList::_NewEnum */
2182 hr = StringList__NewEnum(pStringList, &pUnk);
2183 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
2184 if (hr == S_OK)
2186 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
2187 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2189 if (!pEnum)
2190 skip("IEnumVARIANT tests\n");
2192 /* StringList::Count */
2193 hr = StringList_Count(pStringList, &iCount);
2194 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2196 for (idx=0; idx<iCount; idx++)
2198 /* StringList::Item */
2199 memset(szString, 0, sizeof(szString));
2200 hr = StringList_Item(pStringList, idx, szString);
2201 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2203 if (hr == S_OK)
2205 /* Installer::ProductState */
2206 hr = Installer_ProductState(szString, &iValue);
2207 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2208 if (hr == S_OK)
2209 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
2211 /* Not found our product code yet? Check */
2212 if (!bProductFound && !lstrcmpW(szString, szProductCode))
2213 bProductFound = TRUE;
2215 /* IEnumVARIANT::Next */
2216 if (pEnum)
2218 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2219 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2220 ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
2221 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2222 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2223 VariantClear(&var);
2228 if (bProductInstalled)
2230 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
2231 bProductInstalled ? "be" : "not be",
2232 bProductFound ? "found" : "not found");
2235 if (pEnum)
2237 IEnumVARIANT *pEnum2 = NULL;
2239 if (0) /* Crashes on Windows XP */
2241 /* IEnumVARIANT::Clone, NULL pointer */
2242 IEnumVARIANT_Clone(pEnum, NULL);
2245 /* IEnumVARIANT::Clone */
2246 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
2247 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
2248 if (hr == S_OK)
2250 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
2252 /* IEnumVARIANT::Next of the clone */
2253 if (iCount)
2255 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
2256 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2257 ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
2258 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2259 VariantClear(&var);
2261 else
2262 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
2264 IEnumVARIANT_Release(pEnum2);
2267 /* IEnumVARIANT::Skip should fail */
2268 hr = IEnumVARIANT_Skip(pEnum, 1);
2269 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2271 /* IEnumVARIANT::Next, NULL variant pointer */
2272 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2273 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2274 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2276 /* IEnumVARIANT::Next, should not return any more items */
2277 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2278 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2279 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2280 VariantClear(&var);
2282 /* IEnumVARIANT::Reset */
2283 hr = IEnumVARIANT_Reset(pEnum);
2284 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2286 if (iCount)
2288 /* IEnumVARIANT::Skip to the last product */
2289 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2290 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2292 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2293 * NULL celt pointer. */
2294 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2295 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2296 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2297 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2298 VariantClear(&var);
2300 else
2301 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2304 /* StringList::Item using an invalid index */
2305 memset(szString, 0, sizeof(szString));
2306 hr = StringList_Item(pStringList, iCount, szString);
2307 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2309 if (pEnum) IEnumVARIANT_Release(pEnum);
2310 if (pUnk) IUnknown_Release(pUnk);
2311 IDispatch_Release(pStringList);
2315 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2316 * deleting the subkeys first) */
2317 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey, REGSAM access)
2319 UINT ret;
2320 CHAR *string = NULL;
2321 HKEY hkey;
2322 DWORD dwSize;
2324 ret = RegOpenKeyEx(hkeyParent, subkey, 0, access, &hkey);
2325 if (ret != ERROR_SUCCESS) return ret;
2326 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2327 if (ret != ERROR_SUCCESS) return ret;
2328 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2330 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2331 delete_registry_key(hkey, string, access);
2333 RegCloseKey(hkey);
2334 HeapFree(GetProcessHeap(), 0, string);
2335 delete_key_portable(hkeyParent, subkey, access);
2336 return ERROR_SUCCESS;
2339 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2340 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, REGSAM access, HKEY *phkey)
2342 UINT ret;
2343 CHAR *string = NULL;
2344 int idx = 0;
2345 HKEY hkey;
2346 DWORD dwSize;
2347 BOOL found = FALSE;
2349 *phkey = 0;
2351 ret = RegOpenKeyEx(hkeyParent, subkey, 0, access, &hkey);
2352 if (ret != ERROR_SUCCESS) return ret;
2353 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2354 if (ret != ERROR_SUCCESS) return ret;
2355 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2357 while (!found &&
2358 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2360 if (!strcmp(string, findkey))
2362 *phkey = hkey;
2363 found = TRUE;
2365 else if (find_registry_key(hkey, string, findkey, access, phkey) == ERROR_SUCCESS) found = TRUE;
2368 if (*phkey != hkey) RegCloseKey(hkey);
2369 HeapFree(GetProcessHeap(), 0, string);
2370 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2373 static void test_Installer_InstallProduct(void)
2375 HRESULT hr;
2376 CHAR path[MAX_PATH];
2377 WCHAR szString[MAX_PATH];
2378 LONG res;
2379 HKEY hkey;
2380 DWORD num, size, type;
2381 int iValue, iCount;
2382 IDispatch *pStringList = NULL;
2383 REGSAM access = KEY_ALL_ACCESS;
2385 if (is_wow64)
2386 access |= KEY_WOW64_64KEY;
2388 create_test_files();
2390 /* Avoid an interactive dialog in case of insufficient privileges. */
2391 hr = Installer_UILevelPut(INSTALLUILEVEL_NONE);
2392 ok(hr == S_OK, "Expected UILevel property put invoke to return S_OK, got 0x%08x\n", hr);
2394 /* Installer::InstallProduct */
2395 hr = Installer_InstallProduct(szMsifile, NULL);
2396 if (hr == DISP_E_EXCEPTION)
2398 skip("InstallProduct failed, insufficient rights?\n");
2399 delete_test_files();
2400 return;
2402 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2404 /* Installer::ProductState for our product code, which has been installed */
2405 hr = Installer_ProductState(szProductCode, &iValue);
2406 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2407 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2409 /* Installer::ProductInfo for our product code */
2411 /* NULL attribute */
2412 memset(szString, 0, sizeof(szString));
2413 hr = Installer_ProductInfo(szProductCode, NULL, szString);
2414 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2415 ok_exception(hr, szProductInfoException);
2417 /* Nonexistent attribute */
2418 memset(szString, 0, sizeof(szString));
2419 hr = Installer_ProductInfo(szProductCode, szMsifile, szString);
2420 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2421 ok_exception(hr, szProductInfoException);
2423 /* Package name */
2424 memset(szString, 0, sizeof(szString));
2425 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szString);
2426 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2427 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile);
2429 /* Product name */
2430 memset(szString, 0, sizeof(szString));
2431 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PRODUCTNAMEW, szString);
2432 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2433 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST);
2435 /* Installer::Products */
2436 test_Installer_Products(TRUE);
2438 /* Installer::RelatedProducts for our upgrade code */
2439 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2440 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2441 if (hr == S_OK)
2443 /* StringList::Count */
2444 hr = StringList_Count(pStringList, &iCount);
2445 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2446 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2448 /* StringList::Item */
2449 memset(szString, 0, sizeof(szString));
2450 hr = StringList_Item(pStringList, 0, szString);
2451 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2452 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
2454 IDispatch_Release(pStringList);
2457 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_LOCALPACKAGEW, szString);
2458 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2459 DeleteFileW( szString );
2461 /* Check & clean up installed files & registry keys */
2462 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2463 ok(delete_pf("msitest\\cabout\\new", FALSE), "Directory not created\n");
2464 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2465 ok(delete_pf("msitest\\cabout", FALSE), "Directory not created\n");
2466 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2467 ok(delete_pf("msitest\\changed", FALSE), "Directory not created\n");
2468 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2469 ok(delete_pf("msitest\\first", FALSE), "Directory not created\n");
2470 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2471 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2472 ok(delete_pf("msitest", FALSE), "Directory not created\n");
2474 res = RegOpenKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest", &hkey);
2475 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2477 size = MAX_PATH;
2478 type = REG_SZ;
2479 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2480 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2481 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2483 size = MAX_PATH;
2484 type = REG_SZ;
2485 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2486 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2488 size = sizeof(num);
2489 type = REG_DWORD;
2490 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2491 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2492 ok(num == 314, "Expected 314, got %d\n", num);
2494 size = MAX_PATH;
2495 type = REG_SZ;
2496 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2497 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2498 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2500 RegCloseKey(hkey);
2502 res = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Wine\\msitest");
2503 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2505 /* Remove registry keys written by RegisterProduct standard action */
2506 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2507 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{837450fa-a39b-4bc8-b321-08b393f784b3}",
2508 KEY_WOW64_32KEY);
2509 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2511 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2512 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656", access);
2513 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2515 res = find_registry_key(HKEY_LOCAL_MACHINE,
2516 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "af054738b93a8cb43b12803b397f483b", access, &hkey);
2517 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2519 res = delete_registry_key(hkey, "af054738b93a8cb43b12803b397f483b", access);
2520 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2521 RegCloseKey(hkey);
2523 res = delete_key_portable(HKEY_LOCAL_MACHINE,
2524 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\af054738b93a8cb43b12803b397f483b", access);
2525 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2527 /* Remove registry keys written by PublishProduct standard action */
2528 res = RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2529 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2531 res = delete_registry_key(hkey, "Products\\af054738b93a8cb43b12803b397f483b", KEY_ALL_ACCESS);
2532 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2534 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2535 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2537 RegCloseKey(hkey);
2539 /* Delete installation files we created */
2540 delete_test_files();
2543 static void test_Installer(void)
2545 static WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
2546 static WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
2547 WCHAR szPath[MAX_PATH];
2548 HRESULT hr;
2549 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL;
2550 int iValue, iCount;
2552 if (!pInstaller) return;
2554 /* Installer::CreateRecord */
2556 /* Test for error */
2557 hr = Installer_CreateRecord(-1, &pRecord);
2558 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2559 ok_exception(hr, szCreateRecordException);
2561 /* Test for success */
2562 hr = Installer_CreateRecord(1, &pRecord);
2563 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2564 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2565 if (pRecord)
2567 /* Record::FieldCountGet */
2568 hr = Record_FieldCountGet(pRecord, &iValue);
2569 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2570 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2572 /* Record::IntegerDataGet */
2573 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2574 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2575 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2577 /* Record::IntegerDataGet, bad index */
2578 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2579 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2580 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2582 /* Record::IntegerDataPut */
2583 hr = Record_IntegerDataPut(pRecord, 1, 100);
2584 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2586 /* Record::IntegerDataPut, bad index */
2587 hr = Record_IntegerDataPut(pRecord, 10, 100);
2588 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2589 ok_exception(hr, szIntegerDataException);
2591 /* Record::IntegerDataGet */
2592 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2593 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2594 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2596 IDispatch_Release(pRecord);
2599 create_package(szPath);
2601 /* Installer::OpenPackage */
2602 hr = Installer_OpenPackage(szPath, 0, &pSession);
2603 if (hr == DISP_E_EXCEPTION)
2605 skip("OpenPackage failed, insufficient rights?\n");
2606 DeleteFileW(szPath);
2607 return;
2609 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2610 if (hr == S_OK)
2612 test_Session(pSession);
2613 IDispatch_Release(pSession);
2616 /* Installer::OpenDatabase */
2617 hr = Installer_OpenDatabase(szPath, (INT_PTR)MSIDBOPEN_TRANSACT, &pDatabase);
2618 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2619 if (hr == S_OK)
2621 test_Database(pDatabase, FALSE);
2622 IDispatch_Release(pDatabase);
2625 /* Installer::RegistryValue */
2626 test_Installer_RegistryValue();
2628 /* Installer::ProductState for our product code, which should not be installed */
2629 hr = Installer_ProductState(szProductCode, &iValue);
2630 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2631 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2633 /* Installer::ProductInfo for our product code, which should not be installed */
2635 /* Package name */
2636 memset(szPath, 0, sizeof(szPath));
2637 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szPath);
2638 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2639 ok_exception(hr, szProductInfoException);
2641 /* NULL attribute and NULL product code */
2642 memset(szPath, 0, sizeof(szPath));
2643 hr = Installer_ProductInfo(NULL, NULL, szPath);
2644 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2645 ok_exception(hr, szProductInfoException);
2647 /* Installer::Products */
2648 test_Installer_Products(FALSE);
2650 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2651 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2652 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2653 if (hr == S_OK)
2655 /* StringList::Count */
2656 hr = StringList_Count(pStringList, &iCount);
2657 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2658 ok(!iCount, "Expected no related products but found %d\n", iCount);
2660 IDispatch_Release(pStringList);
2663 /* Installer::Version */
2664 memset(szPath, 0, sizeof(szPath));
2665 hr = Installer_VersionGet(szPath);
2666 ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr);
2668 /* Installer::InstallProduct and other tests that depend on our product being installed */
2669 test_Installer_InstallProduct();
2672 START_TEST(automation)
2674 DWORD len;
2675 char temp_path[MAX_PATH], prev_path[MAX_PATH];
2676 HRESULT hr;
2677 CLSID clsid;
2678 IUnknown *pUnk;
2680 init_functionpointers();
2682 if (pIsWow64Process)
2683 pIsWow64Process(GetCurrentProcess(), &is_wow64);
2685 GetSystemTimeAsFileTime(&systemtime);
2687 GetCurrentDirectoryA(MAX_PATH, prev_path);
2688 GetTempPath(MAX_PATH, temp_path);
2689 SetCurrentDirectoryA(temp_path);
2691 lstrcpyA(CURR_DIR, temp_path);
2692 len = lstrlenA(CURR_DIR);
2694 if(len && (CURR_DIR[len - 1] == '\\'))
2695 CURR_DIR[len - 1] = 0;
2697 get_program_files_dir(PROG_FILES_DIR);
2699 hr = OleInitialize(NULL);
2700 ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr);
2701 hr = CLSIDFromProgID(szProgId, &clsid);
2702 ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr);
2703 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2704 ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr);
2706 if (pUnk)
2708 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2709 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2711 test_dispid();
2712 test_dispatch();
2713 test_Installer();
2715 IDispatch_Release(pInstaller);
2716 IUnknown_Release(pUnk);
2719 OleUninitialize();
2721 SetCurrentDirectoryA(prev_path);