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
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 CHAR CURR_DIR
[MAX_PATH
];
42 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 const WCHAR szOpenPackage
[] = { 'O','p','e','n','P','a','c','k','a','g','e',0 };
48 static const WCHAR szProperty
[] = { 'P','r','o','p','e','r','t','y',0 };
49 static const WCHAR szLanguage
[] = { 'L','a','n','g','u','a','g','e',0 };
50 static const WCHAR szMode
[] = { 'M','o','d','e',0 };
51 static const WCHAR szDatabase
[] = { 'D','a','t','a','b','a','s','e',0 };
52 static const WCHAR szDoAction
[] = { 'D','o','A','c','t','i','o','n',0 };
53 static const WCHAR szSetInstallLevel
[] = { 'S','e','t','I','n','s','t','a','l','l','L','e','v','e','l',0 };
54 static const WCHAR szFeatureCurrentState
[] = { 'F','e','a','t','u','r','e','C','u','r','r','e','n','t','S','t','a','t','e',0 };
55 static const WCHAR szFeatureRequestState
[] = { 'F','e','a','t','u','r','e','R','e','q','u','e','s','t','S','t','a','t','e',0 };
58 static const WCHAR szOpenView
[] = { 'O','p','e','n','V','i','e','w',0 };
61 static const WCHAR szExecute
[] = { 'E','x','e','c','u','t','e',0 };
62 static const WCHAR szFetch
[] = { 'F','e','t','c','h',0 };
63 static const WCHAR szClose
[] = { 'C','l','o','s','e',0 };
66 static const WCHAR szStringData
[] = { 'S','t','r','i','n','g','D','a','t','a',0 };
68 static IDispatch
*pInstaller
;
70 /* msi database data */
72 static const CHAR component_dat
[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
73 "s72\tS38\ts72\ti2\tS255\tS72\n"
74 "Component\tComponent\n"
75 "Five\t{8CC92E9D-14B2-4CA4-B2AA-B11D02078087}\tNEWDIR\t2\t\tfive.txt\n"
76 "Four\t{FD37B4EA-7209-45C0-8917-535F35A2F080}\tCABOUTDIR\t2\t\tfour.txt\n"
77 "One\t{783B242E-E185-4A56-AF86-C09815EC053C}\tMSITESTDIR\t2\t\tone.txt\n"
78 "Three\t{010B6ADD-B27D-4EDD-9B3D-34C4F7D61684}\tCHANGEDDIR\t2\t\tthree.txt\n"
79 "Two\t{BF03D1A6-20DA-4A65-82F3-6CAC995915CE}\tFIRSTDIR\t2\t\ttwo.txt\n"
80 "dangler\t{6091DF25-EF96-45F1-B8E9-A9B1420C7A3C}\tTARGETDIR\t4\t\tregdata\n"
81 "component\t\tMSITESTDIR\t0\t1\tfile\n"
82 "service_comp\t\tMSITESTDIR\t0\t1\tservice_file";
84 static const CHAR directory_dat
[] = "Directory\tDirectory_Parent\tDefaultDir\n"
86 "Directory\tDirectory\n"
87 "CABOUTDIR\tMSITESTDIR\tcabout\n"
88 "CHANGEDDIR\tMSITESTDIR\tchanged:second\n"
89 "FIRSTDIR\tMSITESTDIR\tfirst\n"
90 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
91 "NEWDIR\tCABOUTDIR\tnew\n"
92 "ProgramFilesFolder\tTARGETDIR\t.\n"
93 "TARGETDIR\t\tSourceDir";
95 static const CHAR feature_dat
[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
96 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
98 "Five\t\tFive\tThe Five Feature\t5\t3\tNEWDIR\t0\n"
99 "Four\t\tFour\tThe Four Feature\t4\t3\tCABOUTDIR\t0\n"
100 "One\t\tOne\tThe One Feature\t1\t3\tMSITESTDIR\t0\n"
101 "Three\tOne\tThree\tThe Three Feature\t3\t3\tCHANGEDDIR\t0\n"
102 "Two\tOne\tTwo\tThe Two Feature\t2\t3\tFIRSTDIR\t0\n"
103 "feature\t\t\t\t2\t1\tTARGETDIR\t0\n"
104 "service_feature\t\t\t\t2\t1\tTARGETDIR\t0";
106 static const CHAR feature_comp_dat
[] = "Feature_\tComponent_\n"
108 "FeatureComponents\tFeature_\tComponent_\n"
114 "feature\tcomponent\n"
115 "service_feature\tservice_comp\n";
117 static const CHAR file_dat
[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
118 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
120 "five.txt\tFive\tfive.txt\t1000\t\t\t16384\t5\n"
121 "four.txt\tFour\tfour.txt\t1000\t\t\t16384\t4\n"
122 "one.txt\tOne\tone.txt\t1000\t\t\t0\t1\n"
123 "three.txt\tThree\tthree.txt\t1000\t\t\t0\t3\n"
124 "two.txt\tTwo\ttwo.txt\t1000\t\t\t0\t2\n"
125 "file\tcomponent\tfilename\t100\t\t\t8192\t1\n"
126 "service_file\tservice_comp\tservice.exe\t100\t\t\t8192\t1";
128 static const CHAR install_exec_seq_dat
[] = "Action\tCondition\tSequence\n"
130 "InstallExecuteSequence\tAction\n"
131 "AllocateRegistrySpace\tNOT Installed\t1550\n"
132 "CostFinalize\t\t1000\n"
133 "CostInitialize\t\t800\n"
135 "InstallFiles\t\t4000\n"
136 "InstallServices\t\t5000\n"
137 "InstallFinalize\t\t6600\n"
138 "InstallInitialize\t\t1500\n"
139 "InstallValidate\t\t1400\n"
140 "LaunchConditions\t\t100\n"
141 "WriteRegistryValues\tSourceDir And SOURCEDIR\t5000";
143 static const CHAR media_dat
[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
144 "i2\ti4\tL64\tS255\tS32\tS72\n"
146 "1\t3\t\t\tDISK1\t\n"
147 "2\t5\t\tmsitest.cab\tDISK2\t\n";
149 static const CHAR property_dat
[] = "Property\tValue\n"
151 "Property\tProperty\n"
152 "DefaultUIFont\tDlgFont8\n"
155 "InstallMode\tTypical\n"
156 "Manufacturer\tWine\n"
157 "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n"
158 "ProductCode\t{F1C3AF50-8B56-4A69-A00C-00773FE42F30}\n"
160 "ProductLanguage\t1033\n"
161 "ProductName\tMSITEST\n"
162 "ProductVersion\t1.1.1\n"
163 "PROMPTROLLBACKCOST\tP\n"
165 "UpgradeCode\t{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}";
167 static const CHAR registry_dat
[] = "Registry\tRoot\tKey\tName\tValue\tComponent_\n"
168 "s72\ti2\tl255\tL255\tL0\ts72\n"
169 "Registry\tRegistry\n"
170 "Apples\t2\tSOFTWARE\\Wine\\msitest\tName\timaname\tOne\n"
171 "Oranges\t2\tSOFTWARE\\Wine\\msitest\tnumber\t#314\tTwo\n"
172 "regdata\t2\tSOFTWARE\\Wine\\msitest\tblah\tbad\tdangler\n"
173 "OrderTest\t2\tSOFTWARE\\Wine\\msitest\tOrderTestName\tOrderTestValue\tcomponent";
175 static const CHAR service_install_dat
[] = "ServiceInstall\tName\tDisplayName\tServiceType\tStartType\tErrorControl\t"
176 "LoadOrderGroup\tDependencies\tStartName\tPassword\tArguments\tComponent_\tDescription\n"
177 "s72\ts255\tL255\ti4\ti4\ti4\tS255\tS255\tS255\tS255\tS255\ts72\tL255\n"
178 "ServiceInstall\tServiceInstall\n"
179 "TestService\tTestService\tTestService\t2\t3\t0\t\t\tTestService\t\t\tservice_comp\t\t";
181 static const CHAR service_control_dat
[] = "ServiceControl\tName\tEvent\tArguments\tWait\tComponent_\n"
182 "s72\tl255\ti2\tL255\tI2\ts72\n"
183 "ServiceControl\tServiceControl\n"
184 "ServiceControl\tTestService\t8\t\t0\tservice_comp";
186 typedef struct _msi_table
188 const CHAR
*filename
;
193 #define ADD_TABLE(x) {#x".idt", x##_dat, sizeof(x##_dat)}
195 static const msi_table tables
[] =
197 ADD_TABLE(component
),
198 ADD_TABLE(directory
),
200 ADD_TABLE(feature_comp
),
202 ADD_TABLE(install_exec_seq
),
206 ADD_TABLE(service_install
),
207 ADD_TABLE(service_control
)
214 static void write_file(const CHAR
*filename
, const char *data
, int data_size
)
218 HANDLE hf
= CreateFile(filename
, GENERIC_WRITE
, 0, NULL
,
219 CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
221 WriteFile(hf
, data
, data_size
, &size
, NULL
);
225 static void write_msi_summary_info(MSIHANDLE db
)
230 r
= MsiGetSummaryInformationA(db
, NULL
, 4, &summary
);
231 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
233 r
= MsiSummaryInfoSetPropertyA(summary
, PID_TEMPLATE
, VT_LPSTR
, 0, NULL
, ";1033");
234 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
236 r
= MsiSummaryInfoSetPropertyA(summary
, PID_REVNUMBER
, VT_LPSTR
, 0, NULL
,
237 "{004757CA-5092-49c2-AD20-28E1CE0DF5F2}");
238 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
240 r
= MsiSummaryInfoSetPropertyA(summary
, PID_PAGECOUNT
, VT_I4
, 100, NULL
, NULL
);
241 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
243 r
= MsiSummaryInfoSetPropertyA(summary
, PID_WORDCOUNT
, VT_I4
, 0, NULL
, NULL
);
244 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
246 /* write the summary changes back to the stream */
247 r
= MsiSummaryInfoPersist(summary
);
248 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
250 MsiCloseHandle(summary
);
253 static void create_database(const CHAR
*name
, const msi_table
*tables
, int num_tables
)
259 r
= MsiOpenDatabaseA(name
, MSIDBOPEN_CREATE
, &db
);
260 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
262 /* import the tables into the database */
263 for (j
= 0; j
< num_tables
; j
++)
265 const msi_table
*table
= &tables
[j
];
267 write_file(table
->filename
, table
->data
, (table
->size
- 1) * sizeof(char));
269 r
= MsiDatabaseImportA(db
, CURR_DIR
, table
->filename
);
270 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
272 DeleteFileA(table
->filename
);
275 write_msi_summary_info(db
);
277 r
= MsiDatabaseCommit(db
);
278 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
284 * Automation helpers and tests
287 /* ok-like statement which takes two unicode strings as arguments */
288 static CHAR string1
[MAX_PATH
], string2
[MAX_PATH
];
291 #define ok_w2(format, szString1, szString2) \
293 if (lstrcmpW(szString1, szString2) != 0) \
295 len = WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
296 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError()); \
298 len = WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
299 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError()); \
301 ok(0, format, string1, string2); \
304 /* exception checker */
305 static WCHAR szSource
[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
307 #define ok_exception(hr, szDescription) \
308 if (hr == DISP_E_EXCEPTION) \
310 /* Compare wtype, source, and destination */ \
311 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
313 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
314 if (excepinfo.bstrSource) \
315 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, szSource); \
317 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
318 if (excepinfo.bstrDescription && lstrcmpW(excepinfo.bstrDescription, szDescription) != 0) \
320 len = WideCharToMultiByte(CP_ACP, 0, excepinfo.bstrDescription, -1, string1, MAX_PATH, NULL, NULL); \
321 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError()); \
323 len = WideCharToMultiByte(CP_ACP, 0, szDescription, -1, string2, MAX_PATH, NULL, NULL); \
324 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError()); \
327 /* Our parameter names are different so the descriptions will not match */ \
328 ok(0, "Exception description was \"%s\" but expected to be \"%s\"\n", string1, string2); \
333 static DISPID
get_dispid( IDispatch
*disp
, const char *name
)
340 len
= MultiByteToWideChar(CP_ACP
, 0, name
, -1, NULL
, 0 );
341 str
= HeapAlloc(GetProcessHeap(), 0, len
*sizeof(WCHAR
) );
342 len
= MultiByteToWideChar(CP_ACP
, 0, name
, -1, str
, len
);
344 r
= IDispatch_GetIDsOfNames( disp
, &IID_NULL
, &str
, 1, 0, &id
);
351 static void test_dispid(void)
353 ok( get_dispid( pInstaller
, "OpenPackage" ) == 2, "dispid wrong\n");
356 ok( get_dispid( pInstaller
, "CreateRecord" ) == 1, "dispid wrong\n");
357 ok( get_dispid( pInstaller
, "OpenProduct" ) == 3, "dispid wrong\n");
358 ok( get_dispid( pInstaller
, "OpenDatabase" ) == 4, "dispid wrong\n");
359 ok( get_dispid( pInstaller
, "SummaryInformation" ) == 5, "dispid wrong\n");
360 ok( get_dispid( pInstaller
, "UILevel" ) == 6, "dispid wrong\n");
361 ok( get_dispid( pInstaller
, "EnableLog" ) == 7, "dispid wrong\n");
362 ok( get_dispid( pInstaller
, "InstallProduct" ) == 8, "dispid wrong\n");
363 ok( get_dispid( pInstaller
, "Version" ) == 9, "dispid wrong\n");
364 ok( get_dispid( pInstaller
, "LastErrorRecord" ) == 10, "dispid wrong\n");
365 ok( get_dispid( pInstaller
, "RegistryValue" ) == 11, "dispid wrong\n");
366 ok( get_dispid( pInstaller
, "Environment" ) == 12, "dispid wrong\n");
367 ok( get_dispid( pInstaller
, "FileAttributes" ) == 13, "dispid wrong\n");
369 ok( get_dispid( pInstaller
, "FileSize" ) == 15, "dispid wrong\n");
370 ok( get_dispid( pInstaller
, "FileVersion" ) == 16, "dispid wrong\n");
371 ok( get_dispid( pInstaller
, "ProductState" ) == 17, "dispid wrong\n");
372 ok( get_dispid( pInstaller
, "ProductInfo" ) == 18, "dispid wrong\n");
373 ok( get_dispid( pInstaller
, "ConfigureProduct" ) == 19, "dispid wrong\n");
374 ok( get_dispid( pInstaller
, "ReinstallProduct" ) == 20 , "dispid wrong\n");
375 ok( get_dispid( pInstaller
, "CollectUserInfo" ) == 21, "dispid wrong\n");
376 ok( get_dispid( pInstaller
, "ApplyPatch" ) == 22, "dispid wrong\n");
377 ok( get_dispid( pInstaller
, "FeatureParent" ) == 23, "dispid wrong\n");
378 ok( get_dispid( pInstaller
, "FeatureState" ) == 24, "dispid wrong\n");
379 ok( get_dispid( pInstaller
, "UseFeature" ) == 25, "dispid wrong\n");
380 ok( get_dispid( pInstaller
, "FeatureUsageCount" ) == 26, "dispid wrong\n");
381 ok( get_dispid( pInstaller
, "FeatureUsageDate" ) == 27, "dispid wrong\n");
382 ok( get_dispid( pInstaller
, "ConfigureFeature" ) == 28, "dispid wrong\n");
383 ok( get_dispid( pInstaller
, "ReinstallFeature" ) == 29, "dispid wrong\n");
384 ok( get_dispid( pInstaller
, "ProvideComponent" ) == 30, "dispid wrong\n");
385 ok( get_dispid( pInstaller
, "ComponentPath" ) == 31, "dispid wrong\n");
386 ok( get_dispid( pInstaller
, "ProvideQualifiedComponent" ) == 32, "dispid wrong\n");
387 ok( get_dispid( pInstaller
, "QualifierDescription" ) == 33, "dispid wrong\n");
388 ok( get_dispid( pInstaller
, "ComponentQualifiers" ) == 34, "dispid wrong\n");
389 ok( get_dispid( pInstaller
, "Products" ) == 35, "dispid wrong\n");
390 ok( get_dispid( pInstaller
, "Features" ) == 36, "dispid wrong\n");
391 ok( get_dispid( pInstaller
, "Components" ) == 37, "dispid wrong\n");
392 ok( get_dispid( pInstaller
, "ComponentClients" ) == 38, "dispid wrong\n");
393 ok( get_dispid( pInstaller
, "Patches" ) == 39, "dispid wrong\n");
394 ok( get_dispid( pInstaller
, "RelatedProducts" ) == 40, "dispid wrong\n");
395 ok( get_dispid( pInstaller
, "PatchInfo" ) == 41, "dispid wrong\n");
396 ok( get_dispid( pInstaller
, "PatchTransforms" ) == 42, "dispid wrong\n");
397 ok( get_dispid( pInstaller
, "AddSource" ) == 43, "dispid wrong\n");
398 ok( get_dispid( pInstaller
, "ClearSourceList" ) == 44, "dispid wrong\n");
399 ok( get_dispid( pInstaller
, "ForceSourceListResolution" ) == 45, "dispid wrong\n");
400 ok( get_dispid( pInstaller
, "ShortcutTarget" ) == 46, "dispid wrong\n");
401 ok( get_dispid( pInstaller
, "FileHash" ) == 47, "dispid wrong\n");
402 ok( get_dispid( pInstaller
, "FileSignatureInfo" ) == 48, "dispid wrong\n");
403 ok( get_dispid( pInstaller
, "RemovePatches" ) == 49, "dispid wrong\n");
405 ok( get_dispid( pInstaller
, "ApplyMultiplePatches" ) == 51, "dispid wrong\n");
406 ok( get_dispid( pInstaller
, "ProductsEx" ) == 52, "dispid wrong\n");
408 ok( get_dispid( pInstaller
, "PatchesEx" ) == 55, "dispid wrong\n");
410 ok( get_dispid( pInstaller
, "ExtractPatchXMLData" ) == 57, "dispid wrong\n");
413 /* MSDN claims the following functions exist but IDispatch->GetIDsOfNames disagrees */
416 get_dispid( pInstaller
, "ProductElevated" );
417 get_dispid( pInstaller
, "ProductInfoFromScript" );
418 get_dispid( pInstaller
, "ProvideAssembly" );
419 get_dispid( pInstaller
, "CreateAdvertiseScript" );
420 get_dispid( pInstaller
, "AdvertiseProduct" );
421 get_dispid( pInstaller
, "PatchFiles" );
425 /* FIXME: This should be integrated better into the rest of the tests */
426 static void test_createrecord_and_version(void)
428 IDispatch
*record
= NULL
;
442 param
.cNamedArgs
= 0;
443 param
.rgvarg
= &varg
;
444 param
.rgdispidNamedArgs
= &arg
;
446 dispid
= get_dispid( pInstaller
, "CreateRecord" );
448 r
= IDispatch_Invoke( pInstaller
, dispid
, &IID_NULL
, 0,
449 DISPATCH_METHOD
, ¶m
, &result
, NULL
, NULL
);
450 todo_wine
ok( r
== S_OK
, "dispatch failed %08x\n", r
);
453 ok( V_VT(&result
) == VT_DISPATCH
, "type wrong\n");
455 record
= V_DISPATCH(&result
);
457 memset( &result
, 0, sizeof result
);
458 dispid
= get_dispid( record
, "FieldCount" );
461 param
.cNamedArgs
= 0;
462 param
.rgvarg
= &varg
;
463 param
.rgdispidNamedArgs
= &arg
;
465 r
= IDispatch_Invoke( record
, dispid
, &IID_NULL
, 0,
466 DISPATCH_PROPERTYGET
, ¶m
, &result
, NULL
, NULL
);
467 ok( r
== S_OK
, "dispatch failed %08x\n", r
);
469 ok( V_VT(&result
) == VT_I4
, "type wrong\n");
470 ok( V_I4(&result
) == 1, "field count wrong\n");
472 IDispatch_Release( record
);
475 skip( "failed to create record\n");
477 memset( &result
, 0, sizeof result
);
478 dispid
= get_dispid( pInstaller
, "Version" );
481 param
.cNamedArgs
= 0;
482 param
.rgvarg
= &varg
;
483 param
.rgdispidNamedArgs
= &arg
;
485 r
= IDispatch_Invoke( pInstaller
, dispid
, &IID_NULL
, 0,
486 DISPATCH_PROPERTYGET
, ¶m
, &result
, NULL
, NULL
);
488 ok( r
== S_OK
, "dispatch failed %08x\n", r
);
489 ok( V_VT(&result
) == VT_BSTR
, "type wrong %d\n", V_VT(&result
));
493 /* Test basic IDispatch functions */
494 static void test_dispatch(void)
496 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};
501 VARIANTARG vararg
[2];
502 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
504 /* Test getting ID of a function name that does not exist */
505 name
= (WCHAR
*)szMsifile
;
506 hr
= IDispatch_GetIDsOfNames(pInstaller
, &IID_NULL
, &name
, 1, LOCALE_USER_DEFAULT
, &dispid
);
507 ok(hr
== DISP_E_UNKNOWNNAME
, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr
);
509 /* Test invoking this function */
510 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, NULL
, NULL
, NULL
, NULL
);
511 ok(hr
== DISP_E_MEMBERNOTFOUND
, "IDispatch::Invoke returned 0x%08x\n", hr
);
513 /* Test getting ID of a function name that does exist */
514 name
= (WCHAR
*)szOpenPackage
;
515 hr
= IDispatch_GetIDsOfNames(pInstaller
, &IID_NULL
, &name
, 1, LOCALE_USER_DEFAULT
, &dispid
);
516 ok(SUCCEEDED(hr
), "IDispatch::GetIDsOfNames returned 0x%08x\n", hr
);
518 /* Test invoking this function (without parameters passed) */
519 if (0) /* All of these crash MSI on Windows XP */
521 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, NULL
, NULL
, NULL
, NULL
);
522 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, NULL
, NULL
, &excepinfo
, NULL
);
523 VariantInit(&varresult
);
524 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, NULL
, &varresult
, &excepinfo
, NULL
);
527 /* Try with NULL params */
528 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, &dispparams
, &varresult
, &excepinfo
, NULL
);
529 todo_wine
ok(hr
== DISP_E_TYPEMISMATCH
, "IDispatch::Invoke returned 0x%08x\n", hr
);
531 /* Try one empty parameter */
532 dispparams
.rgvarg
= vararg
;
533 dispparams
.cArgs
= 1;
534 VariantInit(&vararg
[0]);
535 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, &dispparams
, &varresult
, &excepinfo
, NULL
);
536 todo_wine
ok(hr
== DISP_E_TYPEMISMATCH
, "IDispatch::Invoke returned 0x%08x\n", hr
);
538 /* Try one parameter, function requires two */
539 VariantInit(&vararg
[0]);
540 V_VT(&vararg
[0]) = VT_BSTR
;
541 V_BSTR(&vararg
[0]) = SysAllocString(szMsifile
);
542 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, &dispparams
, &varresult
, &excepinfo
, NULL
);
543 VariantClear(&vararg
[0]);
545 ok(hr
== DISP_E_EXCEPTION
, "IDispatch::Invoke returned 0x%08x\n", hr
);
546 ok_exception(hr
, szOpenPackageException
);
549 /* invocation helper function */
550 static HRESULT
invoke(IDispatch
*pDispatch
, LPCWSTR szName
, WORD wFlags
, DISPPARAMS
*pDispParams
, VARIANT
*pVarResult
, VARTYPE vtResult
)
552 OLECHAR
*name
= (WCHAR
*)szName
;
557 hr
= IDispatch_GetIDsOfNames(pDispatch
, &IID_NULL
, &name
, 1, LOCALE_USER_DEFAULT
, &dispid
);
558 ok(SUCCEEDED(hr
), "IDispatch::GetIDsOfNames returned 0x%08x\n", hr
);
559 if (!SUCCEEDED(hr
)) return hr
;
561 VariantInit(pVarResult
);
562 memset(&excepinfo
, 0, sizeof(excepinfo
));
563 hr
= IDispatch_Invoke(pDispatch
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, wFlags
, pDispParams
, pVarResult
, &excepinfo
, NULL
);
567 ok(V_VT(pVarResult
) == vtResult
, "Variant result type is %d, expected %d\n", V_VT(pVarResult
), vtResult
);
568 if (vtResult
!= VT_EMPTY
)
570 hr
= VariantChangeTypeEx(pVarResult
, pVarResult
, LOCALE_NEUTRAL
, 0, vtResult
);
571 ok(SUCCEEDED(hr
), "VariantChangeTypeEx returned 0x%08x\n", hr
);
575 for (i
=0; i
<pDispParams
->cArgs
; i
++)
576 VariantClear(&pDispParams
->rgvarg
[i
]);
581 /* Object_Property helper functions */
583 static HRESULT
Installer_OpenPackage(LPCWSTR szPackagePath
, int options
, IDispatch
**pSession
)
586 VARIANTARG vararg
[2];
587 DISPPARAMS dispparams
= {vararg
, NULL
, sizeof(vararg
)/sizeof(VARIANTARG
), 0};
590 VariantInit(&vararg
[1]);
591 V_VT(&vararg
[1]) = VT_BSTR
;
592 V_BSTR(&vararg
[1]) = SysAllocString(szPackagePath
);
593 VariantInit(&vararg
[0]);
594 V_VT(&vararg
[0]) = VT_I4
;
595 V_I4(&vararg
[0]) = options
;
597 hr
= invoke(pInstaller
, szOpenPackage
, DISPATCH_METHOD
, &dispparams
, &varresult
, VT_DISPATCH
);
598 *pSession
= V_DISPATCH(&varresult
);
602 static HRESULT
Session_PropertyGet(IDispatch
*pSession
, LPCWSTR szName
, LPCWSTR szReturn
)
605 VARIANTARG vararg
[1];
606 DISPPARAMS dispparams
= {vararg
, NULL
, sizeof(vararg
)/sizeof(VARIANTARG
), 0};
609 VariantInit(&vararg
[0]);
610 V_VT(&vararg
[0]) = VT_BSTR
;
611 V_BSTR(&vararg
[0]) = SysAllocString(szName
);
613 hr
= invoke(pSession
, szProperty
, DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_BSTR
);
614 lstrcpyW((WCHAR
*)szReturn
, V_BSTR(&varresult
));
615 VariantClear(&varresult
);
619 static HRESULT
Session_PropertyPut(IDispatch
*pSession
, LPCWSTR szName
, LPCWSTR szValue
)
622 VARIANTARG vararg
[2];
623 DISPID dispid
= DISPID_PROPERTYPUT
;
624 DISPPARAMS dispparams
= {vararg
, &dispid
, sizeof(vararg
)/sizeof(VARIANTARG
), 1};
626 VariantInit(&vararg
[1]);
627 V_VT(&vararg
[1]) = VT_BSTR
;
628 V_BSTR(&vararg
[1]) = SysAllocString(szName
);
629 VariantInit(&vararg
[0]);
630 V_VT(&vararg
[0]) = VT_BSTR
;
631 V_BSTR(&vararg
[0]) = SysAllocString(szValue
);
633 return invoke(pSession
, szProperty
, DISPATCH_PROPERTYPUT
, &dispparams
, &varresult
, VT_EMPTY
);
636 static HRESULT
Session_LanguageGet(IDispatch
*pSession
, UINT
*pLangId
)
639 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
642 hr
= invoke(pSession
, szLanguage
, DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_I4
);
643 *pLangId
= V_I4(&varresult
);
644 VariantClear(&varresult
);
648 static HRESULT
Session_ModeGet(IDispatch
*pSession
, int iFlag
, BOOL
*pMode
)
651 VARIANTARG vararg
[1];
652 DISPPARAMS dispparams
= {vararg
, NULL
, sizeof(vararg
)/sizeof(VARIANTARG
), 0};
655 VariantInit(&vararg
[0]);
656 V_VT(&vararg
[0]) = VT_I4
;
657 V_I4(&vararg
[0]) = iFlag
;
659 hr
= invoke(pSession
, szMode
, DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_BOOL
);
660 *pMode
= V_BOOL(&varresult
);
661 VariantClear(&varresult
);
665 static HRESULT
Session_ModePut(IDispatch
*pSession
, int iFlag
, BOOL bMode
)
668 VARIANTARG vararg
[2];
669 DISPID dispid
= DISPID_PROPERTYPUT
;
670 DISPPARAMS dispparams
= {vararg
, &dispid
, sizeof(vararg
)/sizeof(VARIANTARG
), 1};
672 VariantInit(&vararg
[1]);
673 V_VT(&vararg
[1]) = VT_I4
;
674 V_I4(&vararg
[1]) = iFlag
;
675 VariantInit(&vararg
[0]);
676 V_VT(&vararg
[0]) = VT_BOOL
;
677 V_BOOL(&vararg
[0]) = bMode
;
679 return invoke(pSession
, szMode
, DISPATCH_PROPERTYPUT
, &dispparams
, &varresult
, VT_EMPTY
);
682 static HRESULT
Session_Database(IDispatch
*pSession
, IDispatch
**pDatabase
)
685 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
688 hr
= invoke(pSession
, szDatabase
, DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_DISPATCH
);
689 *pDatabase
= V_DISPATCH(&varresult
);
693 static HRESULT
Session_DoAction(IDispatch
*pSession
, LPCWSTR szAction
, int *iReturn
)
696 VARIANTARG vararg
[1];
697 DISPPARAMS dispparams
= {vararg
, NULL
, sizeof(vararg
)/sizeof(VARIANTARG
), 0};
700 VariantInit(&vararg
[0]);
701 V_VT(&vararg
[0]) = VT_BSTR
;
702 V_BSTR(&vararg
[0]) = SysAllocString(szAction
);
704 hr
= invoke(pSession
, szDoAction
, DISPATCH_METHOD
, &dispparams
, &varresult
, VT_I4
);
705 *iReturn
= V_I4(&varresult
);
706 VariantClear(&varresult
);
710 static HRESULT
Session_SetInstallLevel(IDispatch
*pSession
, long iInstallLevel
)
713 VARIANTARG vararg
[1];
714 DISPPARAMS dispparams
= {vararg
, NULL
, sizeof(vararg
)/sizeof(VARIANTARG
), 0};
716 VariantInit(&vararg
[0]);
717 V_VT(&vararg
[0]) = VT_I4
;
718 V_I4(&vararg
[0]) = iInstallLevel
;
720 return invoke(pSession
, szSetInstallLevel
, DISPATCH_METHOD
, &dispparams
, &varresult
, VT_EMPTY
);
723 static HRESULT
Session_FeatureCurrentState(IDispatch
*pSession
, LPCWSTR szName
, int *pState
)
726 VARIANTARG vararg
[1];
727 DISPPARAMS dispparams
= {vararg
, NULL
, sizeof(vararg
)/sizeof(VARIANTARG
), 0};
730 VariantInit(&vararg
[0]);
731 V_VT(&vararg
[0]) = VT_BSTR
;
732 V_BSTR(&vararg
[0]) = SysAllocString(szName
);
734 hr
= invoke(pSession
, szFeatureCurrentState
, DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_I4
);
735 *pState
= V_I4(&varresult
);
736 VariantClear(&varresult
);
740 static HRESULT
Session_FeatureRequestStateGet(IDispatch
*pSession
, LPCWSTR szName
, int *pState
)
743 VARIANTARG vararg
[1];
744 DISPPARAMS dispparams
= {vararg
, NULL
, sizeof(vararg
)/sizeof(VARIANTARG
), 0};
747 VariantInit(&vararg
[0]);
748 V_VT(&vararg
[0]) = VT_BSTR
;
749 V_BSTR(&vararg
[0]) = SysAllocString(szName
);
751 hr
= invoke(pSession
, szFeatureRequestState
, DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_I4
);
752 *pState
= V_I4(&varresult
);
753 VariantClear(&varresult
);
757 static HRESULT
Session_FeatureRequestStatePut(IDispatch
*pSession
, LPCWSTR szName
, int iState
)
760 VARIANTARG vararg
[2];
761 DISPID dispid
= DISPID_PROPERTYPUT
;
762 DISPPARAMS dispparams
= {vararg
, &dispid
, sizeof(vararg
)/sizeof(VARIANTARG
), 1};
764 VariantInit(&vararg
[1]);
765 V_VT(&vararg
[1]) = VT_BSTR
;
766 V_BSTR(&vararg
[1]) = SysAllocString(szName
);
767 VariantInit(&vararg
[0]);
768 V_VT(&vararg
[0]) = VT_I4
;
769 V_I4(&vararg
[0]) = iState
;
771 return invoke(pSession
, szFeatureRequestState
, DISPATCH_PROPERTYPUT
, &dispparams
, &varresult
, VT_EMPTY
);
774 static HRESULT
Database_OpenView(IDispatch
*pDatabase
, LPCWSTR szSql
, IDispatch
**pView
)
777 VARIANTARG vararg
[1];
778 DISPPARAMS dispparams
= {vararg
, NULL
, sizeof(vararg
)/sizeof(VARIANTARG
), 0};
781 VariantInit(&vararg
[0]);
782 V_VT(&vararg
[0]) = VT_BSTR
;
783 V_BSTR(&vararg
[0]) = SysAllocString(szSql
);
785 hr
= invoke(pDatabase
, szOpenView
, DISPATCH_METHOD
, &dispparams
, &varresult
, VT_DISPATCH
);
786 *pView
= V_DISPATCH(&varresult
);
790 static HRESULT
View_Execute(IDispatch
*pView
, IDispatch
*pRecord
)
793 VARIANTARG vararg
[1];
794 DISPPARAMS dispparams
= {vararg
, NULL
, sizeof(vararg
)/sizeof(VARIANTARG
), 0};
796 VariantInit(&vararg
[0]);
797 V_VT(&vararg
[0]) = VT_DISPATCH
;
798 V_DISPATCH(&vararg
[0]) = pRecord
;
800 return invoke(pView
, szExecute
, DISPATCH_METHOD
, &dispparams
, &varresult
, VT_EMPTY
);
803 static HRESULT
View_Fetch(IDispatch
*pView
, IDispatch
**ppRecord
)
806 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
807 HRESULT hr
= invoke(pView
, szFetch
, DISPATCH_METHOD
, &dispparams
, &varresult
, VT_DISPATCH
);
808 *ppRecord
= V_DISPATCH(&varresult
);
812 static HRESULT
View_Close(IDispatch
*pView
)
815 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
816 return invoke(pView
, szClose
, DISPATCH_METHOD
, &dispparams
, &varresult
, VT_EMPTY
);
819 static HRESULT
Record_StringDataGet(IDispatch
*pRecord
, int iField
, LPCWSTR szString
)
822 VARIANTARG vararg
[1];
823 DISPPARAMS dispparams
= {vararg
, NULL
, sizeof(vararg
)/sizeof(VARIANTARG
), 0};
826 VariantInit(&vararg
[0]);
827 V_VT(&vararg
[0]) = VT_I4
;
828 V_I4(&vararg
[0]) = iField
;
830 hr
= invoke(pRecord
, szStringData
, DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_BSTR
);
831 lstrcpyW((WCHAR
*)szString
, V_BSTR(&varresult
));
832 VariantClear(&varresult
);
836 static HRESULT
Record_StringDataPut(IDispatch
*pRecord
, int iField
, LPCWSTR szString
)
839 VARIANTARG vararg
[2];
840 DISPID dispid
= DISPID_PROPERTYPUT
;
841 DISPPARAMS dispparams
= {vararg
, &dispid
, sizeof(vararg
)/sizeof(VARIANTARG
), 1};
843 VariantInit(&vararg
[1]);
844 V_VT(&vararg
[1]) = VT_I4
;
845 V_I4(&vararg
[1]) = iField
;
846 VariantInit(&vararg
[0]);
847 V_VT(&vararg
[0]) = VT_BSTR
;
848 V_BSTR(&vararg
[0]) = SysAllocString(szString
);
850 return invoke(pRecord
, szStringData
, DISPATCH_PROPERTYPUT
, &dispparams
, &varresult
, VT_BSTR
);
853 /* Test the various objects */
855 static void test_Database(IDispatch
*pDatabase
)
857 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 };
858 static WCHAR szThree
[] = { 'T','h','r','e','e',0 };
859 static WCHAR szTwo
[] = { 'T','w','o',0 };
860 static WCHAR szStringDataField
[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
861 IDispatch
*pView
= NULL
;
864 hr
= Database_OpenView(pDatabase
, szSql
, &pView
);
865 ok(SUCCEEDED(hr
), "Database_OpenView failed, hresult 0x%08x\n", hr
);
868 IDispatch
*pRecord
= NULL
;
869 WCHAR szString
[MAX_PATH
];
872 hr
= View_Execute(pView
, NULL
);
873 ok(SUCCEEDED(hr
), "View_Execute failed, hresult 0x%08x\n", hr
);
876 hr
= View_Fetch(pView
, &pRecord
);
877 ok(SUCCEEDED(hr
), "View_Fetch failed, hresult 0x%08x\n", hr
);
878 ok(pRecord
!= NULL
, "View_Fetch should not have returned NULL record\n");
881 /* Record::StringDataGet */
882 memset(szString
, 0, sizeof(szString
));
883 hr
= Record_StringDataGet(pRecord
, 1, szString
);
884 ok(SUCCEEDED(hr
), "Record_StringDataGet failed, hresult 0x%08x\n", hr
);
885 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString
, szThree
);
887 /* Record::StringDataPut with incorrect index */
888 hr
= Record_StringDataPut(pRecord
, -1, szString
);
889 ok(hr
== DISP_E_EXCEPTION
, "Record_StringDataPut failed, hresult 0x%08x\n", hr
);
890 ok_exception(hr
, szStringDataField
);
892 IDispatch_Release(pRecord
);
896 hr
= View_Fetch(pView
, &pRecord
);
897 ok(SUCCEEDED(hr
), "View_Fetch failed, hresult 0x%08x\n", hr
);
898 ok(pRecord
!= NULL
, "View_Fetch should not have returned NULL record\n");
901 /* Record::StringDataGet */
902 memset(szString
, 0, sizeof(szString
));
903 hr
= Record_StringDataGet(pRecord
, 1, szString
);
904 ok(SUCCEEDED(hr
), "Record_StringDataGet failed, hresult 0x%08x\n", hr
);
905 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString
, szTwo
);
907 IDispatch_Release(pRecord
);
911 hr
= View_Fetch(pView
, &pRecord
);
912 ok(SUCCEEDED(hr
), "View_Fetch failed, hresult 0x%08x\n", hr
);
913 ok(pRecord
== NULL
, "View_Fetch should have returned NULL record\n");
915 IDispatch_Release(pRecord
);
918 hr
= View_Close(pView
);
919 ok(SUCCEEDED(hr
), "View_Close failed, hresult 0x%08x\n", hr
);
921 IDispatch_Release(pView
);
925 static void test_Session(IDispatch
*pSession
)
927 static WCHAR szProductName
[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
928 static WCHAR szMSITEST
[] = { 'M','S','I','T','E','S','T',0 };
929 static WCHAR szOne
[] = { 'O','n','e',0 };
930 static WCHAR szCostInitialize
[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
931 static WCHAR szEmpty
[] = { 0 };
932 static WCHAR szEquals
[] = { '=',0 };
933 static WCHAR szPropertyName
[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
934 WCHAR stringw
[MAX_PATH
];
935 CHAR string
[MAX_PATH
];
939 IDispatch
*pDatabase
= NULL
;
942 /* Session::Property, get */
943 memset(stringw
, 0, sizeof(stringw
));
944 hr
= Session_PropertyGet(pSession
, szProductName
, stringw
);
945 ok(SUCCEEDED(hr
), "Session_PropertyGet failed, hresult 0x%08x\n", hr
);
946 if (lstrcmpW(stringw
, szMSITEST
) != 0)
948 len
= WideCharToMultiByte(CP_ACP
, 0, stringw
, -1, string
, MAX_PATH
, NULL
, NULL
);
949 ok(len
, "WideCharToMultiByteChar returned error %d\n", GetLastError());
950 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string
);
953 /* Session::Property, put */
954 hr
= Session_PropertyPut(pSession
, szProductName
, szProductName
);
955 ok(SUCCEEDED(hr
), "Session_PropertyPut failed, hresult 0x%08x\n", hr
);
956 memset(stringw
, 0, sizeof(stringw
));
957 hr
= Session_PropertyGet(pSession
, szProductName
, stringw
);
958 ok(SUCCEEDED(hr
), "Session_PropertyGet failed, hresult 0x%08x\n", hr
);
959 if (lstrcmpW(stringw
, szProductName
) != 0)
961 len
= WideCharToMultiByte(CP_ACP
, 0, stringw
, -1, string
, MAX_PATH
, NULL
, NULL
);
962 ok(len
, "WideCharToMultiByteChar returned error %d\n", GetLastError());
963 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string
);
966 /* Try putting a property using empty property identifier */
967 hr
= Session_PropertyPut(pSession
, szEmpty
, szProductName
);
968 ok(hr
== DISP_E_EXCEPTION
, "Session_PropertyPut failed, hresult 0x%08x\n", hr
);
969 ok_exception(hr
, szPropertyName
);
971 /* Try putting a property using illegal property identifier */
972 hr
= Session_PropertyPut(pSession
, szEquals
, szProductName
);
973 ok(SUCCEEDED(hr
), "Session_PropertyPut failed, hresult 0x%08x\n", hr
);
975 /* Session::Language, get */
976 hr
= Session_LanguageGet(pSession
, &len
);
977 ok(SUCCEEDED(hr
), "Session_LanguageGet failed, hresult 0x%08x\n", hr
);
978 /* Not sure how to check the language is correct */
980 /* Session::Mode, get */
981 hr
= Session_ModeGet(pSession
, MSIRUNMODE_REBOOTATEND
, &bool);
982 ok(SUCCEEDED(hr
), "Session_ModeGet failed, hresult 0x%08x\n", hr
);
983 todo_wine
ok(!bool, "Reboot at end session mode is %d\n", bool);
985 /* Session::Mode, put */
986 hr
= Session_ModePut(pSession
, MSIRUNMODE_REBOOTATEND
, TRUE
);
987 todo_wine
ok(SUCCEEDED(hr
), "Session_ModePut failed, hresult 0x%08x\n", hr
);
988 hr
= Session_ModeGet(pSession
, MSIRUNMODE_REBOOTATEND
, &bool);
989 ok(SUCCEEDED(hr
), "Session_ModeGet failed, hresult 0x%08x\n", hr
);
990 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
991 hr
= Session_ModePut(pSession
, MSIRUNMODE_REBOOTATEND
, FALSE
); /* set it again so we don't reboot */
992 todo_wine
ok(SUCCEEDED(hr
), "Session_ModePut failed, hresult 0x%08x\n", hr
);
994 /* Session::Database, get */
995 hr
= Session_Database(pSession
, &pDatabase
);
996 ok(SUCCEEDED(hr
), "Session_Database failed, hresult 0x%08x\n", hr
);
999 test_Database(pDatabase
);
1000 IDispatch_Release(pDatabase
);
1003 /* Session::DoAction(CostInitialize) must occur before the next statements */
1004 hr
= Session_DoAction(pSession
, szCostInitialize
, &myint
);
1005 ok(SUCCEEDED(hr
), "Session_DoAction failed, hresult 0x%08x\n", hr
);
1006 ok(myint
== IDOK
, "DoAction(CostInitialize) returned %d, %d expected\n", myint
, IDOK
);
1008 /* Session::SetInstallLevel */
1009 hr
= Session_SetInstallLevel(pSession
, INSTALLLEVEL_MINIMUM
);
1010 ok(SUCCEEDED(hr
), "Session_SetInstallLevel failed, hresult 0x%08x\n", hr
);
1012 /* Session::FeatureCurrentState, get */
1013 hr
= Session_FeatureCurrentState(pSession
, szOne
, &myint
);
1014 ok(SUCCEEDED(hr
), "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr
);
1015 ok(myint
== INSTALLSTATE_UNKNOWN
, "Feature current state was %d but expected %d\n", myint
, INSTALLSTATE_UNKNOWN
);
1017 /* Session::FeatureRequestState, put */
1018 hr
= Session_FeatureRequestStatePut(pSession
, szOne
, INSTALLSTATE_ADVERTISED
);
1019 ok(SUCCEEDED(hr
), "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr
);
1020 hr
= Session_FeatureRequestStateGet(pSession
, szOne
, &myint
);
1021 ok(SUCCEEDED(hr
), "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr
);
1022 ok(myint
== INSTALLSTATE_ADVERTISED
, "Feature request state was %d but expected %d\n", myint
, INSTALLSTATE_ADVERTISED
);
1025 static void test_Installer(void)
1027 static WCHAR szBackslash
[] = { '\\',0 };
1028 WCHAR szPath
[MAX_PATH
];
1031 IDispatch
*pSession
= NULL
;
1033 if (!pInstaller
) return;
1035 create_database(msifile
, tables
, sizeof(tables
) / sizeof(msi_table
));
1037 len
= MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, CURR_DIR
, -1, szPath
, MAX_PATH
);
1038 ok(len
, "MultiByteToWideChar returned error %d\n", GetLastError());
1041 lstrcatW(szPath
, szBackslash
);
1042 lstrcatW(szPath
, szMsifile
);
1044 /* Installer::OpenPackage */
1045 hr
= Installer_OpenPackage(szPath
, 0, &pSession
);
1046 ok(SUCCEEDED(hr
), "Installer_OpenPackage failed, hresult 0x%08x\n", hr
);
1049 test_Session(pSession
);
1050 IDispatch_Release(pSession
);
1053 DeleteFileA(msifile
);
1056 START_TEST(automation
)
1059 char temp_path
[MAX_PATH
], prev_path
[MAX_PATH
];
1064 GetCurrentDirectoryA(MAX_PATH
, prev_path
);
1065 GetTempPath(MAX_PATH
, temp_path
);
1066 SetCurrentDirectoryA(temp_path
);
1068 lstrcpyA(CURR_DIR
, temp_path
);
1069 len
= lstrlenA(CURR_DIR
);
1071 if(len
&& (CURR_DIR
[len
- 1] == '\\'))
1072 CURR_DIR
[len
- 1] = 0;
1074 hr
= OleInitialize(NULL
);
1075 ok (SUCCEEDED(hr
), "OleInitialize returned 0x%08x\n", hr
);
1076 hr
= CLSIDFromProgID(szProgId
, &clsid
);
1077 ok (SUCCEEDED(hr
), "CLSIDFromProgID returned 0x%08x\n", hr
);
1078 hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IUnknown
, (void **)&pUnk
);
1079 ok(SUCCEEDED(hr
), "CoCreateInstance returned 0x%08x\n", hr
);
1083 hr
= IUnknown_QueryInterface(pUnk
, &IID_IDispatch
, (void **)&pInstaller
);
1084 ok (SUCCEEDED(hr
), "IUnknown::QueryInterface returned 0x%08x\n", hr
);
1087 test_createrecord_and_version();
1091 hr
= IUnknown_Release(pUnk
);
1092 ok (SUCCEEDED(hr
), "IUnknown::Release returned 0x%08x\n", hr
);
1097 SetCurrentDirectoryA(prev_path
);