2007-04-29 03:12:09 +02:00
/*
2007-05-01 03:53:26 +02:00
* Copyright ( C ) 2007 Mike McCormack for CodeWeavers
2007-04-29 03:12:09 +02:00
* Copyright ( C ) 2007 Misha Koshelev
*
2007-05-01 03:53:26 +02:00
* A test program for Microsoft Installer OLE automation functionality .
2007-04-29 03:12:09 +02:00
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 , USA
*/
# define COBJMACROS
# include <stdio.h>
# include <windows.h>
# include <msiquery.h>
# include <msidefs.h>
# include <msi.h>
# include <fci.h>
# include "wine/test.h"
static const char * msifile = " winetest.msi " ;
static const WCHAR szMsifile [ ] = { ' w ' , ' i ' , ' n ' , ' e ' , ' t ' , ' e ' , ' s ' , ' t ' , ' . ' , ' m ' , ' s ' , ' i ' , 0 } ;
2007-05-14 19:14:42 +02:00
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 } ;
2007-04-29 03:12:09 +02:00
CHAR CURR_DIR [ MAX_PATH ] ;
EXCEPINFO excepinfo ;
/*
* OLE automation data
* */
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 } ;
static IDispatch * pInstaller ;
/* msi database data */
static const CHAR component_dat [ ] = " Component \t ComponentId \t Directory_ \t Attributes \t Condition \t KeyPath \n "
" s72 \t S38 \t s72 \t i2 \t S255 \t S72 \n "
" Component \t Component \n "
" Five \t {8CC92E9D-14B2-4CA4-B2AA-B11D02078087} \t NEWDIR \t 2 \t \t five.txt \n "
" Four \t {FD37B4EA-7209-45C0-8917-535F35A2F080} \t CABOUTDIR \t 2 \t \t four.txt \n "
" One \t {783B242E-E185-4A56-AF86-C09815EC053C} \t MSITESTDIR \t 2 \t \t one.txt \n "
" Three \t {010B6ADD-B27D-4EDD-9B3D-34C4F7D61684} \t CHANGEDDIR \t 2 \t \t three.txt \n "
" Two \t {BF03D1A6-20DA-4A65-82F3-6CAC995915CE} \t FIRSTDIR \t 2 \t \t two.txt \n "
" dangler \t {6091DF25-EF96-45F1-B8E9-A9B1420C7A3C} \t TARGETDIR \t 4 \t \t regdata \n "
" component \t \t MSITESTDIR \t 0 \t 1 \t file \n "
" service_comp \t \t MSITESTDIR \t 0 \t 1 \t service_file " ;
static const CHAR directory_dat [ ] = " Directory \t Directory_Parent \t DefaultDir \n "
" s72 \t S72 \t l255 \n "
" Directory \t Directory \n "
" CABOUTDIR \t MSITESTDIR \t cabout \n "
" CHANGEDDIR \t MSITESTDIR \t changed:second \n "
" FIRSTDIR \t MSITESTDIR \t first \n "
" MSITESTDIR \t ProgramFilesFolder \t msitest \n "
" NEWDIR \t CABOUTDIR \t new \n "
" ProgramFilesFolder \t TARGETDIR \t . \n "
" TARGETDIR \t \t SourceDir " ;
static const CHAR feature_dat [ ] = " Feature \t Feature_Parent \t Title \t Description \t Display \t Level \t Directory_ \t Attributes \n "
" s38 \t S38 \t L64 \t L255 \t I2 \t i2 \t S72 \t i2 \n "
" Feature \t Feature \n "
" Five \t \t Five \t The Five Feature \t 5 \t 3 \t NEWDIR \t 0 \n "
" Four \t \t Four \t The Four Feature \t 4 \t 3 \t CABOUTDIR \t 0 \n "
" One \t \t One \t The One Feature \t 1 \t 3 \t MSITESTDIR \t 0 \n "
" Three \t One \t Three \t The Three Feature \t 3 \t 3 \t CHANGEDDIR \t 0 \n "
" Two \t One \t Two \t The Two Feature \t 2 \t 3 \t FIRSTDIR \t 0 \n "
" feature \t \t \t \t 2 \t 1 \t TARGETDIR \t 0 \n "
" service_feature \t \t \t \t 2 \t 1 \t TARGETDIR \t 0 " ;
static const CHAR feature_comp_dat [ ] = " Feature_ \t Component_ \n "
" s38 \t s72 \n "
" FeatureComponents \t Feature_ \t Component_ \n "
" Five \t Five \n "
" Four \t Four \n "
" One \t One \n "
" Three \t Three \n "
" Two \t Two \n "
" feature \t component \n "
" service_feature \t service_comp \n " ;
static const CHAR file_dat [ ] = " File \t Component_ \t FileName \t FileSize \t Version \t Language \t Attributes \t Sequence \n "
" s72 \t s72 \t l255 \t i4 \t S72 \t S20 \t I2 \t i2 \n "
" File \t File \n "
2007-05-14 19:14:42 +02:00
" five.txt \t Five \t five.txt \t 1000 \t \t \t 0 \t 5 \n "
" four.txt \t Four \t four.txt \t 1000 \t \t \t 0 \t 4 \n "
2007-04-29 03:12:09 +02:00
" one.txt \t One \t one.txt \t 1000 \t \t \t 0 \t 1 \n "
" three.txt \t Three \t three.txt \t 1000 \t \t \t 0 \t 3 \n "
" two.txt \t Two \t two.txt \t 1000 \t \t \t 0 \t 2 \n "
" file \t component \t filename \t 100 \t \t \t 8192 \t 1 \n "
" service_file \t service_comp \t service.exe \t 100 \t \t \t 8192 \t 1 " ;
static const CHAR install_exec_seq_dat [ ] = " Action \t Condition \t Sequence \n "
" s72 \t S255 \t I2 \n "
" InstallExecuteSequence \t Action \n "
" AllocateRegistrySpace \t NOT Installed \t 1550 \n "
" CostFinalize \t \t 1000 \n "
" CostInitialize \t \t 800 \n "
" FileCost \t \t 900 \n "
" InstallFiles \t \t 4000 \n "
" InstallServices \t \t 5000 \n "
2007-05-14 19:14:42 +02:00
" RegisterProduct \t \t 6100 \n "
" PublishProduct \t \t 6400 \n "
2007-04-29 03:12:09 +02:00
" InstallFinalize \t \t 6600 \n "
" InstallInitialize \t \t 1500 \n "
" InstallValidate \t \t 1400 \n "
" LaunchConditions \t \t 100 \n "
" WriteRegistryValues \t SourceDir And SOURCEDIR \t 5000 " ;
static const CHAR media_dat [ ] = " DiskId \t LastSequence \t DiskPrompt \t Cabinet \t VolumeLabel \t Source \n "
" i2 \t i4 \t L64 \t S255 \t S32 \t S72 \n "
" Media \t DiskId \n "
2007-05-14 19:14:42 +02:00
" 1 \t 5 \t \t \t DISK1 \t \n " ;
2007-04-29 03:12:09 +02:00
static const CHAR property_dat [ ] = " Property \t Value \n "
" s72 \t l0 \n "
" Property \t Property \n "
" DefaultUIFont \t DlgFont8 \n "
" HASUIRUN \t 0 \n "
" INSTALLLEVEL \t 3 \n "
" InstallMode \t Typical \n "
" Manufacturer \t Wine \n "
" PIDTemplate \t 12345<###-%%%%%%%>@@@@@ \n "
" ProductCode \t {F1C3AF50-8B56-4A69-A00C-00773FE42F30} \n "
" ProductID \t none \n "
" ProductLanguage \t 1033 \n "
" ProductName \t MSITEST \n "
" ProductVersion \t 1.1.1 \n "
" PROMPTROLLBACKCOST \t P \n "
" Setup \t Setup \n "
" UpgradeCode \t {CE067E8D-2E1A-4367-B734-4EB2BDAD6565} " ;
static const CHAR registry_dat [ ] = " Registry \t Root \t Key \t Name \t Value \t Component_ \n "
" s72 \t i2 \t l255 \t L255 \t L0 \t s72 \n "
" Registry \t Registry \n "
" Apples \t 2 \t SOFTWARE \\ Wine \\ msitest \t Name \t imaname \t One \n "
" Oranges \t 2 \t SOFTWARE \\ Wine \\ msitest \t number \t #314 \t Two \n "
" regdata \t 2 \t SOFTWARE \\ Wine \\ msitest \t blah \t bad \t dangler \n "
" OrderTest \t 2 \t SOFTWARE \\ Wine \\ msitest \t OrderTestName \t OrderTestValue \t component " ;
static const CHAR service_install_dat [ ] = " ServiceInstall \t Name \t DisplayName \t ServiceType \t StartType \t ErrorControl \t "
" LoadOrderGroup \t Dependencies \t StartName \t Password \t Arguments \t Component_ \t Description \n "
" s72 \t s255 \t L255 \t i4 \t i4 \t i4 \t S255 \t S255 \t S255 \t S255 \t S255 \t s72 \t L255 \n "
" ServiceInstall \t ServiceInstall \n "
" TestService \t TestService \t TestService \t 2 \t 3 \t 0 \t \t \t TestService \t \t \t service_comp \t \t " ;
static const CHAR service_control_dat [ ] = " ServiceControl \t Name \t Event \t Arguments \t Wait \t Component_ \n "
" s72 \t l255 \t i2 \t L255 \t I2 \t s72 \n "
" ServiceControl \t ServiceControl \n "
" ServiceControl \t TestService \t 8 \t \t 0 \t service_comp " ;
typedef struct _msi_table
{
const CHAR * filename ;
const CHAR * data ;
int size ;
} msi_table ;
# define ADD_TABLE(x) {#x".idt", x##_dat, sizeof(x##_dat)}
static const msi_table tables [ ] =
{
ADD_TABLE ( component ) ,
ADD_TABLE ( directory ) ,
ADD_TABLE ( feature ) ,
ADD_TABLE ( feature_comp ) ,
ADD_TABLE ( file ) ,
ADD_TABLE ( install_exec_seq ) ,
ADD_TABLE ( media ) ,
ADD_TABLE ( property ) ,
ADD_TABLE ( registry ) ,
ADD_TABLE ( service_install ) ,
ADD_TABLE ( service_control )
} ;
/*
* Database Helpers
*/
static void write_file ( const CHAR * filename , const char * data , int data_size )
{
DWORD size ;
HANDLE hf = CreateFile ( filename , GENERIC_WRITE , 0 , NULL ,
CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL , NULL ) ;
WriteFile ( hf , data , data_size , & size , NULL ) ;
CloseHandle ( hf ) ;
}
static void write_msi_summary_info ( MSIHANDLE db )
{
MSIHANDLE summary ;
UINT r ;
r = MsiGetSummaryInformationA ( db , NULL , 4 , & summary ) ;
ok ( r = = ERROR_SUCCESS , " Expected ERROR_SUCCESS, got %u \n " , r ) ;
r = MsiSummaryInfoSetPropertyA ( summary , PID_TEMPLATE , VT_LPSTR , 0 , NULL , " ;1033 " ) ;
ok ( r = = ERROR_SUCCESS , " Expected ERROR_SUCCESS, got %u \n " , r ) ;
r = MsiSummaryInfoSetPropertyA ( summary , PID_REVNUMBER , VT_LPSTR , 0 , NULL ,
" {004757CA-5092-49c2-AD20-28E1CE0DF5F2} " ) ;
ok ( r = = ERROR_SUCCESS , " Expected ERROR_SUCCESS, got %u \n " , r ) ;
r = MsiSummaryInfoSetPropertyA ( summary , PID_PAGECOUNT , VT_I4 , 100 , NULL , NULL ) ;
ok ( r = = ERROR_SUCCESS , " Expected ERROR_SUCCESS, got %u \n " , r ) ;
r = MsiSummaryInfoSetPropertyA ( summary , PID_WORDCOUNT , VT_I4 , 0 , NULL , NULL ) ;
ok ( r = = ERROR_SUCCESS , " Expected ERROR_SUCCESS, got %u \n " , r ) ;
/* write the summary changes back to the stream */
r = MsiSummaryInfoPersist ( summary ) ;
ok ( r = = ERROR_SUCCESS , " Expected ERROR_SUCCESS, got %u \n " , r ) ;
MsiCloseHandle ( summary ) ;
}
static void create_database ( const CHAR * name , const msi_table * tables , int num_tables )
{
MSIHANDLE db ;
UINT r ;
int j ;
r = MsiOpenDatabaseA ( name , MSIDBOPEN_CREATE , & db ) ;
ok ( r = = ERROR_SUCCESS , " Expected ERROR_SUCCESS, got %u \n " , r ) ;
/* import the tables into the database */
for ( j = 0 ; j < num_tables ; j + + )
{
const msi_table * table = & tables [ j ] ;
write_file ( table - > filename , table - > data , ( table - > size - 1 ) * sizeof ( char ) ) ;
r = MsiDatabaseImportA ( db , CURR_DIR , table - > filename ) ;
ok ( r = = ERROR_SUCCESS , " Expected ERROR_SUCCESS, got %u \n " , r ) ;
DeleteFileA ( table - > filename ) ;
}
write_msi_summary_info ( db ) ;
r = MsiDatabaseCommit ( db ) ;
ok ( r = = ERROR_SUCCESS , " Expected ERROR_SUCCESS, got %u \n " , r ) ;
MsiCloseHandle ( db ) ;
}
2007-05-14 19:14:42 +02:00
/*
* Installation helpers
*/
static char PROG_FILES_DIR [ MAX_PATH ] ;
static BOOL get_program_files_dir ( LPSTR buf )
{
HKEY hkey ;
DWORD type = REG_EXPAND_SZ , size ;
if ( RegOpenKey ( HKEY_LOCAL_MACHINE ,
" Software \\ Microsoft \\ Windows \\ CurrentVersion " , & hkey ) )
return FALSE ;
size = MAX_PATH ;
if ( RegQueryValueEx ( hkey , " ProgramFilesDir " , 0 , & type , ( LPBYTE ) buf , & size ) )
return FALSE ;
RegCloseKey ( hkey ) ;
return TRUE ;
}
static void create_file ( const CHAR * name , DWORD size )
{
HANDLE file ;
DWORD written , left ;
file = CreateFileA ( name , GENERIC_WRITE , 0 , NULL , CREATE_ALWAYS , 0 , NULL ) ;
ok ( file ! = INVALID_HANDLE_VALUE , " Failure to open file %s \n " , name ) ;
WriteFile ( file , name , strlen ( name ) , & written , NULL ) ;
WriteFile ( file , " \n " , strlen ( " \n " ) , & written , NULL ) ;
left = size - lstrlen ( name ) - 1 ;
SetFilePointer ( file , left , NULL , FILE_CURRENT ) ;
SetEndOfFile ( file ) ;
CloseHandle ( file ) ;
}
static void create_test_files ( void )
{
CreateDirectoryA ( " msitest " , NULL ) ;
create_file ( " msitest \\ one.txt " , 100 ) ;
CreateDirectoryA ( " msitest \\ first " , NULL ) ;
create_file ( " msitest \\ first \\ two.txt " , 100 ) ;
CreateDirectoryA ( " msitest \\ second " , NULL ) ;
create_file ( " msitest \\ second \\ three.txt " , 100 ) ;
CreateDirectoryA ( " msitest \\ cabout " , NULL ) ;
create_file ( " msitest \\ cabout \\ four.txt " , 100 ) ;
CreateDirectoryA ( " msitest \\ cabout \\ new " , NULL ) ;
create_file ( " msitest \\ cabout \\ new \\ five.txt " , 100 ) ;
create_file ( " msitest \\ filename " , 100 ) ;
create_file ( " msitest \\ service.exe " , 100 ) ;
}
static BOOL delete_pf ( const CHAR * rel_path , BOOL is_file )
{
CHAR path [ MAX_PATH ] ;
lstrcpyA ( path , PROG_FILES_DIR ) ;
lstrcatA ( path , " \\ " ) ;
lstrcatA ( path , rel_path ) ;
if ( is_file )
return DeleteFileA ( path ) ;
else
return RemoveDirectoryA ( path ) ;
}
static void delete_test_files ( void )
{
DeleteFileA ( msifile ) ;
DeleteFileA ( " msitest \\ cabout \\ new \\ five.txt " ) ;
DeleteFileA ( " msitest \\ cabout \\ four.txt " ) ;
DeleteFileA ( " msitest \\ second \\ three.txt " ) ;
DeleteFileA ( " msitest \\ first \\ two.txt " ) ;
DeleteFileA ( " msitest \\ one.txt " ) ;
DeleteFileA ( " msitest \\ service.exe " ) ;
DeleteFileA ( " msitest \\ filename " ) ;
RemoveDirectoryA ( " msitest \\ cabout \\ new " ) ;
RemoveDirectoryA ( " msitest \\ cabout " ) ;
RemoveDirectoryA ( " msitest \\ second " ) ;
RemoveDirectoryA ( " msitest \\ first " ) ;
RemoveDirectoryA ( " msitest " ) ;
}
static void check_service_is_installed ( void )
{
SC_HANDLE scm , service ;
BOOL res ;
scm = OpenSCManager ( NULL , NULL , SC_MANAGER_ALL_ACCESS ) ;
ok ( scm ! = NULL , " Failed to open the SC Manager \n " ) ;
service = OpenService ( scm , " TestService " , SC_MANAGER_ALL_ACCESS ) ;
todo_wine ok ( service ! = NULL , " Failed to open TestService \n " ) ;
res = DeleteService ( service ) ;
todo_wine ok ( res , " Failed to delete TestService \n " ) ;
}
2007-04-29 03:12:09 +02:00
/*
* Automation helpers and tests
*/
/* ok-like statement which takes two unicode strings as arguments */
static CHAR string1 [ MAX_PATH ] , string2 [ MAX_PATH ] ;
# define ok_w2(format, szString1, szString2) \
\
if ( lstrcmpW ( szString1 , szString2 ) ! = 0 ) \
{ \
2007-05-08 00:51:36 +02:00
WideCharToMultiByte ( CP_ACP , 0 , szString1 , - 1 , string1 , MAX_PATH , NULL , NULL ) ; \
WideCharToMultiByte ( CP_ACP , 0 , szString2 , - 1 , string2 , MAX_PATH , NULL , NULL ) ; \
2007-04-29 03:12:09 +02:00
ok ( 0 , format , string1 , string2 ) ; \
}
/* exception checker */
static WCHAR szSource [ ] = { ' M ' , ' s ' , ' i ' , ' ' , ' A ' , ' P ' , ' I ' , ' ' , ' E ' , ' r ' , ' r ' , ' o ' , ' r ' , 0 } ;
# define ok_exception(hr, szDescription) \
if ( hr = = DISP_E_EXCEPTION ) \
{ \
/* Compare wtype, source, and destination */ \
ok ( excepinfo . wCode = = 1000 , " Exception info was %d, expected 1000 \n " , excepinfo . wCode ) ; \
\
ok ( excepinfo . bstrSource ! = NULL , " Exception source was NULL \n " ) ; \
if ( excepinfo . bstrSource ) \
ok_w2 ( " Exception source was \" %s \" but expected to be \" %s \" \n " , excepinfo . bstrSource , szSource ) ; \
\
ok ( excepinfo . bstrDescription ! = NULL , " Exception description was NULL \n " ) ; \
2007-05-08 00:52:07 +02:00
if ( excepinfo . bstrDescription ) \
ok_w2 ( " Exception description was \" %s \" but expected to be \" %s \" \n " , excepinfo . bstrDescription , szDescription ) ; \
2007-04-29 03:12:09 +02:00
}
2007-05-01 03:53:26 +02:00
static DISPID get_dispid ( IDispatch * disp , const char * name )
{
LPOLESTR str ;
UINT len ;
2007-05-04 02:01:10 +02:00
DISPID id = - 1 ;
2007-05-01 03:53:26 +02:00
HRESULT r ;
len = MultiByteToWideChar ( CP_ACP , 0 , name , - 1 , NULL , 0 ) ;
str = HeapAlloc ( GetProcessHeap ( ) , 0 , len * sizeof ( WCHAR ) ) ;
2007-05-04 02:01:10 +02:00
if ( str )
{
len = MultiByteToWideChar ( CP_ACP , 0 , name , - 1 , str , len ) ;
r = IDispatch_GetIDsOfNames ( disp , & IID_NULL , & str , 1 , 0 , & id ) ;
HeapFree ( GetProcessHeap ( ) , 0 , str ) ;
if ( r ! = S_OK )
return - 1 ;
}
2007-05-01 03:53:26 +02:00
return id ;
}
static void test_dispid ( void )
{
ok ( get_dispid ( pInstaller , " CreateRecord " ) = = 1 , " dispid wrong \n " ) ;
2007-05-08 00:50:30 +02:00
ok ( get_dispid ( pInstaller , " OpenPackage " ) = = 2 , " dispid wrong \n " ) ;
todo_wine {
2007-05-01 03:53:26 +02:00
ok ( get_dispid ( pInstaller , " OpenProduct " ) = = 3 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " OpenDatabase " ) = = 4 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " SummaryInformation " ) = = 5 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " UILevel " ) = = 6 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " EnableLog " ) = = 7 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " InstallProduct " ) = = 8 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " Version " ) = = 9 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " LastErrorRecord " ) = = 10 , " dispid wrong \n " ) ;
2007-05-10 22:40:28 +02:00
}
2007-05-01 03:53:26 +02:00
ok ( get_dispid ( pInstaller , " RegistryValue " ) = = 11 , " dispid wrong \n " ) ;
2007-05-10 22:40:28 +02:00
todo_wine {
2007-05-01 03:53:26 +02:00
ok ( get_dispid ( pInstaller , " Environment " ) = = 12 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " FileAttributes " ) = = 13 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " FileSize " ) = = 15 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " FileVersion " ) = = 16 , " dispid wrong \n " ) ;
2007-05-08 00:50:30 +02:00
}
2007-05-01 03:53:26 +02:00
ok ( get_dispid ( pInstaller , " ProductState " ) = = 17 , " dispid wrong \n " ) ;
2007-05-08 00:50:30 +02:00
todo_wine {
2007-05-01 03:53:26 +02:00
ok ( get_dispid ( pInstaller , " ProductInfo " ) = = 18 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " ConfigureProduct " ) = = 19 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " ReinstallProduct " ) = = 20 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " CollectUserInfo " ) = = 21 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " ApplyPatch " ) = = 22 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " FeatureParent " ) = = 23 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " FeatureState " ) = = 24 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " UseFeature " ) = = 25 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " FeatureUsageCount " ) = = 26 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " FeatureUsageDate " ) = = 27 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " ConfigureFeature " ) = = 28 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " ReinstallFeature " ) = = 29 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " ProvideComponent " ) = = 30 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " ComponentPath " ) = = 31 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " ProvideQualifiedComponent " ) = = 32 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " QualifierDescription " ) = = 33 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " ComponentQualifiers " ) = = 34 , " dispid wrong \n " ) ;
2007-05-08 00:50:30 +02:00
}
2007-05-01 03:53:26 +02:00
ok ( get_dispid ( pInstaller , " Products " ) = = 35 , " dispid wrong \n " ) ;
2007-05-08 00:50:30 +02:00
todo_wine {
2007-05-01 03:53:26 +02:00
ok ( get_dispid ( pInstaller , " Features " ) = = 36 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " Components " ) = = 37 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " ComponentClients " ) = = 38 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " Patches " ) = = 39 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " RelatedProducts " ) = = 40 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " PatchInfo " ) = = 41 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " PatchTransforms " ) = = 42 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " AddSource " ) = = 43 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " ClearSourceList " ) = = 44 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " ForceSourceListResolution " ) = = 45 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " ShortcutTarget " ) = = 46 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " FileHash " ) = = 47 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " FileSignatureInfo " ) = = 48 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " RemovePatches " ) = = 49 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " ApplyMultiplePatches " ) = = 51 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " ProductsEx " ) = = 52 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " PatchesEx " ) = = 55 , " dispid wrong \n " ) ;
ok ( get_dispid ( pInstaller , " ExtractPatchXMLData " ) = = 57 , " dispid wrong \n " ) ;
}
/* MSDN claims the following functions exist but IDispatch->GetIDsOfNames disagrees */
if ( 0 )
{
get_dispid ( pInstaller , " ProductElevated " ) ;
get_dispid ( pInstaller , " ProductInfoFromScript " ) ;
get_dispid ( pInstaller , " ProvideAssembly " ) ;
get_dispid ( pInstaller , " CreateAdvertiseScript " ) ;
get_dispid ( pInstaller , " AdvertiseProduct " ) ;
get_dispid ( pInstaller , " PatchFiles " ) ;
}
}
2007-04-29 03:12:09 +02:00
/* Test basic IDispatch functions */
static void test_dispatch ( void )
{
2007-05-04 02:02:06 +02:00
static WCHAR szOpenPackage [ ] = { ' O ' , ' p ' , ' e ' , ' n ' , ' P ' , ' a ' , ' c ' , ' k ' , ' a ' , ' g ' , ' e ' , 0 } ;
2007-04-29 03:12:09 +02:00
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 } ;
2007-05-11 21:08:04 +02:00
static WCHAR szProductState [ ] = { ' P ' , ' r ' , ' o ' , ' d ' , ' u ' , ' c ' , ' t ' , ' S ' , ' t ' , ' a ' , ' t ' , ' e ' , 0 } ;
2007-04-29 03:12:09 +02:00
HRESULT hr ;
DISPID dispid ;
OLECHAR * name ;
VARIANT varresult ;
VARIANTARG vararg [ 2 ] ;
DISPPARAMS dispparams = { NULL , NULL , 0 , 0 } ;
/* Test getting ID of a function name that does not exist */
name = ( WCHAR * ) szMsifile ;
hr = IDispatch_GetIDsOfNames ( pInstaller , & IID_NULL , & name , 1 , LOCALE_USER_DEFAULT , & dispid ) ;
ok ( hr = = DISP_E_UNKNOWNNAME , " IDispatch::GetIDsOfNames returned 0x%08x \n " , hr ) ;
/* Test invoking this function */
hr = IDispatch_Invoke ( pInstaller , dispid , & IID_NULL , LOCALE_NEUTRAL , DISPATCH_METHOD , NULL , NULL , NULL , NULL ) ;
ok ( hr = = DISP_E_MEMBERNOTFOUND , " IDispatch::Invoke returned 0x%08x \n " , hr ) ;
/* Test getting ID of a function name that does exist */
name = ( WCHAR * ) szOpenPackage ;
hr = IDispatch_GetIDsOfNames ( pInstaller , & IID_NULL , & name , 1 , LOCALE_USER_DEFAULT , & dispid ) ;
ok ( SUCCEEDED ( hr ) , " IDispatch::GetIDsOfNames returned 0x%08x \n " , hr ) ;
/* Test invoking this function (without parameters passed) */
if ( 0 ) /* All of these crash MSI on Windows XP */
{
hr = IDispatch_Invoke ( pInstaller , dispid , & IID_NULL , LOCALE_NEUTRAL , DISPATCH_METHOD , NULL , NULL , NULL , NULL ) ;
hr = IDispatch_Invoke ( pInstaller , dispid , & IID_NULL , LOCALE_NEUTRAL , DISPATCH_METHOD , NULL , NULL , & excepinfo , NULL ) ;
VariantInit ( & varresult ) ;
hr = IDispatch_Invoke ( pInstaller , dispid , & IID_NULL , LOCALE_NEUTRAL , DISPATCH_METHOD , NULL , & varresult , & excepinfo , NULL ) ;
}
/* Try with NULL params */
hr = IDispatch_Invoke ( pInstaller , dispid , & IID_NULL , LOCALE_NEUTRAL , DISPATCH_METHOD , & dispparams , & varresult , & excepinfo , NULL ) ;
2007-05-01 03:54:31 +02:00
todo_wine ok ( hr = = DISP_E_TYPEMISMATCH , " IDispatch::Invoke returned 0x%08x \n " , hr ) ;
2007-04-29 03:12:09 +02:00
/* Try one empty parameter */
dispparams . rgvarg = vararg ;
dispparams . cArgs = 1 ;
VariantInit ( & vararg [ 0 ] ) ;
hr = IDispatch_Invoke ( pInstaller , dispid , & IID_NULL , LOCALE_NEUTRAL , DISPATCH_METHOD , & dispparams , & varresult , & excepinfo , NULL ) ;
2007-05-01 03:54:31 +02:00
todo_wine ok ( hr = = DISP_E_TYPEMISMATCH , " IDispatch::Invoke returned 0x%08x \n " , hr ) ;
2007-04-29 03:12:09 +02:00
/* Try one parameter, function requires two */
VariantInit ( & vararg [ 0 ] ) ;
V_VT ( & vararg [ 0 ] ) = VT_BSTR ;
V_BSTR ( & vararg [ 0 ] ) = SysAllocString ( szMsifile ) ;
hr = IDispatch_Invoke ( pInstaller , dispid , & IID_NULL , LOCALE_NEUTRAL , DISPATCH_METHOD , & dispparams , & varresult , & excepinfo , NULL ) ;
VariantClear ( & vararg [ 0 ] ) ;
ok ( hr = = DISP_E_EXCEPTION , " IDispatch::Invoke returned 0x%08x \n " , hr ) ;
ok_exception ( hr , szOpenPackageException ) ;
2007-05-11 21:08:04 +02:00
/* Test invoking a method as a DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT */
VariantInit ( & vararg [ 0 ] ) ;
hr = IDispatch_Invoke ( pInstaller , dispid , & IID_NULL , LOCALE_NEUTRAL , DISPATCH_PROPERTYGET , & dispparams , & varresult , & excepinfo , NULL ) ;
2007-05-11 21:08:08 +02:00
ok ( hr = = DISP_E_MEMBERNOTFOUND , " IDispatch::Invoke returned 0x%08x \n " , hr ) ;
2007-05-11 21:08:04 +02:00
VariantInit ( & vararg [ 0 ] ) ;
hr = IDispatch_Invoke ( pInstaller , dispid , & IID_NULL , LOCALE_NEUTRAL , DISPATCH_PROPERTYPUT , & dispparams , & varresult , & excepinfo , NULL ) ;
2007-05-11 21:08:08 +02:00
ok ( hr = = DISP_E_MEMBERNOTFOUND , " IDispatch::Invoke returned 0x%08x \n " , hr ) ;
2007-05-11 21:08:04 +02:00
/* Test invoking a read-only property as DISPATCH_PROPERTYPUT or as a DISPATCH_METHOD */
name = ( WCHAR * ) szProductState ;
hr = IDispatch_GetIDsOfNames ( pInstaller , & IID_NULL , & name , 1 , LOCALE_USER_DEFAULT , & dispid ) ;
ok ( SUCCEEDED ( hr ) , " IDispatch::GetIDsOfNames returned 0x%08x \n " , hr ) ;
dispparams . rgvarg = NULL ;
dispparams . cArgs = 0 ;
hr = IDispatch_Invoke ( pInstaller , dispid , & IID_NULL , LOCALE_NEUTRAL , DISPATCH_PROPERTYPUT , & dispparams , & varresult , & excepinfo , NULL ) ;
2007-05-11 21:08:08 +02:00
ok ( hr = = DISP_E_MEMBERNOTFOUND , " IDispatch::Invoke returned 0x%08x \n " , hr ) ;
2007-05-11 21:08:04 +02:00
dispparams . rgvarg = NULL ;
dispparams . cArgs = 0 ;
hr = IDispatch_Invoke ( pInstaller , dispid , & IID_NULL , LOCALE_NEUTRAL , DISPATCH_METHOD , & dispparams , & varresult , & excepinfo , NULL ) ;
2007-05-11 21:08:08 +02:00
ok ( hr = = DISP_E_MEMBERNOTFOUND , " IDispatch::Invoke returned 0x%08x \n " , hr ) ;
2007-04-29 03:12:09 +02:00
}
/* invocation helper function */
2007-05-04 02:02:06 +02:00
static HRESULT invoke ( IDispatch * pDispatch , LPCSTR szName , WORD wFlags , DISPPARAMS * pDispParams , VARIANT * pVarResult , VARTYPE vtResult )
2007-04-29 03:12:09 +02:00
{
2007-05-04 02:02:06 +02:00
OLECHAR * name = NULL ;
2007-04-29 03:12:09 +02:00
DISPID dispid ;
HRESULT hr ;
int i ;
2007-05-04 02:02:06 +02:00
UINT len ;
2007-04-29 03:12:09 +02:00
2007-05-04 02:02:31 +02:00
memset ( pVarResult , 0 , sizeof ( VARIANT ) ) ;
VariantInit ( pVarResult ) ;
2007-05-04 02:02:06 +02:00
len = MultiByteToWideChar ( CP_ACP , 0 , szName , - 1 , NULL , 0 ) ;
name = HeapAlloc ( GetProcessHeap ( ) , 0 , len * sizeof ( WCHAR ) ) ;
if ( ! name ) return E_FAIL ;
len = MultiByteToWideChar ( CP_ACP , 0 , szName , - 1 , name , len ) ;
2007-04-29 03:12:09 +02:00
hr = IDispatch_GetIDsOfNames ( pDispatch , & IID_NULL , & name , 1 , LOCALE_USER_DEFAULT , & dispid ) ;
2007-05-04 02:02:06 +02:00
HeapFree ( GetProcessHeap ( ) , 0 , name ) ;
2007-04-29 03:12:09 +02:00
ok ( SUCCEEDED ( hr ) , " IDispatch::GetIDsOfNames returned 0x%08x \n " , hr ) ;
if ( ! SUCCEEDED ( hr ) ) return hr ;
memset ( & excepinfo , 0 , sizeof ( excepinfo ) ) ;
hr = IDispatch_Invoke ( pDispatch , dispid , & IID_NULL , LOCALE_NEUTRAL , wFlags , pDispParams , pVarResult , & excepinfo , NULL ) ;
if ( SUCCEEDED ( hr ) )
{
ok ( V_VT ( pVarResult ) = = vtResult , " Variant result type is %d, expected %d \n " , V_VT ( pVarResult ) , vtResult ) ;
if ( vtResult ! = VT_EMPTY )
{
hr = VariantChangeTypeEx ( pVarResult , pVarResult , LOCALE_NEUTRAL , 0 , vtResult ) ;
ok ( SUCCEEDED ( hr ) , " VariantChangeTypeEx returned 0x%08x \n " , hr ) ;
}
}
for ( i = 0 ; i < pDispParams - > cArgs ; i + + )
VariantClear ( & pDispParams - > rgvarg [ i ] ) ;
return hr ;
}
/* Object_Property helper functions */
2007-05-04 02:02:31 +02:00
static HRESULT Installer_CreateRecord ( int count , IDispatch * * pRecord )
{
VARIANT varresult ;
VARIANTARG vararg [ 1 ] ;
DISPPARAMS dispparams = { vararg , NULL , sizeof ( vararg ) / sizeof ( VARIANTARG ) , 0 } ;
HRESULT hr ;
VariantInit ( & vararg [ 0 ] ) ;
V_VT ( & vararg [ 0 ] ) = VT_I4 ;
V_I4 ( & vararg [ 0 ] ) = count ;
hr = invoke ( pInstaller , " CreateRecord " , DISPATCH_METHOD , & dispparams , & varresult , VT_DISPATCH ) ;
* pRecord = V_DISPATCH ( & varresult ) ;
return hr ;
}
2007-05-09 14:56:44 +02:00
static HRESULT Installer_RegistryValue ( HKEY hkey , LPCWSTR szKey , VARIANT vValue , VARIANT * pVarResult , VARTYPE vtExpect )
2007-05-08 00:51:36 +02:00
{
VARIANTARG vararg [ 3 ] ;
DISPPARAMS dispparams = { vararg , NULL , sizeof ( vararg ) / sizeof ( VARIANTARG ) , 0 } ;
VariantInit ( & vararg [ 2 ] ) ;
V_VT ( & vararg [ 2 ] ) = VT_I4 ;
V_I4 ( & vararg [ 2 ] ) = ( int ) hkey ;
VariantInit ( & vararg [ 1 ] ) ;
V_VT ( & vararg [ 1 ] ) = VT_BSTR ;
V_BSTR ( & vararg [ 1 ] ) = SysAllocString ( szKey ) ;
VariantInit ( & vararg [ 0 ] ) ;
2007-05-09 14:56:44 +02:00
VariantCopy ( & vararg [ 0 ] , & vValue ) ;
VariantClear ( & vValue ) ;
return invoke ( pInstaller , " RegistryValue " , DISPATCH_METHOD , & dispparams , pVarResult , vtExpect ) ;
}
static HRESULT Installer_RegistryValueE ( HKEY hkey , LPCWSTR szKey , BOOL * pBool )
{
VARIANT varresult ;
VARIANTARG vararg ;
HRESULT hr ;
2007-05-08 00:51:36 +02:00
2007-05-09 14:56:44 +02:00
VariantInit ( & vararg ) ;
V_VT ( & vararg ) = VT_EMPTY ;
hr = Installer_RegistryValue ( hkey , szKey , vararg , & varresult , VT_BOOL ) ;
2007-05-08 00:51:36 +02:00
* pBool = V_BOOL ( & varresult ) ;
VariantClear ( & varresult ) ;
return hr ;
}
static HRESULT Installer_RegistryValueW ( HKEY hkey , LPCWSTR szKey , LPCWSTR szValue , LPWSTR szString )
{
VARIANT varresult ;
2007-05-09 14:56:44 +02:00
VARIANTARG vararg ;
2007-05-08 00:51:36 +02:00
HRESULT hr ;
2007-05-09 14:56:44 +02:00
VariantInit ( & vararg ) ;
V_VT ( & vararg ) = VT_BSTR ;
V_BSTR ( & vararg ) = SysAllocString ( szValue ) ;
2007-05-08 00:51:36 +02:00
2007-05-09 14:56:44 +02:00
hr = Installer_RegistryValue ( hkey , szKey , vararg , & varresult , VT_BSTR ) ;
2007-05-08 00:51:36 +02:00
lstrcpyW ( szString , V_BSTR ( & varresult ) ) ;
VariantClear ( & varresult ) ;
return hr ;
}
static HRESULT Installer_RegistryValueI ( HKEY hkey , LPCWSTR szKey , int iValue , LPWSTR szString , VARTYPE vtResult )
{
VARIANT varresult ;
2007-05-09 14:56:44 +02:00
VARIANTARG vararg ;
2007-05-08 00:51:36 +02:00
HRESULT hr ;
2007-05-09 14:56:44 +02:00
VariantInit ( & vararg ) ;
V_VT ( & vararg ) = VT_I4 ;
V_I4 ( & vararg ) = iValue ;
2007-05-08 00:51:36 +02:00
2007-05-09 14:56:44 +02:00
hr = Installer_RegistryValue ( hkey , szKey , vararg , & varresult , vtResult ) ;
2007-05-08 00:51:36 +02:00
if ( vtResult = = VT_BSTR ) lstrcpyW ( szString , V_BSTR ( & varresult ) ) ;
VariantClear ( & varresult ) ;
return hr ;
}
2007-04-29 03:12:09 +02:00
static HRESULT Installer_OpenPackage ( LPCWSTR szPackagePath , int options , IDispatch * * pSession )
{
VARIANT varresult ;
VARIANTARG vararg [ 2 ] ;
DISPPARAMS dispparams = { vararg , NULL , sizeof ( vararg ) / sizeof ( VARIANTARG ) , 0 } ;
HRESULT hr ;
VariantInit ( & vararg [ 1 ] ) ;
V_VT ( & vararg [ 1 ] ) = VT_BSTR ;
V_BSTR ( & vararg [ 1 ] ) = SysAllocString ( szPackagePath ) ;
VariantInit ( & vararg [ 0 ] ) ;
V_VT ( & vararg [ 0 ] ) = VT_I4 ;
V_I4 ( & vararg [ 0 ] ) = options ;
2007-05-04 02:02:06 +02:00
hr = invoke ( pInstaller , " OpenPackage " , DISPATCH_METHOD , & dispparams , & varresult , VT_DISPATCH ) ;
2007-04-29 03:12:09 +02:00
* pSession = V_DISPATCH ( & varresult ) ;
return hr ;
}
2007-05-14 19:14:42 +02:00
static HRESULT Installer_InstallProduct ( LPCWSTR szPackagePath , LPCWSTR szPropertyValues )
{
VARIANT varresult ;
VARIANTARG vararg [ 2 ] ;
DISPPARAMS dispparams = { vararg , NULL , sizeof ( vararg ) / sizeof ( VARIANTARG ) , 0 } ;
VariantInit ( & vararg [ 1 ] ) ;
V_VT ( & vararg [ 1 ] ) = VT_BSTR ;
V_BSTR ( & vararg [ 1 ] ) = SysAllocString ( szPackagePath ) ;
VariantInit ( & vararg [ 0 ] ) ;
V_VT ( & vararg [ 0 ] ) = VT_BSTR ;
V_BSTR ( & vararg [ 0 ] ) = SysAllocString ( szPropertyValues ) ;
return invoke ( pInstaller , " InstallProduct " , DISPATCH_METHOD , & dispparams , & varresult , VT_EMPTY ) ;
}
2007-05-08 00:50:05 +02:00
static HRESULT Installer_ProductState ( LPCWSTR szProduct , int * pInstallState )
{
VARIANT varresult ;
VARIANTARG vararg [ 1 ] ;
DISPPARAMS dispparams = { vararg , NULL , sizeof ( vararg ) / sizeof ( VARIANTARG ) , 0 } ;
HRESULT hr ;
VariantInit ( & vararg [ 0 ] ) ;
V_VT ( & vararg [ 0 ] ) = VT_BSTR ;
V_BSTR ( & vararg [ 0 ] ) = SysAllocString ( szProduct ) ;
hr = invoke ( pInstaller , " ProductState " , DISPATCH_PROPERTYGET , & dispparams , & varresult , VT_I4 ) ;
* pInstallState = V_I4 ( & varresult ) ;
VariantClear ( & varresult ) ;
return hr ;
}
static HRESULT Installer_Products ( IDispatch * * pStringList )
{
VARIANT varresult ;
DISPPARAMS dispparams = { NULL , NULL , 0 , 0 } ;
HRESULT hr ;
hr = invoke ( pInstaller , " Products " , DISPATCH_PROPERTYGET , & dispparams , & varresult , VT_DISPATCH ) ;
* pStringList = V_DISPATCH ( & varresult ) ;
return hr ;
}
2007-05-04 02:02:31 +02:00
static HRESULT Installer_VersionGet ( LPCWSTR szVersion )
{
VARIANT varresult ;
DISPPARAMS dispparams = { NULL , NULL , 0 , 0 } ;
HRESULT hr ;
hr = invoke ( pInstaller , " Version " , DISPATCH_PROPERTYGET , & dispparams , & varresult , VT_BSTR ) ;
lstrcpyW ( ( WCHAR * ) szVersion , V_BSTR ( & varresult ) ) ;
VariantClear ( & varresult ) ;
return hr ;
}
2007-05-05 06:17:56 +02:00
static HRESULT Session_Installer ( IDispatch * pSession , IDispatch * * pInst )
{
VARIANT varresult ;
DISPPARAMS dispparams = { NULL , NULL , 0 , 0 } ;
HRESULT hr ;
hr = invoke ( pSession , " Installer " , DISPATCH_PROPERTYGET , & dispparams , & varresult , VT_DISPATCH ) ;
* pInst = V_DISPATCH ( & varresult ) ;
return hr ;
}
2007-04-29 03:12:09 +02:00
static HRESULT Session_PropertyGet ( IDispatch * pSession , LPCWSTR szName , LPCWSTR szReturn )
{
VARIANT varresult ;
VARIANTARG vararg [ 1 ] ;
DISPPARAMS dispparams = { vararg , NULL , sizeof ( vararg ) / sizeof ( VARIANTARG ) , 0 } ;
HRESULT hr ;
VariantInit ( & vararg [ 0 ] ) ;
V_VT ( & vararg [ 0 ] ) = VT_BSTR ;
V_BSTR ( & vararg [ 0 ] ) = SysAllocString ( szName ) ;
2007-05-04 02:02:06 +02:00
hr = invoke ( pSession , " Property " , DISPATCH_PROPERTYGET , & dispparams , & varresult , VT_BSTR ) ;
2007-04-29 03:12:09 +02:00
lstrcpyW ( ( WCHAR * ) szReturn , V_BSTR ( & varresult ) ) ;
VariantClear ( & varresult ) ;
return hr ;
}
static HRESULT Session_PropertyPut ( IDispatch * pSession , LPCWSTR szName , LPCWSTR szValue )
{
VARIANT varresult ;
VARIANTARG vararg [ 2 ] ;
DISPID dispid = DISPID_PROPERTYPUT ;
DISPPARAMS dispparams = { vararg , & dispid , sizeof ( vararg ) / sizeof ( VARIANTARG ) , 1 } ;
VariantInit ( & vararg [ 1 ] ) ;
V_VT ( & vararg [ 1 ] ) = VT_BSTR ;
V_BSTR ( & vararg [ 1 ] ) = SysAllocString ( szName ) ;
VariantInit ( & vararg [ 0 ] ) ;
V_VT ( & vararg [ 0 ] ) = VT_BSTR ;
V_BSTR ( & vararg [ 0 ] ) = SysAllocString ( szValue ) ;
2007-05-04 02:02:06 +02:00
return invoke ( pSession , " Property " , DISPATCH_PROPERTYPUT , & dispparams , & varresult , VT_EMPTY ) ;
2007-04-29 03:12:09 +02:00
}
static HRESULT Session_LanguageGet ( IDispatch * pSession , UINT * pLangId )
{
VARIANT varresult ;
DISPPARAMS dispparams = { NULL , NULL , 0 , 0 } ;
HRESULT hr ;
2007-05-04 02:02:06 +02:00
hr = invoke ( pSession , " Language " , DISPATCH_PROPERTYGET , & dispparams , & varresult , VT_I4 ) ;
2007-04-29 03:12:09 +02:00
* pLangId = V_I4 ( & varresult ) ;
VariantClear ( & varresult ) ;
return hr ;
}
static HRESULT Session_ModeGet ( IDispatch * pSession , int iFlag , BOOL * pMode )
{
VARIANT varresult ;
VARIANTARG vararg [ 1 ] ;
DISPPARAMS dispparams = { vararg , NULL , sizeof ( vararg ) / sizeof ( VARIANTARG ) , 0 } ;
HRESULT hr ;
VariantInit ( & vararg [ 0 ] ) ;
V_VT ( & vararg [ 0 ] ) = VT_I4 ;
V_I4 ( & vararg [ 0 ] ) = iFlag ;
2007-05-04 02:02:06 +02:00
hr = invoke ( pSession , " Mode " , DISPATCH_PROPERTYGET , & dispparams , & varresult , VT_BOOL ) ;
2007-04-29 03:12:09 +02:00
* pMode = V_BOOL ( & varresult ) ;
VariantClear ( & varresult ) ;
return hr ;
}
static HRESULT Session_ModePut ( IDispatch * pSession , int iFlag , BOOL bMode )
{
VARIANT varresult ;
VARIANTARG vararg [ 2 ] ;
DISPID dispid = DISPID_PROPERTYPUT ;
DISPPARAMS dispparams = { vararg , & dispid , sizeof ( vararg ) / sizeof ( VARIANTARG ) , 1 } ;
VariantInit ( & vararg [ 1 ] ) ;
V_VT ( & vararg [ 1 ] ) = VT_I4 ;
V_I4 ( & vararg [ 1 ] ) = iFlag ;
VariantInit ( & vararg [ 0 ] ) ;
V_VT ( & vararg [ 0 ] ) = VT_BOOL ;
V_BOOL ( & vararg [ 0 ] ) = bMode ;
2007-05-04 02:02:06 +02:00
return invoke ( pSession , " Mode " , DISPATCH_PROPERTYPUT , & dispparams , & varresult , VT_EMPTY ) ;
2007-04-29 03:12:09 +02:00
}
static HRESULT Session_Database ( IDispatch * pSession , IDispatch * * pDatabase )
{
VARIANT varresult ;
DISPPARAMS dispparams = { NULL , NULL , 0 , 0 } ;
HRESULT hr ;
2007-05-04 02:02:06 +02:00
hr = invoke ( pSession , " Database " , DISPATCH_PROPERTYGET , & dispparams , & varresult , VT_DISPATCH ) ;
2007-04-29 03:12:09 +02:00
* pDatabase = V_DISPATCH ( & varresult ) ;
return hr ;
}
static HRESULT Session_DoAction ( IDispatch * pSession , LPCWSTR szAction , int * iReturn )
{
VARIANT varresult ;
VARIANTARG vararg [ 1 ] ;
DISPPARAMS dispparams = { vararg , NULL , sizeof ( vararg ) / sizeof ( VARIANTARG ) , 0 } ;
HRESULT hr ;
VariantInit ( & vararg [ 0 ] ) ;
V_VT ( & vararg [ 0 ] ) = VT_BSTR ;
V_BSTR ( & vararg [ 0 ] ) = SysAllocString ( szAction ) ;
2007-05-04 02:02:06 +02:00
hr = invoke ( pSession , " DoAction " , DISPATCH_METHOD , & dispparams , & varresult , VT_I4 ) ;
2007-04-29 03:12:09 +02:00
* iReturn = V_I4 ( & varresult ) ;
VariantClear ( & varresult ) ;
return hr ;
}
2007-05-11 21:07:41 +02:00
static HRESULT Session_EvaluateCondition ( IDispatch * pSession , LPCWSTR szCondition , int * iReturn )
{
VARIANT varresult ;
VARIANTARG vararg [ 1 ] ;
DISPPARAMS dispparams = { vararg , NULL , sizeof ( vararg ) / sizeof ( VARIANTARG ) , 0 } ;
HRESULT hr ;
VariantInit ( & vararg [ 0 ] ) ;
V_VT ( & vararg [ 0 ] ) = VT_BSTR ;
V_BSTR ( & vararg [ 0 ] ) = SysAllocString ( szCondition ) ;
hr = invoke ( pSession , " EvaluateCondition " , DISPATCH_METHOD , & dispparams , & varresult , VT_I4 ) ;
* iReturn = V_I4 ( & varresult ) ;
VariantClear ( & varresult ) ;
return hr ;
}
2007-04-29 03:12:09 +02:00
static HRESULT Session_SetInstallLevel ( IDispatch * pSession , long iInstallLevel )
{
VARIANT varresult ;
VARIANTARG vararg [ 1 ] ;
DISPPARAMS dispparams = { vararg , NULL , sizeof ( vararg ) / sizeof ( VARIANTARG ) , 0 } ;
VariantInit ( & vararg [ 0 ] ) ;
V_VT ( & vararg [ 0 ] ) = VT_I4 ;
V_I4 ( & vararg [ 0 ] ) = iInstallLevel ;
2007-05-04 02:02:06 +02:00
return invoke ( pSession , " SetInstallLevel " , DISPATCH_METHOD , & dispparams , & varresult , VT_EMPTY ) ;
2007-04-29 03:12:09 +02:00
}
static HRESULT Session_FeatureCurrentState ( IDispatch * pSession , LPCWSTR szName , int * pState )
{
VARIANT varresult ;
VARIANTARG vararg [ 1 ] ;
DISPPARAMS dispparams = { vararg , NULL , sizeof ( vararg ) / sizeof ( VARIANTARG ) , 0 } ;
HRESULT hr ;
VariantInit ( & vararg [ 0 ] ) ;
V_VT ( & vararg [ 0 ] ) = VT_BSTR ;
V_BSTR ( & vararg [ 0 ] ) = SysAllocString ( szName ) ;
2007-05-04 02:02:06 +02:00
hr = invoke ( pSession , " FeatureCurrentState " , DISPATCH_PROPERTYGET , & dispparams , & varresult , VT_I4 ) ;
2007-04-29 03:12:09 +02:00
* pState = V_I4 ( & varresult ) ;
VariantClear ( & varresult ) ;
return hr ;
}
static HRESULT Session_FeatureRequestStateGet ( IDispatch * pSession , LPCWSTR szName , int * pState )
{
VARIANT varresult ;
VARIANTARG vararg [ 1 ] ;
DISPPARAMS dispparams = { vararg , NULL , sizeof ( vararg ) / sizeof ( VARIANTARG ) , 0 } ;
HRESULT hr ;
VariantInit ( & vararg [ 0 ] ) ;
V_VT ( & vararg [ 0 ] ) = VT_BSTR ;
V_BSTR ( & vararg [ 0 ] ) = SysAllocString ( szName ) ;
2007-05-04 02:02:06 +02:00
hr = invoke ( pSession , " FeatureRequestState " , DISPATCH_PROPERTYGET , & dispparams , & varresult , VT_I4 ) ;
2007-04-29 03:12:09 +02:00
* pState = V_I4 ( & varresult ) ;
VariantClear ( & varresult ) ;
return hr ;
}
static HRESULT Session_FeatureRequestStatePut ( IDispatch * pSession , LPCWSTR szName , int iState )
{
VARIANT varresult ;
VARIANTARG vararg [ 2 ] ;
DISPID dispid = DISPID_PROPERTYPUT ;
DISPPARAMS dispparams = { vararg , & dispid , sizeof ( vararg ) / sizeof ( VARIANTARG ) , 1 } ;
VariantInit ( & vararg [ 1 ] ) ;
V_VT ( & vararg [ 1 ] ) = VT_BSTR ;
V_BSTR ( & vararg [ 1 ] ) = SysAllocString ( szName ) ;
VariantInit ( & vararg [ 0 ] ) ;
V_VT ( & vararg [ 0 ] ) = VT_I4 ;
V_I4 ( & vararg [ 0 ] ) = iState ;
2007-05-04 02:02:06 +02:00
return invoke ( pSession , " FeatureRequestState " , DISPATCH_PROPERTYPUT , & dispparams , & varresult , VT_EMPTY ) ;
2007-04-29 03:12:09 +02:00
}
static HRESULT Database_OpenView ( IDispatch * pDatabase , LPCWSTR szSql , IDispatch * * pView )
{
VARIANT varresult ;
VARIANTARG vararg [ 1 ] ;
DISPPARAMS dispparams = { vararg , NULL , sizeof ( vararg ) / sizeof ( VARIANTARG ) , 0 } ;
HRESULT hr ;
VariantInit ( & vararg [ 0 ] ) ;
V_VT ( & vararg [ 0 ] ) = VT_BSTR ;
V_BSTR ( & vararg [ 0 ] ) = SysAllocString ( szSql ) ;
2007-05-04 02:02:06 +02:00
hr = invoke ( pDatabase , " OpenView " , DISPATCH_METHOD , & dispparams , & varresult , VT_DISPATCH ) ;
2007-04-29 03:12:09 +02:00
* pView = V_DISPATCH ( & varresult ) ;
return hr ;
}
static HRESULT View_Execute ( IDispatch * pView , IDispatch * pRecord )
{
VARIANT varresult ;
VARIANTARG vararg [ 1 ] ;
DISPPARAMS dispparams = { vararg , NULL , sizeof ( vararg ) / sizeof ( VARIANTARG ) , 0 } ;
VariantInit ( & vararg [ 0 ] ) ;
V_VT ( & vararg [ 0 ] ) = VT_DISPATCH ;
V_DISPATCH ( & vararg [ 0 ] ) = pRecord ;
2007-05-04 02:02:06 +02:00
return invoke ( pView , " Execute " , DISPATCH_METHOD , & dispparams , & varresult , VT_EMPTY ) ;
2007-04-29 03:12:09 +02:00
}
static HRESULT View_Fetch ( IDispatch * pView , IDispatch * * ppRecord )
{
VARIANT varresult ;
DISPPARAMS dispparams = { NULL , NULL , 0 , 0 } ;
2007-05-04 02:02:06 +02:00
HRESULT hr = invoke ( pView , " Fetch " , DISPATCH_METHOD , & dispparams , & varresult , VT_DISPATCH ) ;
2007-04-29 03:12:09 +02:00
* ppRecord = V_DISPATCH ( & varresult ) ;
return hr ;
}
2007-05-11 21:08:38 +02:00
static HRESULT View_Modify ( IDispatch * pView , int iMode , IDispatch * pRecord )
{
VARIANT varresult ;
VARIANTARG vararg [ 2 ] ;
DISPPARAMS dispparams = { vararg , NULL , sizeof ( vararg ) / sizeof ( VARIANTARG ) , 0 } ;
VariantInit ( & vararg [ 1 ] ) ;
V_VT ( & vararg [ 1 ] ) = VT_I4 ;
V_I4 ( & vararg [ 1 ] ) = iMode ;
VariantInit ( & vararg [ 0 ] ) ;
V_VT ( & vararg [ 0 ] ) = VT_DISPATCH ;
V_DISPATCH ( & vararg [ 0 ] ) = pRecord ;
if ( pRecord )
IDispatch_AddRef ( pRecord ) ; /* VariantClear in invoke will call IDispatch_Release */
return invoke ( pView , " Modify " , DISPATCH_METHOD , & dispparams , & varresult , VT_EMPTY ) ;
}
2007-04-29 03:12:09 +02:00
static HRESULT View_Close ( IDispatch * pView )
{
VARIANT varresult ;
DISPPARAMS dispparams = { NULL , NULL , 0 , 0 } ;
2007-05-04 02:02:06 +02:00
return invoke ( pView , " Close " , DISPATCH_METHOD , & dispparams , & varresult , VT_EMPTY ) ;
2007-04-29 03:12:09 +02:00
}
2007-05-04 02:02:31 +02:00
static HRESULT Record_FieldCountGet ( IDispatch * pRecord , int * pFieldCount )
{
VARIANT varresult ;
DISPPARAMS dispparams = { NULL , NULL , 0 , 0 } ;
HRESULT hr = invoke ( pRecord , " FieldCount " , DISPATCH_PROPERTYGET , & dispparams , & varresult , VT_I4 ) ;
* pFieldCount = V_I4 ( & varresult ) ;
VariantClear ( & varresult ) ;
return hr ;
}
2007-04-29 03:12:09 +02:00
static HRESULT Record_StringDataGet ( IDispatch * pRecord , int iField , LPCWSTR szString )
{
VARIANT varresult ;
VARIANTARG vararg [ 1 ] ;
DISPPARAMS dispparams = { vararg , NULL , sizeof ( vararg ) / sizeof ( VARIANTARG ) , 0 } ;
HRESULT hr ;
VariantInit ( & vararg [ 0 ] ) ;
V_VT ( & vararg [ 0 ] ) = VT_I4 ;
V_I4 ( & vararg [ 0 ] ) = iField ;
2007-05-04 02:02:06 +02:00
hr = invoke ( pRecord , " StringData " , DISPATCH_PROPERTYGET , & dispparams , & varresult , VT_BSTR ) ;
2007-04-29 03:12:09 +02:00
lstrcpyW ( ( WCHAR * ) szString , V_BSTR ( & varresult ) ) ;
VariantClear ( & varresult ) ;
return hr ;
}
static HRESULT Record_StringDataPut ( IDispatch * pRecord , int iField , LPCWSTR szString )
{
VARIANT varresult ;
VARIANTARG vararg [ 2 ] ;
DISPID dispid = DISPID_PROPERTYPUT ;
DISPPARAMS dispparams = { vararg , & dispid , sizeof ( vararg ) / sizeof ( VARIANTARG ) , 1 } ;
VariantInit ( & vararg [ 1 ] ) ;
V_VT ( & vararg [ 1 ] ) = VT_I4 ;
V_I4 ( & vararg [ 1 ] ) = iField ;
VariantInit ( & vararg [ 0 ] ) ;
V_VT ( & vararg [ 0 ] ) = VT_BSTR ;
V_BSTR ( & vararg [ 0 ] ) = SysAllocString ( szString ) ;
2007-05-11 21:08:22 +02:00
return invoke ( pRecord , " StringData " , DISPATCH_PROPERTYPUT , & dispparams , & varresult , VT_EMPTY ) ;
2007-04-29 03:12:09 +02:00
}
2007-05-11 21:08:27 +02:00
static HRESULT Record_IntegerDataGet ( IDispatch * pRecord , int iField , int * pValue )
{
VARIANT varresult ;
VARIANTARG vararg [ 1 ] ;
DISPPARAMS dispparams = { vararg , NULL , sizeof ( vararg ) / sizeof ( VARIANTARG ) , 0 } ;
HRESULT hr ;
VariantInit ( & vararg [ 0 ] ) ;
V_VT ( & vararg [ 0 ] ) = VT_I4 ;
V_I4 ( & vararg [ 0 ] ) = iField ;
hr = invoke ( pRecord , " IntegerData " , DISPATCH_PROPERTYGET , & dispparams , & varresult , VT_I4 ) ;
* pValue = V_I4 ( & varresult ) ;
VariantClear ( & varresult ) ;
return hr ;
}
static HRESULT Record_IntegerDataPut ( IDispatch * pRecord , int iField , int iValue )
{
VARIANT varresult ;
VARIANTARG vararg [ 2 ] ;
DISPID dispid = DISPID_PROPERTYPUT ;
DISPPARAMS dispparams = { vararg , & dispid , sizeof ( vararg ) / sizeof ( VARIANTARG ) , 1 } ;
VariantInit ( & vararg [ 1 ] ) ;
V_VT ( & vararg [ 1 ] ) = VT_I4 ;
V_I4 ( & vararg [ 1 ] ) = iField ;
VariantInit ( & vararg [ 0 ] ) ;
V_VT ( & vararg [ 0 ] ) = VT_I4 ;
V_I4 ( & vararg [ 0 ] ) = iValue ;
return invoke ( pRecord , " IntegerData " , DISPATCH_PROPERTYPUT , & dispparams , & varresult , VT_EMPTY ) ;
}
2007-05-08 00:50:05 +02:00
static HRESULT StringList_Item ( IDispatch * pStringList , int iIndex , LPWSTR szString )
{
VARIANT varresult ;
VARIANTARG vararg [ 1 ] ;
DISPPARAMS dispparams = { vararg , NULL , sizeof ( vararg ) / sizeof ( VARIANTARG ) , 0 } ;
HRESULT hr ;
VariantInit ( & vararg [ 0 ] ) ;
V_VT ( & vararg [ 0 ] ) = VT_I4 ;
V_I4 ( & vararg [ 0 ] ) = iIndex ;
hr = invoke ( pStringList , " Item " , DISPATCH_PROPERTYGET , & dispparams , & varresult , VT_BSTR ) ;
lstrcpyW ( szString , V_BSTR ( & varresult ) ) ;
VariantClear ( & varresult ) ;
return hr ;
}
static HRESULT StringList_Count ( IDispatch * pStringList , int * pCount )
{
VARIANT varresult ;
DISPPARAMS dispparams = { NULL , NULL , 0 , 0 } ;
HRESULT hr = invoke ( pStringList , " Count " , DISPATCH_PROPERTYGET , & dispparams , & varresult , VT_I4 ) ;
* pCount = V_I4 ( & varresult ) ;
VariantClear ( & varresult ) ;
return hr ;
}
2007-04-29 03:12:09 +02:00
/* Test the various objects */
static void test_Database ( IDispatch * pDatabase )
{
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 } ;
static WCHAR szThree [ ] = { ' T ' , ' h ' , ' r ' , ' e ' , ' e ' , 0 } ;
static WCHAR szTwo [ ] = { ' T ' , ' w ' , ' o ' , 0 } ;
static WCHAR szStringDataField [ ] = { ' S ' , ' t ' , ' r ' , ' i ' , ' n ' , ' g ' , ' D ' , ' a ' , ' t ' , ' a ' , ' , ' , ' F ' , ' i ' , ' e ' , ' l ' , ' d ' , 0 } ;
2007-05-11 21:08:38 +02:00
static WCHAR szModifyModeRecord [ ] = { ' M ' , ' o ' , ' d ' , ' i ' , ' f ' , ' y ' , ' , ' , ' M ' , ' o ' , ' d ' , ' e ' , ' , ' , ' R ' , ' e ' , ' c ' , ' o ' , ' r ' , ' d ' , 0 } ;
2007-04-29 03:12:09 +02:00
IDispatch * pView = NULL ;
HRESULT hr ;
hr = Database_OpenView ( pDatabase , szSql , & pView ) ;
ok ( SUCCEEDED ( hr ) , " Database_OpenView failed, hresult 0x%08x \n " , hr ) ;
if ( SUCCEEDED ( hr ) )
{
IDispatch * pRecord = NULL ;
WCHAR szString [ MAX_PATH ] ;
/* View::Execute */
hr = View_Execute ( pView , NULL ) ;
ok ( SUCCEEDED ( hr ) , " View_Execute failed, hresult 0x%08x \n " , hr ) ;
/* View::Fetch */
hr = View_Fetch ( pView , & pRecord ) ;
ok ( SUCCEEDED ( hr ) , " View_Fetch failed, hresult 0x%08x \n " , hr ) ;
ok ( pRecord ! = NULL , " View_Fetch should not have returned NULL record \n " ) ;
if ( pRecord )
{
/* Record::StringDataGet */
memset ( szString , 0 , sizeof ( szString ) ) ;
hr = Record_StringDataGet ( pRecord , 1 , szString ) ;
ok ( SUCCEEDED ( hr ) , " Record_StringDataGet failed, hresult 0x%08x \n " , hr ) ;
ok_w2 ( " Record_StringDataGet result was %s but expected %s \n " , szString , szThree ) ;
2007-05-11 21:08:22 +02:00
/* Record::StringDataPut with correct index */
hr = Record_StringDataPut ( pRecord , 1 , szTwo ) ;
ok ( SUCCEEDED ( hr ) , " Record_StringDataPut failed, hresult 0x%08x \n " , hr ) ;
/* Record::StringDataGet */
memset ( szString , 0 , sizeof ( szString ) ) ;
hr = Record_StringDataGet ( pRecord , 1 , szString ) ;
ok ( SUCCEEDED ( hr ) , " Record_StringDataGet failed, hresult 0x%08x \n " , hr ) ;
ok_w2 ( " Record_StringDataGet result was %s but expected %s \n " , szString , szTwo ) ;
2007-04-29 03:12:09 +02:00
/* Record::StringDataPut with incorrect index */
hr = Record_StringDataPut ( pRecord , - 1 , szString ) ;
ok ( hr = = DISP_E_EXCEPTION , " Record_StringDataPut failed, hresult 0x%08x \n " , hr ) ;
ok_exception ( hr , szStringDataField ) ;
2007-05-11 21:08:38 +02:00
/* View::Modify with incorrect parameters */
2007-05-11 21:08:43 +02:00
hr = View_Modify ( pView , - 5 , NULL ) ;
ok ( hr = = DISP_E_EXCEPTION , " View_Modify failed, hresult 0x%08x \n " , hr ) ;
ok_exception ( hr , szModifyModeRecord ) ;
2007-05-11 21:08:38 +02:00
2007-05-11 21:08:43 +02:00
hr = View_Modify ( pView , - 5 , pRecord ) ;
ok ( hr = = DISP_E_EXCEPTION , " View_Modify failed, hresult 0x%08x \n " , hr ) ;
ok_exception ( hr , szModifyModeRecord ) ;
2007-05-11 21:08:38 +02:00
2007-05-11 21:08:43 +02:00
hr = View_Modify ( pView , MSIMODIFY_REFRESH , NULL ) ;
ok ( hr = = DISP_E_EXCEPTION , " View_Modify failed, hresult 0x%08x \n " , hr ) ;
ok_exception ( hr , szModifyModeRecord ) ;
2007-05-11 21:08:38 +02:00
/* View::Modify with MSIMODIFY_REFRESH should undo our changes */
2007-05-11 21:08:43 +02:00
hr = View_Modify ( pView , MSIMODIFY_REFRESH , pRecord ) ;
/* Wine's MsiViewModify currently does not support MSIMODIFY_REFRESH */
todo_wine ok ( SUCCEEDED ( hr ) , " View_Modify failed, hresult 0x%08x \n " , hr ) ;
2007-05-11 21:08:38 +02:00
/* Record::StringDataGet, confirm that the record is back to its unmodified value */
memset ( szString , 0 , sizeof ( szString ) ) ;
hr = Record_StringDataGet ( pRecord , 1 , szString ) ;
ok ( SUCCEEDED ( hr ) , " Record_StringDataGet failed, hresult 0x%08x \n " , hr ) ;
todo_wine ok_w2 ( " Record_StringDataGet result was %s but expected %s \n " , szString , szThree ) ;
2007-04-29 03:12:09 +02:00
IDispatch_Release ( pRecord ) ;
}
/* View::Fetch */
hr = View_Fetch ( pView , & pRecord ) ;
ok ( SUCCEEDED ( hr ) , " View_Fetch failed, hresult 0x%08x \n " , hr ) ;
ok ( pRecord ! = NULL , " View_Fetch should not have returned NULL record \n " ) ;
if ( pRecord )
{
/* Record::StringDataGet */
memset ( szString , 0 , sizeof ( szString ) ) ;
hr = Record_StringDataGet ( pRecord , 1 , szString ) ;
ok ( SUCCEEDED ( hr ) , " Record_StringDataGet failed, hresult 0x%08x \n " , hr ) ;
ok_w2 ( " Record_StringDataGet result was %s but expected %s \n " , szString , szTwo ) ;
IDispatch_Release ( pRecord ) ;
}
/* View::Fetch */
hr = View_Fetch ( pView , & pRecord ) ;
ok ( SUCCEEDED ( hr ) , " View_Fetch failed, hresult 0x%08x \n " , hr ) ;
ok ( pRecord = = NULL , " View_Fetch should have returned NULL record \n " ) ;
if ( pRecord )
IDispatch_Release ( pRecord ) ;
/* View::Close */
hr = View_Close ( pView ) ;
ok ( SUCCEEDED ( hr ) , " View_Close failed, hresult 0x%08x \n " , hr ) ;
IDispatch_Release ( pView ) ;
}
}
static void test_Session ( IDispatch * pSession )
{
static WCHAR szProductName [ ] = { ' P ' , ' r ' , ' o ' , ' d ' , ' u ' , ' c ' , ' t ' , ' N ' , ' a ' , ' m ' , ' e ' , 0 } ;
static WCHAR szMSITEST [ ] = { ' M ' , ' S ' , ' I ' , ' T ' , ' E ' , ' S ' , ' T ' , 0 } ;
static WCHAR szOne [ ] = { ' O ' , ' n ' , ' e ' , 0 } ;
2007-05-11 21:07:41 +02:00
static WCHAR szOneStateFalse [ ] = { ' ! ' , ' O ' , ' n ' , ' e ' , ' > ' , ' 0 ' , 0 } ;
static WCHAR szOneStateTrue [ ] = { ' ! ' , ' O ' , ' n ' , ' e ' , ' = ' , ' - ' , ' 1 ' , 0 } ;
static WCHAR szOneActionFalse [ ] = { ' $ ' , ' O ' , ' n ' , ' e ' , ' = ' , ' - ' , ' 1 ' , 0 } ;
static WCHAR szOneActionTrue [ ] = { ' $ ' , ' O ' , ' n ' , ' e ' , ' > ' , ' 0 ' , 0 } ;
2007-04-29 03:12:09 +02:00
static WCHAR szCostInitialize [ ] = { ' C ' , ' o ' , ' s ' , ' t ' , ' I ' , ' n ' , ' i ' , ' t ' , ' i ' , ' a ' , ' l ' , ' i ' , ' z ' , ' e ' , 0 } ;
static WCHAR szEmpty [ ] = { 0 } ;
static WCHAR szEquals [ ] = { ' = ' , 0 } ;
static WCHAR szPropertyName [ ] = { ' P ' , ' r ' , ' o ' , ' p ' , ' e ' , ' r ' , ' t ' , ' y ' , ' , ' , ' N ' , ' a ' , ' m ' , ' e ' , 0 } ;
WCHAR stringw [ MAX_PATH ] ;
CHAR string [ MAX_PATH ] ;
UINT len ;
BOOL bool ;
int myint ;
2007-05-05 06:17:56 +02:00
IDispatch * pDatabase = NULL , * pInst = NULL ;
2007-04-29 03:12:09 +02:00
HRESULT hr ;
2007-05-05 06:17:56 +02:00
/* Session::Installer */
2007-05-05 06:18:40 +02:00
hr = Session_Installer ( pSession , & pInst ) ;
ok ( SUCCEEDED ( hr ) , " Session_Installer failed, hresult 0x%08x \n " , hr ) ;
ok ( pInst ! = NULL , " Session_Installer returned NULL IDispatch pointer \n " ) ;
ok ( pInst = = pInstaller , " Session_Installer does not match Installer instance from CoCreateInstance \n " ) ;
2007-05-05 06:17:56 +02:00
2007-04-29 03:12:09 +02:00
/* Session::Property, get */
memset ( stringw , 0 , sizeof ( stringw ) ) ;
hr = Session_PropertyGet ( pSession , szProductName , stringw ) ;
ok ( SUCCEEDED ( hr ) , " Session_PropertyGet failed, hresult 0x%08x \n " , hr ) ;
if ( lstrcmpW ( stringw , szMSITEST ) ! = 0 )
{
len = WideCharToMultiByte ( CP_ACP , 0 , stringw , - 1 , string , MAX_PATH , NULL , NULL ) ;
ok ( len , " WideCharToMultiByteChar returned error %d \n " , GetLastError ( ) ) ;
ok ( 0 , " Property \" ProductName \" expected to be \" MSITEST \" but was \" %s \" \n " , string ) ;
}
/* Session::Property, put */
hr = Session_PropertyPut ( pSession , szProductName , szProductName ) ;
ok ( SUCCEEDED ( hr ) , " Session_PropertyPut failed, hresult 0x%08x \n " , hr ) ;
memset ( stringw , 0 , sizeof ( stringw ) ) ;
hr = Session_PropertyGet ( pSession , szProductName , stringw ) ;
ok ( SUCCEEDED ( hr ) , " Session_PropertyGet failed, hresult 0x%08x \n " , hr ) ;
if ( lstrcmpW ( stringw , szProductName ) ! = 0 )
{
len = WideCharToMultiByte ( CP_ACP , 0 , stringw , - 1 , string , MAX_PATH , NULL , NULL ) ;
ok ( len , " WideCharToMultiByteChar returned error %d \n " , GetLastError ( ) ) ;
ok ( 0 , " Property \" ProductName \" expected to be \" ProductName \" but was \" %s \" \n " , string ) ;
}
/* Try putting a property using empty property identifier */
hr = Session_PropertyPut ( pSession , szEmpty , szProductName ) ;
ok ( hr = = DISP_E_EXCEPTION , " Session_PropertyPut failed, hresult 0x%08x \n " , hr ) ;
ok_exception ( hr , szPropertyName ) ;
/* Try putting a property using illegal property identifier */
hr = Session_PropertyPut ( pSession , szEquals , szProductName ) ;
ok ( SUCCEEDED ( hr ) , " Session_PropertyPut failed, hresult 0x%08x \n " , hr ) ;
/* Session::Language, get */
hr = Session_LanguageGet ( pSession , & len ) ;
ok ( SUCCEEDED ( hr ) , " Session_LanguageGet failed, hresult 0x%08x \n " , hr ) ;
/* Not sure how to check the language is correct */
/* Session::Mode, get */
hr = Session_ModeGet ( pSession , MSIRUNMODE_REBOOTATEND , & bool ) ;
ok ( SUCCEEDED ( hr ) , " Session_ModeGet failed, hresult 0x%08x \n " , hr ) ;
2007-05-01 03:54:31 +02:00
todo_wine ok ( ! bool , " Reboot at end session mode is %d \n " , bool ) ;
2007-04-29 03:12:09 +02:00
/* Session::Mode, put */
hr = Session_ModePut ( pSession , MSIRUNMODE_REBOOTATEND , TRUE ) ;
2007-05-01 03:54:31 +02:00
todo_wine ok ( SUCCEEDED ( hr ) , " Session_ModePut failed, hresult 0x%08x \n " , hr ) ;
2007-04-29 03:12:09 +02:00
hr = Session_ModeGet ( pSession , MSIRUNMODE_REBOOTATEND , & bool ) ;
ok ( SUCCEEDED ( hr ) , " Session_ModeGet failed, hresult 0x%08x \n " , hr ) ;
ok ( bool , " Reboot at end session mode is %d, expected 1 \n " , bool ) ;
hr = Session_ModePut ( pSession , MSIRUNMODE_REBOOTATEND , FALSE ) ; /* set it again so we don't reboot */
2007-05-01 03:54:31 +02:00
todo_wine ok ( SUCCEEDED ( hr ) , " Session_ModePut failed, hresult 0x%08x \n " , hr ) ;
2007-04-29 03:12:09 +02:00
/* Session::Database, get */
hr = Session_Database ( pSession , & pDatabase ) ;
ok ( SUCCEEDED ( hr ) , " Session_Database failed, hresult 0x%08x \n " , hr ) ;
if ( SUCCEEDED ( hr ) )
{
test_Database ( pDatabase ) ;
IDispatch_Release ( pDatabase ) ;
}
2007-05-11 21:07:41 +02:00
/* Session::EvaluateCondition */
2007-05-11 21:07:48 +02:00
hr = Session_EvaluateCondition ( pSession , NULL , & myint ) ;
ok ( SUCCEEDED ( hr ) , " Session_EvaluateCondition failed, hresult 0x%08x \n " , hr ) ;
ok ( myint = = MSICONDITION_NONE , " Feature current state was %d but expected %d \n " , myint , INSTALLSTATE_UNKNOWN ) ;
2007-05-11 21:07:41 +02:00
2007-05-11 21:07:48 +02:00
hr = Session_EvaluateCondition ( pSession , szEmpty , & myint ) ;
ok ( SUCCEEDED ( hr ) , " Session_EvaluateCondition failed, hresult 0x%08x \n " , hr ) ;
ok ( myint = = MSICONDITION_NONE , " Feature current state was %d but expected %d \n " , myint , INSTALLSTATE_UNKNOWN ) ;
2007-05-11 21:07:41 +02:00
2007-05-11 21:07:48 +02:00
hr = Session_EvaluateCondition ( pSession , szEquals , & myint ) ;
ok ( SUCCEEDED ( hr ) , " Session_EvaluateCondition failed, hresult 0x%08x \n " , hr ) ;
ok ( myint = = MSICONDITION_ERROR , " Feature current state was %d but expected %d \n " , myint , INSTALLSTATE_UNKNOWN ) ;
2007-05-11 21:07:41 +02:00
2007-04-29 03:12:09 +02:00
/* Session::DoAction(CostInitialize) must occur before the next statements */
hr = Session_DoAction ( pSession , szCostInitialize , & myint ) ;
ok ( SUCCEEDED ( hr ) , " Session_DoAction failed, hresult 0x%08x \n " , hr ) ;
ok ( myint = = IDOK , " DoAction(CostInitialize) returned %d, %d expected \n " , myint , IDOK ) ;
/* Session::SetInstallLevel */
hr = Session_SetInstallLevel ( pSession , INSTALLLEVEL_MINIMUM ) ;
ok ( SUCCEEDED ( hr ) , " Session_SetInstallLevel failed, hresult 0x%08x \n " , hr ) ;
/* Session::FeatureCurrentState, get */
hr = Session_FeatureCurrentState ( pSession , szOne , & myint ) ;
ok ( SUCCEEDED ( hr ) , " Session_FeatureCurrentState failed, hresult 0x%08x \n " , hr ) ;
ok ( myint = = INSTALLSTATE_UNKNOWN , " Feature current state was %d but expected %d \n " , myint , INSTALLSTATE_UNKNOWN ) ;
2007-05-11 21:07:41 +02:00
/* Session::EvaluateCondition */
2007-05-11 21:07:48 +02:00
hr = Session_EvaluateCondition ( pSession , szOneStateFalse , & myint ) ;
ok ( SUCCEEDED ( hr ) , " Session_EvaluateCondition failed, hresult 0x%08x \n " , hr ) ;
if ( SUCCEEDED ( hr ) )
ok ( myint = = MSICONDITION_FALSE , " Feature current state was %d but expected %d \n " , myint , INSTALLSTATE_UNKNOWN ) ;
hr = Session_EvaluateCondition ( pSession , szOneStateTrue , & myint ) ;
ok ( SUCCEEDED ( hr ) , " Session_EvaluateCondition failed, hresult 0x%08x \n " , hr ) ;
ok ( myint = = MSICONDITION_TRUE , " Feature current state was %d but expected %d \n " , myint , INSTALLSTATE_UNKNOWN ) ;
2007-05-11 21:07:41 +02:00
2007-04-29 03:12:09 +02:00
/* Session::FeatureRequestState, put */
hr = Session_FeatureRequestStatePut ( pSession , szOne , INSTALLSTATE_ADVERTISED ) ;
ok ( SUCCEEDED ( hr ) , " Session_FeatureRequestStatePut failed, hresult 0x%08x \n " , hr ) ;
hr = Session_FeatureRequestStateGet ( pSession , szOne , & myint ) ;
ok ( SUCCEEDED ( hr ) , " Session_FeatureRequestStateGet failed, hresult 0x%08x \n " , hr ) ;
ok ( myint = = INSTALLSTATE_ADVERTISED , " Feature request state was %d but expected %d \n " , myint , INSTALLSTATE_ADVERTISED ) ;
2007-05-11 21:07:41 +02:00
/* Session::EvaluateCondition */
2007-05-11 21:07:48 +02:00
hr = Session_EvaluateCondition ( pSession , szOneActionFalse , & myint ) ;
ok ( SUCCEEDED ( hr ) , " Session_EvaluateCondition failed, hresult 0x%08x \n " , hr ) ;
if ( SUCCEEDED ( hr ) )
ok ( myint = = MSICONDITION_FALSE , " Feature current state was %d but expected %d \n " , myint , INSTALLSTATE_UNKNOWN ) ;
hr = Session_EvaluateCondition ( pSession , szOneActionTrue , & myint ) ;
ok ( SUCCEEDED ( hr ) , " Session_EvaluateCondition failed, hresult 0x%08x \n " , hr ) ;
ok ( myint = = MSICONDITION_TRUE , " Feature current state was %d but expected %d \n " , myint , INSTALLSTATE_UNKNOWN ) ;
2007-04-29 03:12:09 +02:00
}
2007-05-08 00:51:36 +02:00
/* delete key and all its subkeys */
static DWORD delete_key ( HKEY hkey )
{
char name [ MAX_PATH ] ;
DWORD ret ;
while ( ! ( ret = RegEnumKeyA ( hkey , 0 , name , sizeof ( name ) ) ) )
{
HKEY tmp ;
if ( ! ( ret = RegOpenKeyExA ( hkey , name , 0 , KEY_ENUMERATE_SUB_KEYS , & tmp ) ) )
{
ret = delete_key ( tmp ) ;
RegCloseKey ( tmp ) ;
}
if ( ret ) break ;
}
if ( ret ! = ERROR_NO_MORE_ITEMS ) return ret ;
RegDeleteKeyA ( hkey , " " ) ;
return 0 ;
}
static void test_Installer_RegistryValue ( void )
{
static const DWORD qw [ 2 ] = { 0x12345678 , 0x87654321 } ;
static const WCHAR szKey [ ] = { ' S ' , ' o ' , ' f ' , ' t ' , ' w ' , ' a ' , ' r ' , ' e ' , ' \\ ' , ' W ' , ' i ' , ' n ' , ' e ' , ' \\ ' , ' T ' , ' e ' , ' s ' , ' t ' , 0 } ;
static const WCHAR szOne [ ] = { ' O ' , ' n ' , ' e ' , 0 } ;
static const WCHAR szTwo [ ] = { ' T ' , ' w ' , ' o ' , 0 } ;
static const WCHAR szThree [ ] = { ' T ' , ' h ' , ' r ' , ' e ' , ' e ' , 0 } ;
2007-05-09 14:56:44 +02:00
static const WCHAR szREG_BINARY [ ] = { ' ( ' , ' R ' , ' E ' , ' G ' , ' _ ' , ' B ' , ' I ' , ' N ' , ' A ' , ' R ' , ' Y ' , ' ) ' , 0 } ;
2007-05-08 00:51:36 +02:00
static const WCHAR szFour [ ] = { ' F ' , ' o ' , ' u ' , ' r ' , 0 } ;
2007-05-09 14:56:44 +02:00
static const WCHAR szExpand [ ] = { ' % ' , ' M ' , ' S ' , ' I ' , ' T ' , ' E ' , ' S ' , ' T ' , ' % ' , 0 } ;
static const WCHAR szFive [ ] = { ' F ' , ' i ' , ' v ' , ' e ' , 0 , ' H ' , ' i ' , 0 , 0 } ;
static const WCHAR szFiveHi [ ] = { ' F ' , ' i ' , ' v ' , ' e ' , ' \n ' , ' H ' , ' i ' , 0 } ;
static const WCHAR szSix [ ] = { ' S ' , ' i ' , ' x ' , 0 } ;
static const WCHAR szREG_ [ ] = { ' ( ' , ' R ' , ' E ' , ' G ' , ' _ ' , ' ] ' , 0 } ;
static const WCHAR szSeven [ ] = { ' S ' , ' e ' , ' v ' , ' e ' , ' n ' , 0 } ;
static const WCHAR szEight [ ] = { ' E ' , ' i ' , ' g ' , ' h ' , ' t ' , 0 } ;
2007-05-08 00:51:36 +02:00
static const WCHAR szBlank [ ] = { 0 } ;
2007-05-09 14:56:44 +02:00
VARIANT varresult ;
VARIANTARG vararg ;
2007-05-08 00:51:36 +02:00
WCHAR szString [ MAX_PATH ] ;
HKEY hkey , hkey_sub ;
HRESULT hr ;
BOOL bRet ;
/* Delete keys */
if ( ! RegOpenKeyW ( HKEY_CURRENT_USER , szKey , & hkey ) ) delete_key ( hkey ) ;
2007-05-09 14:56:44 +02:00
/* Does our key exist? Shouldn't; check with all three possible value parameter types */
2007-05-10 22:40:28 +02:00
hr = Installer_RegistryValueE ( HKEY_CURRENT_USER , szKey , & bRet ) ;
ok ( SUCCEEDED ( hr ) , " Installer_RegistryValueE failed, hresult 0x%08x \n " , hr ) ;
if ( SUCCEEDED ( hr ) )
ok ( ! bRet , " Registry key expected to not exist, but Installer_RegistryValue claims it does \n " ) ;
memset ( szString , 0 , sizeof ( szString ) ) ;
hr = Installer_RegistryValueW ( HKEY_CURRENT_USER , szKey , NULL , szString ) ;
ok ( hr = = DISP_E_BADINDEX , " Installer_RegistryValueW failed, hresult 0x%08x \n " , hr ) ;
memset ( szString , 0 , sizeof ( szString ) ) ;
hr = Installer_RegistryValueI ( HKEY_CURRENT_USER , szKey , 0 , szString , VT_BSTR ) ;
ok ( hr = = DISP_E_BADINDEX , " Installer_RegistryValueI failed, hresult 0x%08x \n " , hr ) ;
2007-05-08 00:51:36 +02:00
/* Create key */
ok ( ! RegCreateKeyW ( HKEY_CURRENT_USER , szKey , & hkey ) , " RegCreateKeyW failed \n " ) ;
ok ( ! RegSetValueExW ( hkey , szOne , 0 , REG_SZ , ( const BYTE * ) szOne , sizeof ( szOne ) ) ,
" RegSetValueExW failed \n " ) ;
ok ( ! RegSetValueExW ( hkey , szTwo , 0 , REG_DWORD , ( const BYTE * ) qw , 4 ) ,
" RegSetValueExW failed \n " ) ;
ok ( ! RegSetValueExW ( hkey , szThree , 0 , REG_BINARY , ( const BYTE * ) qw , 4 ) ,
" RegSetValueExW failed \n " ) ;
2007-05-09 14:56:44 +02:00
ok ( SetEnvironmentVariableA ( " MSITEST " , " Four " ) , " SetEnvironmentVariableA failed %d \n " , GetLastError ( ) ) ;
ok ( ! RegSetValueExW ( hkey , szFour , 0 , REG_EXPAND_SZ , ( const BYTE * ) szExpand , sizeof ( szExpand ) ) ,
" RegSetValueExW failed \n " ) ;
ok ( ! RegSetValueExW ( hkey , szFive , 0 , REG_MULTI_SZ , ( const BYTE * ) szFive , sizeof ( szFive ) ) ,
" RegSetValueExW failed \n " ) ;
ok ( ! RegSetValueExW ( hkey , szSix , 0 , REG_QWORD , ( const BYTE * ) qw , 8 ) ,
" RegSetValueExW failed \n " ) ;
ok ( ! RegSetValueExW ( hkey , szSeven , 0 , REG_NONE , ( const BYTE * ) NULL , 0 ) ,
" RegSetValueExW failed \n " ) ;
2007-05-08 00:51:36 +02:00
ok ( ! RegSetValueExW ( hkey , NULL , 0 , REG_SZ , ( const BYTE * ) szOne , sizeof ( szOne ) ) ,
" RegSetValueExW failed \n " ) ;
2007-05-09 14:56:44 +02:00
ok ( ! RegCreateKeyW ( hkey , szEight , & hkey_sub ) , " RegCreateKeyW failed \n " ) ;
2007-05-08 00:51:36 +02:00
2007-05-10 22:40:28 +02:00
/* Does our key exist? It should, and make sure we retrieve the correct default value */
bRet = FALSE ;
hr = Installer_RegistryValueE ( HKEY_CURRENT_USER , szKey , & bRet ) ;
ok ( SUCCEEDED ( hr ) , " Installer_RegistryValueE failed, hresult 0x%08x \n " , hr ) ;
if ( SUCCEEDED ( hr ) )
ok ( bRet , " Registry key expected to exist, but Installer_RegistryValue claims it does not \n " ) ;
memset ( szString , 0 , sizeof ( szString ) ) ;
hr = Installer_RegistryValueW ( HKEY_CURRENT_USER , szKey , NULL , szString ) ;
ok ( SUCCEEDED ( hr ) , " Installer_RegistryValueW failed, hresult 0x%08x \n " , hr ) ;
ok_w2 ( " Default registry value \" %s \" does not match expected \" %s \" \n " , szString , szOne ) ;
/* Ask for the value of a non-existent key */
memset ( szString , 0 , sizeof ( szString ) ) ;
hr = Installer_RegistryValueW ( HKEY_CURRENT_USER , szKey , szExpand , szString ) ;
ok ( hr = = DISP_E_BADINDEX , " Installer_RegistryValueW failed, hresult 0x%08x \n " , hr ) ;
/* Get values of keys */
memset ( szString , 0 , sizeof ( szString ) ) ;
hr = Installer_RegistryValueW ( HKEY_CURRENT_USER , szKey , szOne , szString ) ;
ok ( SUCCEEDED ( hr ) , " Installer_RegistryValueW failed, hresult 0x%08x \n " , hr ) ;
ok_w2 ( " Registry value \" %s \" does not match expected \" %s \" \n " , szString , szOne ) ;
VariantInit ( & vararg ) ;
V_VT ( & vararg ) = VT_BSTR ;
V_BSTR ( & vararg ) = SysAllocString ( szTwo ) ;
hr = Installer_RegistryValue ( HKEY_CURRENT_USER , szKey , vararg , & varresult , VT_I4 ) ;
ok ( SUCCEEDED ( hr ) , " Installer_RegistryValue failed, hresult 0x%08x \n " , hr ) ;
ok ( V_I4 ( & varresult ) = = 305419896 , " Registry value %d does not match expected value \n " , V_I4 ( & varresult ) ) ;
VariantClear ( & varresult ) ;
memset ( szString , 0 , sizeof ( szString ) ) ;
hr = Installer_RegistryValueW ( HKEY_CURRENT_USER , szKey , szThree , szString ) ;
ok ( SUCCEEDED ( hr ) , " Installer_RegistryValueW failed, hresult 0x%08x \n " , hr ) ;
ok_w2 ( " Registry value \" %s \" does not match expected \" %s \" \n " , szString , szREG_BINARY ) ;
memset ( szString , 0 , sizeof ( szString ) ) ;
hr = Installer_RegistryValueW ( HKEY_CURRENT_USER , szKey , szFour , szString ) ;
ok ( SUCCEEDED ( hr ) , " Installer_RegistryValueW failed, hresult 0x%08x \n " , hr ) ;
ok_w2 ( " Registry value \" %s \" does not match expected \" %s \" \n " , szString , szFour ) ;
memset ( szString , 0 , sizeof ( szString ) ) ;
hr = Installer_RegistryValueW ( HKEY_CURRENT_USER , szKey , szFive , szString ) ;
ok ( SUCCEEDED ( hr ) , " Installer_RegistryValueW failed, hresult 0x%08x \n " , hr ) ;
ok_w2 ( " Registry value \" %s \" does not match expected \" %s \" \n " , szString , szFiveHi ) ;
memset ( szString , 0 , sizeof ( szString ) ) ;
hr = Installer_RegistryValueW ( HKEY_CURRENT_USER , szKey , szSix , szString ) ;
ok ( SUCCEEDED ( hr ) , " Installer_RegistryValueW failed, hresult 0x%08x \n " , hr ) ;
ok_w2 ( " Registry value \" %s \" does not match expected \" %s \" \n " , szString , szREG_ ) ;
VariantInit ( & vararg ) ;
V_VT ( & vararg ) = VT_BSTR ;
V_BSTR ( & vararg ) = SysAllocString ( szSeven ) ;
hr = Installer_RegistryValue ( HKEY_CURRENT_USER , szKey , vararg , & varresult , VT_EMPTY ) ;
ok ( SUCCEEDED ( hr ) , " Installer_RegistryValue failed, hresult 0x%08x \n " , hr ) ;
/* Get string class name for the key */
memset ( szString , 0 , sizeof ( szString ) ) ;
hr = Installer_RegistryValueI ( HKEY_CURRENT_USER , szKey , 0 , szString , VT_BSTR ) ;
ok ( SUCCEEDED ( hr ) , " Installer_RegistryValueI failed, hresult 0x%08x \n " , hr ) ;
ok_w2 ( " Registry name \" %s \" does not match expected \" %s \" \n " , szString , szBlank ) ;
/* Get name of a value by positive number (RegEnumValue like), valid index */
memset ( szString , 0 , sizeof ( szString ) ) ;
hr = Installer_RegistryValueI ( HKEY_CURRENT_USER , szKey , 2 , szString , VT_BSTR ) ;
ok ( SUCCEEDED ( hr ) , " Installer_RegistryValueI failed, hresult 0x%08x \n " , hr ) ;
/* RegEnumValue order seems different on wine */
todo_wine ok_w2 ( " Registry name \" %s \" does not match expected \" %s \" \n " , szString , szTwo ) ;
/* Get name of a value by positive number (RegEnumValue like), invalid index */
memset ( szString , 0 , sizeof ( szString ) ) ;
hr = Installer_RegistryValueI ( HKEY_CURRENT_USER , szKey , 10 , szString , VT_EMPTY ) ;
ok ( SUCCEEDED ( hr ) , " Installer_RegistryValueI failed, hresult 0x%08x \n " , hr ) ;
/* Get name of a subkey by negative number (RegEnumValue like), valid index */
memset ( szString , 0 , sizeof ( szString ) ) ;
hr = Installer_RegistryValueI ( HKEY_CURRENT_USER , szKey , - 1 , szString , VT_BSTR ) ;
ok ( SUCCEEDED ( hr ) , " Installer_RegistryValueI failed, hresult 0x%08x \n " , hr ) ;
ok_w2 ( " Registry name \" %s \" does not match expected \" %s \" \n " , szString , szEight ) ;
/* Get name of a subkey by negative number (RegEnumValue like), invalid index */
memset ( szString , 0 , sizeof ( szString ) ) ;
hr = Installer_RegistryValueI ( HKEY_CURRENT_USER , szKey , - 10 , szString , VT_EMPTY ) ;
ok ( SUCCEEDED ( hr ) , " Installer_RegistryValueI failed, hresult 0x%08x \n " , hr ) ;
2007-05-08 00:51:36 +02:00
/* clean up */
delete_key ( hkey ) ;
}
2007-05-14 19:14:42 +02:00
/* Delete a registry subkey, including all its subkeys (RegDeleteKey does not work on keys with subkeys without
* deleting the subkeys first ) */
static UINT delete_registry_key ( HKEY hkeyParent , LPCSTR subkey )
{
UINT ret ;
CHAR * string = NULL ;
HKEY hkey ;
DWORD dwSize ;
ret = RegOpenKey ( hkeyParent , subkey , & hkey ) ;
if ( ret ! = ERROR_SUCCESS ) return ret ;
ret = RegQueryInfoKeyA ( hkey , NULL , NULL , NULL , NULL , & dwSize , NULL , NULL , NULL , NULL , NULL , NULL ) ;
if ( ret ! = ERROR_SUCCESS ) return ret ;
if ( ! ( string = HeapAlloc ( GetProcessHeap ( ) , 0 , + + dwSize ) ) ) return ERROR_NOT_ENOUGH_MEMORY ;
while ( RegEnumKeyA ( hkey , 0 , string , dwSize ) = = ERROR_SUCCESS )
delete_registry_key ( hkey , string ) ;
RegCloseKey ( hkey ) ;
HeapFree ( GetProcessHeap ( ) , 0 , string ) ;
RegDeleteKeyA ( hkeyParent , subkey ) ;
return ERROR_SUCCESS ;
}
/* Find a specific registry subkey at any depth within the given key and subkey and return its parent key. */
static UINT find_registry_key ( HKEY hkeyParent , LPCSTR subkey , LPCSTR findkey , HKEY * phkey )
{
UINT ret ;
CHAR * string = NULL ;
int idx = 0 ;
HKEY hkey ;
DWORD dwSize ;
BOOL found = FALSE ;
* phkey = 0 ;
ret = RegOpenKey ( hkeyParent , subkey , & hkey ) ;
if ( ret ! = ERROR_SUCCESS ) return ret ;
ret = RegQueryInfoKeyA ( hkey , NULL , NULL , NULL , NULL , & dwSize , NULL , NULL , NULL , NULL , NULL , NULL ) ;
if ( ret ! = ERROR_SUCCESS ) return ret ;
if ( ! ( string = HeapAlloc ( GetProcessHeap ( ) , 0 , + + dwSize ) ) ) return ERROR_NOT_ENOUGH_MEMORY ;
while ( ! found & &
RegEnumKeyA ( hkey , idx + + , string , dwSize ) = = ERROR_SUCCESS )
{
if ( ! strcmp ( string , findkey ) )
{
* phkey = hkey ;
found = TRUE ;
}
else if ( find_registry_key ( hkey , string , findkey , phkey ) = = ERROR_SUCCESS ) found = TRUE ;
}
if ( * phkey ! = hkey ) RegCloseKey ( hkey ) ;
HeapFree ( GetProcessHeap ( ) , 0 , string ) ;
return ( found ? ERROR_SUCCESS : ERROR_FILE_NOT_FOUND ) ;
}
static void test_Installer_InstallProduct ( LPCWSTR szPath )
{
HRESULT hr ;
CHAR path [ MAX_PATH ] ;
LONG res ;
HKEY hkey ;
DWORD num , size , type ;
int iValue ;
create_test_files ( ) ;
/* Installer::InstallProduct */
todo_wine
{
hr = Installer_InstallProduct ( szMsifile , NULL ) ;
ok ( SUCCEEDED ( hr ) , " Installer_InstallProduct failed, hresult 0x%08x \n " , hr ) ;
}
/* Installer::ProductState for our product code, which has been installed */
hr = Installer_ProductState ( szProductCode , & iValue ) ;
ok ( SUCCEEDED ( hr ) , " Installer_ProductState failed, hresult 0x%08x \n " , hr ) ;
todo_wine ok ( iValue = = INSTALLSTATE_DEFAULT , " Installer_ProductState returned %d, expected %d \n " , iValue , INSTALLSTATE_DEFAULT ) ;
/* Check & clean up installed files & registry keys */
todo_wine
{
ok ( delete_pf ( " msitest \\ cabout \\ new \\ five.txt " , TRUE ) , " File not installed \n " ) ;
ok ( delete_pf ( " msitest \\ cabout \\ new " , FALSE ) , " File not installed \n " ) ;
ok ( delete_pf ( " msitest \\ cabout \\ four.txt " , TRUE ) , " File not installed \n " ) ;
ok ( delete_pf ( " msitest \\ cabout " , FALSE ) , " File not installed \n " ) ;
ok ( delete_pf ( " msitest \\ changed \\ three.txt " , TRUE ) , " File not installed \n " ) ;
ok ( delete_pf ( " msitest \\ changed " , FALSE ) , " File not installed \n " ) ;
ok ( delete_pf ( " msitest \\ first \\ two.txt " , TRUE ) , " File not installed \n " ) ;
ok ( delete_pf ( " msitest \\ first " , FALSE ) , " File not installed \n " ) ;
ok ( delete_pf ( " msitest \\ one.txt " , TRUE ) , " File not installed \n " ) ;
ok ( delete_pf ( " msitest \\ filename " , TRUE ) , " File not installed \n " ) ;
ok ( delete_pf ( " msitest \\ service.exe " , TRUE ) , " File not installed \n " ) ;
ok ( delete_pf ( " msitest " , FALSE ) , " File not installed \n " ) ;
res = RegOpenKey ( HKEY_LOCAL_MACHINE , " SOFTWARE \\ Wine \\ msitest " , & hkey ) ;
ok ( res = = ERROR_SUCCESS , " Expected ERROR_SUCCESS, got %d \n " , res ) ;
size = MAX_PATH ;
type = REG_SZ ;
res = RegQueryValueExA ( hkey , " Name " , NULL , & type , ( LPBYTE ) path , & size ) ;
ok ( res = = ERROR_SUCCESS , " Expected ERROR_SUCCESS, got %d \n " , res ) ;
ok ( ! lstrcmpA ( path , " imaname " ) , " Expected imaname, got %s \n " , path ) ;
size = MAX_PATH ;
type = REG_SZ ;
res = RegQueryValueExA ( hkey , " blah " , NULL , & type , ( LPBYTE ) path , & size ) ;
ok ( res = = ERROR_FILE_NOT_FOUND , " Expected ERROR_FILE_NOT_FOUND, got %d \n " , res ) ;
size = sizeof ( num ) ;
type = REG_DWORD ;
res = RegQueryValueExA ( hkey , " number " , NULL , & type , ( LPBYTE ) & num , & size ) ;
ok ( res = = ERROR_SUCCESS , " Expected ERROR_SUCCESS, got %d \n " , res ) ;
ok ( num = = 314 , " Expected 314, got %d \n " , num ) ;
size = MAX_PATH ;
type = REG_SZ ;
res = RegQueryValueExA ( hkey , " OrderTestName " , NULL , & type , ( LPBYTE ) path , & size ) ;
ok ( res = = ERROR_SUCCESS , " Expected ERROR_SUCCESS, got %d \n " , res ) ;
ok ( ! lstrcmpA ( path , " OrderTestValue " ) , " Expected imaname, got %s \n " , path ) ;
RegCloseKey ( hkey ) ;
res = RegDeleteKeyA ( HKEY_LOCAL_MACHINE , " SOFTWARE \\ Wine \\ msitest " ) ;
ok ( res = = ERROR_SUCCESS , " Expected ERROR_SUCCESS, got %d \n " , res ) ;
}
check_service_is_installed ( ) ;
/* Remove registry keys written by RegisterProduct standard action */
todo_wine
{
res = RegDeleteKeyA ( HKEY_LOCAL_MACHINE , " SOFTWARE \\ Microsoft \\ Windows \\ CurrentVersion \\ Uninstall \\ {F1C3AF50-8B56-4A69-A00C-00773FE42F30} " ) ;
ok ( res = = ERROR_SUCCESS , " Expected ERROR_SUCCESS, got %d \n " , res ) ;
res = RegDeleteKeyA ( HKEY_LOCAL_MACHINE , " SOFTWARE \\ Microsoft \\ Windows \\ CurrentVersion \\ Installer \\ UpgradeCodes \\ D8E760ECA1E276347B43E42BDBDA5656 " ) ;
ok ( res = = ERROR_SUCCESS , " Expected ERROR_SUCCESS, got %d \n " , res ) ;
res = find_registry_key ( HKEY_LOCAL_MACHINE , " SOFTWARE \\ Microsoft \\ Windows \\ CurrentVersion \\ Installer \\ UserData " , " 05FA3C1F65B896A40AC00077F34EF203 " , & hkey ) ;
ok ( res = = ERROR_SUCCESS , " Expected ERROR_SUCCESS, got %d \n " , res ) ;
if ( res = = ERROR_SUCCESS )
{
res = delete_registry_key ( hkey , " 05FA3C1F65B896A40AC00077F34EF203 " ) ;
ok ( res = = ERROR_SUCCESS , " Expected ERROR_SUCCESS, got %d \n " , res ) ;
RegCloseKey ( hkey ) ;
}
}
/* Remove registry keys written by PublishProduct standard action */
res = RegOpenKey ( HKEY_CURRENT_USER , " SOFTWARE \\ Microsoft \\ Installer " , & hkey ) ;
ok ( res = = ERROR_SUCCESS , " Expected ERROR_SUCCESS, got %d \n " , res ) ;
todo_wine
{
res = delete_registry_key ( hkey , " Products \\ 05FA3C1F65B896A40AC00077F34EF203 " ) ;
ok ( res = = ERROR_SUCCESS , " Expected ERROR_SUCCESS, got %d \n " , res ) ;
res = RegDeleteKeyA ( hkey , " UpgradeCodes \\ D8E760ECA1E276347B43E42BDBDA5656 " ) ;
ok ( res = = ERROR_SUCCESS , " Expected ERROR_SUCCESS, got %d \n " , res ) ;
}
RegCloseKey ( hkey ) ;
/* Delete installation files we installed */
delete_test_files ( ) ;
}
2007-04-29 03:12:09 +02:00
static void test_Installer ( void )
{
static WCHAR szBackslash [ ] = { ' \\ ' , 0 } ;
2007-05-11 21:07:53 +02:00
static WCHAR szCreateRecordException [ ] = { ' C ' , ' r ' , ' e ' , ' a ' , ' t ' , ' e ' , ' R ' , ' e ' , ' c ' , ' o ' , ' r ' , ' d ' , ' , ' , ' C ' , ' o ' , ' u ' , ' n ' , ' t ' , 0 } ;
2007-05-11 21:08:27 +02:00
static WCHAR szIntegerDataException [ ] = { ' I ' , ' n ' , ' t ' , ' e ' , ' g ' , ' e ' , ' r ' , ' D ' , ' a ' , ' t ' , ' a ' , ' , ' , ' F ' , ' i ' , ' e ' , ' l ' , ' d ' , 0 } ;
2007-04-29 03:12:09 +02:00
WCHAR szPath [ MAX_PATH ] ;
HRESULT hr ;
UINT len ;
2007-05-08 00:50:05 +02:00
IDispatch * pSession = NULL , * pRecord = NULL , * pStringList = NULL ;
2007-05-11 21:08:27 +02:00
int iValue ;
2007-04-29 03:12:09 +02:00
if ( ! pInstaller ) return ;
2007-05-04 02:02:31 +02:00
/* Installer::CreateRecord */
2007-05-11 21:07:58 +02:00
/* Test for error */
hr = Installer_CreateRecord ( - 1 , & pRecord ) ;
ok ( hr = = DISP_E_EXCEPTION , " Installer_CreateRecord failed, hresult 0x%08x \n " , hr ) ;
ok_exception ( hr , szCreateRecordException ) ;
/* Test for success */
hr = Installer_CreateRecord ( 1 , & pRecord ) ;
ok ( SUCCEEDED ( hr ) , " Installer_CreateRecord failed, hresult 0x%08x \n " , hr ) ;
ok ( pRecord ! = NULL , " Installer_CreateRecord should not have returned NULL record \n " ) ;
2007-05-04 02:02:31 +02:00
if ( pRecord )
{
/* Record::FieldCountGet */
2007-05-11 21:08:27 +02:00
hr = Record_FieldCountGet ( pRecord , & iValue ) ;
2007-05-11 21:08:14 +02:00
ok ( SUCCEEDED ( hr ) , " Record_FiledCountGet failed, hresult 0x%08x \n " , hr ) ;
2007-05-11 21:08:27 +02:00
ok ( iValue = = 1 , " Record_FieldCountGet result was %d but expected 1 \n " , iValue ) ;
2007-05-14 19:14:00 +02:00
/* Record::IntegerDataGet */
hr = Record_IntegerDataGet ( pRecord , 1 , & iValue ) ;
ok ( SUCCEEDED ( hr ) , " Record_IntegerDataGet failed, hresult 0x%08x \n " , hr ) ;
ok ( iValue = = MSI_NULL_INTEGER , " Record_IntegerDataGet result was %d but expected %d \n " , iValue , MSI_NULL_INTEGER ) ;
/* Record::IntegerDataGet, bad index */
hr = Record_IntegerDataGet ( pRecord , 10 , & iValue ) ;
ok ( SUCCEEDED ( hr ) , " Record_IntegerDataGet failed, hresult 0x%08x \n " , hr ) ;
ok ( iValue = = MSI_NULL_INTEGER , " Record_IntegerDataGet result was %d but expected %d \n " , iValue , MSI_NULL_INTEGER ) ;
/* Record::IntegerDataPut */
hr = Record_IntegerDataPut ( pRecord , 1 , 100 ) ;
ok ( SUCCEEDED ( hr ) , " Record_IntegerDataPut failed, hresult 0x%08x \n " , hr ) ;
/* Record::IntegerDataPut, bad index */
hr = Record_IntegerDataPut ( pRecord , 10 , 100 ) ;
ok ( hr = = DISP_E_EXCEPTION , " Record_IntegerDataPut failed, hresult 0x%08x \n " , hr ) ;
ok_exception ( hr , szIntegerDataException ) ;
/* Record::IntegerDataGet */
hr = Record_IntegerDataGet ( pRecord , 1 , & iValue ) ;
ok ( SUCCEEDED ( hr ) , " Record_IntegerDataGet failed, hresult 0x%08x \n " , hr ) ;
ok ( iValue = = 100 , " Record_IntegerDataGet result was %d but expected 100 \n " , iValue ) ;
2007-05-04 02:02:31 +02:00
IDispatch_Release ( pRecord ) ;
}
/* Prepare package */
2007-04-29 03:12:09 +02:00
create_database ( msifile , tables , sizeof ( tables ) / sizeof ( msi_table ) ) ;
len = MultiByteToWideChar ( CP_ACP , MB_PRECOMPOSED , CURR_DIR , - 1 , szPath , MAX_PATH ) ;
ok ( len , " MultiByteToWideChar returned error %d \n " , GetLastError ( ) ) ;
if ( ! len ) return ;
lstrcatW ( szPath , szBackslash ) ;
lstrcatW ( szPath , szMsifile ) ;
/* Installer::OpenPackage */
hr = Installer_OpenPackage ( szPath , 0 , & pSession ) ;
ok ( SUCCEEDED ( hr ) , " Installer_OpenPackage failed, hresult 0x%08x \n " , hr ) ;
if ( SUCCEEDED ( hr ) )
{
test_Session ( pSession ) ;
IDispatch_Release ( pSession ) ;
}
2007-05-08 00:51:36 +02:00
/* Installer::RegistryValue */
test_Installer_RegistryValue ( ) ;
2007-05-08 00:50:05 +02:00
/* Installer::Products */
2007-05-08 00:50:30 +02:00
hr = Installer_Products ( & pStringList ) ;
ok ( SUCCEEDED ( hr ) , " Installer_Products failed, hresult 0x%08x \n " , hr ) ;
if ( SUCCEEDED ( hr ) )
{
int iCount = 0 , idx ;
2007-05-08 00:50:05 +02:00
2007-05-08 00:50:30 +02:00
/* StringList::Count */
hr = StringList_Count ( pStringList , & iCount ) ;
ok ( SUCCEEDED ( hr ) , " StringList_Count failed, hresult 0x%08x \n " , hr ) ;
2007-05-08 00:50:05 +02:00
2007-05-08 00:50:30 +02:00
for ( idx = 0 ; idx < iCount ; idx + + )
{
/* StringList::Item */
memset ( szPath , 0 , sizeof ( szPath ) ) ;
hr = StringList_Item ( pStringList , idx , szPath ) ;
ok ( SUCCEEDED ( hr ) , " StringList_Item failed (idx %d, count %d), hresult 0x%08x \n " , idx , iCount , hr ) ;
2007-05-08 00:50:05 +02:00
2007-05-08 00:50:30 +02:00
if ( SUCCEEDED ( hr ) )
{
/* Installer::ProductState */
2007-05-11 21:08:27 +02:00
hr = Installer_ProductState ( szPath , & iValue ) ;
2007-05-08 00:50:30 +02:00
ok ( SUCCEEDED ( hr ) , " Installer_ProductState failed, hresult 0x%08x \n " , hr ) ;
2007-05-08 00:50:05 +02:00
if ( SUCCEEDED ( hr ) )
2007-05-11 21:08:27 +02:00
ok ( iValue = = INSTALLSTATE_DEFAULT | | iValue = = INSTALLSTATE_ADVERTISED , " Installer_ProductState returned %d, expected %d or %d \n " , iValue , INSTALLSTATE_DEFAULT , INSTALLSTATE_ADVERTISED ) ;
2007-05-08 00:50:05 +02:00
}
2007-05-08 00:50:30 +02:00
}
2007-05-08 00:50:05 +02:00
2007-05-08 00:50:30 +02:00
/* StringList::Item using an invalid index */
memset ( szPath , 0 , sizeof ( szPath ) ) ;
hr = StringList_Item ( pStringList , iCount , szPath ) ;
ok ( hr = = DISP_E_BADINDEX , " StringList_Item for an invalid index did not return DISP_E_BADINDEX, hresult 0x%08x \n " , hr ) ;
2007-05-08 00:50:05 +02:00
2007-05-08 00:50:30 +02:00
IDispatch_Release ( pStringList ) ;
2007-05-08 00:50:05 +02:00
}
/* Installer::ProductState for our product code, which should not be installed */
2007-05-11 21:08:27 +02:00
hr = Installer_ProductState ( szProductCode , & iValue ) ;
2007-05-08 00:50:30 +02:00
ok ( SUCCEEDED ( hr ) , " Installer_ProductState failed, hresult 0x%08x \n " , hr ) ;
if ( SUCCEEDED ( hr ) )
2007-05-11 21:08:27 +02:00
ok ( iValue = = INSTALLSTATE_UNKNOWN , " Installer_ProductState returned %d, expected %d \n " , iValue , INSTALLSTATE_UNKNOWN ) ;
2007-05-08 00:50:05 +02:00
2007-05-04 02:02:31 +02:00
/* Installer::Version */
todo_wine {
memset ( szPath , 0 , sizeof ( szPath ) ) ;
hr = Installer_VersionGet ( szPath ) ;
ok ( SUCCEEDED ( hr ) , " Installer_VersionGet failed, hresult 0x%08x \n " , hr ) ;
}
2007-05-14 19:14:42 +02:00
/* Installer::InstallProduct and other tests that depend on our product being installed */
test_Installer_InstallProduct ( szPath ) ;
2007-04-29 03:12:09 +02:00
}
START_TEST ( automation )
{
DWORD len ;
char temp_path [ MAX_PATH ] , prev_path [ MAX_PATH ] ;
HRESULT hr ;
CLSID clsid ;
IUnknown * pUnk ;
GetCurrentDirectoryA ( MAX_PATH , prev_path ) ;
GetTempPath ( MAX_PATH , temp_path ) ;
SetCurrentDirectoryA ( temp_path ) ;
lstrcpyA ( CURR_DIR , temp_path ) ;
len = lstrlenA ( CURR_DIR ) ;
if ( len & & ( CURR_DIR [ len - 1 ] = = ' \\ ' ) )
CURR_DIR [ len - 1 ] = 0 ;
2007-05-14 19:14:42 +02:00
get_program_files_dir ( PROG_FILES_DIR ) ;
2007-04-29 03:12:09 +02:00
hr = OleInitialize ( NULL ) ;
ok ( SUCCEEDED ( hr ) , " OleInitialize returned 0x%08x \n " , hr ) ;
hr = CLSIDFromProgID ( szProgId , & clsid ) ;
ok ( SUCCEEDED ( hr ) , " CLSIDFromProgID returned 0x%08x \n " , hr ) ;
hr = CoCreateInstance ( & clsid , NULL , CLSCTX_INPROC_SERVER , & IID_IUnknown , ( void * * ) & pUnk ) ;
2007-05-01 03:54:31 +02:00
ok ( SUCCEEDED ( hr ) , " CoCreateInstance returned 0x%08x \n " , hr ) ;
2007-04-29 03:12:09 +02:00
if ( pUnk )
{
hr = IUnknown_QueryInterface ( pUnk , & IID_IDispatch , ( void * * ) & pInstaller ) ;
ok ( SUCCEEDED ( hr ) , " IUnknown::QueryInterface returned 0x%08x \n " , hr ) ;
2007-05-01 03:53:26 +02:00
test_dispid ( ) ;
2007-05-01 03:54:31 +02:00
test_dispatch ( ) ;
test_Installer ( ) ;
2007-04-29 03:12:09 +02:00
hr = IUnknown_Release ( pUnk ) ;
ok ( SUCCEEDED ( hr ) , " IUnknown::Release returned 0x%08x \n " , hr ) ;
}
OleUninitialize ( ) ;
SetCurrentDirectoryA ( prev_path ) ;
}