push 149f0a5527ac85057a8ef03858d34d91c36f97e8
[wine/hacks.git] / dlls / msi / tests / automation.c
blobb792fa722bd77c670b533d7aaebd336f2bcb3f8b
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 ok(V_DATE(&var) == V_DATE(&varresult), "SummaryInfo_PropertyGet expected %lf, but returned %lf\n", V_DATE(&var), V_DATE(&varresult));
1510 VariantClear(&varresult);
1511 VariantClear(&var);
1513 /* VT_I4 */
1514 V_VT(&var) = VT_I4;
1515 V_I4(&var) = 1000;
1516 hr = SummaryInfo_PropertyPut(pSummaryInfo, PID_CHARCOUNT, &var);
1517 ok(hr == S_OK, "SummaryInfo_PropertyPut failed, hresult 0x%08x\n", hr);
1519 hr = SummaryInfo_PropertyGet(pSummaryInfo, PID_CHARCOUNT, &varresult, V_VT(&var));
1520 ok(hr == S_OK, "SummaryInfo_PropertyGet failed, hresult 0x%08x\n", hr);
1521 ok(V_I4(&var) == V_I4(&varresult), "SummaryInfo_PropertyGet expected %d, but returned %d\n", V_I4(&var), V_I4(&varresult));
1522 VariantClear(&varresult);
1523 VariantClear(&var);
1525 /* SummaryInfo::PropertyCount */
1526 hr = SummaryInfo_PropertyCountGet(pSummaryInfo, &j);
1527 ok(hr == S_OK, "SummaryInfo_PropertyCount failed, hresult 0x%08x\n", hr);
1528 ok(j == num_info+4, "SummaryInfo_PropertyCount returned %d, expected %d\n", j, num_info);
1532 static void test_Database(IDispatch *pDatabase, BOOL readonly)
1534 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 };
1535 static WCHAR szThree[] = { 'T','h','r','e','e',0 };
1536 static WCHAR szTwo[] = { 'T','w','o',0 };
1537 static WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
1538 static WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 };
1539 IDispatch *pView = NULL, *pSummaryInfo = NULL;
1540 HRESULT hr;
1542 hr = Database_OpenView(pDatabase, szSql, &pView);
1543 ok(hr == S_OK, "Database_OpenView failed, hresult 0x%08x\n", hr);
1544 if (hr == S_OK)
1546 IDispatch *pRecord = NULL;
1547 WCHAR szString[MAX_PATH];
1549 /* View::Execute */
1550 hr = View_Execute(pView, NULL);
1551 ok(hr == S_OK, "View_Execute failed, hresult 0x%08x\n", hr);
1553 /* View::Fetch */
1554 hr = View_Fetch(pView, &pRecord);
1555 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1556 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1557 if (pRecord)
1559 /* Record::StringDataGet */
1560 memset(szString, 0, sizeof(szString));
1561 hr = Record_StringDataGet(pRecord, 1, szString);
1562 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1563 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1565 /* Record::StringDataPut with correct index */
1566 hr = Record_StringDataPut(pRecord, 1, szTwo);
1567 ok(hr == S_OK, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1569 /* Record::StringDataGet */
1570 memset(szString, 0, sizeof(szString));
1571 hr = Record_StringDataGet(pRecord, 1, szString);
1572 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1573 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1575 /* Record::StringDataPut with incorrect index */
1576 hr = Record_StringDataPut(pRecord, -1, szString);
1577 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1578 ok_exception(hr, szStringDataField);
1580 /* View::Modify with incorrect parameters */
1581 hr = View_Modify(pView, -5, NULL);
1582 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1583 ok_exception(hr, szModifyModeRecord);
1585 hr = View_Modify(pView, -5, pRecord);
1586 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1587 ok_exception(hr, szModifyModeRecord);
1589 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1590 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1591 ok_exception(hr, szModifyModeRecord);
1593 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1594 ok(hr == S_OK, "View_Modify failed, hresult 0x%08x\n", hr);
1596 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1597 memset(szString, 0, sizeof(szString));
1598 hr = Record_StringDataGet(pRecord, 1, szString);
1599 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1600 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1602 IDispatch_Release(pRecord);
1605 /* View::Fetch */
1606 hr = View_Fetch(pView, &pRecord);
1607 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1608 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1609 if (pRecord)
1611 /* Record::StringDataGet */
1612 memset(szString, 0, sizeof(szString));
1613 hr = Record_StringDataGet(pRecord, 1, szString);
1614 ok(hr == S_OK, "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1615 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1617 IDispatch_Release(pRecord);
1620 /* View::Fetch */
1621 hr = View_Fetch(pView, &pRecord);
1622 ok(hr == S_OK, "View_Fetch failed, hresult 0x%08x\n", hr);
1623 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1624 if (pRecord)
1625 IDispatch_Release(pRecord);
1627 /* View::Close */
1628 hr = View_Close(pView);
1629 ok(hr == S_OK, "View_Close failed, hresult 0x%08x\n", hr);
1631 IDispatch_Release(pView);
1634 /* Database::SummaryInformation */
1635 hr = Database_SummaryInformation(pDatabase, TEST_SUMMARYINFO_PROPERTIES_MODIFIED, &pSummaryInfo);
1636 ok(hr == S_OK, "Database_SummaryInformation failed, hresult 0x%08x\n", hr);
1637 ok(pSummaryInfo != NULL, "Database_SummaryInformation should not have returned NULL record\n");
1638 if (pSummaryInfo)
1640 test_SummaryInfo(pSummaryInfo, summary_info, sizeof(summary_info)/sizeof(msi_summary_info), readonly);
1641 IDispatch_Release(pSummaryInfo);
1645 static void test_Session(IDispatch *pSession)
1647 static WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
1648 static WCHAR szOne[] = { 'O','n','e',0 };
1649 static WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 };
1650 static WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 };
1651 static WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 };
1652 static WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 };
1653 static WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1654 static WCHAR szEmpty[] = { 0 };
1655 static WCHAR szEquals[] = { '=',0 };
1656 static WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
1657 WCHAR stringw[MAX_PATH];
1658 CHAR string[MAX_PATH];
1659 UINT len;
1660 BOOL bool;
1661 int myint;
1662 IDispatch *pDatabase = NULL, *pInst = NULL, *record = NULL;
1663 HRESULT hr;
1665 /* Session::Installer */
1666 hr = Session_Installer(pSession, &pInst);
1667 ok(hr == S_OK, "Session_Installer failed, hresult 0x%08x\n", hr);
1668 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1669 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1671 /* Session::Property, get */
1672 memset(stringw, 0, sizeof(stringw));
1673 hr = Session_PropertyGet(pSession, szProductName, stringw);
1674 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1675 if (strcmp_ww(stringw, szMSITEST) != 0)
1677 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1678 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1679 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1682 /* Session::Property, put */
1683 hr = Session_PropertyPut(pSession, szProductName, szProductName);
1684 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1685 memset(stringw, 0, sizeof(stringw));
1686 hr = Session_PropertyGet(pSession, szProductName, stringw);
1687 ok(hr == S_OK, "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1688 if (strcmp_ww(stringw, szProductName) != 0)
1690 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1691 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1692 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1695 /* Try putting a property using empty property identifier */
1696 hr = Session_PropertyPut(pSession, szEmpty, szProductName);
1697 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1698 ok_exception(hr, szPropertyName);
1700 /* Try putting a property using illegal property identifier */
1701 hr = Session_PropertyPut(pSession, szEquals, szProductName);
1702 ok(hr == S_OK, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1704 /* Session::Language, get */
1705 hr = Session_LanguageGet(pSession, &len);
1706 ok(hr == S_OK, "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1707 /* Not sure how to check the language is correct */
1709 /* Session::Mode, get */
1710 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1711 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1712 todo_wine ok(!bool, "Reboot at end session mode is %d\n", bool);
1714 /* Session::Mode, put */
1715 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE);
1716 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1717 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1718 ok(hr == S_OK, "Session_ModeGet failed, hresult 0x%08x\n", hr);
1719 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1720 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE); /* set it again so we don't reboot */
1721 ok(hr == S_OK, "Session_ModePut failed, hresult 0x%08x\n", hr);
1723 /* Session::Database, get */
1724 hr = Session_Database(pSession, &pDatabase);
1725 ok(hr == S_OK, "Session_Database failed, hresult 0x%08x\n", hr);
1726 if (hr == S_OK)
1728 test_Database(pDatabase, TRUE);
1729 IDispatch_Release(pDatabase);
1732 /* Session::EvaluateCondition */
1733 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1734 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1735 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1737 hr = Session_EvaluateCondition(pSession, szEmpty, &myint);
1738 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1739 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1741 hr = Session_EvaluateCondition(pSession, szEquals, &myint);
1742 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1743 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1745 /* Session::DoAction(CostInitialize) must occur before the next statements */
1746 hr = Session_DoAction(pSession, szCostInitialize, &myint);
1747 ok(hr == S_OK, "Session_DoAction failed, hresult 0x%08x\n", hr);
1748 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1750 /* Session::SetInstallLevel */
1751 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1752 ok(hr == S_OK, "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
1754 /* Session::FeatureCurrentState, get */
1755 hr = Session_FeatureCurrentState(pSession, szOne, &myint);
1756 ok(hr == S_OK, "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
1757 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1759 /* Session::Message */
1760 hr = Installer_CreateRecord(0, &record);
1761 ok(hr == S_OK, "Installer_CreateRecord failed: %08x\n", hr);
1762 hr = Session_Message(pSession, INSTALLMESSAGE_INFO, record, &myint);
1763 ok(hr == S_OK, "Session_Message failed: %08x\n", hr);
1764 ok(myint == 0, "Session_Message returned %x\n", myint);
1766 /* Session::EvaluateCondition */
1767 hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint);
1768 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1769 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1771 hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint);
1772 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1773 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1775 /* Session::FeatureRequestState, put */
1776 hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED);
1777 ok(hr == S_OK, "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
1778 hr = Session_FeatureRequestStateGet(pSession, szOne, &myint);
1779 ok(hr == S_OK, "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
1780 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
1782 /* Session::EvaluateCondition */
1783 hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint);
1784 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1785 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1787 hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint);
1788 ok(hr == S_OK, "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1789 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1792 /* delete key and all its subkeys */
1793 static DWORD delete_key( HKEY hkey )
1795 char name[MAX_PATH];
1796 DWORD ret;
1798 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
1800 HKEY tmp;
1801 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
1803 ret = delete_key( tmp );
1804 RegCloseKey( tmp );
1806 if (ret) break;
1808 if (ret != ERROR_NO_MORE_ITEMS) return ret;
1809 RegDeleteKeyA( hkey, "" );
1810 return 0;
1813 static void test_Installer_RegistryValue(void)
1815 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
1816 static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 };
1817 static const WCHAR szOne[] = { 'O','n','e',0 };
1818 static const WCHAR szTwo[] = { 'T','w','o',0 };
1819 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
1820 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1821 static const WCHAR szFour[] = { 'F','o','u','r',0 };
1822 static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 };
1823 static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 };
1824 static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 };
1825 static const WCHAR szSix[] = { 'S','i','x',0 };
1826 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1827 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
1828 static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
1829 static const WCHAR szBlank[] = { 0 };
1830 VARIANT varresult;
1831 VARIANTARG vararg;
1832 WCHAR szString[MAX_PATH];
1833 HKEY hkey, hkey_sub;
1834 HKEY curr_user = (HKEY)1;
1835 HRESULT hr;
1836 BOOL bRet;
1837 LONG lRet;
1839 /* Delete keys */
1840 SetLastError(0xdeadbeef);
1841 lRet = RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey );
1842 if (!lRet && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1844 win_skip("Needed W-functions are not implemented\n");
1845 return;
1847 if (!lRet)
1848 delete_key( hkey );
1850 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
1851 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
1852 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1853 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
1855 memset(szString, 0, sizeof(szString));
1856 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
1857 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1859 memset(szString, 0, sizeof(szString));
1860 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
1861 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1863 /* Create key */
1864 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
1866 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1867 "RegSetValueExW failed\n");
1868 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
1869 "RegSetValueExW failed\n");
1870 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
1871 "RegSetValueExW failed\n");
1872 ok(SetEnvironmentVariableA("MSITEST", "Four"), "SetEnvironmentVariableA failed %d\n", GetLastError());
1873 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
1874 "RegSetValueExW failed\n");
1875 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
1876 "RegSetValueExW failed\n");
1877 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
1878 "RegSetValueExW failed\n");
1879 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, NULL, 0),
1880 "RegSetValueExW failed\n");
1882 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1883 "RegSetValueExW failed\n");
1885 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
1887 /* Does our key exist? It should, and make sure we retrieve the correct default value */
1888 bRet = FALSE;
1889 hr = Installer_RegistryValueE(curr_user, szKey, &bRet);
1890 ok(hr == S_OK, "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1891 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
1893 memset(szString, 0, sizeof(szString));
1894 hr = Installer_RegistryValueW(curr_user, szKey, NULL, szString);
1895 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1896 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1898 /* Ask for the value of a nonexistent key */
1899 memset(szString, 0, sizeof(szString));
1900 hr = Installer_RegistryValueW(curr_user, szKey, szExpand, szString);
1901 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1903 /* Get values of keys */
1904 memset(szString, 0, sizeof(szString));
1905 hr = Installer_RegistryValueW(curr_user, szKey, szOne, szString);
1906 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1907 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1909 VariantInit(&vararg);
1910 V_VT(&vararg) = VT_BSTR;
1911 V_BSTR(&vararg) = SysAllocString(szTwo);
1912 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_I4);
1913 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1914 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
1915 VariantClear(&varresult);
1917 memset(szString, 0, sizeof(szString));
1918 hr = Installer_RegistryValueW(curr_user, szKey, szThree, szString);
1919 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1920 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
1922 memset(szString, 0, sizeof(szString));
1923 hr = Installer_RegistryValueW(curr_user, szKey, szFour, szString);
1924 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1925 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
1927 /* Vista does not NULL-terminate this case */
1928 memset(szString, 0, sizeof(szString));
1929 hr = Installer_RegistryValueW(curr_user, szKey, szFive, szString);
1930 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1931 ok_w2n("Registry value \"%s\" does not match expected \"%s\"\n",
1932 szString, szFiveHi, lstrlenW(szFiveHi));
1934 memset(szString, 0, sizeof(szString));
1935 hr = Installer_RegistryValueW(curr_user, szKey, szSix, szString);
1936 ok(hr == S_OK, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1937 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_);
1939 VariantInit(&vararg);
1940 V_VT(&vararg) = VT_BSTR;
1941 V_BSTR(&vararg) = SysAllocString(szSeven);
1942 hr = Installer_RegistryValue(curr_user, szKey, vararg, &varresult, VT_EMPTY);
1943 ok(hr == S_OK, "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1945 /* Get string class name for the key */
1946 memset(szString, 0, sizeof(szString));
1947 hr = Installer_RegistryValueI(curr_user, szKey, 0, szString, VT_BSTR);
1948 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1949 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank);
1951 /* Get name of a value by positive number (RegEnumValue like), valid index */
1952 memset(szString, 0, sizeof(szString));
1953 hr = Installer_RegistryValueI(curr_user, szKey, 2, szString, VT_BSTR);
1954 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1955 /* RegEnumValue order seems different on wine */
1956 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
1958 /* Get name of a value by positive number (RegEnumValue like), invalid index */
1959 memset(szString, 0, sizeof(szString));
1960 hr = Installer_RegistryValueI(curr_user, szKey, 10, szString, VT_EMPTY);
1961 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1963 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
1964 memset(szString, 0, sizeof(szString));
1965 hr = Installer_RegistryValueI(curr_user, szKey, -1, szString, VT_BSTR);
1966 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1967 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
1969 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
1970 memset(szString, 0, sizeof(szString));
1971 hr = Installer_RegistryValueI(curr_user, szKey, -10, szString, VT_EMPTY);
1972 ok(hr == S_OK, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1974 /* clean up */
1975 delete_key(hkey);
1978 static void test_Installer_Products(BOOL bProductInstalled)
1980 WCHAR szString[MAX_PATH];
1981 HRESULT hr;
1982 int idx;
1983 IUnknown *pUnk = NULL;
1984 IEnumVARIANT *pEnum = NULL;
1985 VARIANT var;
1986 ULONG celt;
1987 int iCount, iValue;
1988 IDispatch *pStringList = NULL;
1989 BOOL bProductFound = FALSE;
1991 /* Installer::Products */
1992 hr = Installer_Products(&pStringList);
1993 ok(hr == S_OK, "Installer_Products failed, hresult 0x%08x\n", hr);
1994 if (hr == S_OK)
1996 /* StringList::_NewEnum */
1997 hr = StringList__NewEnum(pStringList, &pUnk);
1998 ok(hr == S_OK, "StringList_NewEnum failed, hresult 0x%08x\n", hr);
1999 if (hr == S_OK)
2001 hr = IUnknown_QueryInterface(pUnk, &IID_IEnumVARIANT, (void **)&pEnum);
2002 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2004 if (!pEnum)
2005 skip("IEnumVARIANT tests\n");
2007 /* StringList::Count */
2008 hr = StringList_Count(pStringList, &iCount);
2009 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2011 for (idx=0; idx<iCount; idx++)
2013 /* StringList::Item */
2014 memset(szString, 0, sizeof(szString));
2015 hr = StringList_Item(pStringList, idx, szString);
2016 ok(hr == S_OK, "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2018 if (hr == S_OK)
2020 /* Installer::ProductState */
2021 hr = Installer_ProductState(szString, &iValue);
2022 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2023 if (hr == S_OK)
2024 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
2026 /* Not found our product code yet? Check */
2027 if (!bProductFound && !strcmp_ww(szString, szProductCode))
2028 bProductFound = TRUE;
2030 /* IEnumVARIANT::Next */
2031 if (pEnum)
2033 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2034 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2035 ok(celt == 1, "%d items were retrieved, expected 1\n", celt);
2036 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2037 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2038 VariantClear(&var);
2043 if (bProductInstalled)
2045 ok(bProductInstalled == bProductFound, "Product expected to %s installed but product code was %s\n",
2046 bProductInstalled ? "be" : "not be",
2047 bProductFound ? "found" : "not found");
2050 if (pEnum)
2052 IEnumVARIANT *pEnum2 = NULL;
2054 if (0) /* Crashes on Windows XP */
2056 /* IEnumVARIANT::Clone, NULL pointer */
2057 hr = IEnumVARIANT_Clone(pEnum, NULL);
2060 /* IEnumVARIANT::Clone */
2061 hr = IEnumVARIANT_Clone(pEnum, &pEnum2);
2062 ok(hr == S_OK, "IEnumVARIANT_Clone failed, hresult 0x%08x\n", hr);
2063 if (hr == S_OK)
2065 /* IEnumVARIANT::Clone is supposed to save the position, but it actually just goes back to the beginning */
2067 /* IEnumVARIANT::Next of the clone */
2068 if (iCount)
2070 hr = IEnumVARIANT_Next(pEnum2, 1, &var, &celt);
2071 ok(hr == S_OK, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2072 ok(celt == 1, "%d items were retrieved, expected 0\n", celt);
2073 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2074 VariantClear(&var);
2076 else
2077 skip("IEnumVARIANT::Next of clone will not return success with 0 products\n");
2079 IEnumVARIANT_Release(pEnum2);
2082 /* IEnumVARIANT::Skip should fail */
2083 hr = IEnumVARIANT_Skip(pEnum, 1);
2084 ok(hr == S_FALSE, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2086 /* IEnumVARIANT::Next, NULL variant pointer */
2087 hr = IEnumVARIANT_Next(pEnum, 1, NULL, &celt);
2088 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2089 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2091 /* IEnumVARIANT::Next, should not return any more items */
2092 hr = IEnumVARIANT_Next(pEnum, 1, &var, &celt);
2093 ok(hr == S_FALSE, "IEnumVARIANT_Next failed, hresult 0x%08x\n", hr);
2094 ok(celt == 0, "%d items were retrieved, expected 0\n", celt);
2095 VariantClear(&var);
2097 /* IEnumVARIANT::Reset */
2098 hr = IEnumVARIANT_Reset(pEnum);
2099 ok(hr == S_OK, "IEnumVARIANT_Reset failed, hresult 0x%08x\n", hr);
2101 if (iCount)
2103 /* IEnumVARIANT::Skip to the last product */
2104 hr = IEnumVARIANT_Skip(pEnum, iCount-1);
2105 ok(hr == S_OK, "IEnumVARIANT_Skip failed, hresult 0x%08x\n", hr);
2107 /* IEnumVARIANT::Next should match the very last retrieved value, also makes sure it works with
2108 * NULL celt pointer. */
2109 hr = IEnumVARIANT_Next(pEnum, 1, &var, NULL);
2110 ok(hr == S_OK, "IEnumVARIANT_Next failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
2111 ok(V_VT(&var) == VT_BSTR, "IEnumVARIANT_Next returned variant of type %d, expected %d\n", V_VT(&var), VT_BSTR);
2112 ok_w2("%s returned by StringList_Item does not match %s returned by IEnumVARIANT_Next\n", szString, V_BSTR(&var));
2113 VariantClear(&var);
2115 else
2116 skip("IEnumVARIANT::Skip impossible for 0 products\n");
2119 /* StringList::Item using an invalid index */
2120 memset(szString, 0, sizeof(szString));
2121 hr = StringList_Item(pStringList, iCount, szString);
2122 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
2124 if (pEnum) IEnumVARIANT_Release(pEnum);
2125 if (pUnk) IUnknown_Release(pUnk);
2126 IDispatch_Release(pStringList);
2130 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
2131 * deleting the subkeys first) */
2132 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey)
2134 UINT ret;
2135 CHAR *string = NULL;
2136 HKEY hkey;
2137 DWORD dwSize;
2139 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2140 if (ret != ERROR_SUCCESS) return ret;
2141 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2142 if (ret != ERROR_SUCCESS) return ret;
2143 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2145 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
2146 delete_registry_key(hkey, string);
2148 RegCloseKey(hkey);
2149 HeapFree(GetProcessHeap(), 0, string);
2150 RegDeleteKeyA(hkeyParent, subkey);
2151 return ERROR_SUCCESS;
2154 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
2155 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, HKEY *phkey)
2157 UINT ret;
2158 CHAR *string = NULL;
2159 int idx = 0;
2160 HKEY hkey;
2161 DWORD dwSize;
2162 BOOL found = FALSE;
2164 *phkey = 0;
2166 ret = RegOpenKey(hkeyParent, subkey, &hkey);
2167 if (ret != ERROR_SUCCESS) return ret;
2168 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
2169 if (ret != ERROR_SUCCESS) return ret;
2170 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
2172 while (!found &&
2173 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
2175 if (!strcmp(string, findkey))
2177 *phkey = hkey;
2178 found = TRUE;
2180 else if (find_registry_key(hkey, string, findkey, phkey) == ERROR_SUCCESS) found = TRUE;
2183 if (*phkey != hkey) RegCloseKey(hkey);
2184 HeapFree(GetProcessHeap(), 0, string);
2185 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
2188 static void test_Installer_InstallProduct(void)
2190 HRESULT hr;
2191 CHAR path[MAX_PATH];
2192 WCHAR szString[MAX_PATH];
2193 LONG res;
2194 HKEY hkey;
2195 DWORD num, size, type;
2196 int iValue, iCount;
2197 IDispatch *pStringList = NULL;
2199 create_test_files();
2201 /* Installer::InstallProduct */
2202 hr = Installer_InstallProduct(szMsifile, NULL);
2203 if (hr == DISP_E_EXCEPTION)
2205 skip("Installer object not supported.\n");
2206 delete_test_files();
2207 return;
2209 ok(hr == S_OK, "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
2211 /* Installer::ProductState for our product code, which has been installed */
2212 hr = Installer_ProductState(szProductCode, &iValue);
2213 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2214 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
2216 /* Installer::ProductInfo for our product code */
2218 /* NULL attribute */
2219 memset(szString, 0, sizeof(szString));
2220 hr = Installer_ProductInfo(szProductCode, NULL, szString);
2221 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2222 ok_exception(hr, szProductInfoException);
2224 /* Nonexistent attribute */
2225 memset(szString, 0, sizeof(szString));
2226 hr = Installer_ProductInfo(szProductCode, szMsifile, szString);
2227 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2228 ok_exception(hr, szProductInfoException);
2230 /* Package name */
2231 memset(szString, 0, sizeof(szString));
2232 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szString);
2233 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2234 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMsifile);
2236 /* Product name */
2237 memset(szString, 0, sizeof(szString));
2238 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PRODUCTNAMEW, szString);
2239 ok(hr == S_OK, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2240 todo_wine ok_w2("Installer_ProductInfo returned %s but expected %s\n", szString, szMSITEST);
2242 /* Installer::Products */
2243 test_Installer_Products(TRUE);
2245 /* Installer::RelatedProducts for our upgrade code */
2246 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2247 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2248 if (hr == S_OK)
2250 /* StringList::Count */
2251 hr = StringList_Count(pStringList, &iCount);
2252 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2253 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
2255 /* StringList::Item */
2256 memset(szString, 0, sizeof(szString));
2257 hr = StringList_Item(pStringList, 0, szString);
2258 ok(hr == S_OK, "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
2259 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
2261 IDispatch_Release(pStringList);
2264 /* Check & clean up installed files & registry keys */
2265 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
2266 ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
2267 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
2268 ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
2269 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
2270 ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
2271 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
2272 ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
2273 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
2274 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
2275 ok(delete_pf("msitest", FALSE), "File not installed\n");
2277 res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
2278 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2280 size = MAX_PATH;
2281 type = REG_SZ;
2282 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
2283 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2284 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
2286 size = MAX_PATH;
2287 type = REG_SZ;
2288 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
2289 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2291 size = sizeof(num);
2292 type = REG_DWORD;
2293 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
2294 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2295 ok(num == 314, "Expected 314, got %d\n", num);
2297 size = MAX_PATH;
2298 type = REG_SZ;
2299 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
2300 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2301 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
2303 RegCloseKey(hkey);
2305 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest");
2306 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2308 /* Remove registry keys written by RegisterProduct standard action */
2309 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F1C3AF50-8B56-4A69-A00C-00773FE42F30}");
2310 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2312 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2313 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2315 res = find_registry_key(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "05FA3C1F65B896A40AC00077F34EF203", &hkey);
2316 ok(res == ERROR_SUCCESS ||
2317 broken(res == ERROR_FILE_NOT_FOUND), /* win9x */
2318 "Expected ERROR_SUCCESS, got %d\n", res);
2319 if (res == ERROR_SUCCESS)
2321 res = delete_registry_key(hkey, "05FA3C1F65B896A40AC00077F34EF203");
2322 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2323 RegCloseKey(hkey);
2325 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203");
2326 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
2328 else
2330 /* win9x defaults to a per-machine install. */
2331 RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\Products\\05FA3C1F65B896A40AC00077F34EF203");
2334 /* Remove registry keys written by PublishProduct standard action */
2335 res = RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
2336 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2338 res = delete_registry_key(hkey, "Products\\05FA3C1F65B896A40AC00077F34EF203");
2339 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2341 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
2342 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
2344 RegCloseKey(hkey);
2346 /* Delete installation files we installed */
2347 delete_test_files();
2350 static void test_Installer(void)
2352 static WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
2353 static WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
2354 WCHAR szPath[MAX_PATH];
2355 HRESULT hr;
2356 UINT len;
2357 IDispatch *pSession = NULL, *pDatabase = NULL, *pRecord = NULL, *pStringList = NULL;
2358 int iValue, iCount;
2360 if (!pInstaller) return;
2362 /* Installer::CreateRecord */
2364 /* Test for error */
2365 hr = Installer_CreateRecord(-1, &pRecord);
2366 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2367 ok_exception(hr, szCreateRecordException);
2369 /* Test for success */
2370 hr = Installer_CreateRecord(1, &pRecord);
2371 ok(hr == S_OK, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
2372 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
2373 if (pRecord)
2375 /* Record::FieldCountGet */
2376 hr = Record_FieldCountGet(pRecord, &iValue);
2377 ok(hr == S_OK, "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
2378 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
2380 /* Record::IntegerDataGet */
2381 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2382 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2383 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2385 /* Record::IntegerDataGet, bad index */
2386 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
2387 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2388 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
2390 /* Record::IntegerDataPut */
2391 hr = Record_IntegerDataPut(pRecord, 1, 100);
2392 ok(hr == S_OK, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2394 /* Record::IntegerDataPut, bad index */
2395 hr = Record_IntegerDataPut(pRecord, 10, 100);
2396 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
2397 ok_exception(hr, szIntegerDataException);
2399 /* Record::IntegerDataGet */
2400 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
2401 ok(hr == S_OK, "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
2402 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
2404 IDispatch_Release(pRecord);
2407 /* Prepare package */
2408 create_database(msifile, tables, sizeof(tables) / sizeof(msi_table),
2409 summary_info, sizeof(summary_info) / sizeof(msi_summary_info));
2411 len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, CURR_DIR, -1, szPath, MAX_PATH);
2412 ok(len, "MultiByteToWideChar returned error %d\n", GetLastError());
2413 if (!len) return;
2415 /* lstrcatW does not work on win95 */
2416 szPath[len - 1] = '\\';
2417 memcpy(&szPath[len], szMsifile, sizeof(szMsifile));
2419 /* Installer::OpenPackage */
2420 hr = Installer_OpenPackage(szPath, 0, &pSession);
2421 ok(hr == S_OK, "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
2422 if (hr == S_OK)
2424 test_Session(pSession);
2425 IDispatch_Release(pSession);
2428 /* Installer::OpenDatabase */
2429 hr = Installer_OpenDatabase(szPath, (INT_PTR)MSIDBOPEN_TRANSACT, &pDatabase);
2430 ok(hr == S_OK, "Installer_OpenDatabase failed, hresult 0x%08x\n", hr);
2431 if (hr == S_OK)
2433 test_Database(pDatabase, FALSE);
2434 IDispatch_Release(pDatabase);
2437 /* Installer::RegistryValue */
2438 test_Installer_RegistryValue();
2440 /* Installer::ProductState for our product code, which should not be installed */
2441 hr = Installer_ProductState(szProductCode, &iValue);
2442 ok(hr == S_OK, "Installer_ProductState failed, hresult 0x%08x\n", hr);
2443 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
2445 /* Installer::ProductInfo for our product code, which should not be installed */
2447 /* Package name */
2448 memset(szPath, 0, sizeof(szPath));
2449 hr = Installer_ProductInfo(szProductCode, WINE_INSTALLPROPERTY_PACKAGENAMEW, szPath);
2450 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2451 ok_exception(hr, szProductInfoException);
2453 /* NULL attribute and NULL product code */
2454 memset(szPath, 0, sizeof(szPath));
2455 hr = Installer_ProductInfo(NULL, NULL, szPath);
2456 ok(hr == DISP_E_EXCEPTION, "Installer_ProductInfo failed, hresult 0x%08x\n", hr);
2457 ok_exception(hr, szProductInfoException);
2459 /* Installer::Products */
2460 test_Installer_Products(FALSE);
2462 /* Installer::RelatedProducts for our upgrade code, should not find anything */
2463 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
2464 ok(hr == S_OK, "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
2465 if (hr == S_OK)
2467 /* StringList::Count */
2468 hr = StringList_Count(pStringList, &iCount);
2469 ok(hr == S_OK, "StringList_Count failed, hresult 0x%08x\n", hr);
2470 ok(!iCount, "Expected no related products but found %d\n", iCount);
2472 IDispatch_Release(pStringList);
2475 /* Installer::Version */
2476 memset(szPath, 0, sizeof(szPath));
2477 hr = Installer_VersionGet(szPath);
2478 ok(hr == S_OK, "Installer_VersionGet failed, hresult 0x%08x\n", hr);
2480 /* Installer::InstallProduct and other tests that depend on our product being installed */
2481 test_Installer_InstallProduct();
2484 START_TEST(automation)
2486 DWORD len;
2487 char temp_path[MAX_PATH], prev_path[MAX_PATH];
2488 HRESULT hr;
2489 CLSID clsid;
2490 IUnknown *pUnk;
2492 GetSystemTimeAsFileTime(&systemtime);
2494 GetCurrentDirectoryA(MAX_PATH, prev_path);
2495 GetTempPath(MAX_PATH, temp_path);
2496 SetCurrentDirectoryA(temp_path);
2498 lstrcpyA(CURR_DIR, temp_path);
2499 len = lstrlenA(CURR_DIR);
2501 if(len && (CURR_DIR[len - 1] == '\\'))
2502 CURR_DIR[len - 1] = 0;
2504 get_program_files_dir(PROG_FILES_DIR);
2506 hr = OleInitialize(NULL);
2507 ok (hr == S_OK, "OleInitialize returned 0x%08x\n", hr);
2508 hr = CLSIDFromProgID(szProgId, &clsid);
2509 ok (hr == S_OK, "CLSIDFromProgID returned 0x%08x\n", hr);
2510 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
2511 ok(hr == S_OK, "CoCreateInstance returned 0x%08x\n", hr);
2513 if (pUnk)
2515 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
2516 ok (hr == S_OK, "IUnknown::QueryInterface returned 0x%08x\n", hr);
2518 test_dispid();
2519 test_dispatch();
2520 test_Installer();
2522 IDispatch_Release(pInstaller);
2523 IUnknown_Release(pUnk);
2526 OleUninitialize();
2528 SetCurrentDirectoryA(prev_path);