reshuffling of dlls
[reactos.git] / reactos / dll / win32 / 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 DEFINE_GUID( CLSID_MsiDatabase, 0x000c1084, 0x0000, 0x0000,
42 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
43 DEFINE_GUID( CLSID_MsiPatch, 0x000c1086, 0x0000, 0x0000,
44 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
45
46 /*
47 * .MSI file format
48 *
49 * An .msi file is a structured storage file.
50 * It contains a number of streams.
51 * A stream for each table in the database.
52 * Two streams for the string table in the database.
53 * Any binary data in a table is a reference to a stream.
54 */
55
56 static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
57 {
58 MSIDATABASE *db = (MSIDATABASE *) arg;
59 DWORD r;
60
61 free_cached_tables( db );
62 msi_free_transforms( db );
63 msi_destroy_stringtable( db->strings );
64 r = IStorage_Release( db->storage );
65 if( r )
66 ERR("database reference count was not zero (%ld)\n", r);
67 }
68
69 UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
70 {
71 IStorage *stg = NULL;
72 HRESULT r;
73 MSIDATABASE *db = NULL;
74 UINT ret = ERROR_FUNCTION_FAILED;
75 LPCWSTR szMode;
76 STATSTG stat;
77
78 TRACE("%s %s\n",debugstr_w(szDBPath),debugstr_w(szPersist) );
79
80 if( !pdb )
81 return ERROR_INVALID_PARAMETER;
82
83 szMode = szPersist;
84 if( HIWORD( szPersist ) )
85 {
86 /* UINT len = lstrlenW( szPerist ) + 1; */
87 FIXME("don't support persist files yet\b");
88 return ERROR_INVALID_PARAMETER;
89 /* szMode = msi_alloc( len * sizeof (DWORD) ); */
90 }
91 else if( szPersist == MSIDBOPEN_READONLY )
92 {
93 r = StgOpenStorage( szDBPath, NULL,
94 STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
95 }
96 else if( szPersist == MSIDBOPEN_CREATE )
97 {
98 r = StgCreateDocfile( szDBPath,
99 STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, &stg);
100 if( r == ERROR_SUCCESS )
101 {
102 IStorage_SetClass( stg, &CLSID_MsiDatabase );
103 r = init_string_table( stg );
104 }
105 }
106 else if( szPersist == MSIDBOPEN_TRANSACT )
107 {
108 r = StgOpenStorage( szDBPath, NULL,
109 STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
110 }
111 else
112 {
113 ERR("unknown flag %p\n",szPersist);
114 return ERROR_INVALID_PARAMETER;
115 }
116
117 if( FAILED( r ) )
118 {
119 FIXME("open failed r = %08lx!\n",r);
120 return ERROR_FUNCTION_FAILED;
121 }
122
123 r = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
124 if( FAILED( r ) )
125 {
126 FIXME("Failed to stat storage\n");
127 goto end;
128 }
129
130 if ( !IsEqualGUID( &stat.clsid, &CLSID_MsiDatabase ) &&
131 !IsEqualGUID( &stat.clsid, &CLSID_MsiPatch ) )
132 {
133 ERR("storage GUID is not a MSI database GUID %s\n",
134 debugstr_guid(&stat.clsid) );
135 goto end;
136 }
137
138 db = alloc_msiobject( MSIHANDLETYPE_DATABASE, sizeof (MSIDATABASE),
139 MSI_CloseDatabase );
140 if( !db )
141 {
142 FIXME("Failed to allocate a handle\n");
143 goto end;
144 }
145
146 if( TRACE_ON( msi ) )
147 enum_stream_names( stg );
148
149 db->storage = stg;
150 db->mode = szMode;
151 list_init( &db->tables );
152 list_init( &db->transforms );
153
154 db->strings = load_string_table( stg );
155 if( !db->strings )
156 goto end;
157
158 ret = ERROR_SUCCESS;
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)(DWORD)szPersist;
212
213 r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB );
214
215 end:
216 if( HIWORD(szPersist) )
217 msi_free( szwPersist );
218 msi_free( szwDBPath );
219
220 return r;
221 }
222
223 UINT MSI_DatabaseImport( MSIDATABASE *db, LPCWSTR folder, LPCWSTR file )
224 {
225 FIXME("%p %s %s\n", db, debugstr_w(folder), debugstr_w(file) );
226
227 if( folder == NULL || file == NULL )
228 return ERROR_INVALID_PARAMETER;
229
230 return ERROR_CALL_NOT_IMPLEMENTED;
231 }
232
233 UINT WINAPI MsiDatabaseImportW(MSIHANDLE handle, LPCWSTR szFolder, LPCWSTR szFilename)
234 {
235 MSIDATABASE *db;
236 UINT r;
237
238 TRACE("%lx %s %s\n",handle,debugstr_w(szFolder), debugstr_w(szFilename));
239
240 db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
241 if( !db )
242 return ERROR_INVALID_HANDLE;
243 r = MSI_DatabaseImport( db, szFolder, szFilename );
244 msiobj_release( &db->hdr );
245 return r;
246 }
247
248 UINT WINAPI MsiDatabaseImportA( MSIHANDLE handle,
249 LPCSTR szFolder, LPCSTR szFilename )
250 {
251 LPWSTR path = NULL, file = NULL;
252 UINT r = ERROR_OUTOFMEMORY;
253
254 TRACE("%lx %s %s\n", handle, debugstr_a(szFolder), debugstr_a(szFilename));
255
256 if( szFolder )
257 {
258 path = strdupAtoW( szFolder );
259 if( !path )
260 goto end;
261 }
262
263 if( szFilename )
264 {
265 file = strdupAtoW( szFilename );
266 if( !file )
267 goto end;
268 }
269
270 r = MsiDatabaseImportW( handle, path, file );
271
272 end:
273 msi_free( path );
274 msi_free( file );
275
276 return r;
277 }
278
279 UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table,
280 LPCWSTR folder, LPCWSTR file )
281 {
282 FIXME("%p %s %s %s\n", db, debugstr_w(table),
283 debugstr_w(folder), debugstr_w(file) );
284
285 if( folder == NULL || file == NULL )
286 return ERROR_INVALID_PARAMETER;
287
288 return ERROR_CALL_NOT_IMPLEMENTED;
289 }
290
291 UINT WINAPI MsiDatabaseExportW( MSIHANDLE handle, LPCWSTR szTable,
292 LPCWSTR szFolder, LPCWSTR szFilename )
293 {
294 MSIDATABASE *db;
295 UINT r;
296
297 TRACE("%lx %s %s %s\n", handle, debugstr_w(szTable),
298 debugstr_w(szFolder), debugstr_w(szFilename));
299
300 db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
301 if( !db )
302 return ERROR_INVALID_HANDLE;
303 r = MSI_DatabaseExport( db, szTable, szFolder, szFilename );
304 msiobj_release( &db->hdr );
305 return r;
306 }
307
308 UINT WINAPI MsiDatabaseExportA( MSIHANDLE handle, LPCSTR szTable,
309 LPCSTR szFolder, LPCSTR szFilename )
310 {
311 LPWSTR path = NULL, file = NULL, table = NULL;
312 UINT r = ERROR_OUTOFMEMORY;
313
314 TRACE("%lx %s %s %s\n", handle, debugstr_a(szTable),
315 debugstr_a(szFolder), debugstr_a(szFilename));
316
317 if( szTable )
318 {
319 table = strdupAtoW( szTable );
320 if( !table )
321 goto end;
322 }
323
324 if( szFolder )
325 {
326 path = strdupAtoW( szFolder );
327 if( !path )
328 goto end;
329 }
330
331 if( szFilename )
332 {
333 file = strdupAtoW( szFilename );
334 if( !file )
335 goto end;
336 }
337
338 r = MsiDatabaseExportW( handle, table, path, file );
339
340 end:
341 msi_free( table );
342 msi_free( path );
343 msi_free( file );
344
345 return r;
346 }