Implement transforms. This still includes some debugging code which
[wine/gsoc_dplay.git] / dlls / msi / database.c
blob6af8b475a75a214ec749a92101837c0874dcd807
1 /*
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <stdarg.h>
23 #define COBJMACROS
24 #define NONAMELESSUNION
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "winnls.h"
30 #include "wine/debug.h"
31 #include "msi.h"
32 #include "msiquery.h"
33 #include "msipriv.h"
34 #include "objidl.h"
35 #include "objbase.h"
37 #include "initguid.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msi);
42 * The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR,
43 * which is a problem because LPCTSTR isn't defined when compiling wine.
44 * To work around this problem, we need to define LPCTSTR as LPCWSTR here,
45 * and make sure to only use it in W functions.
47 #define LPCTSTR LPCWSTR
49 DEFINE_GUID( CLSID_MsiDatabase, 0x000c1084, 0x0000, 0x0000,
50 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
51 DEFINE_GUID( CLSID_MsiPatch, 0x000c1086, 0x0000, 0x0000,
52 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
55 * .MSI file format
57 * An .msi file is a structured storage file.
58 * It contains a number of streams.
59 * A stream for each table in the database.
60 * Two streams for the string table in the database.
61 * Any binary data in a table is a reference to a stream.
64 static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
66 MSIDATABASE *db = (MSIDATABASE *) arg;
67 DWORD r;
69 free_cached_tables( db );
70 msi_free_transforms( db );
71 msi_destroy_stringtable( db->strings );
72 r = IStorage_Release( db->storage );
73 if( r )
74 ERR("database reference count was not zero (%ld)\n", r);
77 UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
79 IStorage *stg = NULL;
80 HRESULT r;
81 MSIDATABASE *db = NULL;
82 UINT ret = ERROR_FUNCTION_FAILED;
83 LPCWSTR szMode;
84 STATSTG stat;
86 TRACE("%s %s\n",debugstr_w(szDBPath),debugstr_w(szPersist) );
88 if( !pdb )
89 return ERROR_INVALID_PARAMETER;
91 szMode = szPersist;
92 if( HIWORD( szPersist ) )
94 /* UINT len = lstrlenW( szPerist ) + 1; */
95 FIXME("don't support persist files yet\b");
96 return ERROR_INVALID_PARAMETER;
97 /* szMode = msi_alloc( len * sizeof (DWORD) ); */
99 else if( szPersist == MSIDBOPEN_READONLY )
101 r = StgOpenStorage( szDBPath, NULL,
102 STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
104 else if( szPersist == MSIDBOPEN_CREATE )
106 r = StgCreateDocfile( szDBPath,
107 STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, &stg);
108 if( r == ERROR_SUCCESS )
110 IStorage_SetClass( stg, &CLSID_MsiDatabase );
111 r = init_string_table( stg );
114 else if( szPersist == MSIDBOPEN_TRANSACT )
116 r = StgOpenStorage( szDBPath, NULL,
117 STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
119 else
121 ERR("unknown flag %p\n",szPersist);
122 return ERROR_INVALID_PARAMETER;
125 if( FAILED( r ) )
127 FIXME("open failed r = %08lx!\n",r);
128 return ERROR_FUNCTION_FAILED;
131 r = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
132 if( FAILED( r ) )
134 FIXME("Failed to stat storage\n");
135 goto end;
138 if ( !IsEqualGUID( &stat.clsid, &CLSID_MsiDatabase ) &&
139 !IsEqualGUID( &stat.clsid, &CLSID_MsiPatch ) )
141 ERR("storage GUID is not a MSI database GUID %s\n",
142 debugstr_guid(&stat.clsid) );
143 goto end;
146 db = alloc_msiobject( MSIHANDLETYPE_DATABASE, sizeof (MSIDATABASE),
147 MSI_CloseDatabase );
148 if( !db )
150 FIXME("Failed to allocate a handle\n");
151 goto end;
154 if( TRACE_ON( msi ) )
155 enum_stream_names( stg );
157 db->storage = stg;
158 db->mode = szMode;
159 list_init( &db->tables );
160 list_init( &db->transforms );
162 db->strings = load_string_table( stg );
163 if( !db->strings )
164 goto end;
166 ret = ERROR_SUCCESS;
168 msiobj_addref( &db->hdr );
169 IStorage_AddRef( stg );
170 *pdb = db;
172 end:
173 if( db )
174 msiobj_release( &db->hdr );
175 if( stg )
176 IStorage_Release( stg );
178 return ret;
181 UINT WINAPI MsiOpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIHANDLE *phDB)
183 MSIDATABASE *db;
184 UINT ret;
186 TRACE("%s %s %p\n",debugstr_w(szDBPath),debugstr_w(szPersist), phDB);
188 ret = MSI_OpenDatabaseW( szDBPath, szPersist, &db );
189 if( ret == ERROR_SUCCESS )
191 *phDB = alloc_msihandle( &db->hdr );
192 msiobj_release( &db->hdr );
195 return ret;
198 UINT WINAPI MsiOpenDatabaseA(LPCSTR szDBPath, LPCSTR szPersist, MSIHANDLE *phDB)
200 HRESULT r = ERROR_FUNCTION_FAILED;
201 LPWSTR szwDBPath = NULL, szwPersist = NULL;
203 TRACE("%s %s %p\n", debugstr_a(szDBPath), debugstr_a(szPersist), phDB);
205 if( szDBPath )
207 szwDBPath = strdupAtoW( szDBPath );
208 if( !szwDBPath )
209 goto end;
212 if( HIWORD(szPersist) )
214 szwPersist = strdupAtoW( szPersist );
215 if( !szwPersist )
216 goto end;
218 else
219 szwPersist = (LPWSTR)(DWORD)szPersist;
221 r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB );
223 end:
224 if( HIWORD(szPersist) )
225 msi_free( szwPersist );
226 msi_free( szwDBPath );
228 return r;
231 UINT MSI_DatabaseImport( MSIDATABASE *db, LPCWSTR folder, LPCWSTR file )
233 FIXME("%p %s %s\n", db, debugstr_w(folder), debugstr_w(file) );
235 if( folder == NULL || file == NULL )
236 return ERROR_INVALID_PARAMETER;
238 return ERROR_CALL_NOT_IMPLEMENTED;
241 UINT WINAPI MsiDatabaseImportW(MSIHANDLE handle, LPCWSTR szFolder, LPCWSTR szFilename)
243 MSIDATABASE *db;
244 UINT r;
246 TRACE("%lx %s %s\n",handle,debugstr_w(szFolder), debugstr_w(szFilename));
248 db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
249 if( !db )
250 return ERROR_INVALID_HANDLE;
251 r = MSI_DatabaseImport( db, szFolder, szFilename );
252 msiobj_release( &db->hdr );
253 return r;
256 UINT WINAPI MsiDatabaseImportA( MSIHANDLE handle,
257 LPCSTR szFolder, LPCSTR szFilename )
259 LPWSTR path = NULL, file = NULL;
260 UINT r = ERROR_OUTOFMEMORY;
262 TRACE("%lx %s %s\n", handle, debugstr_a(szFolder), debugstr_a(szFilename));
264 if( szFolder )
266 path = strdupAtoW( szFolder );
267 if( !path )
268 goto end;
271 if( szFilename )
273 file = strdupAtoW( szFilename );
274 if( !file )
275 goto end;
278 r = MsiDatabaseImportW( handle, path, file );
280 end:
281 msi_free( path );
282 msi_free( file );
284 return r;
287 UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table,
288 LPCWSTR folder, LPCWSTR file )
290 FIXME("%p %s %s %s\n", db, debugstr_w(table),
291 debugstr_w(folder), debugstr_w(file) );
293 if( folder == NULL || file == NULL )
294 return ERROR_INVALID_PARAMETER;
296 return ERROR_CALL_NOT_IMPLEMENTED;
299 UINT WINAPI MsiDatabaseExportW( MSIHANDLE handle, LPCWSTR szTable,
300 LPCWSTR szFolder, LPCWSTR szFilename )
302 MSIDATABASE *db;
303 UINT r;
305 TRACE("%lx %s %s %s\n", handle, debugstr_w(szTable),
306 debugstr_w(szFolder), debugstr_w(szFilename));
308 db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
309 if( !db )
310 return ERROR_INVALID_HANDLE;
311 r = MSI_DatabaseExport( db, szTable, szFolder, szFilename );
312 msiobj_release( &db->hdr );
313 return r;
316 UINT WINAPI MsiDatabaseExportA( MSIHANDLE handle, LPCSTR szTable,
317 LPCSTR szFolder, LPCSTR szFilename )
319 LPWSTR path = NULL, file = NULL, table = NULL;
320 UINT r = ERROR_OUTOFMEMORY;
322 TRACE("%lx %s %s %s\n", handle, debugstr_a(szTable),
323 debugstr_a(szFolder), debugstr_a(szFilename));
325 if( szTable )
327 table = strdupAtoW( szTable );
328 if( !table )
329 goto end;
332 if( szFolder )
334 path = strdupAtoW( szFolder );
335 if( !path )
336 goto end;
339 if( szFilename )
341 file = strdupAtoW( szFilename );
342 if( !file )
343 goto end;
346 r = MsiDatabaseExportW( handle, table, path, file );
348 end:
349 msi_free( table );
350 msi_free( path );
351 msi_free( file );
353 return r;