| /* |
| * Implementation of the Microsoft Installer (msi.dll) |
| * |
| * Copyright 2002,2003,2004,2005 Mike McCormack for CodeWeavers |
| * |
| * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| #include <stdarg.h> |
| |
| #define COBJMACROS |
| #define NONAMELESSUNION |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winreg.h" |
| #include "winnls.h" |
| #include "wine/debug.h" |
| #include "msi.h" |
| #include "msiquery.h" |
| #include "msipriv.h" |
| #include "objidl.h" |
| #include "objbase.h" |
| |
| #include "initguid.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(msi); |
| |
| DEFINE_GUID( CLSID_MsiDatabase, 0x000c1084, 0x0000, 0x0000, |
| 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); |
| DEFINE_GUID( CLSID_MsiPatch, 0x000c1086, 0x0000, 0x0000, |
| 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46); |
| |
| /* |
| * .MSI file format |
| * |
| * An .msi file is a structured storage file. |
| * It contains a number of streams. |
| * A stream for each table in the database. |
| * Two streams for the string table in the database. |
| * Any binary data in a table is a reference to a stream. |
| */ |
| |
| static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg ) |
| { |
| MSIDATABASE *db = (MSIDATABASE *) arg; |
| DWORD r; |
| |
| free_cached_tables( db ); |
| msi_free_transforms( db ); |
| msi_destroy_stringtable( db->strings ); |
| r = IStorage_Release( db->storage ); |
| if( r ) |
| ERR("database reference count was not zero (%ld)\n", r); |
| } |
| |
| UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb) |
| { |
| IStorage *stg = NULL; |
| HRESULT r; |
| MSIDATABASE *db = NULL; |
| UINT ret = ERROR_FUNCTION_FAILED; |
| LPCWSTR szMode; |
| STATSTG stat; |
| |
| TRACE("%s %s\n",debugstr_w(szDBPath),debugstr_w(szPersist) ); |
| |
| if( !pdb ) |
| return ERROR_INVALID_PARAMETER; |
| |
| szMode = szPersist; |
| if( HIWORD( szPersist ) ) |
| { |
| /* UINT len = lstrlenW( szPerist ) + 1; */ |
| FIXME("don't support persist files yet\b"); |
| return ERROR_INVALID_PARAMETER; |
| /* szMode = msi_alloc( len * sizeof (DWORD) ); */ |
| } |
| else if( szPersist == MSIDBOPEN_READONLY ) |
| { |
| r = StgOpenStorage( szDBPath, NULL, |
| STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg); |
| } |
| else if( szPersist == MSIDBOPEN_CREATE ) |
| { |
| r = StgCreateDocfile( szDBPath, |
| STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, &stg); |
| if( r == ERROR_SUCCESS ) |
| { |
| IStorage_SetClass( stg, &CLSID_MsiDatabase ); |
| r = init_string_table( stg ); |
| } |
| } |
| else if( szPersist == MSIDBOPEN_TRANSACT ) |
| { |
| r = StgOpenStorage( szDBPath, NULL, |
| STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg); |
| } |
| else |
| { |
| ERR("unknown flag %p\n",szPersist); |
| return ERROR_INVALID_PARAMETER; |
| } |
| |
| if( FAILED( r ) ) |
| { |
| FIXME("open failed r = %08lx!\n",r); |
| return ERROR_FUNCTION_FAILED; |
| } |
| |
| r = IStorage_Stat( stg, &stat, STATFLAG_NONAME ); |
| if( FAILED( r ) ) |
| { |
| FIXME("Failed to stat storage\n"); |
| goto end; |
| } |
| |
| if ( !IsEqualGUID( &stat.clsid, &CLSID_MsiDatabase ) && |
| !IsEqualGUID( &stat.clsid, &CLSID_MsiPatch ) ) |
| { |
| ERR("storage GUID is not a MSI database GUID %s\n", |
| debugstr_guid(&stat.clsid) ); |
| goto end; |
| } |
| |
| db = alloc_msiobject( MSIHANDLETYPE_DATABASE, sizeof (MSIDATABASE), |
| MSI_CloseDatabase ); |
| if( !db ) |
| { |
| FIXME("Failed to allocate a handle\n"); |
| goto end; |
| } |
| |
| if( TRACE_ON( msi ) ) |
| enum_stream_names( stg ); |
| |
| db->storage = stg; |
| db->mode = szMode; |
| list_init( &db->tables ); |
| list_init( &db->transforms ); |
| |
| db->strings = load_string_table( stg ); |
| if( !db->strings ) |
| goto end; |
| |
| ret = ERROR_SUCCESS; |
| |
| msiobj_addref( &db->hdr ); |
| IStorage_AddRef( stg ); |
| *pdb = db; |
| |
| end: |
| if( db ) |
| msiobj_release( &db->hdr ); |
| if( stg ) |
| IStorage_Release( stg ); |
| |
| return ret; |
| } |
| |
| UINT WINAPI MsiOpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIHANDLE *phDB) |
| { |
| MSIDATABASE *db; |
| UINT ret; |
| |
| TRACE("%s %s %p\n",debugstr_w(szDBPath),debugstr_w(szPersist), phDB); |
| |
| ret = MSI_OpenDatabaseW( szDBPath, szPersist, &db ); |
| if( ret == ERROR_SUCCESS ) |
| { |
| *phDB = alloc_msihandle( &db->hdr ); |
| msiobj_release( &db->hdr ); |
| } |
| |
| return ret; |
| } |
| |
| UINT WINAPI MsiOpenDatabaseA(LPCSTR szDBPath, LPCSTR szPersist, MSIHANDLE *phDB) |
| { |
| HRESULT r = ERROR_FUNCTION_FAILED; |
| LPWSTR szwDBPath = NULL, szwPersist = NULL; |
| |
| TRACE("%s %s %p\n", debugstr_a(szDBPath), debugstr_a(szPersist), phDB); |
| |
| if( szDBPath ) |
| { |
| szwDBPath = strdupAtoW( szDBPath ); |
| if( !szwDBPath ) |
| goto end; |
| } |
| |
| if( HIWORD(szPersist) ) |
| { |
| szwPersist = strdupAtoW( szPersist ); |
| if( !szwPersist ) |
| goto end; |
| } |
| else |
| szwPersist = (LPWSTR)(DWORD)szPersist; |
| |
| r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB ); |
| |
| end: |
| if( HIWORD(szPersist) ) |
| msi_free( szwPersist ); |
| msi_free( szwDBPath ); |
| |
| return r; |
| } |
| |
| UINT MSI_DatabaseImport( MSIDATABASE *db, LPCWSTR folder, LPCWSTR file ) |
| { |
| FIXME("%p %s %s\n", db, debugstr_w(folder), debugstr_w(file) ); |
| |
| if( folder == NULL || file == NULL ) |
| return ERROR_INVALID_PARAMETER; |
| |
| return ERROR_CALL_NOT_IMPLEMENTED; |
| } |
| |
| UINT WINAPI MsiDatabaseImportW(MSIHANDLE handle, LPCWSTR szFolder, LPCWSTR szFilename) |
| { |
| MSIDATABASE *db; |
| UINT r; |
| |
| TRACE("%lx %s %s\n",handle,debugstr_w(szFolder), debugstr_w(szFilename)); |
| |
| db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE ); |
| if( !db ) |
| return ERROR_INVALID_HANDLE; |
| r = MSI_DatabaseImport( db, szFolder, szFilename ); |
| msiobj_release( &db->hdr ); |
| return r; |
| } |
| |
| UINT WINAPI MsiDatabaseImportA( MSIHANDLE handle, |
| LPCSTR szFolder, LPCSTR szFilename ) |
| { |
| LPWSTR path = NULL, file = NULL; |
| UINT r = ERROR_OUTOFMEMORY; |
| |
| TRACE("%lx %s %s\n", handle, debugstr_a(szFolder), debugstr_a(szFilename)); |
| |
| if( szFolder ) |
| { |
| path = strdupAtoW( szFolder ); |
| if( !path ) |
| goto end; |
| } |
| |
| if( szFilename ) |
| { |
| file = strdupAtoW( szFilename ); |
| if( !file ) |
| goto end; |
| } |
| |
| r = MsiDatabaseImportW( handle, path, file ); |
| |
| end: |
| msi_free( path ); |
| msi_free( file ); |
| |
| return r; |
| } |
| |
| UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table, |
| LPCWSTR folder, LPCWSTR file ) |
| { |
| FIXME("%p %s %s %s\n", db, debugstr_w(table), |
| debugstr_w(folder), debugstr_w(file) ); |
| |
| if( folder == NULL || file == NULL ) |
| return ERROR_INVALID_PARAMETER; |
| |
| return ERROR_CALL_NOT_IMPLEMENTED; |
| } |
| |
| UINT WINAPI MsiDatabaseExportW( MSIHANDLE handle, LPCWSTR szTable, |
| LPCWSTR szFolder, LPCWSTR szFilename ) |
| { |
| MSIDATABASE *db; |
| UINT r; |
| |
| TRACE("%lx %s %s %s\n", handle, debugstr_w(szTable), |
| debugstr_w(szFolder), debugstr_w(szFilename)); |
| |
| db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE ); |
| if( !db ) |
| return ERROR_INVALID_HANDLE; |
| r = MSI_DatabaseExport( db, szTable, szFolder, szFilename ); |
| msiobj_release( &db->hdr ); |
| return r; |
| } |
| |
| UINT WINAPI MsiDatabaseExportA( MSIHANDLE handle, LPCSTR szTable, |
| LPCSTR szFolder, LPCSTR szFilename ) |
| { |
| LPWSTR path = NULL, file = NULL, table = NULL; |
| UINT r = ERROR_OUTOFMEMORY; |
| |
| TRACE("%lx %s %s %s\n", handle, debugstr_a(szTable), |
| debugstr_a(szFolder), debugstr_a(szFilename)); |
| |
| if( szTable ) |
| { |
| table = strdupAtoW( szTable ); |
| if( !table ) |
| goto end; |
| } |
| |
| if( szFolder ) |
| { |
| path = strdupAtoW( szFolder ); |
| if( !path ) |
| goto end; |
| } |
| |
| if( szFilename ) |
| { |
| file = strdupAtoW( szFilename ); |
| if( !file ) |
| goto end; |
| } |
| |
| r = MsiDatabaseExportW( handle, table, path, file ); |
| |
| end: |
| msi_free( table ); |
| msi_free( path ); |
| msi_free( file ); |
| |
| return r; |
| } |