Replace a few more direct lpVtbl accesses by the proper macros.
[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 = HeapAlloc( GetProcessHeap(), 0, 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(( memcmp( &stat.clsid, &CLSID_MsiDatabase, sizeof (GUID) ) )
138      && ( memcmp( &stat.clsid, &CLSID_MsiPatch, sizeof (GUID) ) ))
139     {
140         ERR("storage GUID is not a MSI database GUID %s\n",
141              debugstr_guid(&stat.clsid) );
142         goto end;
143     }
144
145
146     db = alloc_msiobject( MSIHANDLETYPE_DATABASE, sizeof (MSIDATABASE),
147                               MSI_CloseDatabase );
148     if( !db )
149     {
150         FIXME("Failed to allocate a handle\n");
151         goto end;
152     }
153
154     if( TRACE_ON( msi ) )
155         enum_stream_names( stg );
156
157     db->storage = stg;
158     db->mode = szMode;
159
160     ret = load_string_table( db );
161     if( ret != ERROR_SUCCESS )
162         goto end;
163
164     msiobj_addref( &db->hdr );
165     IStorage_AddRef( stg );
166     *pdb = db;
167
168 end:
169     if( db )
170         msiobj_release( &db->hdr );
171     if( stg )
172         IStorage_Release( stg );
173
174     return ret;
175 }
176
177 UINT WINAPI MsiOpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIHANDLE *phDB)
178 {
179     MSIDATABASE *db;
180     UINT ret;
181
182     TRACE("%s %s %p\n",debugstr_w(szDBPath),debugstr_w(szPersist), phDB);
183
184     ret = MSI_OpenDatabaseW( szDBPath, szPersist, &db );
185     if( ret == ERROR_SUCCESS )
186     {
187         *phDB = alloc_msihandle( &db->hdr );
188         msiobj_release( &db->hdr );
189     }
190
191     return ret;
192 }
193
194 UINT WINAPI MsiOpenDatabaseA(LPCSTR szDBPath, LPCSTR szPersist, MSIHANDLE *phDB)
195 {
196     HRESULT r = ERROR_FUNCTION_FAILED;
197     LPWSTR szwDBPath = NULL, szwPersist = NULL;
198
199     TRACE("%s %s %p\n", debugstr_a(szDBPath), debugstr_a(szPersist), phDB);
200
201     if( szDBPath )
202     {
203         szwDBPath = strdupAtoW( szDBPath );
204         if( !szwDBPath )
205             goto end;
206     }
207
208     if( HIWORD(szPersist) )
209     {
210         szwPersist = strdupAtoW( szPersist );
211         if( !szwPersist )
212             goto end;
213     }
214     else
215         szwPersist = (LPWSTR)(DWORD)szPersist;
216
217     r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB );
218
219 end:
220     if( HIWORD(szPersist) )
221         HeapFree( GetProcessHeap(), 0, szwPersist );
222     HeapFree( GetProcessHeap(), 0, szwDBPath );
223
224     return r;
225 }
226
227 UINT MSI_DatabaseImport( MSIDATABASE *db, LPCWSTR folder, LPCWSTR file )
228 {
229     FIXME("%p %s %s\n", db, debugstr_w(folder), debugstr_w(file) );
230
231     if( folder == NULL || file == NULL )
232         return ERROR_INVALID_PARAMETER;
233    
234     return ERROR_CALL_NOT_IMPLEMENTED;
235 }
236
237 UINT WINAPI MsiDatabaseImportW(MSIHANDLE handle, LPCWSTR szFolder, LPCWSTR szFilename)
238 {
239     MSIDATABASE *db;
240     UINT r;
241
242     TRACE("%lx %s %s\n",handle,debugstr_w(szFolder), debugstr_w(szFilename));
243
244     db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
245     if( !db )
246         return ERROR_INVALID_HANDLE;
247     r = MSI_DatabaseImport( db, szFolder, szFilename );
248     msiobj_release( &db->hdr );
249     return r;
250 }
251
252 UINT WINAPI MsiDatabaseImportA( MSIHANDLE handle,
253                LPCSTR szFolder, LPCSTR szFilename )
254 {
255     LPWSTR path = NULL, file = NULL;
256     UINT r = ERROR_OUTOFMEMORY;
257
258     TRACE("%lx %s %s\n", handle, debugstr_a(szFolder), debugstr_a(szFilename));
259
260     if( szFolder )
261     {
262         path = strdupAtoW( szFolder );
263         if( !path )
264             goto end;
265     }
266
267     if( szFilename )
268     {
269         file = strdupAtoW( szFilename );
270         if( !file )
271             goto end;
272     }
273
274     r = MsiDatabaseImportW( handle, path, file );
275
276 end:
277     HeapFree( GetProcessHeap(), 0, path );
278     HeapFree( GetProcessHeap(), 0, file );
279
280     return r;
281 }
282
283 UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table,
284                LPCWSTR folder, LPCWSTR file )
285 {
286     FIXME("%p %s %s %s\n", db, debugstr_w(table),
287           debugstr_w(folder), debugstr_w(file) );
288
289     if( folder == NULL || file == NULL )
290         return ERROR_INVALID_PARAMETER;
291    
292     return ERROR_CALL_NOT_IMPLEMENTED;
293 }
294
295 UINT WINAPI MsiDatabaseExportW( MSIHANDLE handle, LPCWSTR szTable,
296                LPCWSTR szFolder, LPCWSTR szFilename )
297 {
298     MSIDATABASE *db;
299     UINT r;
300
301     TRACE("%lx %s %s %s\n", handle, debugstr_w(szTable),
302           debugstr_w(szFolder), debugstr_w(szFilename));
303
304     db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
305     if( !db )
306         return ERROR_INVALID_HANDLE;
307     r = MSI_DatabaseExport( db, szTable, szFolder, szFilename );
308     msiobj_release( &db->hdr );
309     return r;
310 }
311
312 UINT WINAPI MsiDatabaseExportA( MSIHANDLE handle, LPCSTR szTable,
313                LPCSTR szFolder, LPCSTR szFilename )
314 {
315     LPWSTR path = NULL, file = NULL, table = NULL;
316     UINT r = ERROR_OUTOFMEMORY;
317
318     TRACE("%lx %s %s %s\n", handle, debugstr_a(szTable),
319           debugstr_a(szFolder), debugstr_a(szFilename));
320
321     if( szTable )
322     {
323         table = strdupAtoW( szTable );
324         if( !table )
325             goto end;
326     }
327
328     if( szFolder )
329     {
330         path = strdupAtoW( szFolder );
331         if( !path )
332             goto end;
333     }
334
335     if( szFilename )
336     {
337         file = strdupAtoW( szFilename );
338         if( !file )
339             goto end;
340     }
341
342     r = MsiDatabaseExportW( handle, table, path, file );
343
344 end:
345     HeapFree( GetProcessHeap(), 0, table );
346     HeapFree( GetProcessHeap(), 0, path );
347     HeapFree( GetProcessHeap(), 0, file );
348
349     return r;
350 }