Add a stub implementation of the BindImage action.
[wine] / dlls / msi / database.c
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2002,2003,2004,2005 Mike McCormack for CodeWeavers
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25
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"
36
37 #include "initguid.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(msi);
40
41 /*
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.
46  */
47 #define LPCTSTR LPCWSTR
48
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);
53
54 /*
55  *  .MSI  file format
56  *
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.
62  */
63
64 static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
65 {
66     MSIDATABASE *db = (MSIDATABASE *) arg;
67     DWORD r;
68
69     free_cached_tables( db );
70     msi_destroy_stringtable( db->strings );
71     r = IStorage_Release( db->storage );
72     if( r )
73         ERR("database reference count was not zero (%ld)\n", r);
74 }
75
76 UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
77 {
78     IStorage *stg = NULL;
79     HRESULT r;
80     MSIDATABASE *db = NULL;
81     UINT ret = ERROR_FUNCTION_FAILED;
82     LPCWSTR szMode;
83     STATSTG stat;
84
85     TRACE("%s %s\n",debugstr_w(szDBPath),debugstr_w(szPersist) );
86
87     if( !pdb )
88         return ERROR_INVALID_PARAMETER;
89
90     szMode = szPersist;
91     if( HIWORD( szPersist ) )
92     {
93         /* UINT len = lstrlenW( szPerist ) + 1; */
94         FIXME("don't support persist files yet\b");
95         return ERROR_INVALID_PARAMETER;
96         /* szMode = msi_alloc( len * sizeof (DWORD) ); */
97     }
98     else if( szPersist == MSIDBOPEN_READONLY )
99     {
100         r = StgOpenStorage( szDBPath, NULL,
101               STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
102     }
103     else if( szPersist == MSIDBOPEN_CREATE )
104     {
105         r = StgCreateDocfile( szDBPath, 
106               STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, &stg);
107         if( r == ERROR_SUCCESS )
108         {
109             IStorage_SetClass( stg, &CLSID_MsiDatabase );
110             r = init_string_table( stg );
111         }
112     }
113     else if( szPersist == MSIDBOPEN_TRANSACT )
114     {
115         r = StgOpenStorage( szDBPath, NULL,
116               STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
117     }
118     else
119     {
120         ERR("unknown flag %p\n",szPersist);
121         return ERROR_INVALID_PARAMETER;
122     }
123
124     if( FAILED( r ) )
125     {
126         FIXME("open failed r = %08lx!\n",r);
127         return ERROR_FUNCTION_FAILED;
128     }
129
130     r = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
131     if( FAILED( r ) )
132     {
133         FIXME("Failed to stat storage\n");
134         goto end;
135     }
136
137     if ( !IsEqualGUID( &stat.clsid, &CLSID_MsiDatabase ) &&
138          !IsEqualGUID( &stat.clsid, &CLSID_MsiPatch ) ) 
139     {
140         ERR("storage GUID is not a MSI database GUID %s\n",
141              debugstr_guid(&stat.clsid) );
142         goto end;
143     }
144
145     db = alloc_msiobject( MSIHANDLETYPE_DATABASE, sizeof (MSIDATABASE),
146                               MSI_CloseDatabase );
147     if( !db )
148     {
149         FIXME("Failed to allocate a handle\n");
150         goto end;
151     }
152
153     if( TRACE_ON( msi ) )
154         enum_stream_names( stg );
155
156     db->storage = stg;
157     db->mode = szMode;
158     list_init( &db->tables );
159
160     db->strings = load_string_table( stg );
161     if( !db->strings )
162         goto end;
163
164     ret = ERROR_SUCCESS;
165
166     msiobj_addref( &db->hdr );
167     IStorage_AddRef( stg );
168     *pdb = db;
169
170 end:
171     if( db )
172         msiobj_release( &db->hdr );
173     if( stg )
174         IStorage_Release( stg );
175
176     return ret;
177 }
178
179 UINT WINAPI MsiOpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIHANDLE *phDB)
180 {
181     MSIDATABASE *db;
182     UINT ret;
183
184     TRACE("%s %s %p\n",debugstr_w(szDBPath),debugstr_w(szPersist), phDB);
185
186     ret = MSI_OpenDatabaseW( szDBPath, szPersist, &db );
187     if( ret == ERROR_SUCCESS )
188     {
189         *phDB = alloc_msihandle( &db->hdr );
190         msiobj_release( &db->hdr );
191     }
192
193     return ret;
194 }
195
196 UINT WINAPI MsiOpenDatabaseA(LPCSTR szDBPath, LPCSTR szPersist, MSIHANDLE *phDB)
197 {
198     HRESULT r = ERROR_FUNCTION_FAILED;
199     LPWSTR szwDBPath = NULL, szwPersist = NULL;
200
201     TRACE("%s %s %p\n", debugstr_a(szDBPath), debugstr_a(szPersist), phDB);
202
203     if( szDBPath )
204     {
205         szwDBPath = strdupAtoW( szDBPath );
206         if( !szwDBPath )
207             goto end;
208     }
209
210     if( HIWORD(szPersist) )
211     {
212         szwPersist = strdupAtoW( szPersist );
213         if( !szwPersist )
214             goto end;
215     }
216     else
217         szwPersist = (LPWSTR)(DWORD)szPersist;
218
219     r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB );
220
221 end:
222     if( HIWORD(szPersist) )
223         msi_free( szwPersist );
224     msi_free( szwDBPath );
225
226     return r;
227 }
228
229 UINT MSI_DatabaseImport( MSIDATABASE *db, LPCWSTR folder, LPCWSTR file )
230 {
231     FIXME("%p %s %s\n", db, debugstr_w(folder), debugstr_w(file) );
232
233     if( folder == NULL || file == NULL )
234         return ERROR_INVALID_PARAMETER;
235    
236     return ERROR_CALL_NOT_IMPLEMENTED;
237 }
238
239 UINT WINAPI MsiDatabaseImportW(MSIHANDLE handle, LPCWSTR szFolder, LPCWSTR szFilename)
240 {
241     MSIDATABASE *db;
242     UINT r;
243
244     TRACE("%lx %s %s\n",handle,debugstr_w(szFolder), debugstr_w(szFilename));
245
246     db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
247     if( !db )
248         return ERROR_INVALID_HANDLE;
249     r = MSI_DatabaseImport( db, szFolder, szFilename );
250     msiobj_release( &db->hdr );
251     return r;
252 }
253
254 UINT WINAPI MsiDatabaseImportA( MSIHANDLE handle,
255                LPCSTR szFolder, LPCSTR szFilename )
256 {
257     LPWSTR path = NULL, file = NULL;
258     UINT r = ERROR_OUTOFMEMORY;
259
260     TRACE("%lx %s %s\n", handle, debugstr_a(szFolder), debugstr_a(szFilename));
261
262     if( szFolder )
263     {
264         path = strdupAtoW( szFolder );
265         if( !path )
266             goto end;
267     }
268
269     if( szFilename )
270     {
271         file = strdupAtoW( szFilename );
272         if( !file )
273             goto end;
274     }
275
276     r = MsiDatabaseImportW( handle, path, file );
277
278 end:
279     msi_free( path );
280     msi_free( file );
281
282     return r;
283 }
284
285 UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table,
286                LPCWSTR folder, LPCWSTR file )
287 {
288     FIXME("%p %s %s %s\n", db, debugstr_w(table),
289           debugstr_w(folder), debugstr_w(file) );
290
291     if( folder == NULL || file == NULL )
292         return ERROR_INVALID_PARAMETER;
293    
294     return ERROR_CALL_NOT_IMPLEMENTED;
295 }
296
297 UINT WINAPI MsiDatabaseExportW( MSIHANDLE handle, LPCWSTR szTable,
298                LPCWSTR szFolder, LPCWSTR szFilename )
299 {
300     MSIDATABASE *db;
301     UINT r;
302
303     TRACE("%lx %s %s %s\n", handle, debugstr_w(szTable),
304           debugstr_w(szFolder), debugstr_w(szFilename));
305
306     db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
307     if( !db )
308         return ERROR_INVALID_HANDLE;
309     r = MSI_DatabaseExport( db, szTable, szFolder, szFilename );
310     msiobj_release( &db->hdr );
311     return r;
312 }
313
314 UINT WINAPI MsiDatabaseExportA( MSIHANDLE handle, LPCSTR szTable,
315                LPCSTR szFolder, LPCSTR szFilename )
316 {
317     LPWSTR path = NULL, file = NULL, table = NULL;
318     UINT r = ERROR_OUTOFMEMORY;
319
320     TRACE("%lx %s %s %s\n", handle, debugstr_a(szTable),
321           debugstr_a(szFolder), debugstr_a(szFilename));
322
323     if( szTable )
324     {
325         table = strdupAtoW( szTable );
326         if( !table )
327             goto end;
328     }
329
330     if( szFolder )
331     {
332         path = strdupAtoW( szFolder );
333         if( !path )
334             goto end;
335     }
336
337     if( szFilename )
338     {
339         file = strdupAtoW( szFilename );
340         if( !file )
341             goto end;
342     }
343
344     r = MsiDatabaseExportW( handle, table, path, file );
345
346 end:
347     msi_free( table );
348     msi_free( path );
349     msi_free( file );
350
351     return r;
352 }