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