Don't change the UI level during ExecuteAction.
[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_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);
75 }
76
77 UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
78 {
79     IStorage *stg = NULL;
80     HRESULT r;
81     MSIDATABASE *db = NULL;
82     UINT ret = ERROR_FUNCTION_FAILED;
83     LPCWSTR szMode;
84     STATSTG stat;
85
86     TRACE("%s %s\n",debugstr_w(szDBPath),debugstr_w(szPersist) );
87
88     if( !pdb )
89         return ERROR_INVALID_PARAMETER;
90
91     szMode = szPersist;
92     if( HIWORD( szPersist ) )
93     {
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) ); */
98     }
99     else if( szPersist == MSIDBOPEN_READONLY )
100     {
101         r = StgOpenStorage( szDBPath, NULL,
102               STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
103     }
104     else if( szPersist == MSIDBOPEN_CREATE )
105     {
106         r = StgCreateDocfile( szDBPath, 
107               STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, &stg);
108         if( r == ERROR_SUCCESS )
109         {
110             IStorage_SetClass( stg, &CLSID_MsiDatabase );
111             r = init_string_table( stg );
112         }
113     }
114     else if( szPersist == MSIDBOPEN_TRANSACT )
115     {
116         r = StgOpenStorage( szDBPath, NULL,
117               STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
118     }
119     else
120     {
121         ERR("unknown flag %p\n",szPersist);
122         return ERROR_INVALID_PARAMETER;
123     }
124
125     if( FAILED( r ) )
126     {
127         FIXME("open failed r = %08lx!\n",r);
128         return ERROR_FUNCTION_FAILED;
129     }
130
131     r = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
132     if( FAILED( r ) )
133     {
134         FIXME("Failed to stat storage\n");
135         goto end;
136     }
137
138     if ( !IsEqualGUID( &stat.clsid, &CLSID_MsiDatabase ) &&
139          !IsEqualGUID( &stat.clsid, &CLSID_MsiPatch ) ) 
140     {
141         ERR("storage GUID is not a MSI database GUID %s\n",
142              debugstr_guid(&stat.clsid) );
143         goto end;
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     list_init( &db->tables );
160     list_init( &db->transforms );
161
162     db->strings = load_string_table( stg );
163     if( !db->strings )
164         goto end;
165
166     ret = ERROR_SUCCESS;
167
168     msiobj_addref( &db->hdr );
169     IStorage_AddRef( stg );
170     *pdb = db;
171
172 end:
173     if( db )
174         msiobj_release( &db->hdr );
175     if( stg )
176         IStorage_Release( stg );
177
178     return ret;
179 }
180
181 UINT WINAPI MsiOpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIHANDLE *phDB)
182 {
183     MSIDATABASE *db;
184     UINT ret;
185
186     TRACE("%s %s %p\n",debugstr_w(szDBPath),debugstr_w(szPersist), phDB);
187
188     ret = MSI_OpenDatabaseW( szDBPath, szPersist, &db );
189     if( ret == ERROR_SUCCESS )
190     {
191         *phDB = alloc_msihandle( &db->hdr );
192         msiobj_release( &db->hdr );
193     }
194
195     return ret;
196 }
197
198 UINT WINAPI MsiOpenDatabaseA(LPCSTR szDBPath, LPCSTR szPersist, MSIHANDLE *phDB)
199 {
200     HRESULT r = ERROR_FUNCTION_FAILED;
201     LPWSTR szwDBPath = NULL, szwPersist = NULL;
202
203     TRACE("%s %s %p\n", debugstr_a(szDBPath), debugstr_a(szPersist), phDB);
204
205     if( szDBPath )
206     {
207         szwDBPath = strdupAtoW( szDBPath );
208         if( !szwDBPath )
209             goto end;
210     }
211
212     if( HIWORD(szPersist) )
213     {
214         szwPersist = strdupAtoW( szPersist );
215         if( !szwPersist )
216             goto end;
217     }
218     else
219         szwPersist = (LPWSTR)(DWORD)szPersist;
220
221     r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB );
222
223 end:
224     if( HIWORD(szPersist) )
225         msi_free( szwPersist );
226     msi_free( szwDBPath );
227
228     return r;
229 }
230
231 UINT MSI_DatabaseImport( MSIDATABASE *db, LPCWSTR folder, LPCWSTR file )
232 {
233     FIXME("%p %s %s\n", db, debugstr_w(folder), debugstr_w(file) );
234
235     if( folder == NULL || file == NULL )
236         return ERROR_INVALID_PARAMETER;
237    
238     return ERROR_CALL_NOT_IMPLEMENTED;
239 }
240
241 UINT WINAPI MsiDatabaseImportW(MSIHANDLE handle, LPCWSTR szFolder, LPCWSTR szFilename)
242 {
243     MSIDATABASE *db;
244     UINT r;
245
246     TRACE("%lx %s %s\n",handle,debugstr_w(szFolder), debugstr_w(szFilename));
247
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;
254 }
255
256 UINT WINAPI MsiDatabaseImportA( MSIHANDLE handle,
257                LPCSTR szFolder, LPCSTR szFilename )
258 {
259     LPWSTR path = NULL, file = NULL;
260     UINT r = ERROR_OUTOFMEMORY;
261
262     TRACE("%lx %s %s\n", handle, debugstr_a(szFolder), debugstr_a(szFilename));
263
264     if( szFolder )
265     {
266         path = strdupAtoW( szFolder );
267         if( !path )
268             goto end;
269     }
270
271     if( szFilename )
272     {
273         file = strdupAtoW( szFilename );
274         if( !file )
275             goto end;
276     }
277
278     r = MsiDatabaseImportW( handle, path, file );
279
280 end:
281     msi_free( path );
282     msi_free( file );
283
284     return r;
285 }
286
287 UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table,
288                LPCWSTR folder, LPCWSTR file )
289 {
290     FIXME("%p %s %s %s\n", db, debugstr_w(table),
291           debugstr_w(folder), debugstr_w(file) );
292
293     if( folder == NULL || file == NULL )
294         return ERROR_INVALID_PARAMETER;
295    
296     return ERROR_CALL_NOT_IMPLEMENTED;
297 }
298
299 UINT WINAPI MsiDatabaseExportW( MSIHANDLE handle, LPCWSTR szTable,
300                LPCWSTR szFolder, LPCWSTR szFilename )
301 {
302     MSIDATABASE *db;
303     UINT r;
304
305     TRACE("%lx %s %s %s\n", handle, debugstr_w(szTable),
306           debugstr_w(szFolder), debugstr_w(szFilename));
307
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;
314 }
315
316 UINT WINAPI MsiDatabaseExportA( MSIHANDLE handle, LPCSTR szTable,
317                LPCSTR szFolder, LPCSTR szFilename )
318 {
319     LPWSTR path = NULL, file = NULL, table = NULL;
320     UINT r = ERROR_OUTOFMEMORY;
321
322     TRACE("%lx %s %s %s\n", handle, debugstr_a(szTable),
323           debugstr_a(szFolder), debugstr_a(szFilename));
324
325     if( szTable )
326     {
327         table = strdupAtoW( szTable );
328         if( !table )
329             goto end;
330     }
331
332     if( szFolder )
333     {
334         path = strdupAtoW( szFolder );
335         if( !path )
336             goto end;
337     }
338
339     if( szFilename )
340     {
341         file = strdupAtoW( szFilename );
342         if( !file )
343             goto end;
344     }
345
346     r = MsiDatabaseExportW( handle, table, path, file );
347
348 end:
349     msi_free( table );
350     msi_free( path );
351     msi_free( file );
352
353     return r;
354 }