msi/tests: automation: Add tests for Installer::RelatedProducts.
[wine/gsoc_dplay.git] / dlls / msi / tests / automation.c
bloba9da690b1bae148b1159e89a9c44202464d884a1
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 <windows.h>
27 #include <msiquery.h>
28 #include <msidefs.h>
29 #include <msi.h>
30 #include <fci.h>
32 #include "wine/test.h"
34 static const char *msifile = "winetest.msi";
35 static const WCHAR szMsifile[] = {'w','i','n','e','t','e','s','t','.','m','s','i',0};
36 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 };
37 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 };
38 CHAR CURR_DIR[MAX_PATH];
39 EXCEPINFO excepinfo;
42 * OLE automation data
43 **/
44 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 };
45 static IDispatch *pInstaller;
47 /* msi database data */
49 static const CHAR component_dat[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
50 "s72\tS38\ts72\ti2\tS255\tS72\n"
51 "Component\tComponent\n"
52 "Five\t{8CC92E9D-14B2-4CA4-B2AA-B11D02078087}\tNEWDIR\t2\t\tfive.txt\n"
53 "Four\t{FD37B4EA-7209-45C0-8917-535F35A2F080}\tCABOUTDIR\t2\t\tfour.txt\n"
54 "One\t{783B242E-E185-4A56-AF86-C09815EC053C}\tMSITESTDIR\t2\t\tone.txt\n"
55 "Three\t{010B6ADD-B27D-4EDD-9B3D-34C4F7D61684}\tCHANGEDDIR\t2\t\tthree.txt\n"
56 "Two\t{BF03D1A6-20DA-4A65-82F3-6CAC995915CE}\tFIRSTDIR\t2\t\ttwo.txt\n"
57 "dangler\t{6091DF25-EF96-45F1-B8E9-A9B1420C7A3C}\tTARGETDIR\t4\t\tregdata\n"
58 "component\t\tMSITESTDIR\t0\t1\tfile\n"
59 "service_comp\t\tMSITESTDIR\t0\t1\tservice_file";
61 static const CHAR directory_dat[] = "Directory\tDirectory_Parent\tDefaultDir\n"
62 "s72\tS72\tl255\n"
63 "Directory\tDirectory\n"
64 "CABOUTDIR\tMSITESTDIR\tcabout\n"
65 "CHANGEDDIR\tMSITESTDIR\tchanged:second\n"
66 "FIRSTDIR\tMSITESTDIR\tfirst\n"
67 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
68 "NEWDIR\tCABOUTDIR\tnew\n"
69 "ProgramFilesFolder\tTARGETDIR\t.\n"
70 "TARGETDIR\t\tSourceDir";
72 static const CHAR feature_dat[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
73 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
74 "Feature\tFeature\n"
75 "Five\t\tFive\tThe Five Feature\t5\t3\tNEWDIR\t0\n"
76 "Four\t\tFour\tThe Four Feature\t4\t3\tCABOUTDIR\t0\n"
77 "One\t\tOne\tThe One Feature\t1\t3\tMSITESTDIR\t0\n"
78 "Three\tOne\tThree\tThe Three Feature\t3\t3\tCHANGEDDIR\t0\n"
79 "Two\tOne\tTwo\tThe Two Feature\t2\t3\tFIRSTDIR\t0\n"
80 "feature\t\t\t\t2\t1\tTARGETDIR\t0\n"
81 "service_feature\t\t\t\t2\t1\tTARGETDIR\t0";
83 static const CHAR feature_comp_dat[] = "Feature_\tComponent_\n"
84 "s38\ts72\n"
85 "FeatureComponents\tFeature_\tComponent_\n"
86 "Five\tFive\n"
87 "Four\tFour\n"
88 "One\tOne\n"
89 "Three\tThree\n"
90 "Two\tTwo\n"
91 "feature\tcomponent\n"
92 "service_feature\tservice_comp\n";
94 static const CHAR file_dat[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
95 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
96 "File\tFile\n"
97 "five.txt\tFive\tfive.txt\t1000\t\t\t0\t5\n"
98 "four.txt\tFour\tfour.txt\t1000\t\t\t0\t4\n"
99 "one.txt\tOne\tone.txt\t1000\t\t\t0\t1\n"
100 "three.txt\tThree\tthree.txt\t1000\t\t\t0\t3\n"
101 "two.txt\tTwo\ttwo.txt\t1000\t\t\t0\t2\n"
102 "file\tcomponent\tfilename\t100\t\t\t8192\t1\n"
103 "service_file\tservice_comp\tservice.exe\t100\t\t\t8192\t1";
105 static const CHAR install_exec_seq_dat[] = "Action\tCondition\tSequence\n"
106 "s72\tS255\tI2\n"
107 "InstallExecuteSequence\tAction\n"
108 "AllocateRegistrySpace\tNOT Installed\t1550\n"
109 "CostFinalize\t\t1000\n"
110 "CostInitialize\t\t800\n"
111 "FileCost\t\t900\n"
112 "InstallFiles\t\t4000\n"
113 "InstallServices\t\t5000\n"
114 "RegisterProduct\t\t6100\n"
115 "PublishProduct\t\t6400\n"
116 "InstallFinalize\t\t6600\n"
117 "InstallInitialize\t\t1500\n"
118 "InstallValidate\t\t1400\n"
119 "LaunchConditions\t\t100\n"
120 "WriteRegistryValues\tSourceDir And SOURCEDIR\t5000";
122 static const CHAR media_dat[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
123 "i2\ti4\tL64\tS255\tS32\tS72\n"
124 "Media\tDiskId\n"
125 "1\t5\t\t\tDISK1\t\n";
127 static const CHAR property_dat[] = "Property\tValue\n"
128 "s72\tl0\n"
129 "Property\tProperty\n"
130 "DefaultUIFont\tDlgFont8\n"
131 "HASUIRUN\t0\n"
132 "INSTALLLEVEL\t3\n"
133 "InstallMode\tTypical\n"
134 "Manufacturer\tWine\n"
135 "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n"
136 "ProductCode\t{F1C3AF50-8B56-4A69-A00C-00773FE42F30}\n"
137 "ProductID\tnone\n"
138 "ProductLanguage\t1033\n"
139 "ProductName\tMSITEST\n"
140 "ProductVersion\t1.1.1\n"
141 "PROMPTROLLBACKCOST\tP\n"
142 "Setup\tSetup\n"
143 "UpgradeCode\t{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}";
145 static const CHAR registry_dat[] = "Registry\tRoot\tKey\tName\tValue\tComponent_\n"
146 "s72\ti2\tl255\tL255\tL0\ts72\n"
147 "Registry\tRegistry\n"
148 "Apples\t2\tSOFTWARE\\Wine\\msitest\tName\timaname\tOne\n"
149 "Oranges\t2\tSOFTWARE\\Wine\\msitest\tnumber\t#314\tTwo\n"
150 "regdata\t2\tSOFTWARE\\Wine\\msitest\tblah\tbad\tdangler\n"
151 "OrderTest\t2\tSOFTWARE\\Wine\\msitest\tOrderTestName\tOrderTestValue\tcomponent";
153 static const CHAR service_install_dat[] = "ServiceInstall\tName\tDisplayName\tServiceType\tStartType\tErrorControl\t"
154 "LoadOrderGroup\tDependencies\tStartName\tPassword\tArguments\tComponent_\tDescription\n"
155 "s72\ts255\tL255\ti4\ti4\ti4\tS255\tS255\tS255\tS255\tS255\ts72\tL255\n"
156 "ServiceInstall\tServiceInstall\n"
157 "TestService\tTestService\tTestService\t2\t3\t0\t\t\tTestService\t\t\tservice_comp\t\t";
159 static const CHAR service_control_dat[] = "ServiceControl\tName\tEvent\tArguments\tWait\tComponent_\n"
160 "s72\tl255\ti2\tL255\tI2\ts72\n"
161 "ServiceControl\tServiceControl\n"
162 "ServiceControl\tTestService\t8\t\t0\tservice_comp";
164 typedef struct _msi_table
166 const CHAR *filename;
167 const CHAR *data;
168 int size;
169 } msi_table;
171 #define ADD_TABLE(x) {#x".idt", x##_dat, sizeof(x##_dat)}
173 static const msi_table tables[] =
175 ADD_TABLE(component),
176 ADD_TABLE(directory),
177 ADD_TABLE(feature),
178 ADD_TABLE(feature_comp),
179 ADD_TABLE(file),
180 ADD_TABLE(install_exec_seq),
181 ADD_TABLE(media),
182 ADD_TABLE(property),
183 ADD_TABLE(registry),
184 ADD_TABLE(service_install),
185 ADD_TABLE(service_control)
189 * Database Helpers
192 static void write_file(const CHAR *filename, const char *data, int data_size)
194 DWORD size;
196 HANDLE hf = CreateFile(filename, GENERIC_WRITE, 0, NULL,
197 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
199 WriteFile(hf, data, data_size, &size, NULL);
200 CloseHandle(hf);
203 static void write_msi_summary_info(MSIHANDLE db)
205 MSIHANDLE summary;
206 UINT r;
208 r = MsiGetSummaryInformationA(db, NULL, 4, &summary);
209 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
211 r = MsiSummaryInfoSetPropertyA(summary, PID_TEMPLATE, VT_LPSTR, 0, NULL, ";1033");
212 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
214 r = MsiSummaryInfoSetPropertyA(summary, PID_REVNUMBER, VT_LPSTR, 0, NULL,
215 "{004757CA-5092-49c2-AD20-28E1CE0DF5F2}");
216 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
218 r = MsiSummaryInfoSetPropertyA(summary, PID_PAGECOUNT, VT_I4, 100, NULL, NULL);
219 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
221 r = MsiSummaryInfoSetPropertyA(summary, PID_WORDCOUNT, VT_I4, 0, NULL, NULL);
222 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
224 /* write the summary changes back to the stream */
225 r = MsiSummaryInfoPersist(summary);
226 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
228 MsiCloseHandle(summary);
231 static void create_database(const CHAR *name, const msi_table *tables, int num_tables)
233 MSIHANDLE db;
234 UINT r;
235 int j;
237 r = MsiOpenDatabaseA(name, MSIDBOPEN_CREATE, &db);
238 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
240 /* import the tables into the database */
241 for (j = 0; j < num_tables; j++)
243 const msi_table *table = &tables[j];
245 write_file(table->filename, table->data, (table->size - 1) * sizeof(char));
247 r = MsiDatabaseImportA(db, CURR_DIR, table->filename);
248 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
250 DeleteFileA(table->filename);
253 write_msi_summary_info(db);
255 r = MsiDatabaseCommit(db);
256 ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %u\n", r);
258 MsiCloseHandle(db);
262 * Installation helpers
265 static char PROG_FILES_DIR[MAX_PATH];
267 static BOOL get_program_files_dir(LPSTR buf)
269 HKEY hkey;
270 DWORD type = REG_EXPAND_SZ, size;
272 if (RegOpenKey(HKEY_LOCAL_MACHINE,
273 "Software\\Microsoft\\Windows\\CurrentVersion", &hkey))
274 return FALSE;
276 size = MAX_PATH;
277 if (RegQueryValueEx(hkey, "ProgramFilesDir", 0, &type, (LPBYTE)buf, &size))
278 return FALSE;
280 RegCloseKey(hkey);
281 return TRUE;
284 static void create_file(const CHAR *name, DWORD size)
286 HANDLE file;
287 DWORD written, left;
289 file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
290 ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
291 WriteFile(file, name, strlen(name), &written, NULL);
292 WriteFile(file, "\n", strlen("\n"), &written, NULL);
294 left = size - lstrlen(name) - 1;
296 SetFilePointer(file, left, NULL, FILE_CURRENT);
297 SetEndOfFile(file);
299 CloseHandle(file);
302 static void create_test_files(void)
304 CreateDirectoryA("msitest", NULL);
305 create_file("msitest\\one.txt", 100);
306 CreateDirectoryA("msitest\\first", NULL);
307 create_file("msitest\\first\\two.txt", 100);
308 CreateDirectoryA("msitest\\second", NULL);
309 create_file("msitest\\second\\three.txt", 100);
310 CreateDirectoryA("msitest\\cabout",NULL);
311 create_file("msitest\\cabout\\four.txt", 100);
312 CreateDirectoryA("msitest\\cabout\\new",NULL);
313 create_file("msitest\\cabout\\new\\five.txt", 100);
314 create_file("msitest\\filename", 100);
315 create_file("msitest\\service.exe", 100);
318 static BOOL delete_pf(const CHAR *rel_path, BOOL is_file)
320 CHAR path[MAX_PATH];
322 lstrcpyA(path, PROG_FILES_DIR);
323 lstrcatA(path, "\\");
324 lstrcatA(path, rel_path);
326 if (is_file)
327 return DeleteFileA(path);
328 else
329 return RemoveDirectoryA(path);
332 static void delete_test_files(void)
334 DeleteFileA(msifile);
335 DeleteFileA("msitest\\cabout\\new\\five.txt");
336 DeleteFileA("msitest\\cabout\\four.txt");
337 DeleteFileA("msitest\\second\\three.txt");
338 DeleteFileA("msitest\\first\\two.txt");
339 DeleteFileA("msitest\\one.txt");
340 DeleteFileA("msitest\\service.exe");
341 DeleteFileA("msitest\\filename");
342 RemoveDirectoryA("msitest\\cabout\\new");
343 RemoveDirectoryA("msitest\\cabout");
344 RemoveDirectoryA("msitest\\second");
345 RemoveDirectoryA("msitest\\first");
346 RemoveDirectoryA("msitest");
349 static void check_service_is_installed(void)
351 SC_HANDLE scm, service;
352 BOOL res;
354 scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
355 ok(scm != NULL, "Failed to open the SC Manager\n");
357 service = OpenService(scm, "TestService", SC_MANAGER_ALL_ACCESS);
358 ok(service != NULL, "Failed to open TestService\n");
360 res = DeleteService(service);
361 ok(res, "Failed to delete TestService\n");
365 * Automation helpers and tests
368 /* ok-like statement which takes two unicode strings as arguments */
369 static CHAR string1[MAX_PATH], string2[MAX_PATH];
371 #define ok_w2(format, szString1, szString2) \
373 if (lstrcmpW(szString1, szString2) != 0) \
375 WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
376 WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
377 ok(0, format, string1, string2); \
380 /* exception checker */
381 static WCHAR szSource[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
383 #define ok_exception(hr, szDescription) \
384 if (hr == DISP_E_EXCEPTION) \
386 /* Compare wtype, source, and destination */ \
387 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
389 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
390 if (excepinfo.bstrSource) \
391 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, szSource); \
393 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
394 if (excepinfo.bstrDescription) \
395 ok_w2("Exception description was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrDescription, szDescription); \
398 static DISPID get_dispid( IDispatch *disp, const char *name )
400 LPOLESTR str;
401 UINT len;
402 DISPID id = -1;
403 HRESULT r;
405 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0 );
406 str = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
407 if (str)
409 len = MultiByteToWideChar(CP_ACP, 0, name, -1, str, len );
410 r = IDispatch_GetIDsOfNames( disp, &IID_NULL, &str, 1, 0, &id );
411 HeapFree(GetProcessHeap(), 0, str);
412 if (r != S_OK)
413 return -1;
416 return id;
419 static void test_dispid(void)
421 ok( get_dispid( pInstaller, "CreateRecord" ) == 1, "dispid wrong\n");
422 ok( get_dispid( pInstaller, "OpenPackage" ) == 2, "dispid wrong\n");
423 todo_wine {
424 ok( get_dispid( pInstaller, "OpenProduct" ) == 3, "dispid wrong\n");
425 ok( get_dispid( pInstaller, "OpenDatabase" ) == 4, "dispid wrong\n");
426 ok( get_dispid( pInstaller, "SummaryInformation" ) == 5, "dispid wrong\n");
427 ok( get_dispid( pInstaller, "UILevel" ) == 6, "dispid wrong\n");
428 ok( get_dispid( pInstaller, "EnableLog" ) == 7, "dispid wrong\n");
430 ok( get_dispid( pInstaller, "InstallProduct" ) == 8, "dispid wrong\n");
431 todo_wine {
432 ok( get_dispid( pInstaller, "Version" ) == 9, "dispid wrong\n");
433 ok( get_dispid( pInstaller, "LastErrorRecord" ) == 10, "dispid wrong\n");
435 ok( get_dispid( pInstaller, "RegistryValue" ) == 11, "dispid wrong\n");
436 todo_wine {
437 ok( get_dispid( pInstaller, "Environment" ) == 12, "dispid wrong\n");
438 ok( get_dispid( pInstaller, "FileAttributes" ) == 13, "dispid wrong\n");
440 ok( get_dispid( pInstaller, "FileSize" ) == 15, "dispid wrong\n");
441 ok( get_dispid( pInstaller, "FileVersion" ) == 16, "dispid wrong\n");
443 ok( get_dispid( pInstaller, "ProductState" ) == 17, "dispid wrong\n");
444 todo_wine {
445 ok( get_dispid( pInstaller, "ProductInfo" ) == 18, "dispid wrong\n");
446 ok( get_dispid( pInstaller, "ConfigureProduct" ) == 19, "dispid wrong\n");
447 ok( get_dispid( pInstaller, "ReinstallProduct" ) == 20 , "dispid wrong\n");
448 ok( get_dispid( pInstaller, "CollectUserInfo" ) == 21, "dispid wrong\n");
449 ok( get_dispid( pInstaller, "ApplyPatch" ) == 22, "dispid wrong\n");
450 ok( get_dispid( pInstaller, "FeatureParent" ) == 23, "dispid wrong\n");
451 ok( get_dispid( pInstaller, "FeatureState" ) == 24, "dispid wrong\n");
452 ok( get_dispid( pInstaller, "UseFeature" ) == 25, "dispid wrong\n");
453 ok( get_dispid( pInstaller, "FeatureUsageCount" ) == 26, "dispid wrong\n");
454 ok( get_dispid( pInstaller, "FeatureUsageDate" ) == 27, "dispid wrong\n");
455 ok( get_dispid( pInstaller, "ConfigureFeature" ) == 28, "dispid wrong\n");
456 ok( get_dispid( pInstaller, "ReinstallFeature" ) == 29, "dispid wrong\n");
457 ok( get_dispid( pInstaller, "ProvideComponent" ) == 30, "dispid wrong\n");
458 ok( get_dispid( pInstaller, "ComponentPath" ) == 31, "dispid wrong\n");
459 ok( get_dispid( pInstaller, "ProvideQualifiedComponent" ) == 32, "dispid wrong\n");
460 ok( get_dispid( pInstaller, "QualifierDescription" ) == 33, "dispid wrong\n");
461 ok( get_dispid( pInstaller, "ComponentQualifiers" ) == 34, "dispid wrong\n");
463 ok( get_dispid( pInstaller, "Products" ) == 35, "dispid wrong\n");
464 todo_wine {
465 ok( get_dispid( pInstaller, "Features" ) == 36, "dispid wrong\n");
466 ok( get_dispid( pInstaller, "Components" ) == 37, "dispid wrong\n");
467 ok( get_dispid( pInstaller, "ComponentClients" ) == 38, "dispid wrong\n");
468 ok( get_dispid( pInstaller, "Patches" ) == 39, "dispid wrong\n");
469 ok( get_dispid( pInstaller, "RelatedProducts" ) == 40, "dispid wrong\n");
470 ok( get_dispid( pInstaller, "PatchInfo" ) == 41, "dispid wrong\n");
471 ok( get_dispid( pInstaller, "PatchTransforms" ) == 42, "dispid wrong\n");
472 ok( get_dispid( pInstaller, "AddSource" ) == 43, "dispid wrong\n");
473 ok( get_dispid( pInstaller, "ClearSourceList" ) == 44, "dispid wrong\n");
474 ok( get_dispid( pInstaller, "ForceSourceListResolution" ) == 45, "dispid wrong\n");
475 ok( get_dispid( pInstaller, "ShortcutTarget" ) == 46, "dispid wrong\n");
476 ok( get_dispid( pInstaller, "FileHash" ) == 47, "dispid wrong\n");
477 ok( get_dispid( pInstaller, "FileSignatureInfo" ) == 48, "dispid wrong\n");
478 ok( get_dispid( pInstaller, "RemovePatches" ) == 49, "dispid wrong\n");
480 ok( get_dispid( pInstaller, "ApplyMultiplePatches" ) == 51, "dispid wrong\n");
481 ok( get_dispid( pInstaller, "ProductsEx" ) == 52, "dispid wrong\n");
483 ok( get_dispid( pInstaller, "PatchesEx" ) == 55, "dispid wrong\n");
485 ok( get_dispid( pInstaller, "ExtractPatchXMLData" ) == 57, "dispid wrong\n");
488 /* MSDN claims the following functions exist but IDispatch->GetIDsOfNames disagrees */
489 if (0)
491 get_dispid( pInstaller, "ProductElevated" );
492 get_dispid( pInstaller, "ProductInfoFromScript" );
493 get_dispid( pInstaller, "ProvideAssembly" );
494 get_dispid( pInstaller, "CreateAdvertiseScript" );
495 get_dispid( pInstaller, "AdvertiseProduct" );
496 get_dispid( pInstaller, "PatchFiles" );
500 /* Test basic IDispatch functions */
501 static void test_dispatch(void)
503 static WCHAR szOpenPackage[] = { 'O','p','e','n','P','a','c','k','a','g','e',0 };
504 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};
505 static WCHAR szProductState[] = { 'P','r','o','d','u','c','t','S','t','a','t','e',0 };
506 HRESULT hr;
507 DISPID dispid;
508 OLECHAR *name;
509 VARIANT varresult;
510 VARIANTARG vararg[2];
511 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
513 /* Test getting ID of a function name that does not exist */
514 name = (WCHAR *)szMsifile;
515 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
516 ok(hr == DISP_E_UNKNOWNNAME, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
518 /* Test invoking this function */
519 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
520 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
522 /* Test getting ID of a function name that does exist */
523 name = (WCHAR *)szOpenPackage;
524 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
525 ok(SUCCEEDED(hr), "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
527 /* Test invoking this function (without parameters passed) */
528 if (0) /* All of these crash MSI on Windows XP */
530 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, NULL, NULL);
531 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, NULL, &excepinfo, NULL);
532 VariantInit(&varresult);
533 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, NULL, &varresult, &excepinfo, NULL);
536 /* Try with NULL params */
537 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
538 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
540 /* Try one empty parameter */
541 dispparams.rgvarg = vararg;
542 dispparams.cArgs = 1;
543 VariantInit(&vararg[0]);
544 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
545 todo_wine ok(hr == DISP_E_TYPEMISMATCH, "IDispatch::Invoke returned 0x%08x\n", hr);
547 /* Try one parameter, function requires two */
548 VariantInit(&vararg[0]);
549 V_VT(&vararg[0]) = VT_BSTR;
550 V_BSTR(&vararg[0]) = SysAllocString(szMsifile);
551 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
552 VariantClear(&vararg[0]);
554 ok(hr == DISP_E_EXCEPTION, "IDispatch::Invoke returned 0x%08x\n", hr);
555 ok_exception(hr, szOpenPackageException);
557 /* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
558 VariantInit(&vararg[0]);
559 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYGET, &dispparams, &varresult, &excepinfo, NULL);
560 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
562 VariantInit(&vararg[0]);
563 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
564 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
566 /* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
567 name = (WCHAR *)szProductState;
568 hr = IDispatch_GetIDsOfNames(pInstaller, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
569 ok(SUCCEEDED(hr), "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
571 dispparams.rgvarg = NULL;
572 dispparams.cArgs = 0;
573 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_PROPERTYPUT, &dispparams, &varresult, &excepinfo, NULL);
574 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
576 dispparams.rgvarg = NULL;
577 dispparams.cArgs = 0;
578 hr = IDispatch_Invoke(pInstaller, dispid, &IID_NULL, LOCALE_NEUTRAL, DISPATCH_METHOD, &dispparams, &varresult, &excepinfo, NULL);
579 ok(hr == DISP_E_MEMBERNOTFOUND, "IDispatch::Invoke returned 0x%08x\n", hr);
582 /* invocation helper function */
583 static HRESULT invoke(IDispatch *pDispatch, LPCSTR szName, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, VARTYPE vtResult)
585 OLECHAR *name = NULL;
586 DISPID dispid;
587 HRESULT hr;
588 int i;
589 UINT len;
591 memset(pVarResult, 0, sizeof(VARIANT));
592 VariantInit(pVarResult);
594 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, NULL, 0 );
595 name = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR) );
596 if (!name) return E_FAIL;
597 len = MultiByteToWideChar(CP_ACP, 0, szName, -1, name, len );
598 hr = IDispatch_GetIDsOfNames(pDispatch, &IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &dispid);
599 HeapFree(GetProcessHeap(), 0, name);
600 ok(SUCCEEDED(hr), "IDispatch::GetIDsOfNames returned 0x%08x\n", hr);
601 if (!SUCCEEDED(hr)) return hr;
603 memset(&excepinfo, 0, sizeof(excepinfo));
604 hr = IDispatch_Invoke(pDispatch, dispid, &IID_NULL, LOCALE_NEUTRAL, wFlags, pDispParams, pVarResult, &excepinfo, NULL);
606 if (SUCCEEDED(hr))
608 ok(V_VT(pVarResult) == vtResult, "Variant result type is %d, expected %d\n", V_VT(pVarResult), vtResult);
609 if (vtResult != VT_EMPTY)
611 hr = VariantChangeTypeEx(pVarResult, pVarResult, LOCALE_NEUTRAL, 0, vtResult);
612 ok(SUCCEEDED(hr), "VariantChangeTypeEx returned 0x%08x\n", hr);
616 for (i=0; i<pDispParams->cArgs; i++)
617 VariantClear(&pDispParams->rgvarg[i]);
619 return hr;
622 /* Object_Property helper functions */
624 static HRESULT Installer_CreateRecord(int count, IDispatch **pRecord)
626 VARIANT varresult;
627 VARIANTARG vararg[1];
628 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
629 HRESULT hr;
631 VariantInit(&vararg[0]);
632 V_VT(&vararg[0]) = VT_I4;
633 V_I4(&vararg[0]) = count;
635 hr = invoke(pInstaller, "CreateRecord", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
636 *pRecord = V_DISPATCH(&varresult);
637 return hr;
640 static HRESULT Installer_RegistryValue(HKEY hkey, LPCWSTR szKey, VARIANT vValue, VARIANT *pVarResult, VARTYPE vtExpect)
642 VARIANTARG vararg[3];
643 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
645 VariantInit(&vararg[2]);
646 V_VT(&vararg[2]) = VT_I4;
647 V_I4(&vararg[2]) = (int)hkey;
648 VariantInit(&vararg[1]);
649 V_VT(&vararg[1]) = VT_BSTR;
650 V_BSTR(&vararg[1]) = SysAllocString(szKey);
651 VariantInit(&vararg[0]);
652 VariantCopy(&vararg[0], &vValue);
653 VariantClear(&vValue);
655 return invoke(pInstaller, "RegistryValue", DISPATCH_METHOD, &dispparams, pVarResult, vtExpect);
658 static HRESULT Installer_RegistryValueE(HKEY hkey, LPCWSTR szKey, BOOL *pBool)
660 VARIANT varresult;
661 VARIANTARG vararg;
662 HRESULT hr;
664 VariantInit(&vararg);
665 V_VT(&vararg) = VT_EMPTY;
666 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BOOL);
667 *pBool = V_BOOL(&varresult);
668 VariantClear(&varresult);
669 return hr;
672 static HRESULT Installer_RegistryValueW(HKEY hkey, LPCWSTR szKey, LPCWSTR szValue, LPWSTR szString)
674 VARIANT varresult;
675 VARIANTARG vararg;
676 HRESULT hr;
678 VariantInit(&vararg);
679 V_VT(&vararg) = VT_BSTR;
680 V_BSTR(&vararg) = SysAllocString(szValue);
682 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, VT_BSTR);
683 lstrcpyW(szString, V_BSTR(&varresult));
684 VariantClear(&varresult);
685 return hr;
688 static HRESULT Installer_RegistryValueI(HKEY hkey, LPCWSTR szKey, int iValue, LPWSTR szString, VARTYPE vtResult)
690 VARIANT varresult;
691 VARIANTARG vararg;
692 HRESULT hr;
694 VariantInit(&vararg);
695 V_VT(&vararg) = VT_I4;
696 V_I4(&vararg) = iValue;
698 hr = Installer_RegistryValue(hkey, szKey, vararg, &varresult, vtResult);
699 if (vtResult == VT_BSTR) lstrcpyW(szString, V_BSTR(&varresult));
700 VariantClear(&varresult);
701 return hr;
704 static HRESULT Installer_OpenPackage(LPCWSTR szPackagePath, int options, IDispatch **pSession)
706 VARIANT varresult;
707 VARIANTARG vararg[2];
708 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
709 HRESULT hr;
711 VariantInit(&vararg[1]);
712 V_VT(&vararg[1]) = VT_BSTR;
713 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
714 VariantInit(&vararg[0]);
715 V_VT(&vararg[0]) = VT_I4;
716 V_I4(&vararg[0]) = options;
718 hr = invoke(pInstaller, "OpenPackage", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
719 *pSession = V_DISPATCH(&varresult);
720 return hr;
723 static HRESULT Installer_InstallProduct(LPCWSTR szPackagePath, LPCWSTR szPropertyValues)
725 VARIANT varresult;
726 VARIANTARG vararg[2];
727 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
729 VariantInit(&vararg[1]);
730 V_VT(&vararg[1]) = VT_BSTR;
731 V_BSTR(&vararg[1]) = SysAllocString(szPackagePath);
732 VariantInit(&vararg[0]);
733 V_VT(&vararg[0]) = VT_BSTR;
734 V_BSTR(&vararg[0]) = SysAllocString(szPropertyValues);
736 return invoke(pInstaller, "InstallProduct", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
739 static HRESULT Installer_ProductState(LPCWSTR szProduct, int *pInstallState)
741 VARIANT varresult;
742 VARIANTARG vararg[1];
743 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
744 HRESULT hr;
746 VariantInit(&vararg[0]);
747 V_VT(&vararg[0]) = VT_BSTR;
748 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
750 hr = invoke(pInstaller, "ProductState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
751 *pInstallState = V_I4(&varresult);
752 VariantClear(&varresult);
753 return hr;
756 static HRESULT Installer_Products(IDispatch **pStringList)
758 VARIANT varresult;
759 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
760 HRESULT hr;
762 hr = invoke(pInstaller, "Products", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
763 *pStringList = V_DISPATCH(&varresult);
764 return hr;
767 static HRESULT Installer_RelatedProducts(LPCWSTR szProduct, IDispatch **pStringList)
769 VARIANT varresult;
770 VARIANTARG vararg[1];
771 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
772 HRESULT hr;
774 VariantInit(&vararg[0]);
775 V_VT(&vararg[0]) = VT_BSTR;
776 V_BSTR(&vararg[0]) = SysAllocString(szProduct);
778 hr = invoke(pInstaller, "RelatedProducts", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
779 *pStringList = V_DISPATCH(&varresult);
780 return hr;
783 static HRESULT Installer_VersionGet(LPCWSTR szVersion)
785 VARIANT varresult;
786 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
787 HRESULT hr;
789 hr = invoke(pInstaller, "Version", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
790 lstrcpyW((WCHAR *)szVersion, V_BSTR(&varresult));
791 VariantClear(&varresult);
792 return hr;
795 static HRESULT Session_Installer(IDispatch *pSession, IDispatch **pInst)
797 VARIANT varresult;
798 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
799 HRESULT hr;
801 hr = invoke(pSession, "Installer", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
802 *pInst = V_DISPATCH(&varresult);
803 return hr;
806 static HRESULT Session_PropertyGet(IDispatch *pSession, LPCWSTR szName, LPCWSTR szReturn)
808 VARIANT varresult;
809 VARIANTARG vararg[1];
810 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
811 HRESULT hr;
813 VariantInit(&vararg[0]);
814 V_VT(&vararg[0]) = VT_BSTR;
815 V_BSTR(&vararg[0]) = SysAllocString(szName);
817 hr = invoke(pSession, "Property", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
818 lstrcpyW((WCHAR *)szReturn, V_BSTR(&varresult));
819 VariantClear(&varresult);
820 return hr;
823 static HRESULT Session_PropertyPut(IDispatch *pSession, LPCWSTR szName, LPCWSTR szValue)
825 VARIANT varresult;
826 VARIANTARG vararg[2];
827 DISPID dispid = DISPID_PROPERTYPUT;
828 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
830 VariantInit(&vararg[1]);
831 V_VT(&vararg[1]) = VT_BSTR;
832 V_BSTR(&vararg[1]) = SysAllocString(szName);
833 VariantInit(&vararg[0]);
834 V_VT(&vararg[0]) = VT_BSTR;
835 V_BSTR(&vararg[0]) = SysAllocString(szValue);
837 return invoke(pSession, "Property", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
840 static HRESULT Session_LanguageGet(IDispatch *pSession, UINT *pLangId)
842 VARIANT varresult;
843 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
844 HRESULT hr;
846 hr = invoke(pSession, "Language", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
847 *pLangId = V_I4(&varresult);
848 VariantClear(&varresult);
849 return hr;
852 static HRESULT Session_ModeGet(IDispatch *pSession, int iFlag, BOOL *pMode)
854 VARIANT varresult;
855 VARIANTARG vararg[1];
856 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
857 HRESULT hr;
859 VariantInit(&vararg[0]);
860 V_VT(&vararg[0]) = VT_I4;
861 V_I4(&vararg[0]) = iFlag;
863 hr = invoke(pSession, "Mode", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BOOL);
864 *pMode = V_BOOL(&varresult);
865 VariantClear(&varresult);
866 return hr;
869 static HRESULT Session_ModePut(IDispatch *pSession, int iFlag, BOOL bMode)
871 VARIANT varresult;
872 VARIANTARG vararg[2];
873 DISPID dispid = DISPID_PROPERTYPUT;
874 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
876 VariantInit(&vararg[1]);
877 V_VT(&vararg[1]) = VT_I4;
878 V_I4(&vararg[1]) = iFlag;
879 VariantInit(&vararg[0]);
880 V_VT(&vararg[0]) = VT_BOOL;
881 V_BOOL(&vararg[0]) = bMode;
883 return invoke(pSession, "Mode", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
886 static HRESULT Session_Database(IDispatch *pSession, IDispatch **pDatabase)
888 VARIANT varresult;
889 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
890 HRESULT hr;
892 hr = invoke(pSession, "Database", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_DISPATCH);
893 *pDatabase = V_DISPATCH(&varresult);
894 return hr;
897 static HRESULT Session_DoAction(IDispatch *pSession, LPCWSTR szAction, int *iReturn)
899 VARIANT varresult;
900 VARIANTARG vararg[1];
901 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
902 HRESULT hr;
904 VariantInit(&vararg[0]);
905 V_VT(&vararg[0]) = VT_BSTR;
906 V_BSTR(&vararg[0]) = SysAllocString(szAction);
908 hr = invoke(pSession, "DoAction", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
909 *iReturn = V_I4(&varresult);
910 VariantClear(&varresult);
911 return hr;
914 static HRESULT Session_EvaluateCondition(IDispatch *pSession, LPCWSTR szCondition, int *iReturn)
916 VARIANT varresult;
917 VARIANTARG vararg[1];
918 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
919 HRESULT hr;
921 VariantInit(&vararg[0]);
922 V_VT(&vararg[0]) = VT_BSTR;
923 V_BSTR(&vararg[0]) = SysAllocString(szCondition);
925 hr = invoke(pSession, "EvaluateCondition", DISPATCH_METHOD, &dispparams, &varresult, VT_I4);
926 *iReturn = V_I4(&varresult);
927 VariantClear(&varresult);
928 return hr;
931 static HRESULT Session_SetInstallLevel(IDispatch *pSession, long iInstallLevel)
933 VARIANT varresult;
934 VARIANTARG vararg[1];
935 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
937 VariantInit(&vararg[0]);
938 V_VT(&vararg[0]) = VT_I4;
939 V_I4(&vararg[0]) = iInstallLevel;
941 return invoke(pSession, "SetInstallLevel", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
944 static HRESULT Session_FeatureCurrentState(IDispatch *pSession, LPCWSTR szName, int *pState)
946 VARIANT varresult;
947 VARIANTARG vararg[1];
948 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
949 HRESULT hr;
951 VariantInit(&vararg[0]);
952 V_VT(&vararg[0]) = VT_BSTR;
953 V_BSTR(&vararg[0]) = SysAllocString(szName);
955 hr = invoke(pSession, "FeatureCurrentState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
956 *pState = V_I4(&varresult);
957 VariantClear(&varresult);
958 return hr;
961 static HRESULT Session_FeatureRequestStateGet(IDispatch *pSession, LPCWSTR szName, int *pState)
963 VARIANT varresult;
964 VARIANTARG vararg[1];
965 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
966 HRESULT hr;
968 VariantInit(&vararg[0]);
969 V_VT(&vararg[0]) = VT_BSTR;
970 V_BSTR(&vararg[0]) = SysAllocString(szName);
972 hr = invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
973 *pState = V_I4(&varresult);
974 VariantClear(&varresult);
975 return hr;
978 static HRESULT Session_FeatureRequestStatePut(IDispatch *pSession, LPCWSTR szName, int iState)
980 VARIANT varresult;
981 VARIANTARG vararg[2];
982 DISPID dispid = DISPID_PROPERTYPUT;
983 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
985 VariantInit(&vararg[1]);
986 V_VT(&vararg[1]) = VT_BSTR;
987 V_BSTR(&vararg[1]) = SysAllocString(szName);
988 VariantInit(&vararg[0]);
989 V_VT(&vararg[0]) = VT_I4;
990 V_I4(&vararg[0]) = iState;
992 return invoke(pSession, "FeatureRequestState", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
995 static HRESULT Database_OpenView(IDispatch *pDatabase, LPCWSTR szSql, IDispatch **pView)
997 VARIANT varresult;
998 VARIANTARG vararg[1];
999 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1000 HRESULT hr;
1002 VariantInit(&vararg[0]);
1003 V_VT(&vararg[0]) = VT_BSTR;
1004 V_BSTR(&vararg[0]) = SysAllocString(szSql);
1006 hr = invoke(pDatabase, "OpenView", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1007 *pView = V_DISPATCH(&varresult);
1008 return hr;
1011 static HRESULT View_Execute(IDispatch *pView, IDispatch *pRecord)
1013 VARIANT varresult;
1014 VARIANTARG vararg[1];
1015 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1017 VariantInit(&vararg[0]);
1018 V_VT(&vararg[0]) = VT_DISPATCH;
1019 V_DISPATCH(&vararg[0]) = pRecord;
1021 return invoke(pView, "Execute", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1024 static HRESULT View_Fetch(IDispatch *pView, IDispatch **ppRecord)
1026 VARIANT varresult;
1027 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1028 HRESULT hr = invoke(pView, "Fetch", DISPATCH_METHOD, &dispparams, &varresult, VT_DISPATCH);
1029 *ppRecord = V_DISPATCH(&varresult);
1030 return hr;
1033 static HRESULT View_Modify(IDispatch *pView, int iMode, IDispatch *pRecord)
1035 VARIANT varresult;
1036 VARIANTARG vararg[2];
1037 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1039 VariantInit(&vararg[1]);
1040 V_VT(&vararg[1]) = VT_I4;
1041 V_I4(&vararg[1]) = iMode;
1042 VariantInit(&vararg[0]);
1043 V_VT(&vararg[0]) = VT_DISPATCH;
1044 V_DISPATCH(&vararg[0]) = pRecord;
1045 if (pRecord)
1046 IDispatch_AddRef(pRecord); /* VariantClear in invoke will call IDispatch_Release */
1048 return invoke(pView, "Modify", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1051 static HRESULT View_Close(IDispatch *pView)
1053 VARIANT varresult;
1054 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1055 return invoke(pView, "Close", DISPATCH_METHOD, &dispparams, &varresult, VT_EMPTY);
1058 static HRESULT Record_FieldCountGet(IDispatch *pRecord, int *pFieldCount)
1060 VARIANT varresult;
1061 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1062 HRESULT hr = invoke(pRecord, "FieldCount", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1063 *pFieldCount = V_I4(&varresult);
1064 VariantClear(&varresult);
1065 return hr;
1068 static HRESULT Record_StringDataGet(IDispatch *pRecord, int iField, LPCWSTR szString)
1070 VARIANT varresult;
1071 VARIANTARG vararg[1];
1072 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1073 HRESULT hr;
1075 VariantInit(&vararg[0]);
1076 V_VT(&vararg[0]) = VT_I4;
1077 V_I4(&vararg[0]) = iField;
1079 hr = invoke(pRecord, "StringData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1080 lstrcpyW((WCHAR *)szString, V_BSTR(&varresult));
1081 VariantClear(&varresult);
1082 return hr;
1085 static HRESULT Record_StringDataPut(IDispatch *pRecord, int iField, LPCWSTR szString)
1087 VARIANT varresult;
1088 VARIANTARG vararg[2];
1089 DISPID dispid = DISPID_PROPERTYPUT;
1090 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1092 VariantInit(&vararg[1]);
1093 V_VT(&vararg[1]) = VT_I4;
1094 V_I4(&vararg[1]) = iField;
1095 VariantInit(&vararg[0]);
1096 V_VT(&vararg[0]) = VT_BSTR;
1097 V_BSTR(&vararg[0]) = SysAllocString(szString);
1099 return invoke(pRecord, "StringData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1102 static HRESULT Record_IntegerDataGet(IDispatch *pRecord, int iField, int *pValue)
1104 VARIANT varresult;
1105 VARIANTARG vararg[1];
1106 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1107 HRESULT hr;
1109 VariantInit(&vararg[0]);
1110 V_VT(&vararg[0]) = VT_I4;
1111 V_I4(&vararg[0]) = iField;
1113 hr = invoke(pRecord, "IntegerData", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1114 *pValue = V_I4(&varresult);
1115 VariantClear(&varresult);
1116 return hr;
1119 static HRESULT Record_IntegerDataPut(IDispatch *pRecord, int iField, int iValue)
1121 VARIANT varresult;
1122 VARIANTARG vararg[2];
1123 DISPID dispid = DISPID_PROPERTYPUT;
1124 DISPPARAMS dispparams = {vararg, &dispid, sizeof(vararg)/sizeof(VARIANTARG), 1};
1126 VariantInit(&vararg[1]);
1127 V_VT(&vararg[1]) = VT_I4;
1128 V_I4(&vararg[1]) = iField;
1129 VariantInit(&vararg[0]);
1130 V_VT(&vararg[0]) = VT_I4;
1131 V_I4(&vararg[0]) = iValue;
1133 return invoke(pRecord, "IntegerData", DISPATCH_PROPERTYPUT, &dispparams, &varresult, VT_EMPTY);
1136 static HRESULT StringList_Item(IDispatch *pStringList, int iIndex, LPWSTR szString)
1138 VARIANT varresult;
1139 VARIANTARG vararg[1];
1140 DISPPARAMS dispparams = {vararg, NULL, sizeof(vararg)/sizeof(VARIANTARG), 0};
1141 HRESULT hr;
1143 VariantInit(&vararg[0]);
1144 V_VT(&vararg[0]) = VT_I4;
1145 V_I4(&vararg[0]) = iIndex;
1147 hr = invoke(pStringList, "Item", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_BSTR);
1148 lstrcpyW(szString, V_BSTR(&varresult));
1149 VariantClear(&varresult);
1150 return hr;
1153 static HRESULT StringList_Count(IDispatch *pStringList, int *pCount)
1155 VARIANT varresult;
1156 DISPPARAMS dispparams = {NULL, NULL, 0, 0};
1157 HRESULT hr = invoke(pStringList, "Count", DISPATCH_PROPERTYGET, &dispparams, &varresult, VT_I4);
1158 *pCount = V_I4(&varresult);
1159 VariantClear(&varresult);
1160 return hr;
1163 /* Test the various objects */
1165 static void test_Database(IDispatch *pDatabase)
1167 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 };
1168 static WCHAR szThree[] = { 'T','h','r','e','e',0 };
1169 static WCHAR szTwo[] = { 'T','w','o',0 };
1170 static WCHAR szStringDataField[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
1171 static WCHAR szModifyModeRecord[] = { 'M','o','d','i','f','y',',','M','o','d','e',',','R','e','c','o','r','d',0 };
1172 IDispatch *pView = NULL;
1173 HRESULT hr;
1175 hr = Database_OpenView(pDatabase, szSql, &pView);
1176 ok(SUCCEEDED(hr), "Database_OpenView failed, hresult 0x%08x\n", hr);
1177 if (SUCCEEDED(hr))
1179 IDispatch *pRecord = NULL;
1180 WCHAR szString[MAX_PATH];
1182 /* View::Execute */
1183 hr = View_Execute(pView, NULL);
1184 ok(SUCCEEDED(hr), "View_Execute failed, hresult 0x%08x\n", hr);
1186 /* View::Fetch */
1187 hr = View_Fetch(pView, &pRecord);
1188 ok(SUCCEEDED(hr), "View_Fetch failed, hresult 0x%08x\n", hr);
1189 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1190 if (pRecord)
1192 /* Record::StringDataGet */
1193 memset(szString, 0, sizeof(szString));
1194 hr = Record_StringDataGet(pRecord, 1, szString);
1195 ok(SUCCEEDED(hr), "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1196 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1198 /* Record::StringDataPut with correct index */
1199 hr = Record_StringDataPut(pRecord, 1, szTwo);
1200 ok(SUCCEEDED(hr), "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1202 /* Record::StringDataGet */
1203 memset(szString, 0, sizeof(szString));
1204 hr = Record_StringDataGet(pRecord, 1, szString);
1205 ok(SUCCEEDED(hr), "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1206 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1208 /* Record::StringDataPut with incorrect index */
1209 hr = Record_StringDataPut(pRecord, -1, szString);
1210 ok(hr == DISP_E_EXCEPTION, "Record_StringDataPut failed, hresult 0x%08x\n", hr);
1211 ok_exception(hr, szStringDataField);
1213 /* View::Modify with incorrect parameters */
1214 hr = View_Modify(pView, -5, NULL);
1215 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1216 ok_exception(hr, szModifyModeRecord);
1218 hr = View_Modify(pView, -5, pRecord);
1219 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1220 ok_exception(hr, szModifyModeRecord);
1222 hr = View_Modify(pView, MSIMODIFY_REFRESH, NULL);
1223 ok(hr == DISP_E_EXCEPTION, "View_Modify failed, hresult 0x%08x\n", hr);
1224 ok_exception(hr, szModifyModeRecord);
1226 /* View::Modify with MSIMODIFY_REFRESH should undo our changes */
1227 hr = View_Modify(pView, MSIMODIFY_REFRESH, pRecord);
1228 /* Wine's MsiViewModify currently does not support MSIMODIFY_REFRESH */
1229 todo_wine ok(SUCCEEDED(hr), "View_Modify failed, hresult 0x%08x\n", hr);
1231 /* Record::StringDataGet, confirm that the record is back to its unmodified value */
1232 memset(szString, 0, sizeof(szString));
1233 hr = Record_StringDataGet(pRecord, 1, szString);
1234 ok(SUCCEEDED(hr), "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1235 todo_wine ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szThree);
1237 IDispatch_Release(pRecord);
1240 /* View::Fetch */
1241 hr = View_Fetch(pView, &pRecord);
1242 ok(SUCCEEDED(hr), "View_Fetch failed, hresult 0x%08x\n", hr);
1243 ok(pRecord != NULL, "View_Fetch should not have returned NULL record\n");
1244 if (pRecord)
1246 /* Record::StringDataGet */
1247 memset(szString, 0, sizeof(szString));
1248 hr = Record_StringDataGet(pRecord, 1, szString);
1249 ok(SUCCEEDED(hr), "Record_StringDataGet failed, hresult 0x%08x\n", hr);
1250 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString, szTwo);
1252 IDispatch_Release(pRecord);
1255 /* View::Fetch */
1256 hr = View_Fetch(pView, &pRecord);
1257 ok(SUCCEEDED(hr), "View_Fetch failed, hresult 0x%08x\n", hr);
1258 ok(pRecord == NULL, "View_Fetch should have returned NULL record\n");
1259 if (pRecord)
1260 IDispatch_Release(pRecord);
1262 /* View::Close */
1263 hr = View_Close(pView);
1264 ok(SUCCEEDED(hr), "View_Close failed, hresult 0x%08x\n", hr);
1266 IDispatch_Release(pView);
1270 static void test_Session(IDispatch *pSession)
1272 static WCHAR szProductName[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
1273 static WCHAR szMSITEST[] = { 'M','S','I','T','E','S','T',0 };
1274 static WCHAR szOne[] = { 'O','n','e',0 };
1275 static WCHAR szOneStateFalse[] = { '!','O','n','e','>','0',0 };
1276 static WCHAR szOneStateTrue[] = { '!','O','n','e','=','-','1',0 };
1277 static WCHAR szOneActionFalse[] = { '$','O','n','e','=','-','1',0 };
1278 static WCHAR szOneActionTrue[] = { '$','O','n','e','>','0',0 };
1279 static WCHAR szCostInitialize[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
1280 static WCHAR szEmpty[] = { 0 };
1281 static WCHAR szEquals[] = { '=',0 };
1282 static WCHAR szPropertyName[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
1283 WCHAR stringw[MAX_PATH];
1284 CHAR string[MAX_PATH];
1285 UINT len;
1286 BOOL bool;
1287 int myint;
1288 IDispatch *pDatabase = NULL, *pInst = NULL;
1289 HRESULT hr;
1291 /* Session::Installer */
1292 hr = Session_Installer(pSession, &pInst);
1293 ok(SUCCEEDED(hr), "Session_Installer failed, hresult 0x%08x\n", hr);
1294 ok(pInst != NULL, "Session_Installer returned NULL IDispatch pointer\n");
1295 ok(pInst == pInstaller, "Session_Installer does not match Installer instance from CoCreateInstance\n");
1297 /* Session::Property, get */
1298 memset(stringw, 0, sizeof(stringw));
1299 hr = Session_PropertyGet(pSession, szProductName, stringw);
1300 ok(SUCCEEDED(hr), "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1301 if (lstrcmpW(stringw, szMSITEST) != 0)
1303 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1304 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1305 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string);
1308 /* Session::Property, put */
1309 hr = Session_PropertyPut(pSession, szProductName, szProductName);
1310 ok(SUCCEEDED(hr), "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1311 memset(stringw, 0, sizeof(stringw));
1312 hr = Session_PropertyGet(pSession, szProductName, stringw);
1313 ok(SUCCEEDED(hr), "Session_PropertyGet failed, hresult 0x%08x\n", hr);
1314 if (lstrcmpW(stringw, szProductName) != 0)
1316 len = WideCharToMultiByte(CP_ACP, 0, stringw, -1, string, MAX_PATH, NULL, NULL);
1317 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError());
1318 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string);
1321 /* Try putting a property using empty property identifier */
1322 hr = Session_PropertyPut(pSession, szEmpty, szProductName);
1323 ok(hr == DISP_E_EXCEPTION, "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1324 ok_exception(hr, szPropertyName);
1326 /* Try putting a property using illegal property identifier */
1327 hr = Session_PropertyPut(pSession, szEquals, szProductName);
1328 ok(SUCCEEDED(hr), "Session_PropertyPut failed, hresult 0x%08x\n", hr);
1330 /* Session::Language, get */
1331 hr = Session_LanguageGet(pSession, &len);
1332 ok(SUCCEEDED(hr), "Session_LanguageGet failed, hresult 0x%08x\n", hr);
1333 /* Not sure how to check the language is correct */
1335 /* Session::Mode, get */
1336 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1337 ok(SUCCEEDED(hr), "Session_ModeGet failed, hresult 0x%08x\n", hr);
1338 todo_wine ok(!bool, "Reboot at end session mode is %d\n", bool);
1340 /* Session::Mode, put */
1341 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, TRUE);
1342 todo_wine ok(SUCCEEDED(hr), "Session_ModePut failed, hresult 0x%08x\n", hr);
1343 hr = Session_ModeGet(pSession, MSIRUNMODE_REBOOTATEND, &bool);
1344 ok(SUCCEEDED(hr), "Session_ModeGet failed, hresult 0x%08x\n", hr);
1345 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1346 hr = Session_ModePut(pSession, MSIRUNMODE_REBOOTATEND, FALSE); /* set it again so we don't reboot */
1347 todo_wine ok(SUCCEEDED(hr), "Session_ModePut failed, hresult 0x%08x\n", hr);
1349 /* Session::Database, get */
1350 hr = Session_Database(pSession, &pDatabase);
1351 ok(SUCCEEDED(hr), "Session_Database failed, hresult 0x%08x\n", hr);
1352 if (SUCCEEDED(hr))
1354 test_Database(pDatabase);
1355 IDispatch_Release(pDatabase);
1358 /* Session::EvaluateCondition */
1359 hr = Session_EvaluateCondition(pSession, NULL, &myint);
1360 ok(SUCCEEDED(hr), "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1361 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1363 hr = Session_EvaluateCondition(pSession, szEmpty, &myint);
1364 ok(SUCCEEDED(hr), "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1365 ok(myint == MSICONDITION_NONE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1367 hr = Session_EvaluateCondition(pSession, szEquals, &myint);
1368 ok(SUCCEEDED(hr), "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1369 ok(myint == MSICONDITION_ERROR, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1371 /* Session::DoAction(CostInitialize) must occur before the next statements */
1372 hr = Session_DoAction(pSession, szCostInitialize, &myint);
1373 ok(SUCCEEDED(hr), "Session_DoAction failed, hresult 0x%08x\n", hr);
1374 ok(myint == IDOK, "DoAction(CostInitialize) returned %d, %d expected\n", myint, IDOK);
1376 /* Session::SetInstallLevel */
1377 hr = Session_SetInstallLevel(pSession, INSTALLLEVEL_MINIMUM);
1378 ok(SUCCEEDED(hr), "Session_SetInstallLevel failed, hresult 0x%08x\n", hr);
1380 /* Session::FeatureCurrentState, get */
1381 hr = Session_FeatureCurrentState(pSession, szOne, &myint);
1382 ok(SUCCEEDED(hr), "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr);
1383 ok(myint == INSTALLSTATE_UNKNOWN, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1385 /* Session::EvaluateCondition */
1386 hr = Session_EvaluateCondition(pSession, szOneStateFalse, &myint);
1387 ok(SUCCEEDED(hr), "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1388 if (SUCCEEDED(hr))
1389 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1391 hr = Session_EvaluateCondition(pSession, szOneStateTrue, &myint);
1392 ok(SUCCEEDED(hr), "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1393 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1395 /* Session::FeatureRequestState, put */
1396 hr = Session_FeatureRequestStatePut(pSession, szOne, INSTALLSTATE_ADVERTISED);
1397 ok(SUCCEEDED(hr), "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr);
1398 hr = Session_FeatureRequestStateGet(pSession, szOne, &myint);
1399 ok(SUCCEEDED(hr), "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr);
1400 ok(myint == INSTALLSTATE_ADVERTISED, "Feature request state was %d but expected %d\n", myint, INSTALLSTATE_ADVERTISED);
1402 /* Session::EvaluateCondition */
1403 hr = Session_EvaluateCondition(pSession, szOneActionFalse, &myint);
1404 ok(SUCCEEDED(hr), "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1405 if (SUCCEEDED(hr))
1406 ok(myint == MSICONDITION_FALSE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1408 hr = Session_EvaluateCondition(pSession, szOneActionTrue, &myint);
1409 ok(SUCCEEDED(hr), "Session_EvaluateCondition failed, hresult 0x%08x\n", hr);
1410 ok(myint == MSICONDITION_TRUE, "Feature current state was %d but expected %d\n", myint, INSTALLSTATE_UNKNOWN);
1413 /* delete key and all its subkeys */
1414 static DWORD delete_key( HKEY hkey )
1416 char name[MAX_PATH];
1417 DWORD ret;
1419 while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
1421 HKEY tmp;
1422 if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
1424 ret = delete_key( tmp );
1425 RegCloseKey( tmp );
1427 if (ret) break;
1429 if (ret != ERROR_NO_MORE_ITEMS) return ret;
1430 RegDeleteKeyA( hkey, "" );
1431 return 0;
1434 static void test_Installer_RegistryValue(void)
1436 static const DWORD qw[2] = { 0x12345678, 0x87654321 };
1437 static const WCHAR szKey[] = { 'S','o','f','t','w','a','r','e','\\','W','i','n','e','\\','T','e','s','t',0 };
1438 static const WCHAR szOne[] = { 'O','n','e',0 };
1439 static const WCHAR szTwo[] = { 'T','w','o',0 };
1440 static const WCHAR szThree[] = { 'T','h','r','e','e',0 };
1441 static const WCHAR szREG_BINARY[] = { '(','R','E','G','_','B','I','N','A','R','Y',')',0 };
1442 static const WCHAR szFour[] = { 'F','o','u','r',0 };
1443 static const WCHAR szExpand[] = { '%','M','S','I','T','E','S','T','%',0 };
1444 static const WCHAR szFive[] = { 'F','i','v','e',0,'H','i',0,0 };
1445 static const WCHAR szFiveHi[] = { 'F','i','v','e','\n','H','i',0 };
1446 static const WCHAR szSix[] = { 'S','i','x',0 };
1447 static const WCHAR szREG_[] = { '(','R','E','G','_',']',0 };
1448 static const WCHAR szSeven[] = { 'S','e','v','e','n',0 };
1449 static const WCHAR szEight[] = { 'E','i','g','h','t',0 };
1450 static const WCHAR szBlank[] = { 0 };
1451 VARIANT varresult;
1452 VARIANTARG vararg;
1453 WCHAR szString[MAX_PATH];
1454 HKEY hkey, hkey_sub;
1455 HRESULT hr;
1456 BOOL bRet;
1458 /* Delete keys */
1459 if (!RegOpenKeyW( HKEY_CURRENT_USER, szKey, &hkey )) delete_key( hkey );
1461 /* Does our key exist? Shouldn't; check with all three possible value parameter types */
1462 hr = Installer_RegistryValueE(HKEY_CURRENT_USER, szKey, &bRet);
1463 ok(SUCCEEDED(hr), "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1464 if (SUCCEEDED(hr))
1465 ok(!bRet, "Registry key expected to not exist, but Installer_RegistryValue claims it does\n");
1467 memset(szString, 0, sizeof(szString));
1468 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, NULL, szString);
1469 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1471 memset(szString, 0, sizeof(szString));
1472 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 0, szString, VT_BSTR);
1473 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1475 /* Create key */
1476 ok(!RegCreateKeyW( HKEY_CURRENT_USER, szKey, &hkey ), "RegCreateKeyW failed\n");
1478 ok(!RegSetValueExW(hkey,szOne,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1479 "RegSetValueExW failed\n");
1480 ok(!RegSetValueExW(hkey,szTwo,0,REG_DWORD, (const BYTE *)qw, 4),
1481 "RegSetValueExW failed\n");
1482 ok(!RegSetValueExW(hkey,szThree,0,REG_BINARY, (const BYTE *)qw, 4),
1483 "RegSetValueExW failed\n");
1484 ok(SetEnvironmentVariableA("MSITEST", "Four"), "SetEnvironmentVariableA failed %d\n", GetLastError());
1485 ok(!RegSetValueExW(hkey,szFour,0,REG_EXPAND_SZ, (const BYTE *)szExpand, sizeof(szExpand)),
1486 "RegSetValueExW failed\n");
1487 ok(!RegSetValueExW(hkey,szFive,0,REG_MULTI_SZ, (const BYTE *)szFive, sizeof(szFive)),
1488 "RegSetValueExW failed\n");
1489 ok(!RegSetValueExW(hkey,szSix,0,REG_QWORD, (const BYTE *)qw, 8),
1490 "RegSetValueExW failed\n");
1491 ok(!RegSetValueExW(hkey,szSeven,0,REG_NONE, (const BYTE *)NULL, 0),
1492 "RegSetValueExW failed\n");
1494 ok(!RegSetValueExW(hkey,NULL,0,REG_SZ, (const BYTE *)szOne, sizeof(szOne)),
1495 "RegSetValueExW failed\n");
1497 ok(!RegCreateKeyW( hkey, szEight, &hkey_sub ), "RegCreateKeyW failed\n");
1499 /* Does our key exist? It should, and make sure we retrieve the correct default value */
1500 bRet = FALSE;
1501 hr = Installer_RegistryValueE(HKEY_CURRENT_USER, szKey, &bRet);
1502 ok(SUCCEEDED(hr), "Installer_RegistryValueE failed, hresult 0x%08x\n", hr);
1503 if (SUCCEEDED(hr))
1504 ok(bRet, "Registry key expected to exist, but Installer_RegistryValue claims it does not\n");
1506 memset(szString, 0, sizeof(szString));
1507 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, NULL, szString);
1508 ok(SUCCEEDED(hr), "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1509 ok_w2("Default registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1511 /* Ask for the value of a non-existent key */
1512 memset(szString, 0, sizeof(szString));
1513 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szExpand, szString);
1514 ok(hr == DISP_E_BADINDEX, "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1516 /* Get values of keys */
1517 memset(szString, 0, sizeof(szString));
1518 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szOne, szString);
1519 ok(SUCCEEDED(hr), "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1520 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szOne);
1522 VariantInit(&vararg);
1523 V_VT(&vararg) = VT_BSTR;
1524 V_BSTR(&vararg) = SysAllocString(szTwo);
1525 hr = Installer_RegistryValue(HKEY_CURRENT_USER, szKey, vararg, &varresult, VT_I4);
1526 ok(SUCCEEDED(hr), "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1527 ok(V_I4(&varresult) == 305419896, "Registry value %d does not match expected value\n", V_I4(&varresult));
1528 VariantClear(&varresult);
1530 memset(szString, 0, sizeof(szString));
1531 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szThree, szString);
1532 ok(SUCCEEDED(hr), "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1533 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_BINARY);
1535 memset(szString, 0, sizeof(szString));
1536 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szFour, szString);
1537 ok(SUCCEEDED(hr), "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1538 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFour);
1540 memset(szString, 0, sizeof(szString));
1541 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szFive, szString);
1542 ok(SUCCEEDED(hr), "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1543 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szFiveHi);
1545 memset(szString, 0, sizeof(szString));
1546 hr = Installer_RegistryValueW(HKEY_CURRENT_USER, szKey, szSix, szString);
1547 ok(SUCCEEDED(hr), "Installer_RegistryValueW failed, hresult 0x%08x\n", hr);
1548 ok_w2("Registry value \"%s\" does not match expected \"%s\"\n", szString, szREG_);
1550 VariantInit(&vararg);
1551 V_VT(&vararg) = VT_BSTR;
1552 V_BSTR(&vararg) = SysAllocString(szSeven);
1553 hr = Installer_RegistryValue(HKEY_CURRENT_USER, szKey, vararg, &varresult, VT_EMPTY);
1554 ok(SUCCEEDED(hr), "Installer_RegistryValue failed, hresult 0x%08x\n", hr);
1556 /* Get string class name for the key */
1557 memset(szString, 0, sizeof(szString));
1558 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 0, szString, VT_BSTR);
1559 ok(SUCCEEDED(hr), "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1560 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szBlank);
1562 /* Get name of a value by positive number (RegEnumValue like), valid index */
1563 memset(szString, 0, sizeof(szString));
1564 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 2, szString, VT_BSTR);
1565 ok(SUCCEEDED(hr), "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1566 /* RegEnumValue order seems different on wine */
1567 todo_wine ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szTwo);
1569 /* Get name of a value by positive number (RegEnumValue like), invalid index */
1570 memset(szString, 0, sizeof(szString));
1571 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, 10, szString, VT_EMPTY);
1572 ok(SUCCEEDED(hr), "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1574 /* Get name of a subkey by negative number (RegEnumValue like), valid index */
1575 memset(szString, 0, sizeof(szString));
1576 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, -1, szString, VT_BSTR);
1577 ok(SUCCEEDED(hr), "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1578 ok_w2("Registry name \"%s\" does not match expected \"%s\"\n", szString, szEight);
1580 /* Get name of a subkey by negative number (RegEnumValue like), invalid index */
1581 memset(szString, 0, sizeof(szString));
1582 hr = Installer_RegistryValueI(HKEY_CURRENT_USER, szKey, -10, szString, VT_EMPTY);
1583 ok(SUCCEEDED(hr), "Installer_RegistryValueI failed, hresult 0x%08x\n", hr);
1585 /* clean up */
1586 delete_key(hkey);
1589 /* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
1590 * deleting the subkeys first) */
1591 static UINT delete_registry_key(HKEY hkeyParent, LPCSTR subkey)
1593 UINT ret;
1594 CHAR *string = NULL;
1595 HKEY hkey;
1596 DWORD dwSize;
1598 ret = RegOpenKey(hkeyParent, subkey, &hkey);
1599 if (ret != ERROR_SUCCESS) return ret;
1600 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
1601 if (ret != ERROR_SUCCESS) return ret;
1602 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
1604 while (RegEnumKeyA(hkey, 0, string, dwSize) == ERROR_SUCCESS)
1605 delete_registry_key(hkey, string);
1607 RegCloseKey(hkey);
1608 HeapFree(GetProcessHeap(), 0, string);
1609 RegDeleteKeyA(hkeyParent, subkey);
1610 return ERROR_SUCCESS;
1613 /* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
1614 static UINT find_registry_key(HKEY hkeyParent, LPCSTR subkey, LPCSTR findkey, HKEY *phkey)
1616 UINT ret;
1617 CHAR *string = NULL;
1618 int idx = 0;
1619 HKEY hkey;
1620 DWORD dwSize;
1621 BOOL found = FALSE;
1623 *phkey = 0;
1625 ret = RegOpenKey(hkeyParent, subkey, &hkey);
1626 if (ret != ERROR_SUCCESS) return ret;
1627 ret = RegQueryInfoKeyA(hkey, NULL, NULL, NULL, NULL, &dwSize, NULL, NULL, NULL, NULL, NULL, NULL);
1628 if (ret != ERROR_SUCCESS) return ret;
1629 if (!(string = HeapAlloc(GetProcessHeap(), 0, ++dwSize))) return ERROR_NOT_ENOUGH_MEMORY;
1631 while (!found &&
1632 RegEnumKeyA(hkey, idx++, string, dwSize) == ERROR_SUCCESS)
1634 if (!strcmp(string, findkey))
1636 *phkey = hkey;
1637 found = TRUE;
1639 else if (find_registry_key(hkey, string, findkey, phkey) == ERROR_SUCCESS) found = TRUE;
1642 if (*phkey != hkey) RegCloseKey(hkey);
1643 HeapFree(GetProcessHeap(), 0, string);
1644 return (found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND);
1647 static void test_Installer_InstallProduct(LPCWSTR szPath)
1649 HRESULT hr;
1650 CHAR path[MAX_PATH];
1651 WCHAR szString[MAX_PATH];
1652 LONG res;
1653 HKEY hkey;
1654 DWORD num, size, type;
1655 int iValue, iCount;
1656 IDispatch *pStringList = NULL;
1658 create_test_files();
1660 /* Installer::InstallProduct */
1661 hr = Installer_InstallProduct(szMsifile, NULL);
1662 ok(SUCCEEDED(hr), "Installer_InstallProduct failed, hresult 0x%08x\n", hr);
1664 /* Installer::ProductState for our product code, which has been installed */
1665 hr = Installer_ProductState(szProductCode, &iValue);
1666 ok(SUCCEEDED(hr), "Installer_ProductState failed, hresult 0x%08x\n", hr);
1667 ok(iValue == INSTALLSTATE_DEFAULT, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_DEFAULT);
1669 /* Installer::RelatedProducts for our upgrade code */
1670 todo_wine {
1671 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
1672 ok(SUCCEEDED(hr), "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
1673 if (SUCCEEDED(hr))
1675 /* StringList::Count */
1676 hr = StringList_Count(pStringList, &iCount);
1677 ok(SUCCEEDED(hr), "StringList_Count failed, hresult 0x%08x\n", hr);
1678 ok(iCount == 1, "Expected one related product but found %d\n", iCount);
1680 /* StringList::Item */
1681 memset(szString, 0, sizeof(szString));
1682 hr = StringList_Item(pStringList, 0, szString);
1683 ok(SUCCEEDED(hr), "StringList_Item failed (idx 0, count %d), hresult 0x%08x\n", iCount, hr);
1684 ok_w2("StringList_Item returned %s but expected %s\n", szString, szProductCode);
1686 IDispatch_Release(pStringList);
1690 /* Check & clean up installed files & registry keys */
1691 ok(delete_pf("msitest\\cabout\\new\\five.txt", TRUE), "File not installed\n");
1692 ok(delete_pf("msitest\\cabout\\new", FALSE), "File not installed\n");
1693 ok(delete_pf("msitest\\cabout\\four.txt", TRUE), "File not installed\n");
1694 ok(delete_pf("msitest\\cabout", FALSE), "File not installed\n");
1695 ok(delete_pf("msitest\\changed\\three.txt", TRUE), "File not installed\n");
1696 ok(delete_pf("msitest\\changed", FALSE), "File not installed\n");
1697 ok(delete_pf("msitest\\first\\two.txt", TRUE), "File not installed\n");
1698 ok(delete_pf("msitest\\first", FALSE), "File not installed\n");
1699 ok(delete_pf("msitest\\one.txt", TRUE), "File not installed\n");
1700 ok(delete_pf("msitest\\filename", TRUE), "File not installed\n");
1701 ok(delete_pf("msitest\\service.exe", TRUE), "File not installed\n");
1702 ok(delete_pf("msitest", FALSE), "File not installed\n");
1704 res = RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest", &hkey);
1705 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1707 size = MAX_PATH;
1708 type = REG_SZ;
1709 res = RegQueryValueExA(hkey, "Name", NULL, &type, (LPBYTE)path, &size);
1710 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1711 ok(!lstrcmpA(path, "imaname"), "Expected imaname, got %s\n", path);
1713 size = MAX_PATH;
1714 type = REG_SZ;
1715 res = RegQueryValueExA(hkey, "blah", NULL, &type, (LPBYTE)path, &size);
1716 ok(res == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", res);
1718 size = sizeof(num);
1719 type = REG_DWORD;
1720 res = RegQueryValueExA(hkey, "number", NULL, &type, (LPBYTE)&num, &size);
1721 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1722 ok(num == 314, "Expected 314, got %d\n", num);
1724 size = MAX_PATH;
1725 type = REG_SZ;
1726 res = RegQueryValueExA(hkey, "OrderTestName", NULL, &type, (LPBYTE)path, &size);
1727 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1728 ok(!lstrcmpA(path, "OrderTestValue"), "Expected imaname, got %s\n", path);
1730 RegCloseKey(hkey);
1732 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine\\msitest");
1733 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1735 check_service_is_installed();
1737 /* Remove registry keys written by RegisterProduct standard action */
1738 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{F1C3AF50-8B56-4A69-A00C-00773FE42F30}");
1739 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1741 res = RegDeleteKeyA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
1742 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1744 res = find_registry_key(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData", "05FA3C1F65B896A40AC00077F34EF203", &hkey);
1745 todo_wine ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1746 if (res == ERROR_SUCCESS)
1748 res = delete_registry_key(hkey, "05FA3C1F65B896A40AC00077F34EF203");
1749 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1750 RegCloseKey(hkey);
1753 /* Remove registry keys written by PublishProduct standard action */
1754 res = RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Installer", &hkey);
1755 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1757 res = delete_registry_key(hkey, "Products\\05FA3C1F65B896A40AC00077F34EF203");
1758 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1760 res = RegDeleteKeyA(hkey, "UpgradeCodes\\D8E760ECA1E276347B43E42BDBDA5656");
1761 ok(res == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", res);
1763 RegCloseKey(hkey);
1765 /* Delete installation files we installed */
1766 delete_test_files();
1769 static void test_Installer(void)
1771 static WCHAR szBackslash[] = { '\\',0 };
1772 static WCHAR szCreateRecordException[] = { 'C','r','e','a','t','e','R','e','c','o','r','d',',','C','o','u','n','t',0 };
1773 static WCHAR szIntegerDataException[] = { 'I','n','t','e','g','e','r','D','a','t','a',',','F','i','e','l','d',0 };
1774 WCHAR szPath[MAX_PATH];
1775 HRESULT hr;
1776 UINT len;
1777 IDispatch *pSession = NULL, *pRecord = NULL, *pStringList = NULL;
1778 int iValue, iCount;
1780 if (!pInstaller) return;
1782 /* Installer::CreateRecord */
1784 /* Test for error */
1785 hr = Installer_CreateRecord(-1, &pRecord);
1786 ok(hr == DISP_E_EXCEPTION, "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
1787 ok_exception(hr, szCreateRecordException);
1789 /* Test for success */
1790 hr = Installer_CreateRecord(1, &pRecord);
1791 ok(SUCCEEDED(hr), "Installer_CreateRecord failed, hresult 0x%08x\n", hr);
1792 ok(pRecord != NULL, "Installer_CreateRecord should not have returned NULL record\n");
1793 if (pRecord)
1795 /* Record::FieldCountGet */
1796 hr = Record_FieldCountGet(pRecord, &iValue);
1797 ok(SUCCEEDED(hr), "Record_FiledCountGet failed, hresult 0x%08x\n", hr);
1798 ok(iValue == 1, "Record_FieldCountGet result was %d but expected 1\n", iValue);
1800 /* Record::IntegerDataGet */
1801 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
1802 ok(SUCCEEDED(hr), "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
1803 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
1805 /* Record::IntegerDataGet, bad index */
1806 hr = Record_IntegerDataGet(pRecord, 10, &iValue);
1807 ok(SUCCEEDED(hr), "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
1808 ok(iValue == MSI_NULL_INTEGER, "Record_IntegerDataGet result was %d but expected %d\n", iValue, MSI_NULL_INTEGER);
1810 /* Record::IntegerDataPut */
1811 hr = Record_IntegerDataPut(pRecord, 1, 100);
1812 ok(SUCCEEDED(hr), "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
1814 /* Record::IntegerDataPut, bad index */
1815 hr = Record_IntegerDataPut(pRecord, 10, 100);
1816 ok(hr == DISP_E_EXCEPTION, "Record_IntegerDataPut failed, hresult 0x%08x\n", hr);
1817 ok_exception(hr, szIntegerDataException);
1819 /* Record::IntegerDataGet */
1820 hr = Record_IntegerDataGet(pRecord, 1, &iValue);
1821 ok(SUCCEEDED(hr), "Record_IntegerDataGet failed, hresult 0x%08x\n", hr);
1822 ok(iValue == 100, "Record_IntegerDataGet result was %d but expected 100\n", iValue);
1824 IDispatch_Release(pRecord);
1827 /* Prepare package */
1828 create_database(msifile, tables, sizeof(tables) / sizeof(msi_table));
1830 len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, CURR_DIR, -1, szPath, MAX_PATH);
1831 ok(len, "MultiByteToWideChar returned error %d\n", GetLastError());
1832 if (!len) return;
1834 lstrcatW(szPath, szBackslash);
1835 lstrcatW(szPath, szMsifile);
1837 /* Installer::OpenPackage */
1838 hr = Installer_OpenPackage(szPath, 0, &pSession);
1839 ok(SUCCEEDED(hr), "Installer_OpenPackage failed, hresult 0x%08x\n", hr);
1840 if (SUCCEEDED(hr))
1842 test_Session(pSession);
1843 IDispatch_Release(pSession);
1846 /* Installer::RegistryValue */
1847 test_Installer_RegistryValue();
1849 /* Installer::Products */
1850 hr = Installer_Products(&pStringList);
1851 ok(SUCCEEDED(hr), "Installer_Products failed, hresult 0x%08x\n", hr);
1852 if (SUCCEEDED(hr))
1854 int idx;
1856 /* StringList::Count */
1857 hr = StringList_Count(pStringList, &iCount);
1858 ok(SUCCEEDED(hr), "StringList_Count failed, hresult 0x%08x\n", hr);
1860 for (idx=0; idx<iCount; idx++)
1862 /* StringList::Item */
1863 memset(szPath, 0, sizeof(szPath));
1864 hr = StringList_Item(pStringList, idx, szPath);
1865 ok(SUCCEEDED(hr), "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx, iCount, hr);
1867 if (SUCCEEDED(hr))
1869 /* Installer::ProductState */
1870 hr = Installer_ProductState(szPath, &iValue);
1871 ok(SUCCEEDED(hr), "Installer_ProductState failed, hresult 0x%08x\n", hr);
1872 if (SUCCEEDED(hr))
1873 ok(iValue == INSTALLSTATE_DEFAULT || iValue == INSTALLSTATE_ADVERTISED, "Installer_ProductState returned %d, expected %d or %d\n", iValue, INSTALLSTATE_DEFAULT, INSTALLSTATE_ADVERTISED);
1877 /* StringList::Item using an invalid index */
1878 memset(szPath, 0, sizeof(szPath));
1879 hr = StringList_Item(pStringList, iCount, szPath);
1880 ok(hr == DISP_E_BADINDEX, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr);
1882 IDispatch_Release(pStringList);
1885 /* Installer::ProductState for our product code, which should not be installed */
1886 hr = Installer_ProductState(szProductCode, &iValue);
1887 ok(SUCCEEDED(hr), "Installer_ProductState failed, hresult 0x%08x\n", hr);
1888 if (SUCCEEDED(hr))
1889 ok(iValue == INSTALLSTATE_UNKNOWN, "Installer_ProductState returned %d, expected %d\n", iValue, INSTALLSTATE_UNKNOWN);
1891 /* Installer::RelatedProducts for our upgrade code, should not find anything */
1892 todo_wine {
1893 hr = Installer_RelatedProducts(szUpgradeCode, &pStringList);
1894 ok(SUCCEEDED(hr), "Installer_RelatedProducts failed, hresult 0x%08x\n", hr);
1895 if (SUCCEEDED(hr))
1897 /* StringList::Count */
1898 hr = StringList_Count(pStringList, &iCount);
1899 ok(SUCCEEDED(hr), "StringList_Count failed, hresult 0x%08x\n", hr);
1900 ok(!iCount, "Expected no related products but found %d\n", iCount);
1902 IDispatch_Release(pStringList);
1906 /* Installer::Version */
1907 todo_wine {
1908 memset(szPath, 0, sizeof(szPath));
1909 hr = Installer_VersionGet(szPath);
1910 ok(SUCCEEDED(hr), "Installer_VersionGet failed, hresult 0x%08x\n", hr);
1913 /* Installer::InstallProduct and other tests that depend on our product being installed */
1914 test_Installer_InstallProduct(szPath);
1917 START_TEST(automation)
1919 DWORD len;
1920 char temp_path[MAX_PATH], prev_path[MAX_PATH];
1921 HRESULT hr;
1922 CLSID clsid;
1923 IUnknown *pUnk;
1925 GetCurrentDirectoryA(MAX_PATH, prev_path);
1926 GetTempPath(MAX_PATH, temp_path);
1927 SetCurrentDirectoryA(temp_path);
1929 lstrcpyA(CURR_DIR, temp_path);
1930 len = lstrlenA(CURR_DIR);
1932 if(len && (CURR_DIR[len - 1] == '\\'))
1933 CURR_DIR[len - 1] = 0;
1935 get_program_files_dir(PROG_FILES_DIR);
1937 hr = OleInitialize(NULL);
1938 ok (SUCCEEDED(hr), "OleInitialize returned 0x%08x\n", hr);
1939 hr = CLSIDFromProgID(szProgId, &clsid);
1940 ok (SUCCEEDED(hr), "CLSIDFromProgID returned 0x%08x\n", hr);
1941 hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&pUnk);
1942 ok(SUCCEEDED(hr), "CoCreateInstance returned 0x%08x\n", hr);
1944 if (pUnk)
1946 hr = IUnknown_QueryInterface(pUnk, &IID_IDispatch, (void **)&pInstaller);
1947 ok (SUCCEEDED(hr), "IUnknown::QueryInterface returned 0x%08x\n", hr);
1949 test_dispid();
1950 test_dispatch();
1951 test_Installer();
1953 hr = IUnknown_Release(pUnk);
1954 ok (SUCCEEDED(hr), "IUnknown::Release returned 0x%08x\n", hr);
1957 OleUninitialize();
1959 SetCurrentDirectoryA(prev_path);