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 };
43 static IDispatch
*pInstaller
;
45 /* msi database data */
47 static const CHAR component_dat
[] = "Component\tComponentId\tDirectory_\tAttributes\tCondition\tKeyPath\n"
48 "s72\tS38\ts72\ti2\tS255\tS72\n"
49 "Component\tComponent\n"
50 "Five\t{8CC92E9D-14B2-4CA4-B2AA-B11D02078087}\tNEWDIR\t2\t\tfive.txt\n"
51 "Four\t{FD37B4EA-7209-45C0-8917-535F35A2F080}\tCABOUTDIR\t2\t\tfour.txt\n"
52 "One\t{783B242E-E185-4A56-AF86-C09815EC053C}\tMSITESTDIR\t2\t\tone.txt\n"
53 "Three\t{010B6ADD-B27D-4EDD-9B3D-34C4F7D61684}\tCHANGEDDIR\t2\t\tthree.txt\n"
54 "Two\t{BF03D1A6-20DA-4A65-82F3-6CAC995915CE}\tFIRSTDIR\t2\t\ttwo.txt\n"
55 "dangler\t{6091DF25-EF96-45F1-B8E9-A9B1420C7A3C}\tTARGETDIR\t4\t\tregdata\n"
56 "component\t\tMSITESTDIR\t0\t1\tfile\n"
57 "service_comp\t\tMSITESTDIR\t0\t1\tservice_file";
59 static const CHAR directory_dat
[] = "Directory\tDirectory_Parent\tDefaultDir\n"
61 "Directory\tDirectory\n"
62 "CABOUTDIR\tMSITESTDIR\tcabout\n"
63 "CHANGEDDIR\tMSITESTDIR\tchanged:second\n"
64 "FIRSTDIR\tMSITESTDIR\tfirst\n"
65 "MSITESTDIR\tProgramFilesFolder\tmsitest\n"
66 "NEWDIR\tCABOUTDIR\tnew\n"
67 "ProgramFilesFolder\tTARGETDIR\t.\n"
68 "TARGETDIR\t\tSourceDir";
70 static const CHAR feature_dat
[] = "Feature\tFeature_Parent\tTitle\tDescription\tDisplay\tLevel\tDirectory_\tAttributes\n"
71 "s38\tS38\tL64\tL255\tI2\ti2\tS72\ti2\n"
73 "Five\t\tFive\tThe Five Feature\t5\t3\tNEWDIR\t0\n"
74 "Four\t\tFour\tThe Four Feature\t4\t3\tCABOUTDIR\t0\n"
75 "One\t\tOne\tThe One Feature\t1\t3\tMSITESTDIR\t0\n"
76 "Three\tOne\tThree\tThe Three Feature\t3\t3\tCHANGEDDIR\t0\n"
77 "Two\tOne\tTwo\tThe Two Feature\t2\t3\tFIRSTDIR\t0\n"
78 "feature\t\t\t\t2\t1\tTARGETDIR\t0\n"
79 "service_feature\t\t\t\t2\t1\tTARGETDIR\t0";
81 static const CHAR feature_comp_dat
[] = "Feature_\tComponent_\n"
83 "FeatureComponents\tFeature_\tComponent_\n"
89 "feature\tcomponent\n"
90 "service_feature\tservice_comp\n";
92 static const CHAR file_dat
[] = "File\tComponent_\tFileName\tFileSize\tVersion\tLanguage\tAttributes\tSequence\n"
93 "s72\ts72\tl255\ti4\tS72\tS20\tI2\ti2\n"
95 "five.txt\tFive\tfive.txt\t1000\t\t\t16384\t5\n"
96 "four.txt\tFour\tfour.txt\t1000\t\t\t16384\t4\n"
97 "one.txt\tOne\tone.txt\t1000\t\t\t0\t1\n"
98 "three.txt\tThree\tthree.txt\t1000\t\t\t0\t3\n"
99 "two.txt\tTwo\ttwo.txt\t1000\t\t\t0\t2\n"
100 "file\tcomponent\tfilename\t100\t\t\t8192\t1\n"
101 "service_file\tservice_comp\tservice.exe\t100\t\t\t8192\t1";
103 static const CHAR install_exec_seq_dat
[] = "Action\tCondition\tSequence\n"
105 "InstallExecuteSequence\tAction\n"
106 "AllocateRegistrySpace\tNOT Installed\t1550\n"
107 "CostFinalize\t\t1000\n"
108 "CostInitialize\t\t800\n"
110 "InstallFiles\t\t4000\n"
111 "InstallServices\t\t5000\n"
112 "InstallFinalize\t\t6600\n"
113 "InstallInitialize\t\t1500\n"
114 "InstallValidate\t\t1400\n"
115 "LaunchConditions\t\t100\n"
116 "WriteRegistryValues\tSourceDir And SOURCEDIR\t5000";
118 static const CHAR media_dat
[] = "DiskId\tLastSequence\tDiskPrompt\tCabinet\tVolumeLabel\tSource\n"
119 "i2\ti4\tL64\tS255\tS32\tS72\n"
121 "1\t3\t\t\tDISK1\t\n"
122 "2\t5\t\tmsitest.cab\tDISK2\t\n";
124 static const CHAR property_dat
[] = "Property\tValue\n"
126 "Property\tProperty\n"
127 "DefaultUIFont\tDlgFont8\n"
130 "InstallMode\tTypical\n"
131 "Manufacturer\tWine\n"
132 "PIDTemplate\t12345<###-%%%%%%%>@@@@@\n"
133 "ProductCode\t{F1C3AF50-8B56-4A69-A00C-00773FE42F30}\n"
135 "ProductLanguage\t1033\n"
136 "ProductName\tMSITEST\n"
137 "ProductVersion\t1.1.1\n"
138 "PROMPTROLLBACKCOST\tP\n"
140 "UpgradeCode\t{CE067E8D-2E1A-4367-B734-4EB2BDAD6565}";
142 static const CHAR registry_dat
[] = "Registry\tRoot\tKey\tName\tValue\tComponent_\n"
143 "s72\ti2\tl255\tL255\tL0\ts72\n"
144 "Registry\tRegistry\n"
145 "Apples\t2\tSOFTWARE\\Wine\\msitest\tName\timaname\tOne\n"
146 "Oranges\t2\tSOFTWARE\\Wine\\msitest\tnumber\t#314\tTwo\n"
147 "regdata\t2\tSOFTWARE\\Wine\\msitest\tblah\tbad\tdangler\n"
148 "OrderTest\t2\tSOFTWARE\\Wine\\msitest\tOrderTestName\tOrderTestValue\tcomponent";
150 static const CHAR service_install_dat
[] = "ServiceInstall\tName\tDisplayName\tServiceType\tStartType\tErrorControl\t"
151 "LoadOrderGroup\tDependencies\tStartName\tPassword\tArguments\tComponent_\tDescription\n"
152 "s72\ts255\tL255\ti4\ti4\ti4\tS255\tS255\tS255\tS255\tS255\ts72\tL255\n"
153 "ServiceInstall\tServiceInstall\n"
154 "TestService\tTestService\tTestService\t2\t3\t0\t\t\tTestService\t\t\tservice_comp\t\t";
156 static const CHAR service_control_dat
[] = "ServiceControl\tName\tEvent\tArguments\tWait\tComponent_\n"
157 "s72\tl255\ti2\tL255\tI2\ts72\n"
158 "ServiceControl\tServiceControl\n"
159 "ServiceControl\tTestService\t8\t\t0\tservice_comp";
161 typedef struct _msi_table
163 const CHAR
*filename
;
168 #define ADD_TABLE(x) {#x".idt", x##_dat, sizeof(x##_dat)}
170 static const msi_table tables
[] =
172 ADD_TABLE(component
),
173 ADD_TABLE(directory
),
175 ADD_TABLE(feature_comp
),
177 ADD_TABLE(install_exec_seq
),
181 ADD_TABLE(service_install
),
182 ADD_TABLE(service_control
)
189 static void write_file(const CHAR
*filename
, const char *data
, int data_size
)
193 HANDLE hf
= CreateFile(filename
, GENERIC_WRITE
, 0, NULL
,
194 CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
196 WriteFile(hf
, data
, data_size
, &size
, NULL
);
200 static void write_msi_summary_info(MSIHANDLE db
)
205 r
= MsiGetSummaryInformationA(db
, NULL
, 4, &summary
);
206 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
208 r
= MsiSummaryInfoSetPropertyA(summary
, PID_TEMPLATE
, VT_LPSTR
, 0, NULL
, ";1033");
209 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
211 r
= MsiSummaryInfoSetPropertyA(summary
, PID_REVNUMBER
, VT_LPSTR
, 0, NULL
,
212 "{004757CA-5092-49c2-AD20-28E1CE0DF5F2}");
213 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
215 r
= MsiSummaryInfoSetPropertyA(summary
, PID_PAGECOUNT
, VT_I4
, 100, NULL
, NULL
);
216 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
218 r
= MsiSummaryInfoSetPropertyA(summary
, PID_WORDCOUNT
, VT_I4
, 0, NULL
, NULL
);
219 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
221 /* write the summary changes back to the stream */
222 r
= MsiSummaryInfoPersist(summary
);
223 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
225 MsiCloseHandle(summary
);
228 static void create_database(const CHAR
*name
, const msi_table
*tables
, int num_tables
)
234 r
= MsiOpenDatabaseA(name
, MSIDBOPEN_CREATE
, &db
);
235 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
237 /* import the tables into the database */
238 for (j
= 0; j
< num_tables
; j
++)
240 const msi_table
*table
= &tables
[j
];
242 write_file(table
->filename
, table
->data
, (table
->size
- 1) * sizeof(char));
244 r
= MsiDatabaseImportA(db
, CURR_DIR
, table
->filename
);
245 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
247 DeleteFileA(table
->filename
);
250 write_msi_summary_info(db
);
252 r
= MsiDatabaseCommit(db
);
253 ok(r
== ERROR_SUCCESS
, "Expected ERROR_SUCCESS, got %u\n", r
);
259 * Automation helpers and tests
262 /* ok-like statement which takes two unicode strings as arguments */
263 static CHAR string1
[MAX_PATH
], string2
[MAX_PATH
];
266 #define ok_w2(format, szString1, szString2) \
268 if (lstrcmpW(szString1, szString2) != 0) \
270 len = WideCharToMultiByte(CP_ACP, 0, szString1, -1, string1, MAX_PATH, NULL, NULL); \
271 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError()); \
273 len = WideCharToMultiByte(CP_ACP, 0, szString2, -1, string2, MAX_PATH, NULL, NULL); \
274 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError()); \
276 ok(0, format, string1, string2); \
279 /* exception checker */
280 static WCHAR szSource
[] = {'M','s','i',' ','A','P','I',' ','E','r','r','o','r',0};
282 #define ok_exception(hr, szDescription) \
283 if (hr == DISP_E_EXCEPTION) \
285 /* Compare wtype, source, and destination */ \
286 ok(excepinfo.wCode == 1000, "Exception info was %d, expected 1000\n", excepinfo.wCode); \
288 ok(excepinfo.bstrSource != NULL, "Exception source was NULL\n"); \
289 if (excepinfo.bstrSource) \
290 ok_w2("Exception source was \"%s\" but expected to be \"%s\"\n", excepinfo.bstrSource, szSource); \
292 ok(excepinfo.bstrDescription != NULL, "Exception description was NULL\n"); \
293 if (excepinfo.bstrDescription && lstrcmpW(excepinfo.bstrDescription, szDescription) != 0) \
295 len = WideCharToMultiByte(CP_ACP, 0, excepinfo.bstrDescription, -1, string1, MAX_PATH, NULL, NULL); \
296 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError()); \
298 len = WideCharToMultiByte(CP_ACP, 0, szDescription, -1, string2, MAX_PATH, NULL, NULL); \
299 ok(len, "WideCharToMultiByteChar returned error %d\n", GetLastError()); \
301 ok(0, "Exception description was \"%s\" but expected to be \"%s\"\n", string1, string2); \
305 static DISPID
get_dispid( IDispatch
*disp
, const char *name
)
312 len
= MultiByteToWideChar(CP_ACP
, 0, name
, -1, NULL
, 0 );
313 str
= HeapAlloc(GetProcessHeap(), 0, len
*sizeof(WCHAR
) );
316 len
= MultiByteToWideChar(CP_ACP
, 0, name
, -1, str
, len
);
317 r
= IDispatch_GetIDsOfNames( disp
, &IID_NULL
, &str
, 1, 0, &id
);
318 HeapFree(GetProcessHeap(), 0, str
);
326 static void test_dispid(void)
329 ok( get_dispid( pInstaller
, "CreateRecord" ) == 1, "dispid wrong\n");
331 ok( get_dispid( pInstaller
, "OpenPackage" ) == 2, "dispid wrong\n");
333 ok( get_dispid( pInstaller
, "OpenProduct" ) == 3, "dispid wrong\n");
334 ok( get_dispid( pInstaller
, "OpenDatabase" ) == 4, "dispid wrong\n");
335 ok( get_dispid( pInstaller
, "SummaryInformation" ) == 5, "dispid wrong\n");
336 ok( get_dispid( pInstaller
, "UILevel" ) == 6, "dispid wrong\n");
337 ok( get_dispid( pInstaller
, "EnableLog" ) == 7, "dispid wrong\n");
338 ok( get_dispid( pInstaller
, "InstallProduct" ) == 8, "dispid wrong\n");
339 ok( get_dispid( pInstaller
, "Version" ) == 9, "dispid wrong\n");
340 ok( get_dispid( pInstaller
, "LastErrorRecord" ) == 10, "dispid wrong\n");
341 ok( get_dispid( pInstaller
, "RegistryValue" ) == 11, "dispid wrong\n");
342 ok( get_dispid( pInstaller
, "Environment" ) == 12, "dispid wrong\n");
343 ok( get_dispid( pInstaller
, "FileAttributes" ) == 13, "dispid wrong\n");
345 ok( get_dispid( pInstaller
, "FileSize" ) == 15, "dispid wrong\n");
346 ok( get_dispid( pInstaller
, "FileVersion" ) == 16, "dispid wrong\n");
348 ok( get_dispid( pInstaller
, "ProductState" ) == 17, "dispid wrong\n");
350 ok( get_dispid( pInstaller
, "ProductInfo" ) == 18, "dispid wrong\n");
351 ok( get_dispid( pInstaller
, "ConfigureProduct" ) == 19, "dispid wrong\n");
352 ok( get_dispid( pInstaller
, "ReinstallProduct" ) == 20 , "dispid wrong\n");
353 ok( get_dispid( pInstaller
, "CollectUserInfo" ) == 21, "dispid wrong\n");
354 ok( get_dispid( pInstaller
, "ApplyPatch" ) == 22, "dispid wrong\n");
355 ok( get_dispid( pInstaller
, "FeatureParent" ) == 23, "dispid wrong\n");
356 ok( get_dispid( pInstaller
, "FeatureState" ) == 24, "dispid wrong\n");
357 ok( get_dispid( pInstaller
, "UseFeature" ) == 25, "dispid wrong\n");
358 ok( get_dispid( pInstaller
, "FeatureUsageCount" ) == 26, "dispid wrong\n");
359 ok( get_dispid( pInstaller
, "FeatureUsageDate" ) == 27, "dispid wrong\n");
360 ok( get_dispid( pInstaller
, "ConfigureFeature" ) == 28, "dispid wrong\n");
361 ok( get_dispid( pInstaller
, "ReinstallFeature" ) == 29, "dispid wrong\n");
362 ok( get_dispid( pInstaller
, "ProvideComponent" ) == 30, "dispid wrong\n");
363 ok( get_dispid( pInstaller
, "ComponentPath" ) == 31, "dispid wrong\n");
364 ok( get_dispid( pInstaller
, "ProvideQualifiedComponent" ) == 32, "dispid wrong\n");
365 ok( get_dispid( pInstaller
, "QualifierDescription" ) == 33, "dispid wrong\n");
366 ok( get_dispid( pInstaller
, "ComponentQualifiers" ) == 34, "dispid wrong\n");
368 ok( get_dispid( pInstaller
, "Products" ) == 35, "dispid wrong\n");
370 ok( get_dispid( pInstaller
, "Features" ) == 36, "dispid wrong\n");
371 ok( get_dispid( pInstaller
, "Components" ) == 37, "dispid wrong\n");
372 ok( get_dispid( pInstaller
, "ComponentClients" ) == 38, "dispid wrong\n");
373 ok( get_dispid( pInstaller
, "Patches" ) == 39, "dispid wrong\n");
374 ok( get_dispid( pInstaller
, "RelatedProducts" ) == 40, "dispid wrong\n");
375 ok( get_dispid( pInstaller
, "PatchInfo" ) == 41, "dispid wrong\n");
376 ok( get_dispid( pInstaller
, "PatchTransforms" ) == 42, "dispid wrong\n");
377 ok( get_dispid( pInstaller
, "AddSource" ) == 43, "dispid wrong\n");
378 ok( get_dispid( pInstaller
, "ClearSourceList" ) == 44, "dispid wrong\n");
379 ok( get_dispid( pInstaller
, "ForceSourceListResolution" ) == 45, "dispid wrong\n");
380 ok( get_dispid( pInstaller
, "ShortcutTarget" ) == 46, "dispid wrong\n");
381 ok( get_dispid( pInstaller
, "FileHash" ) == 47, "dispid wrong\n");
382 ok( get_dispid( pInstaller
, "FileSignatureInfo" ) == 48, "dispid wrong\n");
383 ok( get_dispid( pInstaller
, "RemovePatches" ) == 49, "dispid wrong\n");
385 ok( get_dispid( pInstaller
, "ApplyMultiplePatches" ) == 51, "dispid wrong\n");
386 ok( get_dispid( pInstaller
, "ProductsEx" ) == 52, "dispid wrong\n");
388 ok( get_dispid( pInstaller
, "PatchesEx" ) == 55, "dispid wrong\n");
390 ok( get_dispid( pInstaller
, "ExtractPatchXMLData" ) == 57, "dispid wrong\n");
393 /* MSDN claims the following functions exist but IDispatch->GetIDsOfNames disagrees */
396 get_dispid( pInstaller
, "ProductElevated" );
397 get_dispid( pInstaller
, "ProductInfoFromScript" );
398 get_dispid( pInstaller
, "ProvideAssembly" );
399 get_dispid( pInstaller
, "CreateAdvertiseScript" );
400 get_dispid( pInstaller
, "AdvertiseProduct" );
401 get_dispid( pInstaller
, "PatchFiles" );
405 /* Test basic IDispatch functions */
406 static void test_dispatch(void)
408 static WCHAR szOpenPackage
[] = { 'O','p','e','n','P','a','c','k','a','g','e',0 };
409 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};
414 VARIANTARG vararg
[2];
415 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
417 /* Test getting ID of a function name that does not exist */
418 name
= (WCHAR
*)szMsifile
;
419 hr
= IDispatch_GetIDsOfNames(pInstaller
, &IID_NULL
, &name
, 1, LOCALE_USER_DEFAULT
, &dispid
);
420 ok(hr
== DISP_E_UNKNOWNNAME
, "IDispatch::GetIDsOfNames returned 0x%08x\n", hr
);
422 /* Test invoking this function */
423 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, NULL
, NULL
, NULL
, NULL
);
424 ok(hr
== DISP_E_MEMBERNOTFOUND
, "IDispatch::Invoke returned 0x%08x\n", hr
);
426 /* Test getting ID of a function name that does exist */
427 name
= (WCHAR
*)szOpenPackage
;
428 hr
= IDispatch_GetIDsOfNames(pInstaller
, &IID_NULL
, &name
, 1, LOCALE_USER_DEFAULT
, &dispid
);
429 ok(SUCCEEDED(hr
), "IDispatch::GetIDsOfNames returned 0x%08x\n", hr
);
431 /* Test invoking this function (without parameters passed) */
432 if (0) /* All of these crash MSI on Windows XP */
434 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, NULL
, NULL
, NULL
, NULL
);
435 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, NULL
, NULL
, &excepinfo
, NULL
);
436 VariantInit(&varresult
);
437 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, NULL
, &varresult
, &excepinfo
, NULL
);
440 /* Try with NULL params */
441 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, &dispparams
, &varresult
, &excepinfo
, NULL
);
442 todo_wine
ok(hr
== DISP_E_TYPEMISMATCH
, "IDispatch::Invoke returned 0x%08x\n", hr
);
444 /* Try one empty parameter */
445 dispparams
.rgvarg
= vararg
;
446 dispparams
.cArgs
= 1;
447 VariantInit(&vararg
[0]);
448 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, &dispparams
, &varresult
, &excepinfo
, NULL
);
449 todo_wine
ok(hr
== DISP_E_TYPEMISMATCH
, "IDispatch::Invoke returned 0x%08x\n", hr
);
451 /* Try one parameter, function requires two */
452 VariantInit(&vararg
[0]);
453 V_VT(&vararg
[0]) = VT_BSTR
;
454 V_BSTR(&vararg
[0]) = SysAllocString(szMsifile
);
455 hr
= IDispatch_Invoke(pInstaller
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, DISPATCH_METHOD
, &dispparams
, &varresult
, &excepinfo
, NULL
);
456 VariantClear(&vararg
[0]);
458 ok(hr
== DISP_E_EXCEPTION
, "IDispatch::Invoke returned 0x%08x\n", hr
);
459 ok_exception(hr
, szOpenPackageException
);
462 /* invocation helper function */
463 static HRESULT
invoke(IDispatch
*pDispatch
, LPCSTR szName
, WORD wFlags
, DISPPARAMS
*pDispParams
, VARIANT
*pVarResult
, VARTYPE vtResult
)
465 OLECHAR
*name
= NULL
;
471 memset(pVarResult
, 0, sizeof(VARIANT
));
472 VariantInit(pVarResult
);
474 len
= MultiByteToWideChar(CP_ACP
, 0, szName
, -1, NULL
, 0 );
475 name
= HeapAlloc(GetProcessHeap(), 0, len
*sizeof(WCHAR
) );
476 if (!name
) return E_FAIL
;
477 len
= MultiByteToWideChar(CP_ACP
, 0, szName
, -1, name
, len
);
478 hr
= IDispatch_GetIDsOfNames(pDispatch
, &IID_NULL
, &name
, 1, LOCALE_USER_DEFAULT
, &dispid
);
479 HeapFree(GetProcessHeap(), 0, name
);
480 ok(SUCCEEDED(hr
), "IDispatch::GetIDsOfNames returned 0x%08x\n", hr
);
481 if (!SUCCEEDED(hr
)) return hr
;
483 memset(&excepinfo
, 0, sizeof(excepinfo
));
484 hr
= IDispatch_Invoke(pDispatch
, dispid
, &IID_NULL
, LOCALE_NEUTRAL
, wFlags
, pDispParams
, pVarResult
, &excepinfo
, NULL
);
488 ok(V_VT(pVarResult
) == vtResult
, "Variant result type is %d, expected %d\n", V_VT(pVarResult
), vtResult
);
489 if (vtResult
!= VT_EMPTY
)
491 hr
= VariantChangeTypeEx(pVarResult
, pVarResult
, LOCALE_NEUTRAL
, 0, vtResult
);
492 ok(SUCCEEDED(hr
), "VariantChangeTypeEx returned 0x%08x\n", hr
);
496 for (i
=0; i
<pDispParams
->cArgs
; i
++)
497 VariantClear(&pDispParams
->rgvarg
[i
]);
502 /* Object_Property helper functions */
504 static HRESULT
Installer_CreateRecord(int count
, IDispatch
**pRecord
)
507 VARIANTARG vararg
[1];
508 DISPPARAMS dispparams
= {vararg
, NULL
, sizeof(vararg
)/sizeof(VARIANTARG
), 0};
511 VariantInit(&vararg
[0]);
512 V_VT(&vararg
[0]) = VT_I4
;
513 V_I4(&vararg
[0]) = count
;
515 hr
= invoke(pInstaller
, "CreateRecord", DISPATCH_METHOD
, &dispparams
, &varresult
, VT_DISPATCH
);
516 *pRecord
= V_DISPATCH(&varresult
);
520 static HRESULT
Installer_OpenPackage(LPCWSTR szPackagePath
, int options
, IDispatch
**pSession
)
523 VARIANTARG vararg
[2];
524 DISPPARAMS dispparams
= {vararg
, NULL
, sizeof(vararg
)/sizeof(VARIANTARG
), 0};
527 VariantInit(&vararg
[1]);
528 V_VT(&vararg
[1]) = VT_BSTR
;
529 V_BSTR(&vararg
[1]) = SysAllocString(szPackagePath
);
530 VariantInit(&vararg
[0]);
531 V_VT(&vararg
[0]) = VT_I4
;
532 V_I4(&vararg
[0]) = options
;
534 hr
= invoke(pInstaller
, "OpenPackage", DISPATCH_METHOD
, &dispparams
, &varresult
, VT_DISPATCH
);
535 *pSession
= V_DISPATCH(&varresult
);
539 static HRESULT
Installer_ProductState(LPCWSTR szProduct
, int *pInstallState
)
542 VARIANTARG vararg
[1];
543 DISPPARAMS dispparams
= {vararg
, NULL
, sizeof(vararg
)/sizeof(VARIANTARG
), 0};
546 VariantInit(&vararg
[0]);
547 V_VT(&vararg
[0]) = VT_BSTR
;
548 V_BSTR(&vararg
[0]) = SysAllocString(szProduct
);
550 hr
= invoke(pInstaller
, "ProductState", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_I4
);
551 *pInstallState
= V_I4(&varresult
);
552 VariantClear(&varresult
);
556 static HRESULT
Installer_Products(IDispatch
**pStringList
)
559 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
562 hr
= invoke(pInstaller
, "Products", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_DISPATCH
);
563 *pStringList
= V_DISPATCH(&varresult
);
567 static HRESULT
Installer_VersionGet(LPCWSTR szVersion
)
570 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
573 hr
= invoke(pInstaller
, "Version", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_BSTR
);
574 lstrcpyW((WCHAR
*)szVersion
, V_BSTR(&varresult
));
575 VariantClear(&varresult
);
579 static HRESULT
Session_Installer(IDispatch
*pSession
, IDispatch
**pInst
)
582 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
585 hr
= invoke(pSession
, "Installer", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_DISPATCH
);
586 *pInst
= V_DISPATCH(&varresult
);
590 static HRESULT
Session_PropertyGet(IDispatch
*pSession
, LPCWSTR szName
, LPCWSTR szReturn
)
593 VARIANTARG vararg
[1];
594 DISPPARAMS dispparams
= {vararg
, NULL
, sizeof(vararg
)/sizeof(VARIANTARG
), 0};
597 VariantInit(&vararg
[0]);
598 V_VT(&vararg
[0]) = VT_BSTR
;
599 V_BSTR(&vararg
[0]) = SysAllocString(szName
);
601 hr
= invoke(pSession
, "Property", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_BSTR
);
602 lstrcpyW((WCHAR
*)szReturn
, V_BSTR(&varresult
));
603 VariantClear(&varresult
);
607 static HRESULT
Session_PropertyPut(IDispatch
*pSession
, LPCWSTR szName
, LPCWSTR szValue
)
610 VARIANTARG vararg
[2];
611 DISPID dispid
= DISPID_PROPERTYPUT
;
612 DISPPARAMS dispparams
= {vararg
, &dispid
, sizeof(vararg
)/sizeof(VARIANTARG
), 1};
614 VariantInit(&vararg
[1]);
615 V_VT(&vararg
[1]) = VT_BSTR
;
616 V_BSTR(&vararg
[1]) = SysAllocString(szName
);
617 VariantInit(&vararg
[0]);
618 V_VT(&vararg
[0]) = VT_BSTR
;
619 V_BSTR(&vararg
[0]) = SysAllocString(szValue
);
621 return invoke(pSession
, "Property", DISPATCH_PROPERTYPUT
, &dispparams
, &varresult
, VT_EMPTY
);
624 static HRESULT
Session_LanguageGet(IDispatch
*pSession
, UINT
*pLangId
)
627 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
630 hr
= invoke(pSession
, "Language", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_I4
);
631 *pLangId
= V_I4(&varresult
);
632 VariantClear(&varresult
);
636 static HRESULT
Session_ModeGet(IDispatch
*pSession
, int iFlag
, BOOL
*pMode
)
639 VARIANTARG vararg
[1];
640 DISPPARAMS dispparams
= {vararg
, NULL
, sizeof(vararg
)/sizeof(VARIANTARG
), 0};
643 VariantInit(&vararg
[0]);
644 V_VT(&vararg
[0]) = VT_I4
;
645 V_I4(&vararg
[0]) = iFlag
;
647 hr
= invoke(pSession
, "Mode", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_BOOL
);
648 *pMode
= V_BOOL(&varresult
);
649 VariantClear(&varresult
);
653 static HRESULT
Session_ModePut(IDispatch
*pSession
, int iFlag
, BOOL bMode
)
656 VARIANTARG vararg
[2];
657 DISPID dispid
= DISPID_PROPERTYPUT
;
658 DISPPARAMS dispparams
= {vararg
, &dispid
, sizeof(vararg
)/sizeof(VARIANTARG
), 1};
660 VariantInit(&vararg
[1]);
661 V_VT(&vararg
[1]) = VT_I4
;
662 V_I4(&vararg
[1]) = iFlag
;
663 VariantInit(&vararg
[0]);
664 V_VT(&vararg
[0]) = VT_BOOL
;
665 V_BOOL(&vararg
[0]) = bMode
;
667 return invoke(pSession
, "Mode", DISPATCH_PROPERTYPUT
, &dispparams
, &varresult
, VT_EMPTY
);
670 static HRESULT
Session_Database(IDispatch
*pSession
, IDispatch
**pDatabase
)
673 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
676 hr
= invoke(pSession
, "Database", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_DISPATCH
);
677 *pDatabase
= V_DISPATCH(&varresult
);
681 static HRESULT
Session_DoAction(IDispatch
*pSession
, LPCWSTR szAction
, int *iReturn
)
684 VARIANTARG vararg
[1];
685 DISPPARAMS dispparams
= {vararg
, NULL
, sizeof(vararg
)/sizeof(VARIANTARG
), 0};
688 VariantInit(&vararg
[0]);
689 V_VT(&vararg
[0]) = VT_BSTR
;
690 V_BSTR(&vararg
[0]) = SysAllocString(szAction
);
692 hr
= invoke(pSession
, "DoAction", DISPATCH_METHOD
, &dispparams
, &varresult
, VT_I4
);
693 *iReturn
= V_I4(&varresult
);
694 VariantClear(&varresult
);
698 static HRESULT
Session_SetInstallLevel(IDispatch
*pSession
, long iInstallLevel
)
701 VARIANTARG vararg
[1];
702 DISPPARAMS dispparams
= {vararg
, NULL
, sizeof(vararg
)/sizeof(VARIANTARG
), 0};
704 VariantInit(&vararg
[0]);
705 V_VT(&vararg
[0]) = VT_I4
;
706 V_I4(&vararg
[0]) = iInstallLevel
;
708 return invoke(pSession
, "SetInstallLevel", DISPATCH_METHOD
, &dispparams
, &varresult
, VT_EMPTY
);
711 static HRESULT
Session_FeatureCurrentState(IDispatch
*pSession
, LPCWSTR szName
, int *pState
)
714 VARIANTARG vararg
[1];
715 DISPPARAMS dispparams
= {vararg
, NULL
, sizeof(vararg
)/sizeof(VARIANTARG
), 0};
718 VariantInit(&vararg
[0]);
719 V_VT(&vararg
[0]) = VT_BSTR
;
720 V_BSTR(&vararg
[0]) = SysAllocString(szName
);
722 hr
= invoke(pSession
, "FeatureCurrentState", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_I4
);
723 *pState
= V_I4(&varresult
);
724 VariantClear(&varresult
);
728 static HRESULT
Session_FeatureRequestStateGet(IDispatch
*pSession
, LPCWSTR szName
, int *pState
)
731 VARIANTARG vararg
[1];
732 DISPPARAMS dispparams
= {vararg
, NULL
, sizeof(vararg
)/sizeof(VARIANTARG
), 0};
735 VariantInit(&vararg
[0]);
736 V_VT(&vararg
[0]) = VT_BSTR
;
737 V_BSTR(&vararg
[0]) = SysAllocString(szName
);
739 hr
= invoke(pSession
, "FeatureRequestState", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_I4
);
740 *pState
= V_I4(&varresult
);
741 VariantClear(&varresult
);
745 static HRESULT
Session_FeatureRequestStatePut(IDispatch
*pSession
, LPCWSTR szName
, int iState
)
748 VARIANTARG vararg
[2];
749 DISPID dispid
= DISPID_PROPERTYPUT
;
750 DISPPARAMS dispparams
= {vararg
, &dispid
, sizeof(vararg
)/sizeof(VARIANTARG
), 1};
752 VariantInit(&vararg
[1]);
753 V_VT(&vararg
[1]) = VT_BSTR
;
754 V_BSTR(&vararg
[1]) = SysAllocString(szName
);
755 VariantInit(&vararg
[0]);
756 V_VT(&vararg
[0]) = VT_I4
;
757 V_I4(&vararg
[0]) = iState
;
759 return invoke(pSession
, "FeatureRequestState", DISPATCH_PROPERTYPUT
, &dispparams
, &varresult
, VT_EMPTY
);
762 static HRESULT
Database_OpenView(IDispatch
*pDatabase
, LPCWSTR szSql
, IDispatch
**pView
)
765 VARIANTARG vararg
[1];
766 DISPPARAMS dispparams
= {vararg
, NULL
, sizeof(vararg
)/sizeof(VARIANTARG
), 0};
769 VariantInit(&vararg
[0]);
770 V_VT(&vararg
[0]) = VT_BSTR
;
771 V_BSTR(&vararg
[0]) = SysAllocString(szSql
);
773 hr
= invoke(pDatabase
, "OpenView", DISPATCH_METHOD
, &dispparams
, &varresult
, VT_DISPATCH
);
774 *pView
= V_DISPATCH(&varresult
);
778 static HRESULT
View_Execute(IDispatch
*pView
, IDispatch
*pRecord
)
781 VARIANTARG vararg
[1];
782 DISPPARAMS dispparams
= {vararg
, NULL
, sizeof(vararg
)/sizeof(VARIANTARG
), 0};
784 VariantInit(&vararg
[0]);
785 V_VT(&vararg
[0]) = VT_DISPATCH
;
786 V_DISPATCH(&vararg
[0]) = pRecord
;
788 return invoke(pView
, "Execute", DISPATCH_METHOD
, &dispparams
, &varresult
, VT_EMPTY
);
791 static HRESULT
View_Fetch(IDispatch
*pView
, IDispatch
**ppRecord
)
794 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
795 HRESULT hr
= invoke(pView
, "Fetch", DISPATCH_METHOD
, &dispparams
, &varresult
, VT_DISPATCH
);
796 *ppRecord
= V_DISPATCH(&varresult
);
800 static HRESULT
View_Close(IDispatch
*pView
)
803 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
804 return invoke(pView
, "Close", DISPATCH_METHOD
, &dispparams
, &varresult
, VT_EMPTY
);
807 static HRESULT
Record_FieldCountGet(IDispatch
*pRecord
, int *pFieldCount
)
810 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
811 HRESULT hr
= invoke(pRecord
, "FieldCount", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_I4
);
812 *pFieldCount
= V_I4(&varresult
);
813 VariantClear(&varresult
);
817 static HRESULT
Record_StringDataGet(IDispatch
*pRecord
, int iField
, LPCWSTR szString
)
820 VARIANTARG vararg
[1];
821 DISPPARAMS dispparams
= {vararg
, NULL
, sizeof(vararg
)/sizeof(VARIANTARG
), 0};
824 VariantInit(&vararg
[0]);
825 V_VT(&vararg
[0]) = VT_I4
;
826 V_I4(&vararg
[0]) = iField
;
828 hr
= invoke(pRecord
, "StringData", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_BSTR
);
829 lstrcpyW((WCHAR
*)szString
, V_BSTR(&varresult
));
830 VariantClear(&varresult
);
834 static HRESULT
Record_StringDataPut(IDispatch
*pRecord
, int iField
, LPCWSTR szString
)
837 VARIANTARG vararg
[2];
838 DISPID dispid
= DISPID_PROPERTYPUT
;
839 DISPPARAMS dispparams
= {vararg
, &dispid
, sizeof(vararg
)/sizeof(VARIANTARG
), 1};
841 VariantInit(&vararg
[1]);
842 V_VT(&vararg
[1]) = VT_I4
;
843 V_I4(&vararg
[1]) = iField
;
844 VariantInit(&vararg
[0]);
845 V_VT(&vararg
[0]) = VT_BSTR
;
846 V_BSTR(&vararg
[0]) = SysAllocString(szString
);
848 return invoke(pRecord
, "StringData", DISPATCH_PROPERTYPUT
, &dispparams
, &varresult
, VT_BSTR
);
851 static HRESULT
StringList_Item(IDispatch
*pStringList
, int iIndex
, LPWSTR szString
)
854 VARIANTARG vararg
[1];
855 DISPPARAMS dispparams
= {vararg
, NULL
, sizeof(vararg
)/sizeof(VARIANTARG
), 0};
858 VariantInit(&vararg
[0]);
859 V_VT(&vararg
[0]) = VT_I4
;
860 V_I4(&vararg
[0]) = iIndex
;
862 hr
= invoke(pStringList
, "Item", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_BSTR
);
863 lstrcpyW(szString
, V_BSTR(&varresult
));
864 VariantClear(&varresult
);
868 static HRESULT
StringList_Count(IDispatch
*pStringList
, int *pCount
)
871 DISPPARAMS dispparams
= {NULL
, NULL
, 0, 0};
872 HRESULT hr
= invoke(pStringList
, "Count", DISPATCH_PROPERTYGET
, &dispparams
, &varresult
, VT_I4
);
873 *pCount
= V_I4(&varresult
);
874 VariantClear(&varresult
);
878 /* Test the various objects */
880 static void test_Database(IDispatch
*pDatabase
)
882 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 };
883 static WCHAR szThree
[] = { 'T','h','r','e','e',0 };
884 static WCHAR szTwo
[] = { 'T','w','o',0 };
885 static WCHAR szStringDataField
[] = { 'S','t','r','i','n','g','D','a','t','a',',','F','i','e','l','d',0 };
886 IDispatch
*pView
= NULL
;
889 hr
= Database_OpenView(pDatabase
, szSql
, &pView
);
890 ok(SUCCEEDED(hr
), "Database_OpenView failed, hresult 0x%08x\n", hr
);
893 IDispatch
*pRecord
= NULL
;
894 WCHAR szString
[MAX_PATH
];
897 hr
= View_Execute(pView
, NULL
);
898 ok(SUCCEEDED(hr
), "View_Execute failed, hresult 0x%08x\n", hr
);
901 hr
= View_Fetch(pView
, &pRecord
);
902 ok(SUCCEEDED(hr
), "View_Fetch failed, hresult 0x%08x\n", hr
);
903 ok(pRecord
!= NULL
, "View_Fetch should not have returned NULL record\n");
906 /* Record::StringDataGet */
907 memset(szString
, 0, sizeof(szString
));
908 hr
= Record_StringDataGet(pRecord
, 1, szString
);
909 ok(SUCCEEDED(hr
), "Record_StringDataGet failed, hresult 0x%08x\n", hr
);
910 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString
, szThree
);
912 /* Record::StringDataPut with incorrect index */
913 hr
= Record_StringDataPut(pRecord
, -1, szString
);
914 ok(hr
== DISP_E_EXCEPTION
, "Record_StringDataPut failed, hresult 0x%08x\n", hr
);
915 ok_exception(hr
, szStringDataField
);
917 IDispatch_Release(pRecord
);
921 hr
= View_Fetch(pView
, &pRecord
);
922 ok(SUCCEEDED(hr
), "View_Fetch failed, hresult 0x%08x\n", hr
);
923 ok(pRecord
!= NULL
, "View_Fetch should not have returned NULL record\n");
926 /* Record::StringDataGet */
927 memset(szString
, 0, sizeof(szString
));
928 hr
= Record_StringDataGet(pRecord
, 1, szString
);
929 ok(SUCCEEDED(hr
), "Record_StringDataGet failed, hresult 0x%08x\n", hr
);
930 ok_w2("Record_StringDataGet result was %s but expected %s\n", szString
, szTwo
);
932 IDispatch_Release(pRecord
);
936 hr
= View_Fetch(pView
, &pRecord
);
937 ok(SUCCEEDED(hr
), "View_Fetch failed, hresult 0x%08x\n", hr
);
938 ok(pRecord
== NULL
, "View_Fetch should have returned NULL record\n");
940 IDispatch_Release(pRecord
);
943 hr
= View_Close(pView
);
944 ok(SUCCEEDED(hr
), "View_Close failed, hresult 0x%08x\n", hr
);
946 IDispatch_Release(pView
);
950 static void test_Session(IDispatch
*pSession
)
952 static WCHAR szProductName
[] = { 'P','r','o','d','u','c','t','N','a','m','e',0 };
953 static WCHAR szMSITEST
[] = { 'M','S','I','T','E','S','T',0 };
954 static WCHAR szOne
[] = { 'O','n','e',0 };
955 static WCHAR szCostInitialize
[] = { 'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0 };
956 static WCHAR szEmpty
[] = { 0 };
957 static WCHAR szEquals
[] = { '=',0 };
958 static WCHAR szPropertyName
[] = { 'P','r','o','p','e','r','t','y',',','N','a','m','e',0 };
959 WCHAR stringw
[MAX_PATH
];
960 CHAR string
[MAX_PATH
];
964 IDispatch
*pDatabase
= NULL
, *pInst
= NULL
;
967 /* Session::Installer */
968 hr
= Session_Installer(pSession
, &pInst
);
969 ok(SUCCEEDED(hr
), "Session_Installer failed, hresult 0x%08x\n", hr
);
970 ok(pInst
!= NULL
, "Session_Installer returned NULL IDispatch pointer\n");
971 ok(pInst
== pInstaller
, "Session_Installer does not match Installer instance from CoCreateInstance\n");
973 /* Session::Property, get */
974 memset(stringw
, 0, sizeof(stringw
));
975 hr
= Session_PropertyGet(pSession
, szProductName
, stringw
);
976 ok(SUCCEEDED(hr
), "Session_PropertyGet failed, hresult 0x%08x\n", hr
);
977 if (lstrcmpW(stringw
, szMSITEST
) != 0)
979 len
= WideCharToMultiByte(CP_ACP
, 0, stringw
, -1, string
, MAX_PATH
, NULL
, NULL
);
980 ok(len
, "WideCharToMultiByteChar returned error %d\n", GetLastError());
981 ok(0, "Property \"ProductName\" expected to be \"MSITEST\" but was \"%s\"\n", string
);
984 /* Session::Property, put */
985 hr
= Session_PropertyPut(pSession
, szProductName
, szProductName
);
986 ok(SUCCEEDED(hr
), "Session_PropertyPut failed, hresult 0x%08x\n", hr
);
987 memset(stringw
, 0, sizeof(stringw
));
988 hr
= Session_PropertyGet(pSession
, szProductName
, stringw
);
989 ok(SUCCEEDED(hr
), "Session_PropertyGet failed, hresult 0x%08x\n", hr
);
990 if (lstrcmpW(stringw
, szProductName
) != 0)
992 len
= WideCharToMultiByte(CP_ACP
, 0, stringw
, -1, string
, MAX_PATH
, NULL
, NULL
);
993 ok(len
, "WideCharToMultiByteChar returned error %d\n", GetLastError());
994 ok(0, "Property \"ProductName\" expected to be \"ProductName\" but was \"%s\"\n", string
);
997 /* Try putting a property using empty property identifier */
998 hr
= Session_PropertyPut(pSession
, szEmpty
, szProductName
);
999 ok(hr
== DISP_E_EXCEPTION
, "Session_PropertyPut failed, hresult 0x%08x\n", hr
);
1000 ok_exception(hr
, szPropertyName
);
1002 /* Try putting a property using illegal property identifier */
1003 hr
= Session_PropertyPut(pSession
, szEquals
, szProductName
);
1004 ok(SUCCEEDED(hr
), "Session_PropertyPut failed, hresult 0x%08x\n", hr
);
1006 /* Session::Language, get */
1007 hr
= Session_LanguageGet(pSession
, &len
);
1008 ok(SUCCEEDED(hr
), "Session_LanguageGet failed, hresult 0x%08x\n", hr
);
1009 /* Not sure how to check the language is correct */
1011 /* Session::Mode, get */
1012 hr
= Session_ModeGet(pSession
, MSIRUNMODE_REBOOTATEND
, &bool);
1013 ok(SUCCEEDED(hr
), "Session_ModeGet failed, hresult 0x%08x\n", hr
);
1014 todo_wine
ok(!bool, "Reboot at end session mode is %d\n", bool);
1016 /* Session::Mode, put */
1017 hr
= Session_ModePut(pSession
, MSIRUNMODE_REBOOTATEND
, TRUE
);
1018 todo_wine
ok(SUCCEEDED(hr
), "Session_ModePut failed, hresult 0x%08x\n", hr
);
1019 hr
= Session_ModeGet(pSession
, MSIRUNMODE_REBOOTATEND
, &bool);
1020 ok(SUCCEEDED(hr
), "Session_ModeGet failed, hresult 0x%08x\n", hr
);
1021 ok(bool, "Reboot at end session mode is %d, expected 1\n", bool);
1022 hr
= Session_ModePut(pSession
, MSIRUNMODE_REBOOTATEND
, FALSE
); /* set it again so we don't reboot */
1023 todo_wine
ok(SUCCEEDED(hr
), "Session_ModePut failed, hresult 0x%08x\n", hr
);
1025 /* Session::Database, get */
1026 hr
= Session_Database(pSession
, &pDatabase
);
1027 ok(SUCCEEDED(hr
), "Session_Database failed, hresult 0x%08x\n", hr
);
1030 test_Database(pDatabase
);
1031 IDispatch_Release(pDatabase
);
1034 /* Session::DoAction(CostInitialize) must occur before the next statements */
1035 hr
= Session_DoAction(pSession
, szCostInitialize
, &myint
);
1036 ok(SUCCEEDED(hr
), "Session_DoAction failed, hresult 0x%08x\n", hr
);
1037 ok(myint
== IDOK
, "DoAction(CostInitialize) returned %d, %d expected\n", myint
, IDOK
);
1039 /* Session::SetInstallLevel */
1040 hr
= Session_SetInstallLevel(pSession
, INSTALLLEVEL_MINIMUM
);
1041 ok(SUCCEEDED(hr
), "Session_SetInstallLevel failed, hresult 0x%08x\n", hr
);
1043 /* Session::FeatureCurrentState, get */
1044 hr
= Session_FeatureCurrentState(pSession
, szOne
, &myint
);
1045 ok(SUCCEEDED(hr
), "Session_FeatureCurrentState failed, hresult 0x%08x\n", hr
);
1046 ok(myint
== INSTALLSTATE_UNKNOWN
, "Feature current state was %d but expected %d\n", myint
, INSTALLSTATE_UNKNOWN
);
1048 /* Session::FeatureRequestState, put */
1049 hr
= Session_FeatureRequestStatePut(pSession
, szOne
, INSTALLSTATE_ADVERTISED
);
1050 ok(SUCCEEDED(hr
), "Session_FeatureRequestStatePut failed, hresult 0x%08x\n", hr
);
1051 hr
= Session_FeatureRequestStateGet(pSession
, szOne
, &myint
);
1052 ok(SUCCEEDED(hr
), "Session_FeatureRequestStateGet failed, hresult 0x%08x\n", hr
);
1053 ok(myint
== INSTALLSTATE_ADVERTISED
, "Feature request state was %d but expected %d\n", myint
, INSTALLSTATE_ADVERTISED
);
1056 static void test_Installer(void)
1058 static 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 };
1059 static WCHAR szBackslash
[] = { '\\',0 };
1060 WCHAR szPath
[MAX_PATH
];
1063 IDispatch
*pSession
= NULL
, *pRecord
= NULL
, *pStringList
= NULL
;
1066 if (!pInstaller
) return;
1068 /* Installer::CreateRecord */
1070 hr
= Installer_CreateRecord(1, &pRecord
);
1071 ok(SUCCEEDED(hr
), "Installer_CreateRecord failed, hresult 0x%08x\n", hr
);
1072 ok(pRecord
!= NULL
, "Installer_CreateRecord should not have returned NULL record\n");
1076 int iFieldCount
= 0;
1078 /* Record::FieldCountGet */
1079 hr
= Record_FieldCountGet(pRecord
, &iFieldCount
);
1080 ok(SUCCEEDED(hr
), "Record_FiledCountGet failed, hresult 0x%08x\n", hr
);
1081 ok(iFieldCount
== 1, "Record_FieldCountGet result was %d but expected 1\n", iFieldCount
);
1083 IDispatch_Release(pRecord
);
1086 /* Prepare package */
1087 create_database(msifile
, tables
, sizeof(tables
) / sizeof(msi_table
));
1089 len
= MultiByteToWideChar(CP_ACP
, MB_PRECOMPOSED
, CURR_DIR
, -1, szPath
, MAX_PATH
);
1090 ok(len
, "MultiByteToWideChar returned error %d\n", GetLastError());
1093 lstrcatW(szPath
, szBackslash
);
1094 lstrcatW(szPath
, szMsifile
);
1096 /* Installer::OpenPackage */
1097 hr
= Installer_OpenPackage(szPath
, 0, &pSession
);
1098 ok(SUCCEEDED(hr
), "Installer_OpenPackage failed, hresult 0x%08x\n", hr
);
1101 test_Session(pSession
);
1102 IDispatch_Release(pSession
);
1105 DeleteFileA(msifile
);
1107 /* Installer::Products */
1108 hr
= Installer_Products(&pStringList
);
1109 ok(SUCCEEDED(hr
), "Installer_Products failed, hresult 0x%08x\n", hr
);
1112 int iCount
= 0, idx
;
1114 /* StringList::Count */
1115 hr
= StringList_Count(pStringList
, &iCount
);
1116 ok(SUCCEEDED(hr
), "StringList_Count failed, hresult 0x%08x\n", hr
);
1118 for (idx
=0; idx
<iCount
; idx
++)
1120 /* StringList::Item */
1121 memset(szPath
, 0, sizeof(szPath
));
1122 hr
= StringList_Item(pStringList
, idx
, szPath
);
1123 ok(SUCCEEDED(hr
), "StringList_Item failed (idx %d, count %d), hresult 0x%08x\n", idx
, iCount
, hr
);
1127 /* Installer::ProductState */
1128 hr
= Installer_ProductState(szPath
, &iState
);
1129 ok(SUCCEEDED(hr
), "Installer_ProductState failed, hresult 0x%08x\n", hr
);
1131 ok(iState
== INSTALLSTATE_DEFAULT
|| iState
== INSTALLSTATE_ADVERTISED
, "Installer_ProductState returned %d, expected %d or %d", iState
, INSTALLSTATE_DEFAULT
, INSTALLSTATE_ADVERTISED
);
1135 /* StringList::Item using an invalid index */
1136 memset(szPath
, 0, sizeof(szPath
));
1137 hr
= StringList_Item(pStringList
, iCount
, szPath
);
1138 ok(hr
== DISP_E_BADINDEX
, "StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x\n", hr
);
1140 IDispatch_Release(pStringList
);
1143 /* Installer::ProductState for our product code, which should not be installed */
1144 hr
= Installer_ProductState(szProductCode
, &iState
);
1145 ok(SUCCEEDED(hr
), "Installer_ProductState failed, hresult 0x%08x\n", hr
);
1147 ok(iState
== INSTALLSTATE_UNKNOWN
, "Installer_ProductState returned %d, expected %d", iState
, INSTALLSTATE_UNKNOWN
);
1149 /* Installer::Version */
1151 memset(szPath
, 0, sizeof(szPath
));
1152 hr
= Installer_VersionGet(szPath
);
1153 ok(SUCCEEDED(hr
), "Installer_VersionGet failed, hresult 0x%08x\n", hr
);
1157 START_TEST(automation
)
1160 char temp_path
[MAX_PATH
], prev_path
[MAX_PATH
];
1165 GetCurrentDirectoryA(MAX_PATH
, prev_path
);
1166 GetTempPath(MAX_PATH
, temp_path
);
1167 SetCurrentDirectoryA(temp_path
);
1169 lstrcpyA(CURR_DIR
, temp_path
);
1170 len
= lstrlenA(CURR_DIR
);
1172 if(len
&& (CURR_DIR
[len
- 1] == '\\'))
1173 CURR_DIR
[len
- 1] = 0;
1175 hr
= OleInitialize(NULL
);
1176 ok (SUCCEEDED(hr
), "OleInitialize returned 0x%08x\n", hr
);
1177 hr
= CLSIDFromProgID(szProgId
, &clsid
);
1178 ok (SUCCEEDED(hr
), "CLSIDFromProgID returned 0x%08x\n", hr
);
1179 hr
= CoCreateInstance(&clsid
, NULL
, CLSCTX_INPROC_SERVER
, &IID_IUnknown
, (void **)&pUnk
);
1180 ok(SUCCEEDED(hr
), "CoCreateInstance returned 0x%08x\n", hr
);
1184 hr
= IUnknown_QueryInterface(pUnk
, &IID_IDispatch
, (void **)&pInstaller
);
1185 ok (SUCCEEDED(hr
), "IUnknown::QueryInterface returned 0x%08x\n", hr
);
1191 hr
= IUnknown_Release(pUnk
);
1192 ok (SUCCEEDED(hr
), "IUnknown::Release returned 0x%08x\n", hr
);
1197 SetCurrentDirectoryA(prev_path
);