push c6bab2db4fc296bd36abf8f7d9cf443d4a73048e
[wine/hacks.git] / dlls / msi / tests / automation.c
blob88ce287ae26171a451bc2d98024b5fe2952d4455
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 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
37 static const char *msifile = "winetest.msi";
38 static const WCHAR szMsifile[] = {'w','i','n','e','t','e','s','t','.','m','s','i',0};
39 static const WCHAR szMSITEST[] = { 'M','S','I','T','E','S','T',0 };
40 static const WCHAR szProductCode[] = { '{','F','1','C','3','A','F','5','0','-','8','B','5','6','-','4','A','6','9','-','A','0','0','C','-','0','0','7','7','3','F','E','4','2','F','3','0','}',0 };
41 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 };
42 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 };
43 static const WCHAR WINE_INSTALLPROPERTY_PACKAGENAMEW[] = {'P','a','c','k','a','g','e','N','a','m','e',0};
44 static const WCHAR WINE_INSTALLPROPERTY_PRODUCTNAMEW[] = {'P','r','o','d','u','c','t','N','a','m','e',0};
45 static FILETIME systemtime;
46 static CHAR CURR_DIR[MAX_PATH];
47 static EXCEPINFO excepinfo;
50 * OLE automation data
51 **/
52 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 };
53 static IDispatch *pInstaller;
55 /* msi database data */
57 static const CHAR component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
58 "s72\tS38\ts72\ti2\tS255\tS72\n"
59 "Component\tComponent\n"
60 "Five\t{8CC92E9D-14B2-4CA4-B2AA-B11D02078087}\tNEWDIR\t2\t\tfive.txt\n"
61 "Four\t{FD37B4EA-7209-45C0-8917-535F35A2F080}\tCABOUTDIR\t2\t\tfour.txt\n"
62 "One\t{783B242E-E185-4A56-AF86-C09815EC053C}\tMSITESTDIR\t2\t\tone.txt\n"
63 "Three\t{010B6ADD-B27D-4EDD-9B3D-34C4F7D61684}\tCHANGEDDIR\t2\t\tthree.txt\n"
64 "Two\t{BF03D1A6-20DA-4A65-82F3-6CAC995915CE}\tFIRSTDIR\t2\t\ttwo.txt\n"
65 "dangler\t{6091DF25-EF96-45F1-B8E9-A9B1420C7A3C}\tTARGETDIR\t4\t\tregdata\n"
66 "component\t\tMSITESTDIR\t0\t1\tfile\n";
68 static const CHAR directory_dat[] = "Directory\tDirectory_Parent\tDefaultDir\n"
69 "s72\tS72\tl255\n"
70 "Directory\tDirectory\n"
71 "CABOUTDIR\tMSITESTDIR\tcabout\n"
72 "CHANGEDDIR\tMSITESTDIR\tchanged:second\n"
73 "FIRSTDIR\tMSITESTDIR\tfirst\n"
74 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
75 "NEWDIR\tCABOUTDIR\tnew\n"
76 "ProgramFilesFolder\tTARGETDIR\t.\n"
77 "TARGETDIR\t\tSourceDir";
79 static const CHAR feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
80 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
81 "Feature\tFeature\n"
82 "Five\t\tFive\tThe Five Feature\t5\t3\tNEWDIR\t0\n"
83 "Four\t\tFour\tThe Four Feature\t4\t3\tCABOUTDIR\t0\n"
84 "One\t\tOne\tThe One Feature\t1\t3\tMSITESTDIR\t0\n"
85 "Three\tOne\tThree\tThe Three Feature\t3\t3\tCHANGEDDIR\t0\n"
86 "Two\tOne\tTwo\tThe Two Feature\t2\t3\tFIRSTDIR\t0\n"
87 "feature\t\t\t\t2\t1\tTARGETDIR\t0\n";
89 static const CHAR feature_comp_dat[] = "Feature_\tComponent_\n"
90 "s38\ts72\n"
91 "FeatureComponents\tFeature_\tComponent_\n"
92 "Five\tFive\n"
93 "Four\tFour\n"
94 "One\tOne\n"
95 "Three\tThree\n"
96 "Two\tTwo\n"
97 "feature\tcomponent\n";
99 static const CHAR file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
100 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
101 "File\tFile\n"
102 "five.txt\tFive\tfive.txt\t1000\t\t\t0\t5\n"
103 "four.txt\tFour\tfour.txt\t1000\t\t\t0\t4\n"
104 "one.txt\tOne\tone.txt\t1000\t\t\t0\t1\n"
105 "three.txt\tThree\tthree.txt\t1000\t\t\t0\t3\n"
106 "two.txt\tTwo\ttwo.txt\t1000\t\t\t0\t2\n"
107 "file\tcomponent\tfilename\t100\t\t\t8192\t1\n";
109 static const CHAR install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
110 "s72\tS255\tI2\n"
111 "InstallExecuteSequence\tAction\n"
112 "AllocateRegistrySpace\tNOT Installed\t1550\n"
113 "CostFinalize\t\t1000\n"
114 "CostInitialize\t\t800\n"
115 "FileCost\t\t900\n"
116 "InstallFiles\t\t4000\n"
117 "RegisterProduct\t\t6100\n"
118 "PublishProduct\t\t6400\n"
119 "InstallFinalize\t\t6600\n"
120 "InstallInitialize\t\t1500\n"
121 "InstallValidate\t\t1400\n"
122 "LaunchConditions\t\t100\n"
123 "WriteRegistryValues\tSourceDir And SOURCEDIR\t5000";
125 static const CHAR media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
126 "i2\ti4\tL64\tS255\tS32\tS72\n"
127 "Media\tDiskId\n"
128 "1\t5\t\t\tDISK1\t\n";
130 static const CHAR property_dat[] = "Property\tValue\n"
131 "s72\tl0\n"
132 "Property\tProperty\n"
133 "DefaultUIFont\tDlgFont8\n"
134 "HASUIRUN\t0\n"
135 "INSTALLLEVEL\t3\n"
136 "InstallMode\tTypical\n"
137 "Manufacturer\tWine\n"
138 "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n"
139 "ProductCode\t{F1C3AF50-8B56-4A69-A00C-00773FE42F30}\n"
140 "ProductID\tnone\n"
141 "ProductLanguage\t1033\n"
142 "ProductName\tMSITEST\n"
143 "ProductVersion\t1.1.1\n"
144 "PROMPTROLLBACKCOST\tP\n"
145 "Setup\tSetup\n"
146 "UpgradeCode\t{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}";
148 static const CHAR registry_dat[] = "Registry\tRoot\tKey\tName\tValue\tComponent_\n"
149 "s72\ti2\tl255\tL255\tL0\ts72\n"
150 "Registry\tRegistry\n"
151 "Apples\t2\tSOFTWARE\\Wine\\msitest\tName\timaname\tOne\n"
152 "Oranges\t2\tSOFTWARE\\Wine\\msitest\tnumber\t#314\tTwo\n"
153 "regdata\t2\tSOFTWARE\\Wine\\msitest\tblah\tbad\tdangler\n"
154 "OrderTest\t2\tSOFTWARE\\Wine\\msitest\tOrderTestName\tOrderTestValue\tcomponent";
156 typedef struct _msi_table
158 const CHAR *filename;
159 const CHAR *data;
160 int size;
161 } msi_table;
163 #define ADD_TABLE(x) {#x".idt", x##_dat, sizeof(x##_dat)}
165 static const msi_table tables[] =
167 ADD_TABLE(component),
168 ADD_TABLE(directory),
169 ADD_TABLE(feature),
170 ADD_TABLE(feature_comp),
171 ADD_TABLE(file),
172 ADD_TABLE(install_exec_seq),
173 ADD_TABLE(media),
174 ADD_TABLE(property),
175 ADD_TABLE(registry)
178 typedef struct _msi_summary_info
180 UINT property;
181 UINT datatype;
182 INT iValue;
183 FILETIME *pftValue;
184 const CHAR *szValue;
185 } msi_summary_info;
187 #define ADD_INFO_I2(property, iValue) {property, VT_I2, iValue, NULL, NULL}
188 #define ADD_INFO_I4(property, iValue) {property, VT_I4, iValue, NULL, NULL}
189 #define ADD_INFO_LPSTR(property, szValue) {property, VT_LPSTR, 0, NULL, szValue}
190 #define ADD_INFO_FILETIME(property, pftValue) {property, VT_FILETIME, 0, pftValue, NULL}
192 static const msi_summary_info summary_info[] =
194 ADD_INFO_LPSTR(PID_TEMPLATE, ";1033"),
195 ADD_INFO_LPSTR(PID_REVNUMBER, "{004757CA-5092-49c2-AD20-28E1CE0DF5F2}"),
196 ADD_INFO_I4(PID_PAGECOUNT, 100),
197 ADD_INFO_I4(PID_WORDCOUNT, 0),
198 ADD_INFO_FILETIME(PID_CREATE_DTM, &systemtime),
199 ADD_INFO_FILETIME(PID_LASTPRINTED, &systemtime)
203 * Database Helpers
206 static void write_file(const CHAR *filename, const char *data, int data_size)
208 DWORD size;
210 HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL,
211 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
213 WriteFile(hf, data, data_size, &size, NULL);
214 CloseHandle(hf);
217 static void write_msi_summary_info(MSIHANDLE db, const msi_summary_info *info, int num_info)
219 MSIHANDLE summary;
220 UINT r;
221 int j;
223 r = MsiGetSummaryInformationA(db, NULL, num_info, &summary);
224 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
226 /* import summary information into the stream */
227 for (j = 0; j < num_info; j++)
229 const msi_summary_info *entry = &info[j];
231 r = MsiSummaryInfoSetPropertyA(summary, entry->property, entry->datatype,
232 entry->iValue, entry->pftValue, entry->szValue);
233 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
236 /* write the summary changes back to the stream */
237 r = MsiSummaryInfoPersist(summary);
238 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
240 MsiCloseHandle(summary);
243 static void create_database(const CHAR *name, const msi_table *tables, int num_tables,
244 const msi_summary_info *info, int num_info)
246 MSIHANDLE db;
247 UINT r;
248 int j;
250 r = MsiOpenDatabaseA(name, MSIDBOPEN_CREATE, &db);
251 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
253 /* import the tables into the database */
254 for (j = 0; j < num_tables; j++)
256 const msi_table *table = &tables[j];
258 write_file(table->filename, table->data, (table->size - 1) * sizeof(char));
260 r = MsiDatabaseImportA(db, CURR_DIR, table->filename);
261 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
263 DeleteFileA(table->filename);
266 write_msi_summary_info(db, info, num_info);
268 r = MsiDatabaseCommit(db);
269 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
271 MsiCloseHandle(db);
275 * Installation helpers
278 static char PROG_FILES_DIR[MAX_PATH];
280 static BOOL get_program_files_dir(LPSTR buf)
282 HKEY hkey;
283 DWORD type = REG_EXPAND_SZ, size;
285 if (RegOpenKey(HKEY_LOCAL_MACHINE,
286 "Software\\Microsoft\\Windows\\CurrentVersion", &hkey))
287 return FALSE;
289 size = MAX_PATH;
290 if (RegQueryValueEx(hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size))
291 return FALSE;
293 RegCloseKey(hkey);
294 return TRUE;
297 static void create_file(const CHAR *name, DWORD size)
299 HANDLE file;
300 DWORD written, left;
302 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
303 ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
304 WriteFile(file, name, strlen(name), &written, NULL);
305 WriteFile(file, "\n", strlen("\n"), &written, NULL);
307 left = size - lstrlen(name) - 1;
309 SetFilePointer(file, left, NULL, FILE_CURRENT);
310 SetEndOfFile(file);
312 CloseHandle(file);
315 static void create_test_files(void)
317 CreateDirectoryA("msitest", NULL);
318 create_file("msitest\\one.txt", 100);
319 CreateDirectoryA("msitest\\first", NULL);
320 create_file("msitest\\first\\two.txt", 100);
321 CreateDirectoryA("msitest\\second", NULL);
322 create_file("msitest\\second\\three.txt", 100);
323 CreateDirectoryA("msitest\\cabout",NULL);
324 create_file("msitest\\cabout\\four.txt", 100);
325 CreateDirectoryA("msitest\\cabout\\new",NULL);
326 create_file("msitest\\cabout\\new\\five.txt", 100);
327 create_file("msitest\\filename", 100);
330 static BOOL delete_pf(const CHAR *rel_path, BOOL is_file)
332 CHAR path[MAX_PATH];
334 lstrcpyA(path, PROG_FILES_DIR);
335 lstrcatA(path, "\\");
336 lstrcatA(path, rel_path);
338 if (is_file)
339 return DeleteFileA(path);
340 else
341 return RemoveDirectoryA(path);
344 static void delete_test_files(void)
346 DeleteFileA(msifile);
347 DeleteFileA("msitest\\cabout\\new\\five.txt");
348 DeleteFileA("msitest\\cabout\\four.txt");
349 DeleteFileA("msitest\\second\\three.txt");
350 DeleteFileA("msitest\\first\\two.txt");
351 DeleteFileA("msitest\\one.txt");
352 DeleteFileA("msitest\\filename");
353 RemoveDirectoryA("msitest\\cabout\\new");
354 RemoveDirectoryA("msitest\\cabout");
355 RemoveDirectoryA("msitest\\second");
356 RemoveDirectoryA("msitest\\first");
357 RemoveDirectoryA("msitest");
361 * Automation helpers and tests
364 /* ok-like statement which takes two unicode strings or one unicode and one ANSI string as arguments */
365 static CHAR string1[MAX_PATH], string2[MAX_PATH];
367 #define ok_w2(format, szString1, szString2) \
369 if (lstrcmpW(szString1, szString2) != 0) \
371 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
372 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
373 ok(0, format, string1, string2); \
376 #define ok_w2n(format, szString1, szString2, len) \
378 if (memcmp(szString1, szString2, len * sizeof(WCHAR)) != 0) \
380 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
381 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
382 ok(0, format, string1, string2); \
385 #define ok_aw(format, aString, wString) \
387 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
388 if (lstrcmpA(string1, aString) != 0) \
389 ok(0, format, string1, aString); \
391 #define ok_awplus(format, extra, aString, wString) \
393 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
394 if (lstrcmpA(string1, aString) != 0) \
395 ok(0, format, extra, string1, aString); \
397 /* exception checker */
398 static WCHAR szSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
400 #define ok_exception(hr, szDescription) \
401 if (hr == DISP_E_EXCEPTION) \
403 /* Compare wtype, source, and destination */ \
404 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
406 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
407 if (excepinfo.bstrSource) \
408 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, szSource); \
410 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
411 if (excepinfo.bstrDescription) \
412 ok_w2("Exception description was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrDescription, szDescription); \
414 SysFreeString(excepinfo.bstrSource); \
415 SysFreeString(excepinfo.bstrDescription); \
416 SysFreeString(excepinfo.bstrHelpFile); \
419 static DISPID get_dispid( IDispatch *disp, const char *name )
421 LPOLESTR str;
422 UINT len;
423 DISPID id = -1;
424 HRESULT r;
426 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
427 str = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
428 if (str)
430 len = MultiByteToWideChar(CP_ACP, 0, name, -1, str, len );
431 r = IDispatch_GetIDsOfNames( disp, &IID_NULL, &str, 1, 0, &id );
432 HeapFree(GetProcessHeap(), 0, str);
433 if (r != S_OK)
434 return -1;
437 return id;
440 static void test_dispid(void)
442 DISPID dispid;
444 dispid = get_dispid(pInstaller, "CreateRecord");
445 ok(dispid == 1, "Expected 1, got %d\n", dispid);
446 dispid = get_dispid(pInstaller, "OpenPackage");
447 ok(dispid == 2, "Expected 2, got %d\n", dispid);
448 dispid = get_dispid(pInstaller, "OpenDatabase");
449 ok(dispid == 4, "Expected 4, got %d\n", dispid);
450 dispid = get_dispid( pInstaller, "UILevel" );
451 ok(dispid == 6, "Expected 6, got %d\n", dispid);
452 dispid = get_dispid(pInstaller, "InstallProduct");
453 ok(dispid == 8, "Expected 8, got %d\n", dispid);
454 dispid = get_dispid(pInstaller, "Version");
455 ok(dispid == 9, "Expected 9, got %d\n", dispid);
456 dispid = get_dispid(pInstaller, "RegistryValue");
457 ok(dispid == 11, "Expected 11, got %d\n", dispid);
458 todo_wine
460 dispid = get_dispid(pInstaller, "OpenProduct");
461 ok(dispid == 3, "Expected 3, got %d\n", dispid);
462 dispid = get_dispid(pInstaller, "SummaryInformation");
463 ok(dispid == 5, "Expected 5, got %d\n", dispid);
464 dispid = get_dispid(pInstaller, "EnableLog");
465 ok(dispid == 7, "Expected 7, got %d\n", dispid);
466 dispid = get_dispid(pInstaller, "LastErrorRecord");
467 ok(dispid == 10, "Expected 10, got %d\n", dispid);
468 dispid = get_dispid(pInstaller, "Environment");
469 ok(dispid == 12, "Expected 12, got %d\n", dispid);
470 dispid = get_dispid(pInstaller, "FileAttributes");
471 ok(dispid == 13, "Expected 13, got %d\n", dispid);
472 dispid = get_dispid(pInstaller, "FileSize");
473 ok(dispid == 15, "Expected 15, got %d\n", dispid);
474 dispid = get_dispid(pInstaller, "FileVersion");
475 ok(dispid == 16, "Expected 16, got %d\n", dispid);
477 dispid = get_dispid(pInstaller, "ProductState");
478 ok(dispid == 17, "Expected 17, got %d\n", dispid);
479 dispid = get_dispid(pInstaller, "ProductInfo");
480 ok(dispid == 18, "Expected 18, got %d\n", dispid);
481 todo_wine
483 dispid = get_dispid(pInstaller, "ConfigureProduct");
484 ok(dispid == 19, "Expected 19, got %d\n", dispid);
485 dispid = get_dispid(pInstaller, "ReinstallProduct");
486 ok(dispid == 20 , "Expected 20, got %d\n", dispid);
487 dispid = get_dispid(pInstaller, "CollectUserInfo");
488 ok(dispid == 21, "Expected 21, got %d\n", dispid);
489 dispid = get_dispid(pInstaller, "ApplyPatch");
490 ok(dispid == 22, "Expected 22, got %d\n", dispid);
491 dispid = get_dispid(pInstaller, "FeatureParent");
492 ok(dispid == 23, "Expected 23, got %d\n", dispid);
493 dispid = get_dispid(pInstaller, "FeatureState");
494 ok(dispid == 24, "Expected 24, got %d\n", dispid);
495 dispid = get_dispid(pInstaller, "UseFeature");
496 ok(dispid == 25, "Expected 25, got %d\n", dispid);
497 dispid = get_dispid(pInstaller, "FeatureUsageCount");
498 ok(dispid == 26, "Expected 26, got %d\n", dispid);
499 dispid = get_dispid(pInstaller, "FeatureUsageDate");
500 ok(dispid == 27, "Expected 27, got %d\n", dispid);
501 dispid = get_dispid(pInstaller, "ConfigureFeature");
502 ok(dispid == 28, "Expected 28, got %d\n", dispid);
503 dispid = get_dispid(pInstaller, "ReinstallFeature");
504 ok(dispid == 29, "Expected 29, got %d\n", dispid);
505 dispid = get_dispid(pInstaller, "ProvideComponent");
506 ok(dispid == 30, "Expected 30, got %d\n", dispid);
507 dispid = get_dispid(pInstaller, "ComponentPath");
508 ok(dispid == 31, "Expected 31, got %d\n", dispid);
509 dispid = get_dispid(pInstaller, "ProvideQualifiedComponent");
510 ok(dispid == 32, "Expected 32, got %d\n", dispid);
511 dispid = get_dispid(pInstaller, "QualifierDescription");
512 ok(dispid == 33, "Expected 33, got %d\n", dispid);
513 dispid = get_dispid(pInstaller, "ComponentQualifiers");
514 ok(dispid == 34, "Expected 34, got %d\n", dispid);
516 dispid = get_dispid(pInstaller, "Products");
517 ok(dispid == 35, "Expected 35, got %d\n", dispid);
518 todo_wine
520 dispid = get_dispid(pInstaller, "Features");
521 ok(dispid == 36, "Expected 36, got %d\n", dispid);
522 dispid = get_dispid(pInstaller, "Components");
523 ok(dispid == 37, "Expected 37, got %d\n", dispid);
524 dispid = get_dispid(pInstaller, "ComponentClients");
525 ok(dispid == 38, "Expected 38, got %d\n", dispid);
526 dispid = get_dispid(pInstaller, "Patches");
527 ok(dispid == 39, "Expected 39, got %d\n", dispid);
529 dispid = get_dispid(pInstaller, "RelatedProducts");
530 ok(dispid == 40, "Expected 40, got %d\n", dispid);
531 todo_wine
533 dispid = get_dispid(pInstaller, "PatchInfo");
534 ok(dispid == 41, "Expected 41, got %d\n", dispid);
535 dispid = get_dispid(pInstaller, "PatchTransforms");
536 ok(dispid == 42, "Expected 42, got %d\n", dispid);
537 dispid = get_dispid(pInstaller, "AddSource");
538 ok(dispid == 43, "Expected 43, got %d\n", dispid);
539 dispid = get_dispid(pInstaller, "ClearSourceList");
540 ok(dispid == 44, "Expected 44, got %d\n", dispid);
541 dispid = get_dispid(pInstaller, "ForceSourceListResolution");
542 ok(dispid == 45, "Expected 45, got %d\n", dispid);
543 dispid = get_dispid(pInstaller, "ShortcutTarget");
544 ok(dispid == 46, "Expected 46, got %d\n", dispid);
545 dispid = get_dispid(pInstaller, "FileHash");
546 ok(dispid == 47, "Expected 47, got %d\n", dispid);
547 dispid = get_dispid(pInstaller, "FileSignatureInfo");
548 ok(dispid == 48, "Expected 48, got %d\n", dispid);
550 dispid = get_dispid(pInstaller, "RemovePatches");
551 ok(dispid == 49 || dispid == -1, "Expected 49 or -1, got %d\n", dispid);
552 dispid = get_dispid(pInstaller, "ApplyMultiplePatches");
553 ok(dispid == 51 || dispid == -1, "Expected 51 or -1, got %d\n", dispid);
554 dispid = get_dispid(pInstaller, "ProductsEx");
555 ok(dispid == 52 || dispid == -1, "Expected 52 or -1, got %d\n", dispid);
556 dispid = get_dispid(pInstaller, "PatchesEx");
557 ok(dispid == 55 || dispid == -1, "Expected 55 or -1, got %d\n", dispid);
558 dispid = get_dispid(pInstaller, "ExtractPatchXMLData");
559 ok(dispid == 57 || dispid == -1, "Expected 57 or -1, got %d\n", dispid);
560 dispid = get_dispid( pInstaller, "ProductElevated" );
561 ok(dispid == 59 || dispid == -1, "Expected 59 or -1, got %d\n", dispid);
562 dispid = get_dispid( pInstaller, "ProvideAssembly" );
563 ok(dispid == 60 || dispid == -1, "Expected 60 or -1, got %d\n", dispid);
564 dispid = get_dispid( pInstaller, "ProductInfoFromScript" );
565 ok(dispid == 61 || dispid == -1, "Expected 61 or -1, got %d\n", dispid);
566 dispid = get_dispid( pInstaller, "AdvertiseProduct" );
567 ok(dispid == 62 || dispid == -1, "Expected 62 or -1, got %d\n", dispid);
568 dispid = get_dispid( pInstaller, "CreateAdvertiseScript" );
569 ok(dispid == 63 || dispid == -1, "Expected 63 or -1, got %d\n", dispid);
570 dispid = get_dispid( pInstaller, "PatchFiles" );
571 ok(dispid == 65 || dispid == -1, "Expected 65 or -1, got %d\n", dispid);
574 /* Test basic IDispatch functions */
575 static void test_dispatch(void)
577 static WCHAR szOpenPackage[] = { 'O','p','e','n','P','a','c','k','a','g','e',0 };
578 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};
579 static WCHAR szProductState[] = { 'P','r','o','d','u','c','t','S','t','a','t','e',0 };
580 HRESULT hr;
581 DISPID dispid;
582 OLECHAR *name;
583 VARIANT varresult;
584 VARIANTARG vararg[2];
585 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
587 /* Test getting ID of a function name that does not exist */
588 name = (WCHAR *)szMsifile;
589 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
590 ok(hr == DISP_E_UNKNOWNNAME, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
592 /* Test invoking this function */
593 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
594 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
596 /* Test getting ID of a function name that does exist */
597 name = szOpenPackage;
598 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
599 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
601 /* Test invoking this function (without parameters passed) */
602 if (0) /* All of these crash MSI on Windows XP */
604 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
605 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL);
606 VariantInit(&varresult);
607 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, &varresult, &excepinfo, NULL);
610 /* Try with NULL params */
611 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
612 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
614 /* Try one empty parameter */
615 dispparams.rgvarg = vararg;
616 dispparams.cArgs = 1;
617 VariantInit(&vararg[0]);
618 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
619 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
621 /* Try one parameter, function requires two */
622 VariantInit(&vararg[0]);
623 V_VT(&vararg[0]) = VT_BSTR;
624 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
625 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
626 VariantClear(&vararg[0]);
628 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
629 ok_exception(hr, szOpenPackageException);
631 /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
632 VariantInit(&vararg[0]);
633 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
634 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
636 VariantInit(&vararg[0]);
637 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
638 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
640 /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
641 name = szProductState;
642 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
643 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
645 dispparams.rgvarg = NULL;
646 dispparams.cArgs = 0;
647 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
648 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
650 dispparams.rgvarg = NULL;
651 dispparams.cArgs = 0;
652 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
653 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
656 /* invocation helper function */
657 static int _invoke_todo_vtResult = 0;
659 static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult)
661 OLECHAR *name = NULL;
662 DISPID dispid;
663 HRESULT hr;
664 UINT i;
665 UINT len;
667 memset(pVarResult, 0, sizeof(VARIANT));
668 VariantInit(pVarResult);
670 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 );
671 name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
672 if (!name) return E_FAIL;
673 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len );
674 hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
675 HeapFree(GetProcessHeap(), 0, name);
676 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
677 if (!hr == S_OK) return hr;
679 memset(&excepinfo, 0, sizeof(excepinfo));
680 hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL);
682 if (hr == S_OK)
684 if (_invoke_todo_vtResult) todo_wine
685 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
686 else
687 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
688 if (vtResult != VT_EMPTY)
690 hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult);
691 ok(hr == S_OK, "VariantChangeTypeEx returned 0x%08x\n", hr);
695 for (i=0; i<pDispParams->cArgs; i++)
696 VariantClear(&pDispParams->rgvarg[i]);
698 return hr;
701 /* Object_Property helper functions */
703 static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord)
705 VARIANT varresult;
706 VARIANTARG vararg[1];
707 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
708 HRESULT hr;
710 VariantInit(&vararg[0]);
711 V_VT(&vararg[0]) = VT_I4;
712 V_I4(&vararg[0]) = count;
714 hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
715 *pRecord = V_DISPATCH(&varresult);
716 return hr;
719 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
721 VARIANTARG vararg[3];
722 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
724 VariantInit(&vararg[2]);
725 V_VT(&vararg[2]) = VT_I4;
726 V_I4(&vararg[2]) = (INT_PTR)hkey;
727 VariantInit(&vararg[1]);
728 V_VT(&vararg[1]) = VT_BSTR;
729 V_BSTR(&vararg[1]) = SysAllocString(szKey);
730 VariantInit(&vararg[0]);
731 VariantCopy(&vararg[0], &vValue);
732 VariantClear(&vValue);
734 return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect);
737 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
739 VARIANT varresult;
740 VARIANTARG vararg;
741 HRESULT hr;
743 VariantInit(&vararg);
744 V_VT(&vararg) = VT_EMPTY;
745 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL);
746 *pBool = V_BOOL(&varresult);
747 VariantClear(&varresult);
748 return hr;
751 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
753 VARIANT varresult;
754 VARIANTARG vararg;
755 HRESULT hr;
757 VariantInit(&vararg);
758 V_VT(&vararg) = VT_BSTR;
759 V_BSTR(&vararg) = SysAllocString(szValue);
761 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR);
762 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
763 VariantClear(&varresult);
764 return hr;
767 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
769 VARIANT varresult;
770 VARIANTARG vararg;
771 HRESULT hr;
773 VariantInit(&vararg);
774 V_VT(&vararg) = VT_I4;
775 V_I4(&vararg) = iValue;
777 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult);
778 if (SUCCEEDED(hr) && vtResult == VT_BSTR) lstrcpyW(szString, V_BSTR(&varresult));
779 VariantClear(&varresult);
780 return hr;
783 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
785 VARIANT varresult;
786 VARIANTARG vararg[2];
787 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
788 HRESULT hr;
790 VariantInit(&vararg[1]);
791 V_VT(&vararg[1]) = VT_BSTR;
792 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
793 VariantInit(&vararg[0]);
794 V_VT(&vararg[0]) = VT_I4;
795 V_I4(&vararg[0]) = options;
797 hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
798 *pSession = V_DISPATCH(&varresult);
799 return hr;
802 static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase)
804 VARIANT varresult;
805 VARIANTARG vararg[2];
806 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
807 HRESULT hr;
809 VariantInit(&vararg[1]);
810 V_VT(&vararg[1]) = VT_BSTR;
811 V_BSTR(&vararg[1]) = SysAllocString(szDatabasePath);
812 VariantInit(&vararg[0]);
813 V_VT(&vararg[0]) = VT_I4;
814 V_I4(&vararg[0]) = openmode;
816 hr = invoke(pInstaller, "OpenDatabase", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
817 *pDatabase = V_DISPATCH(&varresult);
818 return hr;
821 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
823 VARIANT varresult;
824 VARIANTARG vararg[2];
825 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
827 VariantInit(&vararg[1]);
828 V_VT(&vararg[1]) = VT_BSTR;
829 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
830 VariantInit(&vararg[0]);
831 V_VT(&vararg[0]) = VT_BSTR;
832 V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues);
834 return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
837 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
839 VARIANT varresult;
840 VARIANTARG vararg[1];
841 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
842 HRESULT hr;
844 VariantInit(&vararg[0]);
845 V_VT(&vararg[0]) = VT_BSTR;
846 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
848 hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
849 *pInstallState = V_I4(&varresult);
850 VariantClear(&varresult);
851 return hr;
854 static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szString)
856 VARIANT varresult;
857 VARIANTARG vararg[2];
858 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
859 HRESULT hr;
861 VariantInit(&vararg[1]);
862 V_VT(&vararg[1]) = VT_BSTR;
863 V_BSTR(&vararg[1]) = SysAllocString(szProduct);
864 VariantInit(&vararg[0]);
865 V_VT(&vararg[0]) = VT_BSTR;
866 V_BSTR(&vararg[0]) = SysAllocString(szAttribute);
868 hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
869 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
870 VariantClear(&varresult);
871 return hr;
874 static HRESULT Installer_Products(IDispatch **pStringList)
876 VARIANT varresult;
877 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
878 HRESULT hr;
880 hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
881 *pStringList = V_DISPATCH(&varresult);
882 return hr;
885 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
887 VARIANT varresult;
888 VARIANTARG vararg[1];
889 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
890 HRESULT hr;
892 VariantInit(&vararg[0]);
893 V_VT(&vararg[0]) = VT_BSTR;
894 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
896 hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
897 *pStringList = V_DISPATCH(&varresult);
898 return hr;
901 static HRESULT Installer_VersionGet(LPWSTR szVersion)
903 VARIANT varresult;
904 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
905 HRESULT hr;
907 hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
908 if (V_BSTR(&varresult)) lstrcpyW(szVersion, V_BSTR(&varresult));
909 VariantClear(&varresult);
910 return hr;
913 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
915 VARIANT varresult;
916 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
917 HRESULT hr;
919 hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
920 *pInst = V_DISPATCH(&varresult);
921 return hr;
924 static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn)
926 VARIANT varresult;
927 VARIANTARG vararg[1];
928 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
929 HRESULT hr;
931 VariantInit(&vararg[0]);
932 V_VT(&vararg[0]) = VT_BSTR;
933 V_BSTR(&vararg[0]) = SysAllocString(szName);
935 hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
936 if (V_BSTR(&varresult)) lstrcpyW(szReturn, V_BSTR(&varresult));
937 VariantClear(&varresult);
938 return hr;
941 static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue)
943 VARIANT varresult;
944 VARIANTARG vararg[2];
945 DISPID dispid = DISPID_PROPERTYPUT;
946 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
948 VariantInit(&vararg[1]);
949 V_VT(&vararg[1]) = VT_BSTR;
950 V_BSTR(&vararg[1]) = SysAllocString(szName);
951 VariantInit(&vararg[0]);
952 V_VT(&vararg[0]) = VT_BSTR;
953 V_BSTR(&vararg[0]) = SysAllocString(szValue);
955 return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
958 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
960 VARIANT varresult;
961 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
962 HRESULT hr;
964 hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
965 *pLangId = V_I4(&varresult);
966 VariantClear(&varresult);
967 return hr;
970 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, BOOL *pMode)
972 VARIANT varresult;
973 VARIANTARG vararg[1];
974 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
975 HRESULT hr;
977 VariantInit(&vararg[0]);
978 V_VT(&vararg[0]) = VT_I4;
979 V_I4(&vararg[0]) = iFlag;
981 hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL);
982 *pMode = V_BOOL(&varresult);
983 VariantClear(&varresult);
984 return hr;
987 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, BOOL bMode)
989 VARIANT varresult;
990 VARIANTARG vararg[2];
991 DISPID dispid = DISPID_PROPERTYPUT;
992 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
994 VariantInit(&vararg[1]);
995 V_VT(&vararg[1]) = VT_I4;
996 V_I4(&vararg[1]) = iFlag;
997 VariantInit(&vararg[0]);
998 V_VT(&vararg[0]) = VT_BOOL;
999 V_BOOL(&vararg[0]) = bMode;
1001 return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1004 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
1006 VARIANT varresult;
1007 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1008 HRESULT hr;
1010 hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1011 *pDatabase = V_DISPATCH(&varresult);
1012 return hr;
1015 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn)
1017 VARIANT varresult;
1018 VARIANTARG vararg[1];
1019 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1020 HRESULT hr;
1022 VariantInit(&vararg[0]);
1023 V_VT(&vararg[0]) = VT_BSTR;
1024 V_BSTR(&vararg[0]) = SysAllocString(szAction);
1026 hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1027 *iReturn = V_I4(&varresult);
1028 VariantClear(&varresult);
1029 return hr;
1032 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
1034 VARIANT varresult;
1035 VARIANTARG vararg[1];
1036 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1037 HRESULT hr;
1039 VariantInit(&vararg[0]);
1040 V_VT(&vararg[0]) = VT_BSTR;
1041 V_BSTR(&vararg[0]) = SysAllocString(szCondition);
1043 hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1044 *iReturn = V_I4(&varresult);
1045 VariantClear(&varresult);
1046 return hr;
1049 static HRESULT Session_Message(IDispatch *pSession, LONG kind, IDispatch *record, int *ret)
1051 VARIANT varresult;
1052 VARIANTARG vararg[2];
1053 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1054 HRESULT hr;
1056 VariantInit(&varresult);
1057 V_VT(vararg) = VT_DISPATCH;
1058 V_DISPATCH(vararg) = record;
1059 V_VT(vararg+1) = VT_I4;
1060 V_I4(vararg+1) = kind;
1062 hr = invoke(pSession, "Message", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1064 ok(V_VT(&varresult) == VT_I4, "V_VT(varresult) = %d\n", V_VT(&varresult));
1065 *ret = V_I4(&varresult);
1067 return hr;
1070 static HRESULT Session_SetInstallLevel(IDispatch *pSession, LONG iInstallLevel)
1072 VARIANT varresult;
1073 VARIANTARG vararg[1];
1074 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1076 VariantInit(&vararg[0]);
1077 V_VT(&vararg[0]) = VT_I4;
1078 V_I4(&vararg[0]) = iInstallLevel;
1080 return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1083 static HRESULT Session_FeatureCurrentState(IDispatch *pSession, LPCWSTR szName, int *pState)
1085 VARIANT varresult;
1086 VARIANTARG vararg[1];
1087 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1088 HRESULT hr;
1090 VariantInit(&vararg[0]);
1091 V_VT(&vararg[0]) = VT_BSTR;
1092 V_BSTR(&vararg[0]) = SysAllocString(szName);
1094 hr = invoke(pSession, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1095 *pState = V_I4(&varresult);
1096 VariantClear(&varresult);
1097 return hr;
1100 static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState)
1102 VARIANT varresult;
1103 VARIANTARG vararg[1];
1104 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1105 HRESULT hr;
1107 VariantInit(&vararg[0]);
1108 V_VT(&vararg[0]) = VT_BSTR;
1109 V_BSTR(&vararg[0]) = SysAllocString(szName);
1111 hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1112 *pState = V_I4(&varresult);
1113 VariantClear(&varresult);
1114 return hr;
1117 static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState)
1119 VARIANT varresult;
1120 VARIANTARG vararg[2];
1121 DISPID dispid = DISPID_PROPERTYPUT;
1122 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1124 VariantInit(&vararg[1]);
1125 V_VT(&vararg[1]) = VT_BSTR;
1126 V_BSTR(&vararg[1]) = SysAllocString(szName);
1127 VariantInit(&vararg[0]);
1128 V_VT(&vararg[0]) = VT_I4;
1129 V_I4(&vararg[0]) = iState;
1131 return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1134 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
1136 VARIANT varresult;
1137 VARIANTARG vararg[1];
1138 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1139 HRESULT hr;
1141 VariantInit(&vararg[0]);
1142 V_VT(&vararg[0]) = VT_BSTR;
1143 V_BSTR(&vararg[0]) = SysAllocString(szSql);
1145 hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1146 *pView = V_DISPATCH(&varresult);
1147 return hr;
1150 static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo)
1152 VARIANT varresult;
1153 VARIANTARG vararg[1];
1154 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1155 HRESULT hr;
1157 VariantInit(&vararg[0]);
1158 V_VT(&vararg[0]) = VT_I4;
1159 V_I4(&vararg[0]) = iUpdateCount;
1161 hr = invoke(pDatabase, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1162 *pSummaryInfo = V_DISPATCH(&varresult);
1163 return hr;
1166 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
1168 VARIANT varresult;
1169 VARIANTARG vararg[1];
1170 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1172 VariantInit(&vararg[0]);
1173 V_VT(&vararg[0]) = VT_DISPATCH;
1174 V_DISPATCH(&vararg[0]) = pRecord;
1176 return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1179 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
1181 VARIANT varresult;
1182 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1183 HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1184 *ppRecord = V_DISPATCH(&varresult);
1185 return hr;
1188 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
1190 VARIANT varresult;
1191 VARIANTARG vararg[2];
1192 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1194 VariantInit(&vararg[1]);
1195 V_VT(&vararg[1]) = VT_I4;
1196 V_I4(&vararg[1]) = iMode;
1197 VariantInit(&vararg[0]);
1198 V_VT(&vararg[0]) = VT_DISPATCH;
1199 V_DISPATCH(&vararg[0]) = pRecord;
1200 if (pRecord)
1201 IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */
1203 return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1206 static HRESULT View_Close(IDispatch *pView)
1208 VARIANT varresult;
1209 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1210 return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1213 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
1215 VARIANT varresult;
1216 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1217 HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1218 *pFieldCount = V_I4(&varresult);
1219 VariantClear(&varresult);
1220 return hr;
1223 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString)
1225 VARIANT varresult;
1226 VARIANTARG vararg[1];
1227 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1228 HRESULT hr;
1230 VariantInit(&vararg[0]);
1231 V_VT(&vararg[0]) = VT_I4;
1232 V_I4(&vararg[0]) = iField;
1234 hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1235 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1236 VariantClear(&varresult);
1237 return hr;
1240 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
1242 VARIANT varresult;
1243 VARIANTARG vararg[2];
1244 DISPID dispid = DISPID_PROPERTYPUT;
1245 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1247 VariantInit(&vararg[1]);
1248 V_VT(&vararg[1]) = VT_I4;
1249 V_I4(&vararg[1]) = iField;
1250 VariantInit(&vararg[0]);
1251 V_VT(&vararg[0]) = VT_BSTR;
1252 V_BSTR(&vararg[0]) = SysAllocString(szString);
1254 return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1257 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
1259 VARIANT varresult;
1260 VARIANTARG vararg[1];
1261 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1262 HRESULT hr;
1264 VariantInit(&vararg[0]);
1265 V_VT(&vararg[0]) = VT_I4;
1266 V_I4(&vararg[0]) = iField;
1268 hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1269 *pValue = V_I4(&varresult);
1270 VariantClear(&varresult);
1271 return hr;
1274 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
1276 VARIANT varresult;
1277 VARIANTARG vararg[2];
1278 DISPID dispid = DISPID_PROPERTYPUT;
1279 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1281 VariantInit(&vararg[1]);
1282 V_VT(&vararg[1]) = VT_I4;
1283 V_I4(&vararg[1]) = iField;
1284 VariantInit(&vararg[0]);
1285 V_VT(&vararg[0]) = VT_I4;
1286 V_I4(&vararg[0]) = iValue;
1288 return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1291 static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT)
1293 VARIANT varresult;
1294 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1295 HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN);
1296 *ppEnumVARIANT = V_UNKNOWN(&varresult);
1297 return hr;
1300 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
1302 VARIANT varresult;
1303 VARIANTARG vararg[1];
1304 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1305 HRESULT hr;
1307 VariantInit(&vararg[0]);
1308 V_VT(&vararg[0]) = VT_I4;
1309 V_I4(&vararg[0]) = iIndex;
1311 hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1312 if (V_BSTR(&varresult)) lstrcpyW(szString, V_BSTR(&varresult));
1313 VariantClear(&varresult);
1314 return hr;
1317 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
1319 VARIANT varresult;
1320 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1321 HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1322 *pCount = V_I4(&varresult);
1323 VariantClear(&varresult);
1324 return hr;
1327 static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect)
1329 VARIANTARG vararg[1];
1330 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1332 VariantInit(&vararg[0]);
1333 V_VT(&vararg[0]) = VT_I4;
1334 V_I4(&vararg[0]) = pid;
1335 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYGET, &dispparams, pVarResult, vtExpect);
1338 static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant)
1340 VARIANT varresult;
1341 VARIANTARG vararg[2];
1342 DISPID dispid = DISPID_PROPERTYPUT;
1343 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1345 VariantInit(&vararg[1]);
1346 V_VT(&vararg[1]) = VT_I4;
1347 V_I4(&vararg[1]) = pid;
1348 VariantInit(&vararg[0]);
1349 VariantCopyInd(vararg, pVariant);
1351 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1354 static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount)
1356 VARIANT varresult;
1357 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1358 HRESULT hr;
1360 hr = invoke(pSummaryInfo, "PropertyCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1361 *pCount = V_I4(&varresult);
1362 VariantClear(&varresult);
1363 return hr;
1366 /* Test the various objects */
1368 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4
1370 static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly)
1372 static const WCHAR szPropertyException[] = { 'P','r','o','p','e','r','t','y',',','P','i','d',0 };
1373 static const WCHAR szTitle[] = { 'T','i','t','l','e',0 };
1374 VARIANT varresult, var;
1375 SYSTEMTIME st;
1376 HRESULT hr;
1377 int j;
1379 /* SummaryInfo::PropertyCount */
1380 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1381 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1382 ok(j == num_info, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1384 /* SummaryInfo::Property, get for properties we have set */
1385 for (j = 0; j < num_info; j++)
1387 const msi_summary_info *entry = &info[j];
1389 int vt = entry->datatype;
1390 if (vt == VT_LPSTR) vt = VT_BSTR;
1391 else if (vt == VT_FILETIME) vt = VT_DATE;
1392 else if (vt == VT_I2) vt = VT_I4;
1394 hr = SummaryInfo_PropertyGet(pSummaryInfo, entry->property, &varresult, vt);
1395 ok(hr == S_OK, "SummaryInfo_Property (pid %d) failed, hresult 0x%08x\n", entry->property, hr);
1396 if (V_VT(&varresult) != vt)
1397 skip("Skipping property tests due to type mismatch\n");
1398 else if (vt == VT_I4)
1399 ok(V_I4(&varresult) == entry->iValue, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %d\n",
1400 entry->property, entry->iValue, V_I4(&varresult));
1401 else if (vt == VT_DATE)
1403 FILETIME ft;
1404 DATE d;
1406 FileTimeToLocalFileTime(entry->pftValue, &ft);
1407 FileTimeToSystemTime(&ft, &st);
1408 SystemTimeToVariantTime(&st, &d);
1409 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));
1411 else if (vt == VT_BSTR)
1413 ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry->property, entry->szValue, V_BSTR(&varresult));
1415 else
1416 skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry->property, vt);
1418 VariantClear(&varresult);
1421 /* SummaryInfo::Property, get; invalid arguments */
1423 /* Invalid pids */
1424 hr = SummaryInfo_PropertyGet(pSummaryInfo, -1, &varresult, VT_EMPTY);
1425 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1426 ok_exception(hr, szPropertyException);
1428 hr = SummaryInfo_PropertyGet(pSummaryInfo, 1000, &varresult, VT_EMPTY);
1429 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1430 ok_exception(hr, szPropertyException);
1432 /* Unsupported pids */
1433 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_DICTIONARY, &varresult, VT_EMPTY);
1434 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1436 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY);
1437 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1439 /* Pids we have not set, one for each type */
1440 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_EMPTY);
1441 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1443 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY);
1444 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1446 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY);
1447 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1449 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY);
1450 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1452 if (!readonly)
1454 /* SummaryInfo::Property, put; one for each type */
1456 /* VT_I2 */
1457 VariantInit(&var);
1458 V_VT(&var) = VT_I2;
1459 V_I2(&var) = 1;
1460 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CODEPAGE, &var);
1461 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1463 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */);
1464 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1465 ok(V_I2(&var) == V_I2(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var), V_I2(&varresult));
1466 VariantClear(&varresult);
1467 VariantClear(&var);
1469 /* VT_BSTR */
1470 V_VT(&var) = VT_BSTR;
1471 V_BSTR(&var) = SysAllocString(szTitle);
1472 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_TITLE, &var);
1473 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1475 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var));
1476 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1477 ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var), V_BSTR(&varresult));
1478 VariantClear(&varresult);
1479 VariantClear(&var);
1481 /* VT_DATE */
1482 V_VT(&var) = VT_DATE;
1483 FileTimeToSystemTime(&systemtime, &st);
1484 SystemTimeToVariantTime(&st, &V_DATE(&var));
1485 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_LASTSAVE_DTM, &var);
1486 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1488 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var));
1489 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1490 /* FIXME: Off by one second */
1491 todo_wine ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1492 VariantClear(&varresult);
1493 VariantClear(&var);
1495 /* VT_I4 */
1496 V_VT(&var) = VT_I4;
1497 V_I4(&var) = 1000;
1498 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1499 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1501 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1502 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1503 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult));
1504 VariantClear(&varresult);
1505 VariantClear(&var);
1507 /* SummaryInfo::PropertyCount */
1508 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1509 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1510 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1514 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1516 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 };
1517 static WCHAR szThree[] = { 'T','h','r','e','e',0 };
1518 static WCHAR szTwo[] = { 'T','w','o',0 };
1519 static WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
1520 static WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 };
1521 IDispatch *pView = NULL, *pSummaryInfo = NULL;
1522 HRESULT hr;
1524 hr = Database_OpenView(pDatabase, szSql, &pView);
1525 ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr);
1526 if (hr == S_OK)
1528 IDispatch *pRecord = NULL;
1529 WCHAR szString[MAX_PATH];
1531 /* View::Execute */
1532 hr = View_Execute(pView, NULL);
1533 ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr);
1535 /* View::Fetch */
1536 hr = View_Fetch(pView, &pRecord);
1537 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1538 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1539 if (pRecord)
1541 /* Record::StringDataGet */
1542 memset(szString, 0, sizeof(szString));
1543 hr = Record_StringDataGet(pRecord, 1, szString);
1544 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1545 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1547 /* Record::StringDataPut with correct index */
1548 hr = Record_StringDataPut(pRecord, 1, szTwo);
1549 ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1551 /* Record::StringDataGet */
1552 memset(szString, 0, sizeof(szString));
1553 hr = Record_StringDataGet(pRecord, 1, szString);
1554 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1555 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1557 /* Record::StringDataPut with incorrect index */
1558 hr = Record_StringDataPut(pRecord, -1, szString);
1559 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1560 ok_exception(hr, szStringDataField);
1562 /* View::Modify with incorrect parameters */
1563 hr = View_Modify(pView, -5, NULL);
1564 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1565 ok_exception(hr, szModifyModeRecord);
1567 hr = View_Modify(pView, -5, pRecord);
1568 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1569 ok_exception(hr, szModifyModeRecord);
1571 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1572 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1573 ok_exception(hr, szModifyModeRecord);
1575 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1576 ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr);
1578 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1579 memset(szString, 0, sizeof(szString));
1580 hr = Record_StringDataGet(pRecord, 1, szString);
1581 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1582 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1584 IDispatch_Release(pRecord);
1587 /* View::Fetch */
1588 hr = View_Fetch(pView, &pRecord);
1589 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1590 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1591 if (pRecord)
1593 /* Record::StringDataGet */
1594 memset(szString, 0, sizeof(szString));
1595 hr = Record_StringDataGet(pRecord, 1, szString);
1596 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1597 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1599 IDispatch_Release(pRecord);
1602 /* View::Fetch */
1603 hr = View_Fetch(pView, &pRecord);
1604 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1605 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1606 if (pRecord)
1607 IDispatch_Release(pRecord);
1609 /* View::Close */
1610 hr = View_Close(pView);
1611 ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr);
1613 IDispatch_Release(pView);
1616 /* Database::SummaryInformation */
1617 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo);
1618 ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr);
1619 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1620 if (pSummaryInfo)
1622 test_SummaryInfo(pSummaryInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), readonly);
1623 IDispatch_Release(pSummaryInfo);
1627 static void test_Session(IDispatch *pSession)
1629 static WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
1630 static WCHAR szOne[] = { 'O','n','e',0 };
1631 static WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 };
1632 static WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 };
1633 static WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 };
1634 static WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 };
1635 static WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1636 static WCHAR szEmpty[] = { 0 };
1637 static WCHAR szEquals[] = { '=',0 };
1638 static WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
1639 WCHAR stringw[MAX_PATH];
1640 CHAR string[MAX_PATH];
1641 UINT len;
1642 BOOL bool;
1643 int myint;
1644 IDispatch *pDatabase = NULL, *pInst = NULL, *record = NULL;
1645 HRESULT hr;
1647 /* Session::Installer */
1648 hr = Session_Installer(pSession, &pInst);
1649 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1650 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1651 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1653 /* Session::Property, get */
1654 memset(stringw, 0, sizeof(stringw));
1655 hr = Session_PropertyGet(pSession, szProductName, stringw);
1656 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1657 if (lstrcmpW(stringw, szMSITEST) != 0)
1659 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1660 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1661 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1664 /* Session::Property, put */
1665 hr = Session_PropertyPut(pSession, szProductName, szProductName);
1666 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1667 memset(stringw, 0, sizeof(stringw));
1668 hr = Session_PropertyGet(pSession, szProductName, stringw);
1669 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1670 if (lstrcmpW(stringw, szProductName) != 0)
1672 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1673 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1674 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1677 /* Try putting a property using empty property identifier */
1678 hr = Session_PropertyPut(pSession, szEmpty, szProductName);
1679 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1680 ok_exception(hr, szPropertyName);
1682 /* Try putting a property using illegal property identifier */
1683 hr = Session_PropertyPut(pSession, szEquals, szProductName);
1684 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1686 /* Session::Language, get */
1687 hr = Session_LanguageGet(pSession, &len);
1688 ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1689 /* Not sure how to check the language is correct */
1691 /* Session::Mode, get */
1692 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1693 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1694 todo_wine ok(!bool, "Reboot at end session mode is %d\n", bool);
1696 /* Session::Mode, put */
1697 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE);
1698 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1699 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1700 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1701 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1702 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE); /* set it again so we don't reboot */
1703 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1705 /* Session::Database, get */
1706 hr = Session_Database(pSession, &pDatabase);
1707 ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr);
1708 if (hr == S_OK)
1710 test_Database(pDatabase, TRUE);
1711 IDispatch_Release(pDatabase);
1714 /* Session::EvaluateCondition */
1715 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1716 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1717 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1719 hr = Session_EvaluateCondition(pSession, szEmpty, &myint);
1720 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1721 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1723 hr = Session_EvaluateCondition(pSession, szEquals, &myint);
1724 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1725 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1727 /* Session::DoAction(CostInitialize) must occur before the next statements */
1728 hr = Session_DoAction(pSession, szCostInitialize, &myint);
1729 ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr);
1730 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1732 /* Session::SetInstallLevel */
1733 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1734 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
1736 /* Session::FeatureCurrentState, get */
1737 hr = Session_FeatureCurrentState(pSession, szOne, &myint);
1738 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
1739 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1741 /* Session::Message */
1742 hr = Installer_CreateRecord(0, &record);
1743 ok(hr == S_OK, "Installer_CreateRecord failed: %08x\n", hr);
1744 hr = Session_Message(pSession, INSTALLMESSAGE_INFO, record, &myint);
1745 ok(hr == S_OK, "Session_Message failed: %08x\n", hr);
1746 ok(myint == 0, "Session_Message returned %x\n", myint);
1748 /* Session::EvaluateCondition */
1749 hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint);
1750 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1751 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1753 hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint);
1754 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1755 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1757 /* Session::FeatureRequestState, put */
1758 hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED);
1759 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
1760 hr = Session_FeatureRequestStateGet(pSession, szOne, &myint);
1761 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
1762 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
1764 /* Session::EvaluateCondition */
1765 hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint);
1766 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1767 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1769 hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint);
1770 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1771 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1774 /* delete key and all its subkeys */
1775 static DWORD delete_key( HKEY hkey )
1777 char name[MAX_PATH];
1778 DWORD ret;
1780 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
1782 HKEY tmp;
1783 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
1785 ret = delete_key( tmp );
1786 RegCloseKey( tmp );
1788 if (ret) break;
1790 if (ret != ERROR_NO_MORE_ITEMS) return ret;
1791 RegDeleteKeyA( hkey, "" );
1792 return 0;
1795 static void test_Installer_RegistryValue(void)
1797 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
1798 static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 };
1799 static const WCHAR szOne[] = { 'O','n','e',0 };
1800 static const WCHAR szTwo[] = { 'T','w','o',0 };
1801 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
1802 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1803 static const WCHAR szFour[] = { 'F','o','u','r',0 };
1804 static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 };
1805 static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 };
1806 static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 };
1807 static const WCHAR szSix[] = { 'S','i','x',0 };
1808 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1809 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
1810 static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
1811 static const WCHAR szBlank[] = { 0 };
1812 VARIANT varresult;
1813 VARIANTARG vararg;
1814 WCHAR szString[MAX_PATH];
1815 HKEY hkey, hkey_sub;
1816 HKEY curr_user = (HKEY)1;
1817 HRESULT hr;
1818 BOOL bRet;
1819 LONG lRet;
1821 /* Delete keys */
1822 SetLastError(0xdeadbeef);
1823 lRet = RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey );
1824 if (!lRet && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1826 win_skip("Needed W-functions are not implemented\n");
1827 return;
1829 if (!lRet)
1830 delete_key( hkey );
1832 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
1833 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
1834 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1835 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
1837 memset(szString, 0, sizeof(szString));
1838 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
1839 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1841 memset(szString, 0, sizeof(szString));
1842 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
1843 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1845 /* Create key */
1846 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
1848 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1849 "RegSetValueExW failed\n");
1850 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
1851 "RegSetValueExW failed\n");
1852 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
1853 "RegSetValueExW failed\n");
1854 ok(SetEnvironmentVariableA("MSITEST", "Four"), "SetEnvironmentVariableA failed %d\n", GetLastError());
1855 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
1856 "RegSetValueExW failed\n");
1857 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
1858 "RegSetValueExW failed\n");
1859 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
1860 "RegSetValueExW failed\n");
1861 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, NULL, 0),
1862 "RegSetValueExW failed\n");
1864 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1865 "RegSetValueExW failed\n");
1867 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
1869 /* Does our key exist? It should, and make sure we retrieve the correct default value */
1870 bRet = FALSE;
1871 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
1872 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1873 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
1875 memset(szString, 0, sizeof(szString));
1876 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
1877 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1878 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1880 /* Ask for the value of a nonexistent key */
1881 memset(szString, 0, sizeof(szString));
1882 hr = Installer_RegistryValueW(curr_user, szKey, szExpand, szString);
1883 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1885 /* Get values of keys */
1886 memset(szString, 0, sizeof(szString));
1887 hr = Installer_RegistryValueW(curr_user, szKey, szOne, szString);
1888 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1889 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1891 VariantInit(&vararg);
1892 V_VT(&vararg) = VT_BSTR;
1893 V_BSTR(&vararg) = SysAllocString(szTwo);
1894 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_I4);
1895 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1896 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
1897 VariantClear(&varresult);
1899 memset(szString, 0, sizeof(szString));
1900 hr = Installer_RegistryValueW(curr_user, szKey, szThree, szString);
1901 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1902 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
1904 memset(szString, 0, sizeof(szString));
1905 hr = Installer_RegistryValueW(curr_user, szKey, szFour, szString);
1906 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1907 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
1909 /* Vista does not NULL-terminate this case */
1910 memset(szString, 0, sizeof(szString));
1911 hr = Installer_RegistryValueW(curr_user, szKey, szFive, szString);
1912 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1913 ok_w2n("Registry value \"%s\" does not match expected \"%s\"\n",
1914 szString, szFiveHi, lstrlenW(szFiveHi));
1916 memset(szString, 0, sizeof(szString));
1917 hr = Installer_RegistryValueW(curr_user, szKey, szSix, szString);
1918 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1919 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_);
1921 VariantInit(&vararg);
1922 V_VT(&vararg) = VT_BSTR;
1923 V_BSTR(&vararg) = SysAllocString(szSeven);
1924 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_EMPTY);
1925 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1927 /* Get string class name for the key */
1928 memset(szString, 0, sizeof(szString));
1929 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
1930 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1931 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank);
1933 /* Get name of a value by positive number (RegEnumValue like), valid index */
1934 memset(szString, 0, sizeof(szString));
1935 hr = Installer_RegistryValueI(curr_user, szKey, 2, szString, VT_BSTR);
1936 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1937 /* RegEnumValue order seems different on wine */
1938 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
1940 /* Get name of a value by positive number (RegEnumValue like), invalid index */
1941 memset(szString, 0, sizeof(szString));
1942 hr = Installer_RegistryValueI(curr_user, szKey, 10, szString, VT_EMPTY);
1943 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1945 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
1946 memset(szString, 0, sizeof(szString));
1947 hr = Installer_RegistryValueI(curr_user, szKey, -1, szString, VT_BSTR);
1948 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1949 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
1951 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
1952 memset(szString, 0, sizeof(szString));
1953 hr = Installer_RegistryValueI(curr_user, szKey, -10, szString, VT_EMPTY);
1954 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1956 /* clean up */
1957 delete_key(hkey);
1960 static void test_Installer_Products(BOOL bProductInstalled)
1962 WCHAR szString[MAX_PATH];
1963 HRESULT hr;
1964 int idx;
1965 IUnknown *pUnk = NULL;
1966 IEnumVARIANT *pEnum = NULL;
1967 VARIANT var;
1968 ULONG celt;
1969 int iCount, iValue;
1970 IDispatch *pStringList = NULL;
1971 BOOL bProductFound = FALSE;
1973 /* Installer::Products */
1974 hr = Installer_Products(&pStringList);
1975 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
1976 if (hr == S_OK)
1978 /* StringList::_NewEnum */
1979 hr = StringList__NewEnum(pStringList, &pUnk);
1980 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
1981 if (hr == S_OK)
1983 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
1984 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
1986 if (!pEnum)
1987 skip("IEnumVARIANT tests\n");
1989 /* StringList::Count */
1990 hr = StringList_Count(pStringList, &iCount);
1991 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
1993 for (idx=0; idx<iCount; idx++)
1995 /* StringList::Item */
1996 memset(szString, 0, sizeof(szString));
1997 hr = StringList_Item(pStringList, idx, szString);
1998 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2000 if (hr == S_OK)
2002 /* Installer::ProductState */
2003 hr = Installer_ProductState(szString, &iValue);
2004 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2005 if (hr == S_OK)
2006 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
2008 /* Not found our product code yet? Check */
2009 if (!bProductFound && !lstrcmpW(szString, szProductCode))
2010 bProductFound = TRUE;
2012 /* IEnumVARIANT::Next */
2013 if (pEnum)
2015 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2016 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2017 ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
2018 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2019 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2020 VariantClear(&var);
2025 if (bProductInstalled)
2027 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
2028 bProductInstalled ? "be" : "not be",
2029 bProductFound ? "found" : "not found");
2032 if (pEnum)
2034 IEnumVARIANT *pEnum2 = NULL;
2036 if (0) /* Crashes on Windows XP */
2038 /* IEnumVARIANT::Clone, NULL pointer */
2039 hr = IEnumVARIANT_Clone(pEnum, NULL);
2042 /* IEnumVARIANT::Clone */
2043 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
2044 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
2045 if (hr == S_OK)
2047 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
2049 /* IEnumVARIANT::Next of the clone */
2050 if (iCount)
2052 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
2053 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2054 ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
2055 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2056 VariantClear(&var);
2058 else
2059 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
2061 IEnumVARIANT_Release(pEnum2);
2064 /* IEnumVARIANT::Skip should fail */
2065 hr = IEnumVARIANT_Skip(pEnum, 1);
2066 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2068 /* IEnumVARIANT::Next, NULL variant pointer */
2069 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2070 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2071 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2073 /* IEnumVARIANT::Next, should not return any more items */
2074 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2075 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2076 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2077 VariantClear(&var);
2079 /* IEnumVARIANT::Reset */
2080 hr = IEnumVARIANT_Reset(pEnum);
2081 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2083 if (iCount)
2085 /* IEnumVARIANT::Skip to the last product */
2086 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2087 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2089 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2090 * NULL celt pointer. */
2091 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2092 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2093 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2094 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2095 VariantClear(&var);
2097 else
2098 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2101 /* StringList::Item using an invalid index */
2102 memset(szString, 0, sizeof(szString));
2103 hr = StringList_Item(pStringList, iCount, szString);
2104 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2106 if (pEnum) IEnumVARIANT_Release(pEnum);
2107 if (pUnk) IUnknown_Release(pUnk);
2108 IDispatch_Release(pStringList);
2112 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2113 * deleting the subkeys first) */
2114 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey)
2116 UINT ret;
2117 CHAR *string = NULL;
2118 HKEY hkey;
2119 DWORD dwSize;
2121 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2122 if (ret != ERROR_SUCCESS) return ret;
2123 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2124 if (ret != ERROR_SUCCESS) return ret;
2125 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2127 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2128 delete_registry_key(hkey, string);
2130 RegCloseKey(hkey);
2131 HeapFree(GetProcessHeap(), 0, string);
2132 RegDeleteKeyA(hkeyParent, subkey);
2133 return ERROR_SUCCESS;
2136 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2137 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, HKEY *phkey)
2139 UINT ret;
2140 CHAR *string = NULL;
2141 int idx = 0;
2142 HKEY hkey;
2143 DWORD dwSize;
2144 BOOL found = FALSE;
2146 *phkey = 0;
2148 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2149 if (ret != ERROR_SUCCESS) return ret;
2150 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2151 if (ret != ERROR_SUCCESS) return ret;
2152 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2154 while (!found &&
2155 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2157 if (!strcmp(string, findkey))
2159 *phkey = hkey;
2160 found = TRUE;
2162 else if (find_registry_key(hkey, string, findkey, phkey) == ERROR_SUCCESS) found = TRUE;
2165 if (*phkey != hkey) RegCloseKey(hkey);
2166 HeapFree(GetProcessHeap(), 0, string);
2167 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2170 static void test_Installer_InstallProduct(void)
2172 HRESULT hr;
2173 CHAR path[MAX_PATH];
2174 WCHAR szString[MAX_PATH];
2175 LONG res;
2176 HKEY hkey;
2177 DWORD num, size, type;
2178 int iValue, iCount;
2179 IDispatch *pStringList = NULL;
2181 create_test_files();
2183 /* Installer::InstallProduct */
2184 hr = Installer_InstallProduct(szMsifile, NULL);
2185 if (hr == DISP_E_EXCEPTION)
2187 skip("Installer object not supported.\n");
2188 delete_test_files();
2189 return;
2191 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2193 /* Installer::ProductState for our product code, which has been installed */
2194 hr = Installer_ProductState(szProductCode, &iValue);
2195 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2196 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2198 /* Installer::ProductInfo for our product code */
2200 /* NULL attribute */
2201 memset(szString, 0, sizeof(szString));
2202 hr = Installer_ProductInfo(szProductCode, NULL, szString);
2203 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2204 ok_exception(hr, szProductInfoException);
2206 /* Nonexistent attribute */
2207 memset(szString, 0, sizeof(szString));
2208 hr = Installer_ProductInfo(szProductCode, szMsifile, szString);
2209 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2210 ok_exception(hr, szProductInfoException);
2212 /* Package name */
2213 memset(szString, 0, sizeof(szString));
2214 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szString);
2215 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2216 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile);
2218 /* Product name */
2219 memset(szString, 0, sizeof(szString));
2220 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PRODUCTNAMEW, szString);
2221 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2222 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST);
2224 /* Installer::Products */
2225 test_Installer_Products(TRUE);
2227 /* Installer::RelatedProducts for our upgrade code */
2228 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2229 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2230 if (hr == S_OK)
2232 /* StringList::Count */
2233 hr = StringList_Count(pStringList, &iCount);
2234 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2235 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2237 /* StringList::Item */
2238 memset(szString, 0, sizeof(szString));
2239 hr = StringList_Item(pStringList, 0, szString);
2240 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2241 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
2243 IDispatch_Release(pStringList);
2246 /* Check & clean up installed files & registry keys */
2247 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2248 ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
2249 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2250 ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
2251 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2252 ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
2253 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2254 ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
2255 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2256 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2257 ok(delete_pf("msitest", FALSE), "File not installed\n");
2259 res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
2260 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2262 size = MAX_PATH;
2263 type = REG_SZ;
2264 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2265 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2266 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2268 size = MAX_PATH;
2269 type = REG_SZ;
2270 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2271 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2273 size = sizeof(num);
2274 type = REG_DWORD;
2275 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2276 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2277 ok(num == 314, "Expected 314, got %d\n", num);
2279 size = MAX_PATH;
2280 type = REG_SZ;
2281 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2282 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2283 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2285 RegCloseKey(hkey);
2287 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest");
2288 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2290 /* Remove registry keys written by RegisterProduct standard action */
2291 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F1C3AF50-8B56-4A69-A00C-00773FE42F30}");
2292 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2294 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2295 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2297 res = find_registry_key(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "05FA3C1F65B896A40AC00077F34EF203", &hkey);
2298 ok(res == ERROR_SUCCESS ||
2299 broken(res == ERROR_FILE_NOT_FOUND), /* win9x */
2300 "Expected ERROR_SUCCESS, got %d\n", res);
2301 if (res == ERROR_SUCCESS)
2303 res = delete_registry_key(hkey, "05FA3C1F65B896A40AC00077F34EF203");
2304 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2305 RegCloseKey(hkey);
2307 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203");
2308 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2310 else
2312 /* win9x defaults to a per-machine install. */
2313 RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203");
2316 /* Remove registry keys written by PublishProduct standard action */
2317 res = RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2318 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2320 res = delete_registry_key(hkey, "Products\\05FA3C1F65B896A40AC00077F34EF203");
2321 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2323 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2324 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2326 RegCloseKey(hkey);
2328 /* Delete installation files we installed */
2329 delete_test_files();
2332 static void test_Installer(void)
2334 static WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
2335 static WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
2336 WCHAR szPath[MAX_PATH];
2337 HRESULT hr;
2338 UINT len;
2339 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL;
2340 int iValue, iCount;
2342 if (!pInstaller) return;
2344 /* Installer::CreateRecord */
2346 /* Test for error */
2347 hr = Installer_CreateRecord(-1, &pRecord);
2348 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2349 ok_exception(hr, szCreateRecordException);
2351 /* Test for success */
2352 hr = Installer_CreateRecord(1, &pRecord);
2353 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2354 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2355 if (pRecord)
2357 /* Record::FieldCountGet */
2358 hr = Record_FieldCountGet(pRecord, &iValue);
2359 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2360 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2362 /* Record::IntegerDataGet */
2363 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2364 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2365 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2367 /* Record::IntegerDataGet, bad index */
2368 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2369 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2370 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2372 /* Record::IntegerDataPut */
2373 hr = Record_IntegerDataPut(pRecord, 1, 100);
2374 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2376 /* Record::IntegerDataPut, bad index */
2377 hr = Record_IntegerDataPut(pRecord, 10, 100);
2378 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2379 ok_exception(hr, szIntegerDataException);
2381 /* Record::IntegerDataGet */
2382 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2383 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2384 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2386 IDispatch_Release(pRecord);
2389 /* Prepare package */
2390 create_database(msifile, tables, sizeof(tables) / sizeof(msi_table),
2391 summary_info, sizeof(summary_info) / sizeof(msi_summary_info));
2393 len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, CURR_DIR, -1, szPath, MAX_PATH);
2394 ok(len, "MultiByteToWideChar returned error %d\n", GetLastError());
2395 if (!len) return;
2397 /* lstrcatW does not work on win95 */
2398 szPath[len - 1] = '\\';
2399 memcpy(&szPath[len], szMsifile, sizeof(szMsifile));
2401 /* Installer::OpenPackage */
2402 hr = Installer_OpenPackage(szPath, 0, &pSession);
2403 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2404 if (hr == S_OK)
2406 test_Session(pSession);
2407 IDispatch_Release(pSession);
2410 /* Installer::OpenDatabase */
2411 hr = Installer_OpenDatabase(szPath, (INT_PTR)MSIDBOPEN_TRANSACT, &pDatabase);
2412 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2413 if (hr == S_OK)
2415 test_Database(pDatabase, FALSE);
2416 IDispatch_Release(pDatabase);
2419 /* Installer::RegistryValue */
2420 test_Installer_RegistryValue();
2422 /* Installer::ProductState for our product code, which should not be installed */
2423 hr = Installer_ProductState(szProductCode, &iValue);
2424 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2425 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2427 /* Installer::ProductInfo for our product code, which should not be installed */
2429 /* Package name */
2430 memset(szPath, 0, sizeof(szPath));
2431 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szPath);
2432 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2433 ok_exception(hr, szProductInfoException);
2435 /* NULL attribute and NULL product code */
2436 memset(szPath, 0, sizeof(szPath));
2437 hr = Installer_ProductInfo(NULL, NULL, szPath);
2438 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2439 ok_exception(hr, szProductInfoException);
2441 /* Installer::Products */
2442 test_Installer_Products(FALSE);
2444 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2445 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2446 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2447 if (hr == S_OK)
2449 /* StringList::Count */
2450 hr = StringList_Count(pStringList, &iCount);
2451 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2452 ok(!iCount, "Expected no related products but found %d\n", iCount);
2454 IDispatch_Release(pStringList);
2457 /* Installer::Version */
2458 memset(szPath, 0, sizeof(szPath));
2459 hr = Installer_VersionGet(szPath);
2460 ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr);
2462 /* Installer::InstallProduct and other tests that depend on our product being installed */
2463 test_Installer_InstallProduct();
2466 START_TEST(automation)
2468 DWORD len;
2469 char temp_path[MAX_PATH], prev_path[MAX_PATH];
2470 HRESULT hr;
2471 CLSID clsid;
2472 IUnknown *pUnk;
2474 GetSystemTimeAsFileTime(&systemtime);
2476 GetCurrentDirectoryA(MAX_PATH, prev_path);
2477 GetTempPath(MAX_PATH, temp_path);
2478 SetCurrentDirectoryA(temp_path);
2480 lstrcpyA(CURR_DIR, temp_path);
2481 len = lstrlenA(CURR_DIR);
2483 if(len && (CURR_DIR[len - 1] == '\\'))
2484 CURR_DIR[len - 1] = 0;
2486 get_program_files_dir(PROG_FILES_DIR);
2488 hr = OleInitialize(NULL);
2489 ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr);
2490 hr = CLSIDFromProgID(szProgId, &clsid);
2491 ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr);
2492 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2493 ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr);
2495 if (pUnk)
2497 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2498 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2500 test_dispid();
2501 test_dispatch();
2502 test_Installer();
2504 IDispatch_Release(pInstaller);
2505 IUnknown_Release(pUnk);
2508 OleUninitialize();
2510 SetCurrentDirectoryA(prev_path);