push 5c57339901c8d80068fee18365e7574a1e8d922a
[wine/hacks.git] / dlls / msi / tests / automation.c
blob4af37aa8219f58900b27ca78d12cdfb69f37f342
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 /* lstrcmpW is not supported on Win9x */
368 static int strcmp_ww(const WCHAR* str1, const WCHAR* str2)
370 CHAR str1A[MAX_PATH], str2A[MAX_PATH];
372 WideCharToMultiByte(CP_ACP, 0, str1, -1, str1A, MAX_PATH, NULL, NULL);
373 WideCharToMultiByte(CP_ACP, 0, str2, -1, str2A, MAX_PATH, NULL, NULL);
375 return lstrcmpA(str1A, str2A);
378 #define ok_w2(format, szString1, szString2) \
380 do { \
381 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
382 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
383 if (lstrcmpA(string1, string2) != 0) \
384 ok(0, format, string1, string2); \
385 } while(0);
387 #define ok_w2n(format, szString1, szString2, len) \
389 if (memcmp(szString1, szString2, len * sizeof(WCHAR)) != 0) \
391 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
392 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
393 ok(0, format, string1, string2); \
396 #define ok_aw(format, aString, wString) \
398 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
399 if (lstrcmpA(string1, aString) != 0) \
400 ok(0, format, string1, aString); \
402 #define ok_awplus(format, extra, aString, wString) \
404 WideCharToMultiByte(CP_ACP, 0, wString, -1, string1, MAX_PATH, NULL, NULL); \
405 if (lstrcmpA(string1, aString) != 0) \
406 ok(0, format, extra, string1, aString); \
408 /* exception checker */
409 static WCHAR szSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
411 #define ok_exception(hr, szDescription) \
412 if (hr == DISP_E_EXCEPTION) \
414 /* Compare wtype, source, and destination */ \
415 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
417 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
418 if (excepinfo.bstrSource) \
419 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, szSource); \
421 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
422 if (excepinfo.bstrDescription) \
423 ok_w2("Exception description was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrDescription, szDescription); \
425 SysFreeString(excepinfo.bstrSource); \
426 SysFreeString(excepinfo.bstrDescription); \
427 SysFreeString(excepinfo.bstrHelpFile); \
430 static DISPID get_dispid( IDispatch *disp, const char *name )
432 LPOLESTR str;
433 UINT len;
434 DISPID id = -1;
435 HRESULT r;
437 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
438 str = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
439 if (str)
441 len = MultiByteToWideChar(CP_ACP, 0, name, -1, str, len );
442 r = IDispatch_GetIDsOfNames( disp, &IID_NULL, &str, 1, 0, &id );
443 HeapFree(GetProcessHeap(), 0, str);
444 if (r != S_OK)
445 return -1;
448 return id;
451 static void test_dispid(void)
453 DISPID dispid;
455 dispid = get_dispid(pInstaller, "CreateRecord");
456 ok(dispid == 1, "Expected 1, got %d\n", dispid);
457 dispid = get_dispid(pInstaller, "OpenPackage");
458 ok(dispid == 2, "Expected 2, got %d\n", dispid);
459 dispid = get_dispid(pInstaller, "OpenDatabase");
460 ok(dispid == 4, "Expected 4, got %d\n", dispid);
461 dispid = get_dispid( pInstaller, "UILevel" );
462 ok(dispid == 6, "Expected 6, got %d\n", dispid);
463 dispid = get_dispid(pInstaller, "InstallProduct");
464 ok(dispid == 8, "Expected 8, got %d\n", dispid);
465 dispid = get_dispid(pInstaller, "Version");
466 ok(dispid == 9, "Expected 9, got %d\n", dispid);
467 dispid = get_dispid(pInstaller, "RegistryValue");
468 ok(dispid == 11, "Expected 11, got %d\n", dispid);
469 todo_wine
471 dispid = get_dispid(pInstaller, "OpenProduct");
472 ok(dispid == 3, "Expected 3, got %d\n", dispid);
473 dispid = get_dispid(pInstaller, "SummaryInformation");
474 ok(dispid == 5, "Expected 5, got %d\n", dispid);
475 dispid = get_dispid(pInstaller, "EnableLog");
476 ok(dispid == 7, "Expected 7, got %d\n", dispid);
477 dispid = get_dispid(pInstaller, "LastErrorRecord");
478 ok(dispid == 10, "Expected 10, got %d\n", dispid);
479 dispid = get_dispid(pInstaller, "Environment");
480 ok(dispid == 12, "Expected 12, got %d\n", dispid);
481 dispid = get_dispid(pInstaller, "FileAttributes");
482 ok(dispid == 13, "Expected 13, got %d\n", dispid);
483 dispid = get_dispid(pInstaller, "FileSize");
484 ok(dispid == 15, "Expected 15, got %d\n", dispid);
485 dispid = get_dispid(pInstaller, "FileVersion");
486 ok(dispid == 16, "Expected 16, got %d\n", dispid);
488 dispid = get_dispid(pInstaller, "ProductState");
489 ok(dispid == 17, "Expected 17, got %d\n", dispid);
490 dispid = get_dispid(pInstaller, "ProductInfo");
491 ok(dispid == 18, "Expected 18, got %d\n", dispid);
492 todo_wine
494 dispid = get_dispid(pInstaller, "ConfigureProduct");
495 ok(dispid == 19, "Expected 19, got %d\n", dispid);
496 dispid = get_dispid(pInstaller, "ReinstallProduct");
497 ok(dispid == 20 , "Expected 20, got %d\n", dispid);
498 dispid = get_dispid(pInstaller, "CollectUserInfo");
499 ok(dispid == 21, "Expected 21, got %d\n", dispid);
500 dispid = get_dispid(pInstaller, "ApplyPatch");
501 ok(dispid == 22, "Expected 22, got %d\n", dispid);
502 dispid = get_dispid(pInstaller, "FeatureParent");
503 ok(dispid == 23, "Expected 23, got %d\n", dispid);
504 dispid = get_dispid(pInstaller, "FeatureState");
505 ok(dispid == 24, "Expected 24, got %d\n", dispid);
506 dispid = get_dispid(pInstaller, "UseFeature");
507 ok(dispid == 25, "Expected 25, got %d\n", dispid);
508 dispid = get_dispid(pInstaller, "FeatureUsageCount");
509 ok(dispid == 26, "Expected 26, got %d\n", dispid);
510 dispid = get_dispid(pInstaller, "FeatureUsageDate");
511 ok(dispid == 27, "Expected 27, got %d\n", dispid);
512 dispid = get_dispid(pInstaller, "ConfigureFeature");
513 ok(dispid == 28, "Expected 28, got %d\n", dispid);
514 dispid = get_dispid(pInstaller, "ReinstallFeature");
515 ok(dispid == 29, "Expected 29, got %d\n", dispid);
516 dispid = get_dispid(pInstaller, "ProvideComponent");
517 ok(dispid == 30, "Expected 30, got %d\n", dispid);
518 dispid = get_dispid(pInstaller, "ComponentPath");
519 ok(dispid == 31, "Expected 31, got %d\n", dispid);
520 dispid = get_dispid(pInstaller, "ProvideQualifiedComponent");
521 ok(dispid == 32, "Expected 32, got %d\n", dispid);
522 dispid = get_dispid(pInstaller, "QualifierDescription");
523 ok(dispid == 33, "Expected 33, got %d\n", dispid);
524 dispid = get_dispid(pInstaller, "ComponentQualifiers");
525 ok(dispid == 34, "Expected 34, got %d\n", dispid);
527 dispid = get_dispid(pInstaller, "Products");
528 ok(dispid == 35, "Expected 35, got %d\n", dispid);
529 todo_wine
531 dispid = get_dispid(pInstaller, "Features");
532 ok(dispid == 36, "Expected 36, got %d\n", dispid);
533 dispid = get_dispid(pInstaller, "Components");
534 ok(dispid == 37, "Expected 37, got %d\n", dispid);
535 dispid = get_dispid(pInstaller, "ComponentClients");
536 ok(dispid == 38, "Expected 38, got %d\n", dispid);
537 dispid = get_dispid(pInstaller, "Patches");
538 ok(dispid == 39, "Expected 39, got %d\n", dispid);
540 dispid = get_dispid(pInstaller, "RelatedProducts");
541 ok(dispid == 40, "Expected 40, got %d\n", dispid);
542 todo_wine
544 dispid = get_dispid(pInstaller, "PatchInfo");
545 ok(dispid == 41, "Expected 41, got %d\n", dispid);
546 dispid = get_dispid(pInstaller, "PatchTransforms");
547 ok(dispid == 42, "Expected 42, got %d\n", dispid);
548 dispid = get_dispid(pInstaller, "AddSource");
549 ok(dispid == 43, "Expected 43, got %d\n", dispid);
550 dispid = get_dispid(pInstaller, "ClearSourceList");
551 ok(dispid == 44, "Expected 44, got %d\n", dispid);
552 dispid = get_dispid(pInstaller, "ForceSourceListResolution");
553 ok(dispid == 45, "Expected 45, got %d\n", dispid);
554 dispid = get_dispid(pInstaller, "ShortcutTarget");
555 ok(dispid == 46, "Expected 46, got %d\n", dispid);
556 dispid = get_dispid(pInstaller, "FileHash");
557 ok(dispid == 47, "Expected 47, got %d\n", dispid);
558 dispid = get_dispid(pInstaller, "FileSignatureInfo");
559 ok(dispid == 48, "Expected 48, got %d\n", dispid);
561 dispid = get_dispid(pInstaller, "RemovePatches");
562 ok(dispid == 49 || dispid == -1, "Expected 49 or -1, got %d\n", dispid);
563 dispid = get_dispid(pInstaller, "ApplyMultiplePatches");
564 ok(dispid == 51 || dispid == -1, "Expected 51 or -1, got %d\n", dispid);
565 dispid = get_dispid(pInstaller, "ProductsEx");
566 ok(dispid == 52 || dispid == -1, "Expected 52 or -1, got %d\n", dispid);
567 dispid = get_dispid(pInstaller, "PatchesEx");
568 ok(dispid == 55 || dispid == -1, "Expected 55 or -1, got %d\n", dispid);
569 dispid = get_dispid(pInstaller, "ExtractPatchXMLData");
570 ok(dispid == 57 || dispid == -1, "Expected 57 or -1, got %d\n", dispid);
571 dispid = get_dispid( pInstaller, "ProductElevated" );
572 ok(dispid == 59 || dispid == -1, "Expected 59 or -1, got %d\n", dispid);
573 dispid = get_dispid( pInstaller, "ProvideAssembly" );
574 ok(dispid == 60 || dispid == -1, "Expected 60 or -1, got %d\n", dispid);
575 dispid = get_dispid( pInstaller, "ProductInfoFromScript" );
576 ok(dispid == 61 || dispid == -1, "Expected 61 or -1, got %d\n", dispid);
577 dispid = get_dispid( pInstaller, "AdvertiseProduct" );
578 ok(dispid == 62 || dispid == -1, "Expected 62 or -1, got %d\n", dispid);
579 dispid = get_dispid( pInstaller, "CreateAdvertiseScript" );
580 ok(dispid == 63 || dispid == -1, "Expected 63 or -1, got %d\n", dispid);
581 dispid = get_dispid( pInstaller, "PatchFiles" );
582 ok(dispid == 65 || dispid == -1, "Expected 65 or -1, got %d\n", dispid);
585 /* Test basic IDispatch functions */
586 static void test_dispatch(void)
588 static WCHAR szOpenPackage[] = { 'O','p','e','n','P','a','c','k','a','g','e',0 };
589 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};
590 static WCHAR szProductState[] = { 'P','r','o','d','u','c','t','S','t','a','t','e',0 };
591 HRESULT hr;
592 DISPID dispid;
593 OLECHAR *name;
594 VARIANT varresult;
595 VARIANTARG vararg[2];
596 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
598 /* Test getting ID of a function name that does not exist */
599 name = (WCHAR *)szMsifile;
600 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
601 ok(hr == DISP_E_UNKNOWNNAME, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
603 /* Test invoking this function */
604 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
605 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
607 /* Test getting ID of a function name that does exist */
608 name = szOpenPackage;
609 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
610 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
612 /* Test invoking this function (without parameters passed) */
613 if (0) /* All of these crash MSI on Windows XP */
615 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
616 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL);
617 VariantInit(&varresult);
618 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, &varresult, &excepinfo, NULL);
621 /* Try with NULL params */
622 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
623 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
625 /* Try one empty parameter */
626 dispparams.rgvarg = vararg;
627 dispparams.cArgs = 1;
628 VariantInit(&vararg[0]);
629 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
630 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
632 /* Try one parameter, function requires two */
633 VariantInit(&vararg[0]);
634 V_VT(&vararg[0]) = VT_BSTR;
635 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
636 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
637 VariantClear(&vararg[0]);
639 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
640 ok_exception(hr, szOpenPackageException);
642 /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
643 VariantInit(&vararg[0]);
644 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
645 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
647 VariantInit(&vararg[0]);
648 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
649 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
651 /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
652 name = szProductState;
653 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
654 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
656 dispparams.rgvarg = NULL;
657 dispparams.cArgs = 0;
658 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
659 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
661 dispparams.rgvarg = NULL;
662 dispparams.cArgs = 0;
663 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
664 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
667 /* invocation helper function */
668 static int _invoke_todo_vtResult = 0;
670 static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult)
672 OLECHAR *name = NULL;
673 DISPID dispid;
674 HRESULT hr;
675 UINT i;
676 UINT len;
678 memset(pVarResult, 0, sizeof(VARIANT));
679 VariantInit(pVarResult);
681 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 );
682 name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
683 if (!name) return E_FAIL;
684 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len );
685 hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
686 HeapFree(GetProcessHeap(), 0, name);
687 ok(hr == S_OK, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
688 if (!hr == S_OK) return hr;
690 memset(&excepinfo, 0, sizeof(excepinfo));
691 hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL);
693 if (hr == S_OK)
695 if (_invoke_todo_vtResult) todo_wine
696 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
697 else
698 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
699 if (vtResult != VT_EMPTY)
701 hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult);
702 ok(hr == S_OK, "VariantChangeTypeEx returned 0x%08x\n", hr);
706 for (i=0; i<pDispParams->cArgs; i++)
707 VariantClear(&pDispParams->rgvarg[i]);
709 return hr;
712 /* Object_Property helper functions */
714 static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord)
716 VARIANT varresult;
717 VARIANTARG vararg[1];
718 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
719 HRESULT hr;
721 VariantInit(&vararg[0]);
722 V_VT(&vararg[0]) = VT_I4;
723 V_I4(&vararg[0]) = count;
725 hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
726 *pRecord = V_DISPATCH(&varresult);
727 return hr;
730 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
732 VARIANTARG vararg[3];
733 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
735 VariantInit(&vararg[2]);
736 V_VT(&vararg[2]) = VT_I4;
737 V_I4(&vararg[2]) = (INT_PTR)hkey;
738 VariantInit(&vararg[1]);
739 V_VT(&vararg[1]) = VT_BSTR;
740 V_BSTR(&vararg[1]) = SysAllocString(szKey);
741 VariantInit(&vararg[0]);
742 VariantCopy(&vararg[0], &vValue);
743 VariantClear(&vValue);
745 return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect);
748 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
750 VARIANT varresult;
751 VARIANTARG vararg;
752 HRESULT hr;
754 VariantInit(&vararg);
755 V_VT(&vararg) = VT_EMPTY;
756 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL);
757 *pBool = V_BOOL(&varresult);
758 VariantClear(&varresult);
759 return hr;
762 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
764 VARIANT varresult;
765 VARIANTARG vararg;
766 HRESULT hr;
768 VariantInit(&vararg);
769 V_VT(&vararg) = VT_BSTR;
770 V_BSTR(&vararg) = SysAllocString(szValue);
772 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR);
773 if (V_BSTR(&varresult))
774 /* lstrcpyW is not implemented on Win95 (lstrlenW is though) */
775 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
776 VariantClear(&varresult);
777 return hr;
780 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
782 VARIANT varresult;
783 VARIANTARG vararg;
784 HRESULT hr;
786 VariantInit(&vararg);
787 V_VT(&vararg) = VT_I4;
788 V_I4(&vararg) = iValue;
790 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult);
791 if (SUCCEEDED(hr) && vtResult == VT_BSTR)
792 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
793 VariantClear(&varresult);
794 return hr;
797 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
799 VARIANT varresult;
800 VARIANTARG vararg[2];
801 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
802 HRESULT hr;
804 VariantInit(&vararg[1]);
805 V_VT(&vararg[1]) = VT_BSTR;
806 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
807 VariantInit(&vararg[0]);
808 V_VT(&vararg[0]) = VT_I4;
809 V_I4(&vararg[0]) = options;
811 hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
812 *pSession = V_DISPATCH(&varresult);
813 return hr;
816 static HRESULT Installer_OpenDatabase(LPCWSTR szDatabasePath, int openmode, IDispatch **pDatabase)
818 VARIANT varresult;
819 VARIANTARG vararg[2];
820 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
821 HRESULT hr;
823 VariantInit(&vararg[1]);
824 V_VT(&vararg[1]) = VT_BSTR;
825 V_BSTR(&vararg[1]) = SysAllocString(szDatabasePath);
826 VariantInit(&vararg[0]);
827 V_VT(&vararg[0]) = VT_I4;
828 V_I4(&vararg[0]) = openmode;
830 hr = invoke(pInstaller, "OpenDatabase", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
831 *pDatabase = V_DISPATCH(&varresult);
832 return hr;
835 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
837 VARIANT varresult;
838 VARIANTARG vararg[2];
839 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
841 VariantInit(&vararg[1]);
842 V_VT(&vararg[1]) = VT_BSTR;
843 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
844 VariantInit(&vararg[0]);
845 V_VT(&vararg[0]) = VT_BSTR;
846 V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues);
848 return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
851 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
853 VARIANT varresult;
854 VARIANTARG vararg[1];
855 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
856 HRESULT hr;
858 VariantInit(&vararg[0]);
859 V_VT(&vararg[0]) = VT_BSTR;
860 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
862 hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
863 *pInstallState = V_I4(&varresult);
864 VariantClear(&varresult);
865 return hr;
868 static HRESULT Installer_ProductInfo(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szString)
870 VARIANT varresult;
871 VARIANTARG vararg[2];
872 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
873 HRESULT hr;
875 VariantInit(&vararg[1]);
876 V_VT(&vararg[1]) = VT_BSTR;
877 V_BSTR(&vararg[1]) = SysAllocString(szProduct);
878 VariantInit(&vararg[0]);
879 V_VT(&vararg[0]) = VT_BSTR;
880 V_BSTR(&vararg[0]) = SysAllocString(szAttribute);
882 hr = invoke(pInstaller, "ProductInfo", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
883 if (V_BSTR(&varresult))
884 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
885 VariantClear(&varresult);
886 return hr;
889 static HRESULT Installer_Products(IDispatch **pStringList)
891 VARIANT varresult;
892 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
893 HRESULT hr;
895 hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
896 *pStringList = V_DISPATCH(&varresult);
897 return hr;
900 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
902 VARIANT varresult;
903 VARIANTARG vararg[1];
904 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
905 HRESULT hr;
907 VariantInit(&vararg[0]);
908 V_VT(&vararg[0]) = VT_BSTR;
909 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
911 hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
912 *pStringList = V_DISPATCH(&varresult);
913 return hr;
916 static HRESULT Installer_VersionGet(LPWSTR szVersion)
918 VARIANT varresult;
919 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
920 HRESULT hr;
922 hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
923 if (V_BSTR(&varresult))
924 memcpy(szVersion, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
925 VariantClear(&varresult);
926 return hr;
929 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
931 VARIANT varresult;
932 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
933 HRESULT hr;
935 hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
936 *pInst = V_DISPATCH(&varresult);
937 return hr;
940 static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPWSTR szReturn)
942 VARIANT varresult;
943 VARIANTARG vararg[1];
944 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
945 HRESULT hr;
947 VariantInit(&vararg[0]);
948 V_VT(&vararg[0]) = VT_BSTR;
949 V_BSTR(&vararg[0]) = SysAllocString(szName);
951 hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
952 if (V_BSTR(&varresult))
953 memcpy(szReturn, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
954 VariantClear(&varresult);
955 return hr;
958 static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue)
960 VARIANT varresult;
961 VARIANTARG vararg[2];
962 DISPID dispid = DISPID_PROPERTYPUT;
963 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
965 VariantInit(&vararg[1]);
966 V_VT(&vararg[1]) = VT_BSTR;
967 V_BSTR(&vararg[1]) = SysAllocString(szName);
968 VariantInit(&vararg[0]);
969 V_VT(&vararg[0]) = VT_BSTR;
970 V_BSTR(&vararg[0]) = SysAllocString(szValue);
972 return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
975 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
977 VARIANT varresult;
978 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
979 HRESULT hr;
981 hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
982 *pLangId = V_I4(&varresult);
983 VariantClear(&varresult);
984 return hr;
987 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, BOOL *pMode)
989 VARIANT varresult;
990 VARIANTARG vararg[1];
991 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
992 HRESULT hr;
994 VariantInit(&vararg[0]);
995 V_VT(&vararg[0]) = VT_I4;
996 V_I4(&vararg[0]) = iFlag;
998 hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL);
999 *pMode = V_BOOL(&varresult);
1000 VariantClear(&varresult);
1001 return hr;
1004 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, BOOL bMode)
1006 VARIANT varresult;
1007 VARIANTARG vararg[2];
1008 DISPID dispid = DISPID_PROPERTYPUT;
1009 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1011 VariantInit(&vararg[1]);
1012 V_VT(&vararg[1]) = VT_I4;
1013 V_I4(&vararg[1]) = iFlag;
1014 VariantInit(&vararg[0]);
1015 V_VT(&vararg[0]) = VT_BOOL;
1016 V_BOOL(&vararg[0]) = bMode;
1018 return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1021 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
1023 VARIANT varresult;
1024 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1025 HRESULT hr;
1027 hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1028 *pDatabase = V_DISPATCH(&varresult);
1029 return hr;
1032 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, 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(szAction);
1043 hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1044 *iReturn = V_I4(&varresult);
1045 VariantClear(&varresult);
1046 return hr;
1049 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
1051 VARIANT varresult;
1052 VARIANTARG vararg[1];
1053 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1054 HRESULT hr;
1056 VariantInit(&vararg[0]);
1057 V_VT(&vararg[0]) = VT_BSTR;
1058 V_BSTR(&vararg[0]) = SysAllocString(szCondition);
1060 hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1061 *iReturn = V_I4(&varresult);
1062 VariantClear(&varresult);
1063 return hr;
1066 static HRESULT Session_Message(IDispatch *pSession, LONG kind, IDispatch *record, int *ret)
1068 VARIANT varresult;
1069 VARIANTARG vararg[2];
1070 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1071 HRESULT hr;
1073 VariantInit(&varresult);
1074 V_VT(vararg) = VT_DISPATCH;
1075 V_DISPATCH(vararg) = record;
1076 V_VT(vararg+1) = VT_I4;
1077 V_I4(vararg+1) = kind;
1079 hr = invoke(pSession, "Message", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
1081 ok(V_VT(&varresult) == VT_I4, "V_VT(varresult) = %d\n", V_VT(&varresult));
1082 *ret = V_I4(&varresult);
1084 return hr;
1087 static HRESULT Session_SetInstallLevel(IDispatch *pSession, LONG iInstallLevel)
1089 VARIANT varresult;
1090 VARIANTARG vararg[1];
1091 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1093 VariantInit(&vararg[0]);
1094 V_VT(&vararg[0]) = VT_I4;
1095 V_I4(&vararg[0]) = iInstallLevel;
1097 return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1100 static HRESULT Session_FeatureCurrentState(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, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1112 *pState = V_I4(&varresult);
1113 VariantClear(&varresult);
1114 return hr;
1117 static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState)
1119 VARIANT varresult;
1120 VARIANTARG vararg[1];
1121 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1122 HRESULT hr;
1124 VariantInit(&vararg[0]);
1125 V_VT(&vararg[0]) = VT_BSTR;
1126 V_BSTR(&vararg[0]) = SysAllocString(szName);
1128 hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1129 *pState = V_I4(&varresult);
1130 VariantClear(&varresult);
1131 return hr;
1134 static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState)
1136 VARIANT varresult;
1137 VARIANTARG vararg[2];
1138 DISPID dispid = DISPID_PROPERTYPUT;
1139 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1141 VariantInit(&vararg[1]);
1142 V_VT(&vararg[1]) = VT_BSTR;
1143 V_BSTR(&vararg[1]) = SysAllocString(szName);
1144 VariantInit(&vararg[0]);
1145 V_VT(&vararg[0]) = VT_I4;
1146 V_I4(&vararg[0]) = iState;
1148 return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1151 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
1153 VARIANT varresult;
1154 VARIANTARG vararg[1];
1155 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1156 HRESULT hr;
1158 VariantInit(&vararg[0]);
1159 V_VT(&vararg[0]) = VT_BSTR;
1160 V_BSTR(&vararg[0]) = SysAllocString(szSql);
1162 hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1163 *pView = V_DISPATCH(&varresult);
1164 return hr;
1167 static HRESULT Database_SummaryInformation(IDispatch *pDatabase, int iUpdateCount, IDispatch **pSummaryInfo)
1169 VARIANT varresult;
1170 VARIANTARG vararg[1];
1171 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1172 HRESULT hr;
1174 VariantInit(&vararg[0]);
1175 V_VT(&vararg[0]) = VT_I4;
1176 V_I4(&vararg[0]) = iUpdateCount;
1178 hr = invoke(pDatabase, "SummaryInformation", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
1179 *pSummaryInfo = V_DISPATCH(&varresult);
1180 return hr;
1183 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
1185 VARIANT varresult;
1186 VARIANTARG vararg[1];
1187 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1189 VariantInit(&vararg[0]);
1190 V_VT(&vararg[0]) = VT_DISPATCH;
1191 V_DISPATCH(&vararg[0]) = pRecord;
1193 return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1196 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
1198 VARIANT varresult;
1199 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1200 HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1201 *ppRecord = V_DISPATCH(&varresult);
1202 return hr;
1205 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
1207 VARIANT varresult;
1208 VARIANTARG vararg[2];
1209 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1211 VariantInit(&vararg[1]);
1212 V_VT(&vararg[1]) = VT_I4;
1213 V_I4(&vararg[1]) = iMode;
1214 VariantInit(&vararg[0]);
1215 V_VT(&vararg[0]) = VT_DISPATCH;
1216 V_DISPATCH(&vararg[0]) = pRecord;
1217 if (pRecord)
1218 IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */
1220 return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1223 static HRESULT View_Close(IDispatch *pView)
1225 VARIANT varresult;
1226 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1227 return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1230 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
1232 VARIANT varresult;
1233 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1234 HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1235 *pFieldCount = V_I4(&varresult);
1236 VariantClear(&varresult);
1237 return hr;
1240 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPWSTR szString)
1242 VARIANT varresult;
1243 VARIANTARG vararg[1];
1244 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1245 HRESULT hr;
1247 VariantInit(&vararg[0]);
1248 V_VT(&vararg[0]) = VT_I4;
1249 V_I4(&vararg[0]) = iField;
1251 hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1252 if (V_BSTR(&varresult))
1253 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
1254 VariantClear(&varresult);
1255 return hr;
1258 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
1260 VARIANT varresult;
1261 VARIANTARG vararg[2];
1262 DISPID dispid = DISPID_PROPERTYPUT;
1263 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1265 VariantInit(&vararg[1]);
1266 V_VT(&vararg[1]) = VT_I4;
1267 V_I4(&vararg[1]) = iField;
1268 VariantInit(&vararg[0]);
1269 V_VT(&vararg[0]) = VT_BSTR;
1270 V_BSTR(&vararg[0]) = SysAllocString(szString);
1272 return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1275 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
1277 VARIANT varresult;
1278 VARIANTARG vararg[1];
1279 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1280 HRESULT hr;
1282 VariantInit(&vararg[0]);
1283 V_VT(&vararg[0]) = VT_I4;
1284 V_I4(&vararg[0]) = iField;
1286 hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1287 *pValue = V_I4(&varresult);
1288 VariantClear(&varresult);
1289 return hr;
1292 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
1294 VARIANT varresult;
1295 VARIANTARG vararg[2];
1296 DISPID dispid = DISPID_PROPERTYPUT;
1297 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1299 VariantInit(&vararg[1]);
1300 V_VT(&vararg[1]) = VT_I4;
1301 V_I4(&vararg[1]) = iField;
1302 VariantInit(&vararg[0]);
1303 V_VT(&vararg[0]) = VT_I4;
1304 V_I4(&vararg[0]) = iValue;
1306 return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1309 static HRESULT StringList__NewEnum(IDispatch *pList, IUnknown **ppEnumVARIANT)
1311 VARIANT varresult;
1312 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1313 HRESULT hr = invoke(pList, "_NewEnum", DISPATCH_METHOD, &dispparams, &varresult, VT_UNKNOWN);
1314 *ppEnumVARIANT = V_UNKNOWN(&varresult);
1315 return hr;
1318 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
1320 VARIANT varresult;
1321 VARIANTARG vararg[1];
1322 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1323 HRESULT hr;
1325 VariantInit(&vararg[0]);
1326 V_VT(&vararg[0]) = VT_I4;
1327 V_I4(&vararg[0]) = iIndex;
1329 hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1330 if (V_BSTR(&varresult))
1331 memcpy(szString, V_BSTR(&varresult), (lstrlenW(V_BSTR(&varresult)) + 1) * sizeof(WCHAR));
1332 VariantClear(&varresult);
1333 return hr;
1336 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
1338 VARIANT varresult;
1339 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1340 HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1341 *pCount = V_I4(&varresult);
1342 VariantClear(&varresult);
1343 return hr;
1346 static HRESULT SummaryInfo_PropertyGet(IDispatch *pSummaryInfo, int pid, VARIANT *pVarResult, VARTYPE vtExpect)
1348 VARIANTARG vararg[1];
1349 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1351 VariantInit(&vararg[0]);
1352 V_VT(&vararg[0]) = VT_I4;
1353 V_I4(&vararg[0]) = pid;
1354 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYGET, &dispparams, pVarResult, vtExpect);
1357 static HRESULT SummaryInfo_PropertyPut(IDispatch *pSummaryInfo, int pid, VARIANT *pVariant)
1359 VARIANT varresult;
1360 VARIANTARG vararg[2];
1361 DISPID dispid = DISPID_PROPERTYPUT;
1362 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1364 VariantInit(&vararg[1]);
1365 V_VT(&vararg[1]) = VT_I4;
1366 V_I4(&vararg[1]) = pid;
1367 VariantInit(&vararg[0]);
1368 VariantCopyInd(vararg, pVariant);
1370 return invoke(pSummaryInfo, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1373 static HRESULT SummaryInfo_PropertyCountGet(IDispatch *pSummaryInfo, int *pCount)
1375 VARIANT varresult;
1376 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1377 HRESULT hr;
1379 hr = invoke(pSummaryInfo, "PropertyCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1380 *pCount = V_I4(&varresult);
1381 VariantClear(&varresult);
1382 return hr;
1385 /* Test the various objects */
1387 #define TEST_SUMMARYINFO_PROPERTIES_MODIFIED 4
1389 static void test_SummaryInfo(IDispatch *pSummaryInfo, const msi_summary_info *info, int num_info, BOOL readonly)
1391 static const WCHAR szPropertyException[] = { 'P','r','o','p','e','r','t','y',',','P','i','d',0 };
1392 static const WCHAR szTitle[] = { 'T','i','t','l','e',0 };
1393 VARIANT varresult, var;
1394 SYSTEMTIME st;
1395 HRESULT hr;
1396 int j;
1398 /* SummaryInfo::PropertyCount */
1399 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1400 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1401 ok(j == num_info, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1403 /* SummaryInfo::Property, get for properties we have set */
1404 for (j = 0; j < num_info; j++)
1406 const msi_summary_info *entry = &info[j];
1408 int vt = entry->datatype;
1409 if (vt == VT_LPSTR) vt = VT_BSTR;
1410 else if (vt == VT_FILETIME) vt = VT_DATE;
1411 else if (vt == VT_I2) vt = VT_I4;
1413 hr = SummaryInfo_PropertyGet(pSummaryInfo, entry->property, &varresult, vt);
1414 ok(hr == S_OK, "SummaryInfo_Property (pid %d) failed, hresult 0x%08x\n", entry->property, hr);
1415 if (V_VT(&varresult) != vt)
1416 skip("Skipping property tests due to type mismatch\n");
1417 else if (vt == VT_I4)
1418 ok(V_I4(&varresult) == entry->iValue, "SummaryInfo_Property (pid %d) I4 result expected to be %d, but was %d\n",
1419 entry->property, entry->iValue, V_I4(&varresult));
1420 else if (vt == VT_DATE)
1422 FILETIME ft;
1423 DATE d;
1425 FileTimeToLocalFileTime(entry->pftValue, &ft);
1426 FileTimeToSystemTime(&ft, &st);
1427 SystemTimeToVariantTime(&st, &d);
1428 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));
1430 else if (vt == VT_BSTR)
1432 ok_awplus("SummaryInfo_Property (pid %d) BSTR result expected to be %s, but was %s\n", entry->property, entry->szValue, V_BSTR(&varresult));
1434 else
1435 skip("SummaryInfo_Property (pid %d) unhandled result type %d\n", entry->property, vt);
1437 VariantClear(&varresult);
1440 /* SummaryInfo::Property, get; invalid arguments */
1442 /* Invalid pids */
1443 hr = SummaryInfo_PropertyGet(pSummaryInfo, -1, &varresult, VT_EMPTY);
1444 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1445 ok_exception(hr, szPropertyException);
1447 hr = SummaryInfo_PropertyGet(pSummaryInfo, 1000, &varresult, VT_EMPTY);
1448 ok(hr == DISP_E_EXCEPTION, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1449 ok_exception(hr, szPropertyException);
1451 /* Unsupported pids */
1452 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_DICTIONARY, &varresult, VT_EMPTY);
1453 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1455 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_THUMBNAIL, &varresult, VT_EMPTY);
1456 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1458 /* Pids we have not set, one for each type */
1459 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_EMPTY);
1460 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1462 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, VT_EMPTY);
1463 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1465 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_EDITTIME, &varresult, VT_EMPTY);
1466 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1468 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, VT_EMPTY);
1469 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1471 if (!readonly)
1473 /* SummaryInfo::Property, put; one for each type */
1475 /* VT_I2 */
1476 VariantInit(&var);
1477 V_VT(&var) = VT_I2;
1478 V_I2(&var) = 1;
1479 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CODEPAGE, &var);
1480 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1482 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CODEPAGE, &varresult, VT_I4 /* NOT VT_I2 */);
1483 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1484 ok(V_I2(&var) == V_I2(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I2(&var), V_I2(&varresult));
1485 VariantClear(&varresult);
1486 VariantClear(&var);
1488 /* VT_BSTR */
1489 V_VT(&var) = VT_BSTR;
1490 V_BSTR(&var) = SysAllocString(szTitle);
1491 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_TITLE, &var);
1492 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1494 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_TITLE, &varresult, V_VT(&var));
1495 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1496 ok_w2("SummaryInfo_PropertyGet expected %s, but returned %s\n", V_BSTR(&var), V_BSTR(&varresult));
1497 VariantClear(&varresult);
1498 VariantClear(&var);
1500 /* VT_DATE */
1501 V_VT(&var) = VT_DATE;
1502 FileTimeToSystemTime(&systemtime, &st);
1503 SystemTimeToVariantTime(&st, &V_DATE(&var));
1504 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_LASTSAVE_DTM, &var);
1505 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1507 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_LASTSAVE_DTM, &varresult, V_VT(&var));
1508 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1509 /* FIXME: Off by one second */
1510 todo_wine ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1511 VariantClear(&varresult);
1512 VariantClear(&var);
1514 /* VT_I4 */
1515 V_VT(&var) = VT_I4;
1516 V_I4(&var) = 1000;
1517 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1518 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1520 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1521 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1522 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult));
1523 VariantClear(&varresult);
1524 VariantClear(&var);
1526 /* SummaryInfo::PropertyCount */
1527 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1528 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1529 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1533 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1535 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 };
1536 static WCHAR szThree[] = { 'T','h','r','e','e',0 };
1537 static WCHAR szTwo[] = { 'T','w','o',0 };
1538 static WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
1539 static WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 };
1540 IDispatch *pView = NULL, *pSummaryInfo = NULL;
1541 HRESULT hr;
1543 hr = Database_OpenView(pDatabase, szSql, &pView);
1544 ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr);
1545 if (hr == S_OK)
1547 IDispatch *pRecord = NULL;
1548 WCHAR szString[MAX_PATH];
1550 /* View::Execute */
1551 hr = View_Execute(pView, NULL);
1552 ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr);
1554 /* View::Fetch */
1555 hr = View_Fetch(pView, &pRecord);
1556 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1557 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1558 if (pRecord)
1560 /* Record::StringDataGet */
1561 memset(szString, 0, sizeof(szString));
1562 hr = Record_StringDataGet(pRecord, 1, szString);
1563 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1564 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1566 /* Record::StringDataPut with correct index */
1567 hr = Record_StringDataPut(pRecord, 1, szTwo);
1568 ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1570 /* Record::StringDataGet */
1571 memset(szString, 0, sizeof(szString));
1572 hr = Record_StringDataGet(pRecord, 1, szString);
1573 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1574 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1576 /* Record::StringDataPut with incorrect index */
1577 hr = Record_StringDataPut(pRecord, -1, szString);
1578 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1579 ok_exception(hr, szStringDataField);
1581 /* View::Modify with incorrect parameters */
1582 hr = View_Modify(pView, -5, NULL);
1583 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1584 ok_exception(hr, szModifyModeRecord);
1586 hr = View_Modify(pView, -5, pRecord);
1587 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1588 ok_exception(hr, szModifyModeRecord);
1590 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1591 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1592 ok_exception(hr, szModifyModeRecord);
1594 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1595 ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr);
1597 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1598 memset(szString, 0, sizeof(szString));
1599 hr = Record_StringDataGet(pRecord, 1, szString);
1600 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1601 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1603 IDispatch_Release(pRecord);
1606 /* View::Fetch */
1607 hr = View_Fetch(pView, &pRecord);
1608 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1609 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1610 if (pRecord)
1612 /* Record::StringDataGet */
1613 memset(szString, 0, sizeof(szString));
1614 hr = Record_StringDataGet(pRecord, 1, szString);
1615 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1616 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1618 IDispatch_Release(pRecord);
1621 /* View::Fetch */
1622 hr = View_Fetch(pView, &pRecord);
1623 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1624 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1625 if (pRecord)
1626 IDispatch_Release(pRecord);
1628 /* View::Close */
1629 hr = View_Close(pView);
1630 ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr);
1632 IDispatch_Release(pView);
1635 /* Database::SummaryInformation */
1636 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo);
1637 ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr);
1638 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1639 if (pSummaryInfo)
1641 test_SummaryInfo(pSummaryInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), readonly);
1642 IDispatch_Release(pSummaryInfo);
1646 static void test_Session(IDispatch *pSession)
1648 static WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
1649 static WCHAR szOne[] = { 'O','n','e',0 };
1650 static WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 };
1651 static WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 };
1652 static WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 };
1653 static WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 };
1654 static WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1655 static WCHAR szEmpty[] = { 0 };
1656 static WCHAR szEquals[] = { '=',0 };
1657 static WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
1658 WCHAR stringw[MAX_PATH];
1659 CHAR string[MAX_PATH];
1660 UINT len;
1661 BOOL bool;
1662 int myint;
1663 IDispatch *pDatabase = NULL, *pInst = NULL, *record = NULL;
1664 HRESULT hr;
1666 /* Session::Installer */
1667 hr = Session_Installer(pSession, &pInst);
1668 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1669 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1670 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1672 /* Session::Property, get */
1673 memset(stringw, 0, sizeof(stringw));
1674 hr = Session_PropertyGet(pSession, szProductName, stringw);
1675 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1676 if (strcmp_ww(stringw, szMSITEST) != 0)
1678 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1679 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1680 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1683 /* Session::Property, put */
1684 hr = Session_PropertyPut(pSession, szProductName, szProductName);
1685 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1686 memset(stringw, 0, sizeof(stringw));
1687 hr = Session_PropertyGet(pSession, szProductName, stringw);
1688 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1689 if (strcmp_ww(stringw, szProductName) != 0)
1691 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1692 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1693 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1696 /* Try putting a property using empty property identifier */
1697 hr = Session_PropertyPut(pSession, szEmpty, szProductName);
1698 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1699 ok_exception(hr, szPropertyName);
1701 /* Try putting a property using illegal property identifier */
1702 hr = Session_PropertyPut(pSession, szEquals, szProductName);
1703 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1705 /* Session::Language, get */
1706 hr = Session_LanguageGet(pSession, &len);
1707 ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1708 /* Not sure how to check the language is correct */
1710 /* Session::Mode, get */
1711 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1712 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1713 todo_wine ok(!bool, "Reboot at end session mode is %d\n", bool);
1715 /* Session::Mode, put */
1716 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE);
1717 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1718 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1719 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1720 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1721 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE); /* set it again so we don't reboot */
1722 todo_wine ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1724 /* Session::Database, get */
1725 hr = Session_Database(pSession, &pDatabase);
1726 ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr);
1727 if (hr == S_OK)
1729 test_Database(pDatabase, TRUE);
1730 IDispatch_Release(pDatabase);
1733 /* Session::EvaluateCondition */
1734 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1735 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1736 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1738 hr = Session_EvaluateCondition(pSession, szEmpty, &myint);
1739 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1740 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1742 hr = Session_EvaluateCondition(pSession, szEquals, &myint);
1743 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1744 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1746 /* Session::DoAction(CostInitialize) must occur before the next statements */
1747 hr = Session_DoAction(pSession, szCostInitialize, &myint);
1748 ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr);
1749 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1751 /* Session::SetInstallLevel */
1752 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1753 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
1755 /* Session::FeatureCurrentState, get */
1756 hr = Session_FeatureCurrentState(pSession, szOne, &myint);
1757 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
1758 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1760 /* Session::Message */
1761 hr = Installer_CreateRecord(0, &record);
1762 ok(hr == S_OK, "Installer_CreateRecord failed: %08x\n", hr);
1763 hr = Session_Message(pSession, INSTALLMESSAGE_INFO, record, &myint);
1764 ok(hr == S_OK, "Session_Message failed: %08x\n", hr);
1765 ok(myint == 0, "Session_Message returned %x\n", myint);
1767 /* Session::EvaluateCondition */
1768 hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint);
1769 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1770 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1772 hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint);
1773 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1774 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1776 /* Session::FeatureRequestState, put */
1777 hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED);
1778 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
1779 hr = Session_FeatureRequestStateGet(pSession, szOne, &myint);
1780 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
1781 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
1783 /* Session::EvaluateCondition */
1784 hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint);
1785 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1786 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1788 hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint);
1789 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1790 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1793 /* delete key and all its subkeys */
1794 static DWORD delete_key( HKEY hkey )
1796 char name[MAX_PATH];
1797 DWORD ret;
1799 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
1801 HKEY tmp;
1802 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
1804 ret = delete_key( tmp );
1805 RegCloseKey( tmp );
1807 if (ret) break;
1809 if (ret != ERROR_NO_MORE_ITEMS) return ret;
1810 RegDeleteKeyA( hkey, "" );
1811 return 0;
1814 static void test_Installer_RegistryValue(void)
1816 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
1817 static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 };
1818 static const WCHAR szOne[] = { 'O','n','e',0 };
1819 static const WCHAR szTwo[] = { 'T','w','o',0 };
1820 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
1821 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1822 static const WCHAR szFour[] = { 'F','o','u','r',0 };
1823 static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 };
1824 static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 };
1825 static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 };
1826 static const WCHAR szSix[] = { 'S','i','x',0 };
1827 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1828 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
1829 static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
1830 static const WCHAR szBlank[] = { 0 };
1831 VARIANT varresult;
1832 VARIANTARG vararg;
1833 WCHAR szString[MAX_PATH];
1834 HKEY hkey, hkey_sub;
1835 HKEY curr_user = (HKEY)1;
1836 HRESULT hr;
1837 BOOL bRet;
1838 LONG lRet;
1840 /* Delete keys */
1841 SetLastError(0xdeadbeef);
1842 lRet = RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey );
1843 if (!lRet && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1845 win_skip("Needed W-functions are not implemented\n");
1846 return;
1848 if (!lRet)
1849 delete_key( hkey );
1851 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
1852 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
1853 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1854 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
1856 memset(szString, 0, sizeof(szString));
1857 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
1858 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1860 memset(szString, 0, sizeof(szString));
1861 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
1862 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1864 /* Create key */
1865 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
1867 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1868 "RegSetValueExW failed\n");
1869 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
1870 "RegSetValueExW failed\n");
1871 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
1872 "RegSetValueExW failed\n");
1873 ok(SetEnvironmentVariableA("MSITEST", "Four"), "SetEnvironmentVariableA failed %d\n", GetLastError());
1874 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
1875 "RegSetValueExW failed\n");
1876 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
1877 "RegSetValueExW failed\n");
1878 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
1879 "RegSetValueExW failed\n");
1880 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, NULL, 0),
1881 "RegSetValueExW failed\n");
1883 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1884 "RegSetValueExW failed\n");
1886 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
1888 /* Does our key exist? It should, and make sure we retrieve the correct default value */
1889 bRet = FALSE;
1890 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
1891 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1892 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
1894 memset(szString, 0, sizeof(szString));
1895 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
1896 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1897 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1899 /* Ask for the value of a nonexistent key */
1900 memset(szString, 0, sizeof(szString));
1901 hr = Installer_RegistryValueW(curr_user, szKey, szExpand, szString);
1902 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1904 /* Get values of keys */
1905 memset(szString, 0, sizeof(szString));
1906 hr = Installer_RegistryValueW(curr_user, szKey, szOne, szString);
1907 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1908 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1910 VariantInit(&vararg);
1911 V_VT(&vararg) = VT_BSTR;
1912 V_BSTR(&vararg) = SysAllocString(szTwo);
1913 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_I4);
1914 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1915 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
1916 VariantClear(&varresult);
1918 memset(szString, 0, sizeof(szString));
1919 hr = Installer_RegistryValueW(curr_user, szKey, szThree, szString);
1920 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1921 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
1923 memset(szString, 0, sizeof(szString));
1924 hr = Installer_RegistryValueW(curr_user, szKey, szFour, szString);
1925 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1926 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
1928 /* Vista does not NULL-terminate this case */
1929 memset(szString, 0, sizeof(szString));
1930 hr = Installer_RegistryValueW(curr_user, szKey, szFive, szString);
1931 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1932 ok_w2n("Registry value \"%s\" does not match expected \"%s\"\n",
1933 szString, szFiveHi, lstrlenW(szFiveHi));
1935 memset(szString, 0, sizeof(szString));
1936 hr = Installer_RegistryValueW(curr_user, szKey, szSix, szString);
1937 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1938 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_);
1940 VariantInit(&vararg);
1941 V_VT(&vararg) = VT_BSTR;
1942 V_BSTR(&vararg) = SysAllocString(szSeven);
1943 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_EMPTY);
1944 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1946 /* Get string class name for the key */
1947 memset(szString, 0, sizeof(szString));
1948 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
1949 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1950 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank);
1952 /* Get name of a value by positive number (RegEnumValue like), valid index */
1953 memset(szString, 0, sizeof(szString));
1954 hr = Installer_RegistryValueI(curr_user, szKey, 2, szString, VT_BSTR);
1955 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1956 /* RegEnumValue order seems different on wine */
1957 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
1959 /* Get name of a value by positive number (RegEnumValue like), invalid index */
1960 memset(szString, 0, sizeof(szString));
1961 hr = Installer_RegistryValueI(curr_user, szKey, 10, szString, VT_EMPTY);
1962 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1964 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
1965 memset(szString, 0, sizeof(szString));
1966 hr = Installer_RegistryValueI(curr_user, szKey, -1, szString, VT_BSTR);
1967 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1968 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
1970 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
1971 memset(szString, 0, sizeof(szString));
1972 hr = Installer_RegistryValueI(curr_user, szKey, -10, szString, VT_EMPTY);
1973 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1975 /* clean up */
1976 delete_key(hkey);
1979 static void test_Installer_Products(BOOL bProductInstalled)
1981 WCHAR szString[MAX_PATH];
1982 HRESULT hr;
1983 int idx;
1984 IUnknown *pUnk = NULL;
1985 IEnumVARIANT *pEnum = NULL;
1986 VARIANT var;
1987 ULONG celt;
1988 int iCount, iValue;
1989 IDispatch *pStringList = NULL;
1990 BOOL bProductFound = FALSE;
1992 /* Installer::Products */
1993 hr = Installer_Products(&pStringList);
1994 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
1995 if (hr == S_OK)
1997 /* StringList::_NewEnum */
1998 hr = StringList__NewEnum(pStringList, &pUnk);
1999 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
2000 if (hr == S_OK)
2002 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
2003 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2005 if (!pEnum)
2006 skip("IEnumVARIANT tests\n");
2008 /* StringList::Count */
2009 hr = StringList_Count(pStringList, &iCount);
2010 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2012 for (idx=0; idx<iCount; idx++)
2014 /* StringList::Item */
2015 memset(szString, 0, sizeof(szString));
2016 hr = StringList_Item(pStringList, idx, szString);
2017 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2019 if (hr == S_OK)
2021 /* Installer::ProductState */
2022 hr = Installer_ProductState(szString, &iValue);
2023 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2024 if (hr == S_OK)
2025 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
2027 /* Not found our product code yet? Check */
2028 if (!bProductFound && !strcmp_ww(szString, szProductCode))
2029 bProductFound = TRUE;
2031 /* IEnumVARIANT::Next */
2032 if (pEnum)
2034 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2035 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2036 ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
2037 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2038 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2039 VariantClear(&var);
2044 if (bProductInstalled)
2046 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
2047 bProductInstalled ? "be" : "not be",
2048 bProductFound ? "found" : "not found");
2051 if (pEnum)
2053 IEnumVARIANT *pEnum2 = NULL;
2055 if (0) /* Crashes on Windows XP */
2057 /* IEnumVARIANT::Clone, NULL pointer */
2058 hr = IEnumVARIANT_Clone(pEnum, NULL);
2061 /* IEnumVARIANT::Clone */
2062 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
2063 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
2064 if (hr == S_OK)
2066 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
2068 /* IEnumVARIANT::Next of the clone */
2069 if (iCount)
2071 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
2072 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2073 ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
2074 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2075 VariantClear(&var);
2077 else
2078 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
2080 IEnumVARIANT_Release(pEnum2);
2083 /* IEnumVARIANT::Skip should fail */
2084 hr = IEnumVARIANT_Skip(pEnum, 1);
2085 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2087 /* IEnumVARIANT::Next, NULL variant pointer */
2088 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2089 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2090 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2092 /* IEnumVARIANT::Next, should not return any more items */
2093 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2094 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2095 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2096 VariantClear(&var);
2098 /* IEnumVARIANT::Reset */
2099 hr = IEnumVARIANT_Reset(pEnum);
2100 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2102 if (iCount)
2104 /* IEnumVARIANT::Skip to the last product */
2105 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2106 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2108 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2109 * NULL celt pointer. */
2110 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2111 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2112 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2113 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2114 VariantClear(&var);
2116 else
2117 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2120 /* StringList::Item using an invalid index */
2121 memset(szString, 0, sizeof(szString));
2122 hr = StringList_Item(pStringList, iCount, szString);
2123 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2125 if (pEnum) IEnumVARIANT_Release(pEnum);
2126 if (pUnk) IUnknown_Release(pUnk);
2127 IDispatch_Release(pStringList);
2131 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2132 * deleting the subkeys first) */
2133 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey)
2135 UINT ret;
2136 CHAR *string = NULL;
2137 HKEY hkey;
2138 DWORD dwSize;
2140 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2141 if (ret != ERROR_SUCCESS) return ret;
2142 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2143 if (ret != ERROR_SUCCESS) return ret;
2144 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2146 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2147 delete_registry_key(hkey, string);
2149 RegCloseKey(hkey);
2150 HeapFree(GetProcessHeap(), 0, string);
2151 RegDeleteKeyA(hkeyParent, subkey);
2152 return ERROR_SUCCESS;
2155 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2156 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, HKEY *phkey)
2158 UINT ret;
2159 CHAR *string = NULL;
2160 int idx = 0;
2161 HKEY hkey;
2162 DWORD dwSize;
2163 BOOL found = FALSE;
2165 *phkey = 0;
2167 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2168 if (ret != ERROR_SUCCESS) return ret;
2169 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2170 if (ret != ERROR_SUCCESS) return ret;
2171 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2173 while (!found &&
2174 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2176 if (!strcmp(string, findkey))
2178 *phkey = hkey;
2179 found = TRUE;
2181 else if (find_registry_key(hkey, string, findkey, phkey) == ERROR_SUCCESS) found = TRUE;
2184 if (*phkey != hkey) RegCloseKey(hkey);
2185 HeapFree(GetProcessHeap(), 0, string);
2186 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2189 static void test_Installer_InstallProduct(void)
2191 HRESULT hr;
2192 CHAR path[MAX_PATH];
2193 WCHAR szString[MAX_PATH];
2194 LONG res;
2195 HKEY hkey;
2196 DWORD num, size, type;
2197 int iValue, iCount;
2198 IDispatch *pStringList = NULL;
2200 create_test_files();
2202 /* Installer::InstallProduct */
2203 hr = Installer_InstallProduct(szMsifile, NULL);
2204 if (hr == DISP_E_EXCEPTION)
2206 skip("Installer object not supported.\n");
2207 delete_test_files();
2208 return;
2210 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2212 /* Installer::ProductState for our product code, which has been installed */
2213 hr = Installer_ProductState(szProductCode, &iValue);
2214 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2215 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2217 /* Installer::ProductInfo for our product code */
2219 /* NULL attribute */
2220 memset(szString, 0, sizeof(szString));
2221 hr = Installer_ProductInfo(szProductCode, NULL, szString);
2222 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2223 ok_exception(hr, szProductInfoException);
2225 /* Nonexistent attribute */
2226 memset(szString, 0, sizeof(szString));
2227 hr = Installer_ProductInfo(szProductCode, szMsifile, szString);
2228 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2229 ok_exception(hr, szProductInfoException);
2231 /* Package name */
2232 memset(szString, 0, sizeof(szString));
2233 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szString);
2234 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2235 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile);
2237 /* Product name */
2238 memset(szString, 0, sizeof(szString));
2239 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PRODUCTNAMEW, szString);
2240 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2241 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST);
2243 /* Installer::Products */
2244 test_Installer_Products(TRUE);
2246 /* Installer::RelatedProducts for our upgrade code */
2247 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2248 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2249 if (hr == S_OK)
2251 /* StringList::Count */
2252 hr = StringList_Count(pStringList, &iCount);
2253 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2254 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2256 /* StringList::Item */
2257 memset(szString, 0, sizeof(szString));
2258 hr = StringList_Item(pStringList, 0, szString);
2259 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2260 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
2262 IDispatch_Release(pStringList);
2265 /* Check & clean up installed files & registry keys */
2266 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2267 ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
2268 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2269 ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
2270 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2271 ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
2272 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2273 ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
2274 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2275 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2276 ok(delete_pf("msitest", FALSE), "File not installed\n");
2278 res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
2279 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2281 size = MAX_PATH;
2282 type = REG_SZ;
2283 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2284 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2285 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2287 size = MAX_PATH;
2288 type = REG_SZ;
2289 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2290 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2292 size = sizeof(num);
2293 type = REG_DWORD;
2294 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2295 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2296 ok(num == 314, "Expected 314, got %d\n", num);
2298 size = MAX_PATH;
2299 type = REG_SZ;
2300 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2301 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2302 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2304 RegCloseKey(hkey);
2306 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest");
2307 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2309 /* Remove registry keys written by RegisterProduct standard action */
2310 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F1C3AF50-8B56-4A69-A00C-00773FE42F30}");
2311 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2313 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2314 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2316 res = find_registry_key(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "05FA3C1F65B896A40AC00077F34EF203", &hkey);
2317 ok(res == ERROR_SUCCESS ||
2318 broken(res == ERROR_FILE_NOT_FOUND), /* win9x */
2319 "Expected ERROR_SUCCESS, got %d\n", res);
2320 if (res == ERROR_SUCCESS)
2322 res = delete_registry_key(hkey, "05FA3C1F65B896A40AC00077F34EF203");
2323 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2324 RegCloseKey(hkey);
2326 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203");
2327 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2329 else
2331 /* win9x defaults to a per-machine install. */
2332 RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203");
2335 /* Remove registry keys written by PublishProduct standard action */
2336 res = RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2337 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2339 res = delete_registry_key(hkey, "Products\\05FA3C1F65B896A40AC00077F34EF203");
2340 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2342 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2343 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2345 RegCloseKey(hkey);
2347 /* Delete installation files we installed */
2348 delete_test_files();
2351 static void test_Installer(void)
2353 static WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
2354 static WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
2355 WCHAR szPath[MAX_PATH];
2356 HRESULT hr;
2357 UINT len;
2358 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL;
2359 int iValue, iCount;
2361 if (!pInstaller) return;
2363 /* Installer::CreateRecord */
2365 /* Test for error */
2366 hr = Installer_CreateRecord(-1, &pRecord);
2367 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2368 ok_exception(hr, szCreateRecordException);
2370 /* Test for success */
2371 hr = Installer_CreateRecord(1, &pRecord);
2372 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2373 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2374 if (pRecord)
2376 /* Record::FieldCountGet */
2377 hr = Record_FieldCountGet(pRecord, &iValue);
2378 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2379 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
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 == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2386 /* Record::IntegerDataGet, bad index */
2387 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2388 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2389 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2391 /* Record::IntegerDataPut */
2392 hr = Record_IntegerDataPut(pRecord, 1, 100);
2393 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2395 /* Record::IntegerDataPut, bad index */
2396 hr = Record_IntegerDataPut(pRecord, 10, 100);
2397 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2398 ok_exception(hr, szIntegerDataException);
2400 /* Record::IntegerDataGet */
2401 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2402 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2403 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2405 IDispatch_Release(pRecord);
2408 /* Prepare package */
2409 create_database(msifile, tables, sizeof(tables) / sizeof(msi_table),
2410 summary_info, sizeof(summary_info) / sizeof(msi_summary_info));
2412 len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, CURR_DIR, -1, szPath, MAX_PATH);
2413 ok(len, "MultiByteToWideChar returned error %d\n", GetLastError());
2414 if (!len) return;
2416 /* lstrcatW does not work on win95 */
2417 szPath[len - 1] = '\\';
2418 memcpy(&szPath[len], szMsifile, sizeof(szMsifile));
2420 /* Installer::OpenPackage */
2421 hr = Installer_OpenPackage(szPath, 0, &pSession);
2422 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2423 if (hr == S_OK)
2425 test_Session(pSession);
2426 IDispatch_Release(pSession);
2429 /* Installer::OpenDatabase */
2430 hr = Installer_OpenDatabase(szPath, (INT_PTR)MSIDBOPEN_TRANSACT, &pDatabase);
2431 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2432 if (hr == S_OK)
2434 test_Database(pDatabase, FALSE);
2435 IDispatch_Release(pDatabase);
2438 /* Installer::RegistryValue */
2439 test_Installer_RegistryValue();
2441 /* Installer::ProductState for our product code, which should not be installed */
2442 hr = Installer_ProductState(szProductCode, &iValue);
2443 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2444 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2446 /* Installer::ProductInfo for our product code, which should not be installed */
2448 /* Package name */
2449 memset(szPath, 0, sizeof(szPath));
2450 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szPath);
2451 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2452 ok_exception(hr, szProductInfoException);
2454 /* NULL attribute and NULL product code */
2455 memset(szPath, 0, sizeof(szPath));
2456 hr = Installer_ProductInfo(NULL, NULL, szPath);
2457 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2458 ok_exception(hr, szProductInfoException);
2460 /* Installer::Products */
2461 test_Installer_Products(FALSE);
2463 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2464 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2465 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2466 if (hr == S_OK)
2468 /* StringList::Count */
2469 hr = StringList_Count(pStringList, &iCount);
2470 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2471 ok(!iCount, "Expected no related products but found %d\n", iCount);
2473 IDispatch_Release(pStringList);
2476 /* Installer::Version */
2477 memset(szPath, 0, sizeof(szPath));
2478 hr = Installer_VersionGet(szPath);
2479 ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr);
2481 /* Installer::InstallProduct and other tests that depend on our product being installed */
2482 test_Installer_InstallProduct();
2485 START_TEST(automation)
2487 DWORD len;
2488 char temp_path[MAX_PATH], prev_path[MAX_PATH];
2489 HRESULT hr;
2490 CLSID clsid;
2491 IUnknown *pUnk;
2493 GetSystemTimeAsFileTime(&systemtime);
2495 GetCurrentDirectoryA(MAX_PATH, prev_path);
2496 GetTempPath(MAX_PATH, temp_path);
2497 SetCurrentDirectoryA(temp_path);
2499 lstrcpyA(CURR_DIR, temp_path);
2500 len = lstrlenA(CURR_DIR);
2502 if(len && (CURR_DIR[len - 1] == '\\'))
2503 CURR_DIR[len - 1] = 0;
2505 get_program_files_dir(PROG_FILES_DIR);
2507 hr = OleInitialize(NULL);
2508 ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr);
2509 hr = CLSIDFromProgID(szProgId, &clsid);
2510 ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr);
2511 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2512 ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr);
2514 if (pUnk)
2516 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2517 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2519 test_dispid();
2520 test_dispatch();
2521 test_Installer();
2523 IDispatch_Release(pInstaller);
2524 IUnknown_Release(pUnk);
2527 OleUninitialize();
2529 SetCurrentDirectoryA(prev_path);