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