2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2002,2003,2004,2005 Mike McCormack for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #define NONAMELESSUNION
30 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msi
);
41 DEFINE_GUID( CLSID_MsiDatabase
, 0x000c1084, 0x0000, 0x0000,
42 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
43 DEFINE_GUID( CLSID_MsiPatch
, 0x000c1086, 0x0000, 0x0000,
44 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
49 * An .msi file is a structured storage file.
50 * It contains a number of streams.
51 * A stream for each table in the database.
52 * Two streams for the string table in the database.
53 * Any binary data in a table is a reference to a stream.
56 static VOID
MSI_CloseDatabase( MSIOBJECTHDR
*arg
)
58 MSIDATABASE
*db
= (MSIDATABASE
*) arg
;
61 free_cached_tables( db
);
62 msi_free_transforms( db
);
63 msi_destroy_stringtable( db
->strings
);
64 r
= IStorage_Release( db
->storage
);
66 ERR("database reference count was not zero (%ld)\n", r
);
69 UINT
MSI_OpenDatabaseW(LPCWSTR szDBPath
, LPCWSTR szPersist
, MSIDATABASE
**pdb
)
73 MSIDATABASE
*db
= NULL
;
74 UINT ret
= ERROR_FUNCTION_FAILED
;
78 TRACE("%s %s\n",debugstr_w(szDBPath
),debugstr_w(szPersist
) );
81 return ERROR_INVALID_PARAMETER
;
84 if( HIWORD( szPersist
) )
86 /* UINT len = lstrlenW( szPerist ) + 1; */
87 FIXME("don't support persist files yet\b");
88 return ERROR_INVALID_PARAMETER
;
89 /* szMode = msi_alloc( len * sizeof (DWORD) ); */
91 else if( szPersist
== MSIDBOPEN_READONLY
)
93 r
= StgOpenStorage( szDBPath
, NULL
,
94 STGM_DIRECT
|STGM_READ
|STGM_SHARE_DENY_WRITE
, NULL
, 0, &stg
);
96 else if( szPersist
== MSIDBOPEN_CREATE
|| szPersist
== MSIDBOPEN_CREATEDIRECT
)
98 /* FIXME: MSIDBOPEN_CREATE should case STGM_TRANSACTED flag to be
100 r
= StgCreateDocfile( szDBPath
,
101 STGM_DIRECT
|STGM_READWRITE
|STGM_SHARE_EXCLUSIVE
, 0, &stg
);
102 if( r
== ERROR_SUCCESS
)
104 IStorage_SetClass( stg
, &CLSID_MsiDatabase
);
105 r
= init_string_table( stg
);
108 else if( szPersist
== MSIDBOPEN_TRANSACT
)
110 /* FIXME: MSIDBOPEN_TRANSACT should case STGM_TRANSACTED flag to be
112 r
= StgOpenStorage( szDBPath
, NULL
,
113 STGM_DIRECT
|STGM_READWRITE
|STGM_SHARE_EXCLUSIVE
, NULL
, 0, &stg
);
115 else if( szPersist
== MSIDBOPEN_DIRECT
)
117 r
= StgOpenStorage( szDBPath
, NULL
,
118 STGM_DIRECT
|STGM_READWRITE
|STGM_SHARE_EXCLUSIVE
, NULL
, 0, &stg
);
122 ERR("unknown flag %p\n",szPersist
);
123 return ERROR_INVALID_PARAMETER
;
128 FIXME("open failed r = %08lx!\n",r
);
129 return ERROR_FUNCTION_FAILED
;
132 r
= IStorage_Stat( stg
, &stat
, STATFLAG_NONAME
);
135 FIXME("Failed to stat storage\n");
139 if ( !IsEqualGUID( &stat
.clsid
, &CLSID_MsiDatabase
) &&
140 !IsEqualGUID( &stat
.clsid
, &CLSID_MsiPatch
) )
142 ERR("storage GUID is not a MSI database GUID %s\n",
143 debugstr_guid(&stat
.clsid
) );
147 db
= alloc_msiobject( MSIHANDLETYPE_DATABASE
, sizeof (MSIDATABASE
),
151 FIXME("Failed to allocate a handle\n");
155 if( TRACE_ON( msi
) )
156 enum_stream_names( stg
);
160 list_init( &db
->tables
);
161 list_init( &db
->transforms
);
163 db
->strings
= load_string_table( stg
);
169 msiobj_addref( &db
->hdr
);
170 IStorage_AddRef( stg
);
175 msiobj_release( &db
->hdr
);
177 IStorage_Release( stg
);
182 UINT WINAPI
MsiOpenDatabaseW(LPCWSTR szDBPath
, LPCWSTR szPersist
, MSIHANDLE
*phDB
)
187 TRACE("%s %s %p\n",debugstr_w(szDBPath
),debugstr_w(szPersist
), phDB
);
189 ret
= MSI_OpenDatabaseW( szDBPath
, szPersist
, &db
);
190 if( ret
== ERROR_SUCCESS
)
192 *phDB
= alloc_msihandle( &db
->hdr
);
194 ret
= ERROR_NOT_ENOUGH_MEMORY
;
195 msiobj_release( &db
->hdr
);
201 UINT WINAPI
MsiOpenDatabaseA(LPCSTR szDBPath
, LPCSTR szPersist
, MSIHANDLE
*phDB
)
203 HRESULT r
= ERROR_FUNCTION_FAILED
;
204 LPWSTR szwDBPath
= NULL
, szwPersist
= NULL
;
206 TRACE("%s %s %p\n", debugstr_a(szDBPath
), debugstr_a(szPersist
), phDB
);
210 szwDBPath
= strdupAtoW( szDBPath
);
215 if( HIWORD(szPersist
) )
217 szwPersist
= strdupAtoW( szPersist
);
222 szwPersist
= (LPWSTR
)(DWORD_PTR
)szPersist
;
224 r
= MsiOpenDatabaseW( szwDBPath
, szwPersist
, phDB
);
227 if( HIWORD(szPersist
) )
228 msi_free( szwPersist
);
229 msi_free( szwDBPath
);
234 UINT
MSI_DatabaseImport( MSIDATABASE
*db
, LPCWSTR folder
, LPCWSTR file
)
236 FIXME("%p %s %s\n", db
, debugstr_w(folder
), debugstr_w(file
) );
238 if( folder
== NULL
|| file
== NULL
)
239 return ERROR_INVALID_PARAMETER
;
241 return ERROR_CALL_NOT_IMPLEMENTED
;
244 UINT WINAPI
MsiDatabaseImportW(MSIHANDLE handle
, LPCWSTR szFolder
, LPCWSTR szFilename
)
249 TRACE("%lx %s %s\n",handle
,debugstr_w(szFolder
), debugstr_w(szFilename
));
251 db
= msihandle2msiinfo( handle
, MSIHANDLETYPE_DATABASE
);
253 return ERROR_INVALID_HANDLE
;
254 r
= MSI_DatabaseImport( db
, szFolder
, szFilename
);
255 msiobj_release( &db
->hdr
);
259 UINT WINAPI
MsiDatabaseImportA( MSIHANDLE handle
,
260 LPCSTR szFolder
, LPCSTR szFilename
)
262 LPWSTR path
= NULL
, file
= NULL
;
263 UINT r
= ERROR_OUTOFMEMORY
;
265 TRACE("%lx %s %s\n", handle
, debugstr_a(szFolder
), debugstr_a(szFilename
));
269 path
= strdupAtoW( szFolder
);
276 file
= strdupAtoW( szFilename
);
281 r
= MsiDatabaseImportW( handle
, path
, file
);
290 UINT
MSI_DatabaseExport( MSIDATABASE
*db
, LPCWSTR table
,
291 LPCWSTR folder
, LPCWSTR file
)
293 FIXME("%p %s %s %s\n", db
, debugstr_w(table
),
294 debugstr_w(folder
), debugstr_w(file
) );
296 if( folder
== NULL
|| file
== NULL
)
297 return ERROR_INVALID_PARAMETER
;
299 return ERROR_CALL_NOT_IMPLEMENTED
;
302 UINT WINAPI
MsiDatabaseExportW( MSIHANDLE handle
, LPCWSTR szTable
,
303 LPCWSTR szFolder
, LPCWSTR szFilename
)
308 TRACE("%lx %s %s %s\n", handle
, debugstr_w(szTable
),
309 debugstr_w(szFolder
), debugstr_w(szFilename
));
311 db
= msihandle2msiinfo( handle
, MSIHANDLETYPE_DATABASE
);
313 return ERROR_INVALID_HANDLE
;
314 r
= MSI_DatabaseExport( db
, szTable
, szFolder
, szFilename
);
315 msiobj_release( &db
->hdr
);
319 UINT WINAPI
MsiDatabaseExportA( MSIHANDLE handle
, LPCSTR szTable
,
320 LPCSTR szFolder
, LPCSTR szFilename
)
322 LPWSTR path
= NULL
, file
= NULL
, table
= NULL
;
323 UINT r
= ERROR_OUTOFMEMORY
;
325 TRACE("%lx %s %s %s\n", handle
, debugstr_a(szTable
),
326 debugstr_a(szFolder
), debugstr_a(szFilename
));
330 table
= strdupAtoW( szTable
);
337 path
= strdupAtoW( szFolder
);
344 file
= strdupAtoW( szFilename
);
349 r
= MsiDatabaseExportW( handle
, table
, path
, file
);
359 MSIDBSTATE WINAPI
MsiGetDatabaseState( MSIHANDLE handle
)
361 MSIDBSTATE ret
= MSIDBSTATE_READ
;
364 TRACE("%ld\n", handle
);
366 db
= msihandle2msiinfo( handle
, MSIHANDLETYPE_DATABASE
);
368 return MSIDBSTATE_ERROR
;
369 if (db
->mode
!= MSIDBOPEN_READONLY
)
370 ret
= MSIDBSTATE_WRITE
;
371 msiobj_release( &db
->hdr
);