msi: Honor msidbFeatureAttributesFollowParent.
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22 #include <stdio.h>
23
24 #define COBJMACROS
25 #define NONAMELESSUNION
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winreg.h"
30 #include "winnls.h"
31 #include "wine/debug.h"
32 #include "wine/unicode.h"
33 #include "msi.h"
34 #include "msiquery.h"
35 #include "msipriv.h"
36 #include "objidl.h"
37 #include "objbase.h"
38 #include "msiserver.h"
39 #include "query.h"
40
41 #include "initguid.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(msi);
44
45 /*
46  *  .MSI  file format
47  *
48  *  An .msi file is a structured storage file.
49  *  It contains a number of streams.
50  *  A stream for each table in the database.
51  *  Two streams for the string table in the database.
52  *  Any binary data in a table is a reference to a stream.
53  */
54
55 #define IS_INTMSIDBOPEN(x)      (((ULONG_PTR)(x) >> 16) == 0)
56
57 typedef struct tagMSITRANSFORM {
58     struct list entry;
59     IStorage *stg;
60 } MSITRANSFORM;
61
62 typedef struct tagMSISTREAM {
63     struct list entry;
64     IStream *stm;
65 } MSISTREAM;
66
67 static UINT find_open_stream( MSIDATABASE *db, LPCWSTR name, IStream **stm )
68 {
69     MSISTREAM *stream;
70
71     LIST_FOR_EACH_ENTRY( stream, &db->streams, MSISTREAM, entry )
72     {
73         HRESULT r;
74         STATSTG stat;
75
76         r = IStream_Stat( stream->stm, &stat, 0 );
77         if( FAILED( r ) )
78         {
79             WARN("failed to stat stream r = %08x!\n", r);
80             continue;
81         }
82
83         if( !strcmpW( name, stat.pwcsName ) )
84         {
85             TRACE("found %s\n", debugstr_w(name));
86             *stm = stream->stm;
87             CoTaskMemFree( stat.pwcsName );
88             return ERROR_SUCCESS;
89         }
90
91         CoTaskMemFree( stat.pwcsName );
92     }
93
94     return ERROR_FUNCTION_FAILED;
95 }
96
97 static UINT clone_open_stream( MSIDATABASE *db, LPCWSTR name, IStream **stm )
98 {
99     IStream *stream;
100
101     if (find_open_stream( db, name, &stream ) == ERROR_SUCCESS)
102     {
103         HRESULT r;
104         LARGE_INTEGER pos;
105
106         r = IStream_Clone( stream, stm );
107         if( FAILED( r ) )
108         {
109             WARN("failed to clone stream r = %08x!\n", r);
110             return ERROR_FUNCTION_FAILED;
111         }
112
113         pos.QuadPart = 0;
114         r = IStream_Seek( *stm, pos, STREAM_SEEK_SET, NULL );
115         if( FAILED( r ) )
116         {
117             IStream_Release( *stm );
118             return ERROR_FUNCTION_FAILED;
119         }
120
121         return ERROR_SUCCESS;
122     }
123
124     return ERROR_FUNCTION_FAILED;
125 }
126
127 UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm )
128 {
129     HRESULT r;
130     WCHAR decoded[MAX_STREAM_NAME_LEN];
131
132     decode_streamname( stname, decoded );
133     TRACE("%s -> %s\n", debugstr_w(stname), debugstr_w(decoded));
134
135     if (clone_open_stream( db, stname, stm ) == ERROR_SUCCESS)
136         return ERROR_SUCCESS;
137
138     r = IStorage_OpenStream( db->storage, stname, NULL,
139                              STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm );
140     if( FAILED( r ) )
141     {
142         MSITRANSFORM *transform;
143
144         LIST_FOR_EACH_ENTRY( transform, &db->transforms, MSITRANSFORM, entry )
145         {
146             r = IStorage_OpenStream( transform->stg, stname, NULL,
147                                      STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm );
148             if (SUCCEEDED(r))
149                 break;
150         }
151     }
152
153     if( SUCCEEDED(r) )
154     {
155         MSISTREAM *stream;
156
157         stream = msi_alloc( sizeof(MSISTREAM) );
158         if( !stream )
159             return ERROR_NOT_ENOUGH_MEMORY;
160
161         stream->stm = *stm;
162         IStream_AddRef( *stm );
163         list_add_tail( &db->streams, &stream->entry );
164     }
165
166     return SUCCEEDED(r) ? ERROR_SUCCESS : ERROR_FUNCTION_FAILED;
167 }
168
169 static void free_transforms( MSIDATABASE *db )
170 {
171     while( !list_empty( &db->transforms ) )
172     {
173         MSITRANSFORM *t = LIST_ENTRY( list_head( &db->transforms ),
174                                       MSITRANSFORM, entry );
175         list_remove( &t->entry );
176         IStorage_Release( t->stg );
177         msi_free( t );
178     }
179 }
180
181 void db_destroy_stream( MSIDATABASE *db, LPCWSTR stname )
182 {
183     MSISTREAM *stream, *stream2;
184
185     LIST_FOR_EACH_ENTRY_SAFE( stream, stream2, &db->streams, MSISTREAM, entry )
186     {
187         HRESULT r;
188         STATSTG stat;
189
190         r = IStream_Stat( stream->stm, &stat, 0 );
191         if (FAILED(r))
192         {
193             WARN("failed to stat stream r = %08x\n", r);
194             continue;
195         }
196
197         if (!strcmpW( stname, stat.pwcsName ))
198         {
199             TRACE("destroying %s\n", debugstr_w(stname));
200
201             list_remove( &stream->entry );
202             IStream_Release( stream->stm );
203             msi_free( stream );
204             IStorage_DestroyElement( db->storage, stname );
205             CoTaskMemFree( stat.pwcsName );
206             break;
207         }
208         CoTaskMemFree( stat.pwcsName );
209     }
210 }
211
212 static void free_streams( MSIDATABASE *db )
213 {
214     while( !list_empty( &db->streams ) )
215     {
216         MSISTREAM *s = LIST_ENTRY( list_head( &db->streams ),
217                                    MSISTREAM, entry );
218         list_remove( &s->entry );
219         IStream_Release( s->stm );
220         msi_free( s );
221     }
222 }
223
224 void append_storage_to_db( MSIDATABASE *db, IStorage *stg )
225 {
226     MSITRANSFORM *t;
227
228     t = msi_alloc( sizeof *t );
229     t->stg = stg;
230     IStorage_AddRef( stg );
231     list_add_head( &db->transforms, &t->entry );
232
233     /* the transform may add or replace streams */
234     free_streams( db );
235 }
236
237 static VOID MSI_CloseDatabase( MSIOBJECTHDR *arg )
238 {
239     MSIDATABASE *db = (MSIDATABASE *) arg;
240
241     msi_free(db->path);
242     free_cached_tables( db );
243     free_streams( db );
244     free_transforms( db );
245     if (db->strings) msi_destroy_stringtable( db->strings );
246     IStorage_Release( db->storage );
247     if (db->deletefile)
248     {
249         DeleteFileW( db->deletefile );
250         msi_free( db->deletefile );
251     }
252     if (db->localfile)
253     {
254         DeleteFileW( db->localfile );
255         msi_free( db->localfile );
256     }
257 }
258
259 static HRESULT db_initialize( IStorage *stg, const GUID *clsid )
260 {
261     static const WCHAR szTables[]  = { '_','T','a','b','l','e','s',0 };
262     HRESULT hr;
263
264     hr = IStorage_SetClass( stg, clsid );
265     if (FAILED( hr ))
266     {
267         WARN("failed to set class id 0x%08x\n", hr);
268         return hr;
269     }
270
271     /* create the _Tables stream */
272     hr = write_stream_data( stg, szTables, NULL, 0, TRUE );
273     if (FAILED( hr ))
274     {
275         WARN("failed to create _Tables stream 0x%08x\n", hr);
276         return hr;
277     }
278
279     hr = msi_init_string_table( stg );
280     if (FAILED( hr ))
281     {
282         WARN("failed to initialize string table 0x%08x\n", hr);
283         return hr;
284     }
285
286     hr = IStorage_Commit( stg, 0 );
287     if (FAILED( hr ))
288     {
289         WARN("failed to commit changes 0x%08x\n", hr);
290         return hr;
291     }
292
293     return S_OK;
294 }
295
296 UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
297 {
298     IStorage *stg = NULL;
299     HRESULT r;
300     MSIDATABASE *db = NULL;
301     UINT ret = ERROR_FUNCTION_FAILED;
302     LPCWSTR szMode, save_path;
303     STATSTG stat;
304     BOOL created = FALSE, patch = FALSE;
305     WCHAR path[MAX_PATH];
306
307     TRACE("%s %s\n",debugstr_w(szDBPath),debugstr_w(szPersist) );
308
309     if( !pdb )
310         return ERROR_INVALID_PARAMETER;
311
312     if (szPersist - MSIDBOPEN_PATCHFILE >= MSIDBOPEN_READONLY &&
313         szPersist - MSIDBOPEN_PATCHFILE <= MSIDBOPEN_CREATEDIRECT)
314     {
315         TRACE("Database is a patch\n");
316         szPersist -= MSIDBOPEN_PATCHFILE;
317         patch = TRUE;
318     }
319
320     save_path = szDBPath;
321     szMode = szPersist;
322     if( !IS_INTMSIDBOPEN(szPersist) )
323     {
324         if (!CopyFileW( szDBPath, szPersist, FALSE ))
325             return ERROR_OPEN_FAILED;
326
327         szDBPath = szPersist;
328         szPersist = MSIDBOPEN_TRANSACT;
329         created = TRUE;
330     }
331
332     if( szPersist == MSIDBOPEN_READONLY )
333     {
334         r = StgOpenStorage( szDBPath, NULL,
335               STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
336     }
337     else if( szPersist == MSIDBOPEN_CREATE )
338     {
339         r = StgCreateDocfile( szDBPath,
340               STGM_CREATE|STGM_TRANSACTED|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, &stg );
341
342         if( SUCCEEDED(r) )
343             r = db_initialize( stg, patch ? &CLSID_MsiPatch : &CLSID_MsiDatabase );
344         created = TRUE;
345     }
346     else if( szPersist == MSIDBOPEN_CREATEDIRECT )
347     {
348         r = StgCreateDocfile( szDBPath,
349               STGM_CREATE|STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, &stg );
350
351         if( SUCCEEDED(r) )
352             r = db_initialize( stg, patch ? &CLSID_MsiPatch : &CLSID_MsiDatabase );
353         created = TRUE;
354     }
355     else if( szPersist == MSIDBOPEN_TRANSACT )
356     {
357         r = StgOpenStorage( szDBPath, NULL,
358               STGM_TRANSACTED|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
359     }
360     else if( szPersist == MSIDBOPEN_DIRECT )
361     {
362         r = StgOpenStorage( szDBPath, NULL,
363               STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
364     }
365     else
366     {
367         ERR("unknown flag %p\n",szPersist);
368         return ERROR_INVALID_PARAMETER;
369     }
370
371     if( FAILED( r ) || !stg )
372     {
373         FIXME("open failed r = %08x for %s\n", r, debugstr_w(szDBPath));
374         return ERROR_FUNCTION_FAILED;
375     }
376
377     r = IStorage_Stat( stg, &stat, STATFLAG_NONAME );
378     if( FAILED( r ) )
379     {
380         FIXME("Failed to stat storage\n");
381         goto end;
382     }
383
384     if ( !IsEqualGUID( &stat.clsid, &CLSID_MsiDatabase ) &&
385          !IsEqualGUID( &stat.clsid, &CLSID_MsiPatch ) &&
386          !IsEqualGUID( &stat.clsid, &CLSID_MsiTransform ) )
387     {
388         ERR("storage GUID is not a MSI database GUID %s\n",
389              debugstr_guid(&stat.clsid) );
390         goto end;
391     }
392
393     if ( patch && !IsEqualGUID( &stat.clsid, &CLSID_MsiPatch ) )
394     {
395         ERR("storage GUID is not the MSI patch GUID %s\n",
396              debugstr_guid(&stat.clsid) );
397         ret = ERROR_OPEN_FAILED;
398         goto end;
399     }
400
401     db = alloc_msiobject( MSIHANDLETYPE_DATABASE, sizeof (MSIDATABASE),
402                               MSI_CloseDatabase );
403     if( !db )
404     {
405         FIXME("Failed to allocate a handle\n");
406         goto end;
407     }
408
409     if (!strchrW( save_path, '\\' ))
410     {
411         GetCurrentDirectoryW( MAX_PATH, path );
412         lstrcatW( path, szBackSlash );
413         lstrcatW( path, save_path );
414     }
415     else
416         lstrcpyW( path, save_path );
417
418     db->path = strdupW( path );
419
420     db->media_transform_offset = MSI_INITIAL_MEDIA_TRANSFORM_OFFSET;
421
422     if( TRACE_ON( msi ) )
423         enum_stream_names( stg );
424
425     db->storage = stg;
426     db->mode = szMode;
427     if (created)
428         db->deletefile = strdupW( szDBPath );
429     list_init( &db->tables );
430     list_init( &db->transforms );
431     list_init( &db->streams );
432
433     db->strings = msi_load_string_table( stg, &db->bytes_per_strref );
434     if( !db->strings )
435         goto end;
436
437     ret = ERROR_SUCCESS;
438
439     msiobj_addref( &db->hdr );
440     IStorage_AddRef( stg );
441     *pdb = db;
442
443 end:
444     if( db )
445         msiobj_release( &db->hdr );
446     if( stg )
447         IStorage_Release( stg );
448
449     return ret;
450 }
451
452 UINT WINAPI MsiOpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIHANDLE *phDB)
453 {
454     MSIDATABASE *db;
455     UINT ret;
456
457     TRACE("%s %s %p\n",debugstr_w(szDBPath),debugstr_w(szPersist), phDB);
458
459     ret = MSI_OpenDatabaseW( szDBPath, szPersist, &db );
460     if( ret == ERROR_SUCCESS )
461     {
462         *phDB = alloc_msihandle( &db->hdr );
463         if (! *phDB)
464             ret = ERROR_NOT_ENOUGH_MEMORY;
465         msiobj_release( &db->hdr );
466     }
467
468     return ret;
469 }
470
471 UINT WINAPI MsiOpenDatabaseA(LPCSTR szDBPath, LPCSTR szPersist, MSIHANDLE *phDB)
472 {
473     HRESULT r = ERROR_FUNCTION_FAILED;
474     LPWSTR szwDBPath = NULL, szwPersist = NULL;
475
476     TRACE("%s %s %p\n", debugstr_a(szDBPath), debugstr_a(szPersist), phDB);
477
478     if( szDBPath )
479     {
480         szwDBPath = strdupAtoW( szDBPath );
481         if( !szwDBPath )
482             goto end;
483     }
484
485     if( !IS_INTMSIDBOPEN(szPersist) )
486     {
487         szwPersist = strdupAtoW( szPersist );
488         if( !szwPersist )
489             goto end;
490     }
491     else
492         szwPersist = (LPWSTR)(DWORD_PTR)szPersist;
493
494     r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB );
495
496 end:
497     if( !IS_INTMSIDBOPEN(szPersist) )
498         msi_free( szwPersist );
499     msi_free( szwDBPath );
500
501     return r;
502 }
503
504 static LPWSTR msi_read_text_archive(LPCWSTR path)
505 {
506     HANDLE file;
507     LPSTR data = NULL;
508     LPWSTR wdata = NULL;
509     DWORD read, size = 0;
510
511     file = CreateFileW( path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
512     if (file == INVALID_HANDLE_VALUE)
513         return NULL;
514
515     size = GetFileSize( file, NULL );
516     data = msi_alloc( size + 1 );
517     if (!data)
518         goto done;
519
520     if (!ReadFile( file, data, size, &read, NULL ))
521         goto done;
522
523     data[size] = '\0';
524     wdata = strdupAtoW( data );
525
526 done:
527     CloseHandle( file );
528     msi_free( data );
529     return wdata;
530 }
531
532 static void msi_parse_line(LPWSTR *line, LPWSTR **entries, DWORD *num_entries)
533 {
534     LPWSTR ptr = *line, save;
535     DWORD i, count = 1;
536
537     *entries = NULL;
538
539     /* stay on this line */
540     while (*ptr && *ptr != '\n')
541     {
542         /* entries are separated by tabs */
543         if (*ptr == '\t')
544             count++;
545
546         ptr++;
547     }
548
549     *entries = msi_alloc(count * sizeof(LPWSTR));
550     if (!*entries)
551         return;
552
553     /* store pointers into the data */
554     for (i = 0, ptr = *line; i < count; i++)
555     {
556         while (*ptr && *ptr == '\r') ptr++;
557         save = ptr;
558
559         while (*ptr && *ptr != '\t' && *ptr != '\n' && *ptr != '\r') ptr++;
560
561         /* NULL-separate the data */
562         if (*ptr == '\n' || *ptr == '\r')
563         {
564             while (*ptr == '\n' || *ptr == '\r')
565                 *(ptr++) = '\0';
566         }
567         else if (*ptr)
568             *ptr++ = '\0';
569
570         (*entries)[i] = save;
571     }
572
573     /* move to the next line if there's more, else EOF */
574     *line = ptr;
575
576     if (num_entries)
577         *num_entries = count;
578 }
579
580 static LPWSTR msi_build_createsql_prelude(LPWSTR table)
581 {
582     LPWSTR prelude;
583     DWORD size;
584
585     static const WCHAR create_fmt[] = {'C','R','E','A','T','E',' ','T','A','B','L','E',' ','`','%','s','`',' ','(',' ',0};
586
587     size = sizeof(create_fmt)/sizeof(create_fmt[0]) + lstrlenW(table) - 2;
588     prelude = msi_alloc(size * sizeof(WCHAR));
589     if (!prelude)
590         return NULL;
591
592     sprintfW(prelude, create_fmt, table);
593     return prelude;
594 }
595
596 static LPWSTR msi_build_createsql_columns(LPWSTR *columns_data, LPWSTR *types, DWORD num_columns)
597 {
598     LPWSTR columns, p;
599     LPCWSTR type;
600     DWORD sql_size = 1, i, len;
601     WCHAR expanded[128], *ptr;
602     WCHAR size[10], comma[2], extra[30];
603
604     static const WCHAR column_fmt[] = {'`','%','s','`',' ','%','s','%','s','%','s','%','s',' ',0};
605     static const WCHAR size_fmt[] = {'(','%','s',')',0};
606     static const WCHAR type_char[] = {'C','H','A','R',0};
607     static const WCHAR type_int[] = {'I','N','T',0};
608     static const WCHAR type_long[] = {'L','O','N','G',0};
609     static const WCHAR type_object[] = {'O','B','J','E','C','T',0};
610     static const WCHAR type_notnull[] = {' ','N','O','T',' ','N','U','L','L',0};
611     static const WCHAR localizable[] = {' ','L','O','C','A','L','I','Z','A','B','L','E',0};
612
613     columns = msi_alloc_zero(sql_size * sizeof(WCHAR));
614     if (!columns)
615         return NULL;
616
617     for (i = 0; i < num_columns; i++)
618     {
619         type = NULL;
620         comma[1] = size[0] = extra[0] = '\0';
621
622         if (i == num_columns - 1)
623             comma[0] = '\0';
624         else
625             comma[0] = ',';
626
627         ptr = &types[i][1];
628         len = atolW(ptr);
629         extra[0] = '\0';
630
631         switch (types[i][0])
632         {
633             case 'l':
634                 lstrcpyW(extra, type_notnull);
635             case 'L':
636                 lstrcatW(extra, localizable);
637                 type = type_char;
638                 sprintfW(size, size_fmt, ptr);
639                 break;
640             case 's':
641                 lstrcpyW(extra, type_notnull);
642             case 'S':
643                 type = type_char;
644                 sprintfW(size, size_fmt, ptr);
645                 break;
646             case 'i':
647                 lstrcpyW(extra, type_notnull);
648             case 'I':
649                 if (len <= 2)
650                     type = type_int;
651                 else if (len == 4)
652                     type = type_long;
653                 else
654                 {
655                     WARN("invalid int width %u\n", len);
656                     msi_free(columns);
657                     return NULL;
658                 }
659                 break;
660             case 'v':
661                 lstrcpyW(extra, type_notnull);
662             case 'V':
663                 type = type_object;
664                 break;
665             default:
666                 ERR("Unknown type: %c\n", types[i][0]);
667                 msi_free(columns);
668                 return NULL;
669         }
670
671         sprintfW(expanded, column_fmt, columns_data[i], type, size, extra, comma);
672         sql_size += lstrlenW(expanded);
673
674         p = msi_realloc(columns, sql_size * sizeof(WCHAR));
675         if (!p)
676         {
677             msi_free(columns);
678             return NULL;
679         }
680         columns = p;
681
682         lstrcatW(columns, expanded);
683     }
684
685     return columns;
686 }
687
688 static LPWSTR msi_build_createsql_postlude(LPWSTR *primary_keys, DWORD num_keys)
689 {
690     LPWSTR postlude, keys, ptr;
691     DWORD size, key_size, i;
692
693     static const WCHAR key_fmt[] = {'`','%','s','`',',',' ',0};
694     static const WCHAR postlude_fmt[] = {'P','R','I','M','A','R','Y',' ','K','E','Y',' ','%','s',')',0};
695
696     for (i = 0, size = 1; i < num_keys; i++)
697         size += lstrlenW(key_fmt) + lstrlenW(primary_keys[i]) - 2;
698
699     keys = msi_alloc(size * sizeof(WCHAR));
700     if (!keys)
701         return NULL;
702
703     for (i = 0, ptr = keys; i < num_keys; i++)
704     {
705         key_size = lstrlenW(key_fmt) + lstrlenW(primary_keys[i]) -2;
706         sprintfW(ptr, key_fmt, primary_keys[i]);
707         ptr += key_size;
708     }
709
710     /* remove final ', ' */
711     *(ptr - 2) = '\0';
712
713     size = lstrlenW(postlude_fmt) + size - 1;
714     postlude = msi_alloc(size * sizeof(WCHAR));
715     if (!postlude)
716         goto done;
717
718     sprintfW(postlude, postlude_fmt, keys);
719
720 done:
721     msi_free(keys);
722     return postlude;
723 }
724
725 static UINT msi_add_table_to_db(MSIDATABASE *db, LPWSTR *columns, LPWSTR *types, LPWSTR *labels, DWORD num_labels, DWORD num_columns)
726 {
727     UINT r = ERROR_OUTOFMEMORY;
728     DWORD size;
729     MSIQUERY *view;
730     LPWSTR create_sql = NULL;
731     LPWSTR prelude, columns_sql, postlude;
732
733     prelude = msi_build_createsql_prelude(labels[0]);
734     columns_sql = msi_build_createsql_columns(columns, types, num_columns);
735     postlude = msi_build_createsql_postlude(labels + 1, num_labels - 1); /* skip over table name */
736
737     if (!prelude || !columns_sql || !postlude)
738         goto done;
739
740     size = lstrlenW(prelude) + lstrlenW(columns_sql) + lstrlenW(postlude) + 1;
741     create_sql = msi_alloc(size * sizeof(WCHAR));
742     if (!create_sql)
743         goto done;
744
745     lstrcpyW(create_sql, prelude);
746     lstrcatW(create_sql, columns_sql);
747     lstrcatW(create_sql, postlude);
748
749     r = MSI_DatabaseOpenViewW( db, create_sql, &view );
750     if (r != ERROR_SUCCESS)
751         goto done;
752
753     r = MSI_ViewExecute(view, NULL);
754     MSI_ViewClose(view);
755     msiobj_release(&view->hdr);
756
757 done:
758     msi_free(prelude);
759     msi_free(columns_sql);
760     msi_free(postlude);
761     msi_free(create_sql);
762     return r;
763 }
764
765 static LPWSTR msi_import_stream_filename(LPCWSTR path, LPCWSTR name)
766 {
767     DWORD len;
768     LPWSTR fullname, ptr;
769
770     len = lstrlenW(path) + lstrlenW(name) + 1;
771     fullname = msi_alloc(len*sizeof(WCHAR));
772     if (!fullname)
773        return NULL;
774
775     lstrcpyW( fullname, path );
776
777     /* chop off extension from path */
778     ptr = strrchrW(fullname, '.');
779     if (!ptr)
780     {
781         msi_free (fullname);
782         return NULL;
783     }
784     *ptr++ = '\\';
785     lstrcpyW( ptr, name );
786     return fullname;
787 }
788
789 static UINT construct_record(DWORD num_columns, LPWSTR *types,
790                              LPWSTR *data, LPWSTR path, MSIRECORD **rec)
791 {
792     UINT i;
793
794     *rec = MSI_CreateRecord(num_columns);
795     if (!*rec)
796         return ERROR_OUTOFMEMORY;
797
798     for (i = 0; i < num_columns; i++)
799     {
800         switch (types[i][0])
801         {
802             case 'L': case 'l': case 'S': case 's':
803                 MSI_RecordSetStringW(*rec, i + 1, data[i]);
804                 break;
805             case 'I': case 'i':
806                 if (*data[i])
807                     MSI_RecordSetInteger(*rec, i + 1, atoiW(data[i]));
808                 break;
809             case 'V': case 'v':
810                 if (*data[i])
811                 {
812                     UINT r;
813                     LPWSTR file = msi_import_stream_filename(path, data[i]);
814                     if (!file)
815                         return ERROR_FUNCTION_FAILED;
816
817                     r = MSI_RecordSetStreamFromFileW(*rec, i + 1, file);
818                     msi_free (file);
819                     if (r != ERROR_SUCCESS)
820                         return ERROR_FUNCTION_FAILED;
821                 }
822                 break;
823             default:
824                 ERR("Unhandled column type: %c\n", types[i][0]);
825                 msiobj_release(&(*rec)->hdr);
826                 return ERROR_FUNCTION_FAILED;
827         }
828     }
829
830     return ERROR_SUCCESS;
831 }
832
833 static UINT msi_add_records_to_table(MSIDATABASE *db, LPWSTR *columns, LPWSTR *types,
834                                      LPWSTR *labels, LPWSTR **records,
835                                      int num_columns, int num_records,
836                                      LPWSTR path)
837 {
838     UINT r;
839     int i;
840     MSIQUERY *view;
841     MSIRECORD *rec;
842
843     static const WCHAR select[] = {
844         'S','E','L','E','C','T',' ','*',' ',
845         'F','R','O','M',' ','`','%','s','`',0
846     };
847
848     r = MSI_OpenQuery(db, &view, select, labels[0]);
849     if (r != ERROR_SUCCESS)
850         return r;
851
852     while (MSI_ViewFetch(view, &rec) != ERROR_NO_MORE_ITEMS)
853     {
854         r = MSI_ViewModify(view, MSIMODIFY_DELETE, rec);
855         msiobj_release(&rec->hdr);
856         if (r != ERROR_SUCCESS)
857             goto done;
858     }
859
860     for (i = 0; i < num_records; i++)
861     {
862         r = construct_record(num_columns, types, records[i], path, &rec);
863         if (r != ERROR_SUCCESS)
864             goto done;
865
866         r = MSI_ViewModify(view, MSIMODIFY_INSERT, rec);
867         if (r != ERROR_SUCCESS)
868         {
869             msiobj_release(&rec->hdr);
870             goto done;
871         }
872
873         msiobj_release(&rec->hdr);
874     }
875
876 done:
877     msiobj_release(&view->hdr);
878     return r;
879 }
880
881 static UINT MSI_DatabaseImport(MSIDATABASE *db, LPCWSTR folder, LPCWSTR file)
882 {
883     UINT r;
884     DWORD len, i;
885     DWORD num_labels, num_types;
886     DWORD num_columns, num_records = 0;
887     LPWSTR *columns, *types, *labels;
888     LPWSTR path, ptr, data;
889     LPWSTR **records = NULL;
890     LPWSTR **temp_records;
891
892     static const WCHAR suminfo[] =
893         {'_','S','u','m','m','a','r','y','I','n','f','o','r','m','a','t','i','o','n',0};
894     static const WCHAR forcecodepage[] =
895         {'_','F','o','r','c','e','C','o','d','e','p','a','g','e',0};
896
897     TRACE("%p %s %s\n", db, debugstr_w(folder), debugstr_w(file) );
898
899     if( folder == NULL || file == NULL )
900         return ERROR_INVALID_PARAMETER;
901
902     len = lstrlenW(folder) + lstrlenW(szBackSlash) + lstrlenW(file) + 1;
903     path = msi_alloc( len * sizeof(WCHAR) );
904     if (!path)
905         return ERROR_OUTOFMEMORY;
906
907     lstrcpyW( path, folder );
908     lstrcatW( path, szBackSlash );
909     lstrcatW( path, file );
910
911     data = msi_read_text_archive( path );
912
913     ptr = data;
914     msi_parse_line( &ptr, &columns, &num_columns );
915     msi_parse_line( &ptr, &types, &num_types );
916     msi_parse_line( &ptr, &labels, &num_labels );
917
918     if (num_columns == 1 && !columns[0][0] && num_labels == 1 && !labels[0][0] &&
919         num_types == 2 && !strcmpW( types[1], forcecodepage ))
920     {
921         r = msi_set_string_table_codepage( db->strings, atoiW( types[0] ) );
922         goto done;
923     }
924
925     if (num_columns != num_types)
926     {
927         r = ERROR_FUNCTION_FAILED;
928         goto done;
929     }
930
931     records = msi_alloc(sizeof(LPWSTR *));
932     if (!records)
933     {
934         r = ERROR_OUTOFMEMORY;
935         goto done;
936     }
937
938     /* read in the table records */
939     while (*ptr)
940     {
941         msi_parse_line( &ptr, &records[num_records], NULL );
942
943         num_records++;
944         temp_records = msi_realloc(records, (num_records + 1) * sizeof(LPWSTR *));
945         if (!temp_records)
946         {
947             r = ERROR_OUTOFMEMORY;
948             goto done;
949         }
950         records = temp_records;
951     }
952
953     if (!strcmpW(labels[0], suminfo))
954     {
955         r = msi_add_suminfo( db, records, num_records, num_columns );
956         if (r != ERROR_SUCCESS)
957         {
958             r = ERROR_FUNCTION_FAILED;
959             goto done;
960         }
961     }
962     else
963     {
964         if (!TABLE_Exists(db, labels[0]))
965         {
966             r = msi_add_table_to_db( db, columns, types, labels, num_labels, num_columns );
967             if (r != ERROR_SUCCESS)
968             {
969                 r = ERROR_FUNCTION_FAILED;
970                 goto done;
971             }
972         }
973
974         r = msi_add_records_to_table( db, columns, types, labels, records, num_columns, num_records, path );
975     }
976
977 done:
978     msi_free(path);
979     msi_free(data);
980     msi_free(columns);
981     msi_free(types);
982     msi_free(labels);
983
984     for (i = 0; i < num_records; i++)
985         msi_free(records[i]);
986
987     msi_free(records);
988
989     return r;
990 }
991
992 UINT WINAPI MsiDatabaseImportW(MSIHANDLE handle, LPCWSTR szFolder, LPCWSTR szFilename)
993 {
994     MSIDATABASE *db;
995     UINT r;
996
997     TRACE("%x %s %s\n",handle,debugstr_w(szFolder), debugstr_w(szFilename));
998
999     db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
1000     if( !db )
1001     {
1002         IWineMsiRemoteDatabase *remote_database;
1003
1004         remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( handle );
1005         if ( !remote_database )
1006             return ERROR_INVALID_HANDLE;
1007
1008         IWineMsiRemoteDatabase_Release( remote_database );
1009         WARN("MsiDatabaseImport not allowed during a custom action!\n");
1010
1011         return ERROR_SUCCESS;
1012     }
1013
1014     r = MSI_DatabaseImport( db, szFolder, szFilename );
1015     msiobj_release( &db->hdr );
1016     return r;
1017 }
1018
1019 UINT WINAPI MsiDatabaseImportA( MSIHANDLE handle,
1020                LPCSTR szFolder, LPCSTR szFilename )
1021 {
1022     LPWSTR path = NULL, file = NULL;
1023     UINT r = ERROR_OUTOFMEMORY;
1024
1025     TRACE("%x %s %s\n", handle, debugstr_a(szFolder), debugstr_a(szFilename));
1026
1027     if( szFolder )
1028     {
1029         path = strdupAtoW( szFolder );
1030         if( !path )
1031             goto end;
1032     }
1033
1034     if( szFilename )
1035     {
1036         file = strdupAtoW( szFilename );
1037         if( !file )
1038             goto end;
1039     }
1040
1041     r = MsiDatabaseImportW( handle, path, file );
1042
1043 end:
1044     msi_free( path );
1045     msi_free( file );
1046
1047     return r;
1048 }
1049
1050 static UINT msi_export_record( HANDLE handle, MSIRECORD *row, UINT start )
1051 {
1052     UINT i, count, len, r = ERROR_SUCCESS;
1053     const char *sep;
1054     char *buffer;
1055     DWORD sz;
1056
1057     len = 0x100;
1058     buffer = msi_alloc( len );
1059     if ( !buffer )
1060         return ERROR_OUTOFMEMORY;
1061
1062     count = MSI_RecordGetFieldCount( row );
1063     for ( i=start; i<=count; i++ )
1064     {
1065         sz = len;
1066         r = MSI_RecordGetStringA( row, i, buffer, &sz );
1067         if (r == ERROR_MORE_DATA)
1068         {
1069             char *p = msi_realloc( buffer, sz + 1 );
1070             if (!p)
1071                 break;
1072             len = sz + 1;
1073             buffer = p;
1074         }
1075         sz = len;
1076         r = MSI_RecordGetStringA( row, i, buffer, &sz );
1077         if (r != ERROR_SUCCESS)
1078             break;
1079
1080         if (!WriteFile( handle, buffer, sz, &sz, NULL ))
1081         {
1082             r = ERROR_FUNCTION_FAILED;
1083             break;
1084         }
1085
1086         sep = (i < count) ? "\t" : "\r\n";
1087         if (!WriteFile( handle, sep, strlen(sep), &sz, NULL ))
1088         {
1089             r = ERROR_FUNCTION_FAILED;
1090             break;
1091         }
1092     }
1093     msi_free( buffer );
1094     return r;
1095 }
1096
1097 static UINT msi_export_row( MSIRECORD *row, void *arg )
1098 {
1099     return msi_export_record( arg, row, 1 );
1100 }
1101
1102 static UINT msi_export_forcecodepage( HANDLE handle, UINT codepage )
1103 {
1104     static const char fmt[] = "\r\n\r\n%u\t_ForceCodepage\r\n";
1105     char data[sizeof(fmt) + 10];
1106     DWORD sz;
1107
1108     sprintf( data, fmt, codepage );
1109
1110     sz = lstrlenA(data) + 1;
1111     if (!WriteFile(handle, data, sz, &sz, NULL))
1112         return ERROR_FUNCTION_FAILED;
1113
1114     return ERROR_SUCCESS;
1115 }
1116
1117 static UINT MSI_DatabaseExport( MSIDATABASE *db, LPCWSTR table,
1118                LPCWSTR folder, LPCWSTR file )
1119 {
1120     static const WCHAR query[] = {
1121         's','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','%','s',0 };
1122     static const WCHAR forcecodepage[] = {
1123         '_','F','o','r','c','e','C','o','d','e','p','a','g','e',0 };
1124     MSIRECORD *rec = NULL;
1125     MSIQUERY *view = NULL;
1126     LPWSTR filename;
1127     HANDLE handle;
1128     UINT len, r;
1129
1130     TRACE("%p %s %s %s\n", db, debugstr_w(table),
1131           debugstr_w(folder), debugstr_w(file) );
1132
1133     if( folder == NULL || file == NULL )
1134         return ERROR_INVALID_PARAMETER;
1135
1136     len = lstrlenW(folder) + lstrlenW(file) + 2;
1137     filename = msi_alloc(len * sizeof (WCHAR));
1138     if (!filename)
1139         return ERROR_OUTOFMEMORY;
1140
1141     lstrcpyW( filename, folder );
1142     lstrcatW( filename, szBackSlash );
1143     lstrcatW( filename, file );
1144
1145     handle = CreateFileW( filename, GENERIC_READ | GENERIC_WRITE, 0,
1146                           NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
1147     msi_free( filename );
1148     if (handle == INVALID_HANDLE_VALUE)
1149         return ERROR_FUNCTION_FAILED;
1150
1151     if (!strcmpW( table, forcecodepage ))
1152     {
1153         UINT codepage = msi_get_string_table_codepage( db->strings );
1154         r = msi_export_forcecodepage( handle, codepage );
1155         goto done;
1156     }
1157
1158     r = MSI_OpenQuery( db, &view, query, table );
1159     if (r == ERROR_SUCCESS)
1160     {
1161         /* write out row 1, the column names */
1162         r = MSI_ViewGetColumnInfo(view, MSICOLINFO_NAMES, &rec);
1163         if (r == ERROR_SUCCESS)
1164         {
1165             msi_export_record( handle, rec, 1 );
1166             msiobj_release( &rec->hdr );
1167         }
1168
1169         /* write out row 2, the column types */
1170         r = MSI_ViewGetColumnInfo(view, MSICOLINFO_TYPES, &rec);
1171         if (r == ERROR_SUCCESS)
1172         {
1173             msi_export_record( handle, rec, 1 );
1174             msiobj_release( &rec->hdr );
1175         }
1176
1177         /* write out row 3, the table name + keys */
1178         r = MSI_DatabaseGetPrimaryKeys( db, table, &rec );
1179         if (r == ERROR_SUCCESS)
1180         {
1181             MSI_RecordSetStringW( rec, 0, table );
1182             msi_export_record( handle, rec, 0 );
1183             msiobj_release( &rec->hdr );
1184         }
1185
1186         /* write out row 4 onwards, the data */
1187         r = MSI_IterateRecords( view, 0, msi_export_row, handle );
1188         msiobj_release( &view->hdr );
1189     }
1190
1191 done:
1192     CloseHandle( handle );
1193     return r;
1194 }
1195
1196 /***********************************************************************
1197  * MsiExportDatabaseW        [MSI.@]
1198  *
1199  * Writes a file containing the table data as tab separated ASCII.
1200  *
1201  * The format is as follows:
1202  *
1203  * row1 : colname1 <tab> colname2 <tab> .... colnameN <cr> <lf>
1204  * row2 : coltype1 <tab> coltype2 <tab> .... coltypeN <cr> <lf>
1205  * row3 : tablename <tab> key1 <tab> key2 <tab> ... keyM <cr> <lf>
1206  *
1207  * Followed by the data, starting at row 1 with one row per line
1208  *
1209  * row4 : data <tab> data <tab> data <tab> ... data <cr> <lf>
1210  */
1211 UINT WINAPI MsiDatabaseExportW( MSIHANDLE handle, LPCWSTR szTable,
1212                LPCWSTR szFolder, LPCWSTR szFilename )
1213 {
1214     MSIDATABASE *db;
1215     UINT r;
1216
1217     TRACE("%x %s %s %s\n", handle, debugstr_w(szTable),
1218           debugstr_w(szFolder), debugstr_w(szFilename));
1219
1220     db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
1221     if( !db )
1222     {
1223         IWineMsiRemoteDatabase *remote_database;
1224
1225         remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( handle );
1226         if ( !remote_database )
1227             return ERROR_INVALID_HANDLE;
1228
1229         IWineMsiRemoteDatabase_Release( remote_database );
1230         WARN("MsiDatabaseExport not allowed during a custom action!\n");
1231
1232         return ERROR_SUCCESS;
1233     }
1234
1235     r = MSI_DatabaseExport( db, szTable, szFolder, szFilename );
1236     msiobj_release( &db->hdr );
1237     return r;
1238 }
1239
1240 UINT WINAPI MsiDatabaseExportA( MSIHANDLE handle, LPCSTR szTable,
1241                LPCSTR szFolder, LPCSTR szFilename )
1242 {
1243     LPWSTR path = NULL, file = NULL, table = NULL;
1244     UINT r = ERROR_OUTOFMEMORY;
1245
1246     TRACE("%x %s %s %s\n", handle, debugstr_a(szTable),
1247           debugstr_a(szFolder), debugstr_a(szFilename));
1248
1249     if( szTable )
1250     {
1251         table = strdupAtoW( szTable );
1252         if( !table )
1253             goto end;
1254     }
1255
1256     if( szFolder )
1257     {
1258         path = strdupAtoW( szFolder );
1259         if( !path )
1260             goto end;
1261     }
1262
1263     if( szFilename )
1264     {
1265         file = strdupAtoW( szFilename );
1266         if( !file )
1267             goto end;
1268     }
1269
1270     r = MsiDatabaseExportW( handle, table, path, file );
1271
1272 end:
1273     msi_free( table );
1274     msi_free( path );
1275     msi_free( file );
1276
1277     return r;
1278 }
1279
1280 UINT WINAPI MsiDatabaseMergeA(MSIHANDLE hDatabase, MSIHANDLE hDatabaseMerge,
1281                               LPCSTR szTableName)
1282 {
1283     UINT r;
1284     LPWSTR table;
1285
1286     TRACE("(%d, %d, %s)\n", hDatabase, hDatabaseMerge,
1287           debugstr_a(szTableName));
1288
1289     table = strdupAtoW(szTableName);
1290     r = MsiDatabaseMergeW(hDatabase, hDatabaseMerge, table);
1291
1292     msi_free(table);
1293     return r;
1294 }
1295
1296 typedef struct _tagMERGETABLE
1297 {
1298     struct list entry;
1299     struct list rows;
1300     LPWSTR name;
1301     DWORD numconflicts;
1302     LPWSTR *columns;
1303     DWORD numcolumns;
1304     LPWSTR *types;
1305     DWORD numtypes;
1306     LPWSTR *labels;
1307     DWORD numlabels;
1308 } MERGETABLE;
1309
1310 typedef struct _tagMERGEROW
1311 {
1312     struct list entry;
1313     MSIRECORD *data;
1314 } MERGEROW;
1315
1316 typedef struct _tagMERGEDATA
1317 {
1318     MSIDATABASE *db;
1319     MSIDATABASE *merge;
1320     MERGETABLE *curtable;
1321     MSIQUERY *curview;
1322     struct list *tabledata;
1323 } MERGEDATA;
1324
1325 static BOOL merge_type_match(LPCWSTR type1, LPCWSTR type2)
1326 {
1327     if (((type1[0] == 'l') || (type1[0] == 's')) &&
1328         ((type2[0] == 'l') || (type2[0] == 's')))
1329         return TRUE;
1330
1331     if (((type1[0] == 'L') || (type1[0] == 'S')) &&
1332         ((type2[0] == 'L') || (type2[0] == 'S')))
1333         return TRUE;
1334
1335     return !strcmpW( type1, type2 );
1336 }
1337
1338 static UINT merge_verify_colnames(MSIQUERY *dbview, MSIQUERY *mergeview)
1339 {
1340     MSIRECORD *dbrec, *mergerec;
1341     UINT r, i, count;
1342
1343     r = MSI_ViewGetColumnInfo(dbview, MSICOLINFO_NAMES, &dbrec);
1344     if (r != ERROR_SUCCESS)
1345         return r;
1346
1347     r = MSI_ViewGetColumnInfo(mergeview, MSICOLINFO_NAMES, &mergerec);
1348     if (r != ERROR_SUCCESS)
1349         return r;
1350
1351     count = MSI_RecordGetFieldCount(dbrec);
1352     for (i = 1; i <= count; i++)
1353     {
1354         if (!MSI_RecordGetString(mergerec, i))
1355             break;
1356
1357         if (strcmpW( MSI_RecordGetString( dbrec, i ), MSI_RecordGetString( mergerec, i ) ))
1358         {
1359             r = ERROR_DATATYPE_MISMATCH;
1360             goto done;
1361         }
1362     }
1363
1364     msiobj_release(&dbrec->hdr);
1365     msiobj_release(&mergerec->hdr);
1366     dbrec = mergerec = NULL;
1367
1368     r = MSI_ViewGetColumnInfo(dbview, MSICOLINFO_TYPES, &dbrec);
1369     if (r != ERROR_SUCCESS)
1370         return r;
1371
1372     r = MSI_ViewGetColumnInfo(mergeview, MSICOLINFO_TYPES, &mergerec);
1373     if (r != ERROR_SUCCESS)
1374         return r;
1375
1376     count = MSI_RecordGetFieldCount(dbrec);
1377     for (i = 1; i <= count; i++)
1378     {
1379         if (!MSI_RecordGetString(mergerec, i))
1380             break;
1381
1382         if (!merge_type_match(MSI_RecordGetString(dbrec, i),
1383                      MSI_RecordGetString(mergerec, i)))
1384         {
1385             r = ERROR_DATATYPE_MISMATCH;
1386             break;
1387         }
1388     }
1389
1390 done:
1391     msiobj_release(&dbrec->hdr);
1392     msiobj_release(&mergerec->hdr);
1393
1394     return r;
1395 }
1396
1397 static UINT merge_verify_primary_keys(MSIDATABASE *db, MSIDATABASE *mergedb,
1398                                       LPCWSTR table)
1399 {
1400     MSIRECORD *dbrec, *mergerec = NULL;
1401     UINT r, i, count;
1402
1403     r = MSI_DatabaseGetPrimaryKeys(db, table, &dbrec);
1404     if (r != ERROR_SUCCESS)
1405         return r;
1406
1407     r = MSI_DatabaseGetPrimaryKeys(mergedb, table, &mergerec);
1408     if (r != ERROR_SUCCESS)
1409         goto done;
1410
1411     count = MSI_RecordGetFieldCount(dbrec);
1412     if (count != MSI_RecordGetFieldCount(mergerec))
1413     {
1414         r = ERROR_DATATYPE_MISMATCH;
1415         goto done;
1416     }
1417
1418     for (i = 1; i <= count; i++)
1419     {
1420         if (strcmpW( MSI_RecordGetString( dbrec, i ), MSI_RecordGetString( mergerec, i ) ))
1421         {
1422             r = ERROR_DATATYPE_MISMATCH;
1423             goto done;
1424         }
1425     }
1426
1427 done:
1428     msiobj_release(&dbrec->hdr);
1429     msiobj_release(&mergerec->hdr);
1430
1431     return r;
1432 }
1433
1434 static LPWSTR get_key_value(MSIQUERY *view, LPCWSTR key, MSIRECORD *rec)
1435 {
1436     MSIRECORD *colnames;
1437     LPWSTR str, val;
1438     UINT r, i = 0, sz = 0;
1439     int cmp;
1440
1441     r = MSI_ViewGetColumnInfo(view, MSICOLINFO_NAMES, &colnames);
1442     if (r != ERROR_SUCCESS)
1443         return NULL;
1444
1445     do
1446     {
1447         str = msi_dup_record_field(colnames, ++i);
1448         cmp = strcmpW( key, str );
1449         msi_free(str);
1450     } while (cmp);
1451
1452     msiobj_release(&colnames->hdr);
1453
1454     r = MSI_RecordGetStringW(rec, i, NULL, &sz);
1455     if (r != ERROR_SUCCESS)
1456         return NULL;
1457     sz++;
1458
1459     if (MSI_RecordGetString(rec, i))  /* check record field is a string */
1460     {
1461         /* quote string record fields */
1462         const WCHAR szQuote[] = {'\'', 0};
1463         sz += 2;
1464         val = msi_alloc(sz*sizeof(WCHAR));
1465         if (!val)
1466             return NULL;
1467
1468         lstrcpyW(val, szQuote);
1469         r = MSI_RecordGetStringW(rec, i, val+1, &sz);
1470         lstrcpyW(val+1+sz, szQuote);
1471     }
1472     else
1473     {
1474         /* do not quote integer record fields */
1475         val = msi_alloc(sz*sizeof(WCHAR));
1476         if (!val)
1477             return NULL;
1478
1479         r = MSI_RecordGetStringW(rec, i, val, &sz);
1480     }
1481
1482     if (r != ERROR_SUCCESS)
1483     {
1484         ERR("failed to get string!\n");
1485         msi_free(val);
1486         return NULL;
1487     }
1488
1489     return val;
1490 }
1491
1492 static LPWSTR create_diff_row_query(MSIDATABASE *merge, MSIQUERY *view,
1493                                     LPWSTR table, MSIRECORD *rec)
1494 {
1495     LPWSTR query = NULL, clause = NULL;
1496     LPWSTR ptr = NULL, val;
1497     LPCWSTR setptr;
1498     DWORD size = 1, oldsize;
1499     LPCWSTR key;
1500     MSIRECORD *keys;
1501     UINT r, i, count;
1502
1503     static const WCHAR keyset[] = {
1504         '`','%','s','`',' ','=',' ','%','s',' ','A','N','D',' ',0};
1505     static const WCHAR lastkeyset[] = {
1506         '`','%','s','`',' ','=',' ','%','s',' ',0};
1507     static const WCHAR fmt[] = {'S','E','L','E','C','T',' ','*',' ',
1508         'F','R','O','M',' ','`','%','s','`',' ',
1509         'W','H','E','R','E',' ','%','s',0};
1510
1511     r = MSI_DatabaseGetPrimaryKeys(merge, table, &keys);
1512     if (r != ERROR_SUCCESS)
1513         return NULL;
1514
1515     clause = msi_alloc_zero(size * sizeof(WCHAR));
1516     if (!clause)
1517         goto done;
1518
1519     ptr = clause;
1520     count = MSI_RecordGetFieldCount(keys);
1521     for (i = 1; i <= count; i++)
1522     {
1523         key = MSI_RecordGetString(keys, i);
1524         val = get_key_value(view, key, rec);
1525
1526         if (i == count)
1527             setptr = lastkeyset;
1528         else
1529             setptr = keyset;
1530
1531         oldsize = size;
1532         size += lstrlenW(setptr) + lstrlenW(key) + lstrlenW(val) - 4;
1533         clause = msi_realloc(clause, size * sizeof (WCHAR));
1534         if (!clause)
1535         {
1536             msi_free(val);
1537             goto done;
1538         }
1539
1540         ptr = clause + oldsize - 1;
1541         sprintfW(ptr, setptr, key, val);
1542         msi_free(val);
1543     }
1544
1545     size = lstrlenW(fmt) + lstrlenW(table) + lstrlenW(clause) + 1;
1546     query = msi_alloc(size * sizeof(WCHAR));
1547     if (!query)
1548         goto done;
1549
1550     sprintfW(query, fmt, table, clause);
1551
1552 done:
1553     msi_free(clause);
1554     msiobj_release(&keys->hdr);
1555     return query;
1556 }
1557
1558 static UINT merge_diff_row(MSIRECORD *rec, LPVOID param)
1559 {
1560     MERGEDATA *data = param;
1561     MERGETABLE *table = data->curtable;
1562     MERGEROW *mergerow;
1563     MSIQUERY *dbview = NULL;
1564     MSIRECORD *row = NULL;
1565     LPWSTR query = NULL;
1566     UINT r = ERROR_SUCCESS;
1567
1568     if (TABLE_Exists(data->db, table->name))
1569     {
1570         query = create_diff_row_query(data->merge, data->curview, table->name, rec);
1571         if (!query)
1572             return ERROR_OUTOFMEMORY;
1573
1574         r = MSI_DatabaseOpenViewW(data->db, query, &dbview);
1575         if (r != ERROR_SUCCESS)
1576             goto done;
1577
1578         r = MSI_ViewExecute(dbview, NULL);
1579         if (r != ERROR_SUCCESS)
1580             goto done;
1581
1582         r = MSI_ViewFetch(dbview, &row);
1583         if (r == ERROR_SUCCESS && !MSI_RecordsAreEqual(rec, row))
1584         {
1585             table->numconflicts++;
1586             goto done;
1587         }
1588         else if (r != ERROR_NO_MORE_ITEMS)
1589             goto done;
1590
1591         r = ERROR_SUCCESS;
1592     }
1593
1594     mergerow = msi_alloc(sizeof(MERGEROW));
1595     if (!mergerow)
1596     {
1597         r = ERROR_OUTOFMEMORY;
1598         goto done;
1599     }
1600
1601     mergerow->data = MSI_CloneRecord(rec);
1602     if (!mergerow->data)
1603     {
1604         r = ERROR_OUTOFMEMORY;
1605         msi_free(mergerow);
1606         goto done;
1607     }
1608
1609     list_add_tail(&table->rows, &mergerow->entry);
1610
1611 done:
1612     msi_free(query);
1613     msiobj_release(&row->hdr);
1614     msiobj_release(&dbview->hdr);
1615     return r;
1616 }
1617
1618 static UINT msi_get_table_labels(MSIDATABASE *db, LPCWSTR table, LPWSTR **labels, DWORD *numlabels)
1619 {
1620     UINT r, i, count;
1621     MSIRECORD *prec = NULL;
1622
1623     r = MSI_DatabaseGetPrimaryKeys(db, table, &prec);
1624     if (r != ERROR_SUCCESS)
1625         return r;
1626
1627     count = MSI_RecordGetFieldCount(prec);
1628     *numlabels = count + 1;
1629     *labels = msi_alloc((*numlabels)*sizeof(LPWSTR));
1630     if (!*labels)
1631     {
1632         r = ERROR_OUTOFMEMORY;
1633         goto end;
1634     }
1635
1636     (*labels)[0] = strdupW(table);
1637     for (i=1; i<=count; i++ )
1638     {
1639         (*labels)[i] = strdupW(MSI_RecordGetString(prec, i));
1640     }
1641
1642 end:
1643     msiobj_release( &prec->hdr );
1644     return r;
1645 }
1646
1647 static UINT msi_get_query_columns(MSIQUERY *query, LPWSTR **columns, DWORD *numcolumns)
1648 {
1649     UINT r, i, count;
1650     MSIRECORD *prec = NULL;
1651
1652     r = MSI_ViewGetColumnInfo(query, MSICOLINFO_NAMES, &prec);
1653     if (r != ERROR_SUCCESS)
1654         return r;
1655
1656     count = MSI_RecordGetFieldCount(prec);
1657     *columns = msi_alloc(count*sizeof(LPWSTR));
1658     if (!*columns)
1659     {
1660         r = ERROR_OUTOFMEMORY;
1661         goto end;
1662     }
1663
1664     for (i=1; i<=count; i++ )
1665     {
1666         (*columns)[i-1] = strdupW(MSI_RecordGetString(prec, i));
1667     }
1668
1669     *numcolumns = count;
1670
1671 end:
1672     msiobj_release( &prec->hdr );
1673     return r;
1674 }
1675
1676 static UINT msi_get_query_types(MSIQUERY *query, LPWSTR **types, DWORD *numtypes)
1677 {
1678     UINT r, i, count;
1679     MSIRECORD *prec = NULL;
1680
1681     r = MSI_ViewGetColumnInfo(query, MSICOLINFO_TYPES, &prec);
1682     if (r != ERROR_SUCCESS)
1683         return r;
1684
1685     count = MSI_RecordGetFieldCount(prec);
1686     *types = msi_alloc(count*sizeof(LPWSTR));
1687     if (!*types)
1688     {
1689         r = ERROR_OUTOFMEMORY;
1690         goto end;
1691     }
1692
1693     *numtypes = count;
1694     for (i=1; i<=count; i++ )
1695     {
1696         (*types)[i-1] = strdupW(MSI_RecordGetString(prec, i));
1697     }
1698
1699 end:
1700     msiobj_release( &prec->hdr );
1701     return r;
1702 }
1703
1704 static void merge_free_rows(MERGETABLE *table)
1705 {
1706     struct list *item, *cursor;
1707
1708     LIST_FOR_EACH_SAFE(item, cursor, &table->rows)
1709     {
1710         MERGEROW *row = LIST_ENTRY(item, MERGEROW, entry);
1711
1712         list_remove(&row->entry);
1713         msiobj_release(&row->data->hdr);
1714         msi_free(row);
1715     }
1716 }
1717
1718 static void free_merge_table(MERGETABLE *table)
1719 {
1720     UINT i;
1721
1722     if (table->labels != NULL)
1723     {
1724         for (i = 0; i < table->numlabels; i++)
1725             msi_free(table->labels[i]);
1726
1727         msi_free(table->labels);
1728     }
1729
1730     if (table->columns != NULL)
1731     {
1732         for (i = 0; i < table->numcolumns; i++)
1733             msi_free(table->columns[i]);
1734
1735         msi_free(table->columns);
1736     }
1737
1738     if (table->types != NULL)
1739     {
1740         for (i = 0; i < table->numtypes; i++)
1741             msi_free(table->types[i]);
1742
1743         msi_free(table->types);
1744     }
1745
1746     msi_free(table->name);
1747     merge_free_rows(table);
1748
1749     msi_free(table);
1750 }
1751
1752 static UINT msi_get_merge_table (MSIDATABASE *db, LPCWSTR name, MERGETABLE **ptable)
1753 {
1754     UINT r;
1755     MERGETABLE *table;
1756     MSIQUERY *mergeview = NULL;
1757
1758     static const WCHAR query[] = {'S','E','L','E','C','T',' ','*',' ',
1759         'F','R','O','M',' ','`','%','s','`',0};
1760
1761     table = msi_alloc_zero(sizeof(MERGETABLE));
1762     if (!table)
1763     {
1764        *ptable = NULL;
1765        return ERROR_OUTOFMEMORY;
1766     }
1767
1768     r = msi_get_table_labels(db, name, &table->labels, &table->numlabels);
1769     if (r != ERROR_SUCCESS)
1770         goto err;
1771
1772     r = MSI_OpenQuery(db, &mergeview, query, name);
1773     if (r != ERROR_SUCCESS)
1774         goto err;
1775
1776     r = msi_get_query_columns(mergeview, &table->columns, &table->numcolumns);
1777     if (r != ERROR_SUCCESS)
1778         goto err;
1779
1780     r = msi_get_query_types(mergeview, &table->types, &table->numtypes);
1781     if (r != ERROR_SUCCESS)
1782         goto err;
1783
1784     list_init(&table->rows);
1785
1786     table->name = strdupW(name);
1787     table->numconflicts = 0;
1788
1789     msiobj_release(&mergeview->hdr);
1790     *ptable = table;
1791     return ERROR_SUCCESS;
1792
1793 err:
1794     msiobj_release(&mergeview->hdr);
1795     free_merge_table(table);
1796     *ptable = NULL;
1797     return r;
1798 }
1799
1800 static UINT merge_diff_tables(MSIRECORD *rec, LPVOID param)
1801 {
1802     MERGEDATA *data = param;
1803     MERGETABLE *table;
1804     MSIQUERY *dbview = NULL;
1805     MSIQUERY *mergeview = NULL;
1806     LPCWSTR name;
1807     UINT r;
1808
1809     static const WCHAR query[] = {'S','E','L','E','C','T',' ','*',' ',
1810         'F','R','O','M',' ','`','%','s','`',0};
1811
1812     name = MSI_RecordGetString(rec, 1);
1813
1814     r = MSI_OpenQuery(data->merge, &mergeview, query, name);
1815     if (r != ERROR_SUCCESS)
1816         goto done;
1817
1818     if (TABLE_Exists(data->db, name))
1819     {
1820         r = MSI_OpenQuery(data->db, &dbview, query, name);
1821         if (r != ERROR_SUCCESS)
1822             goto done;
1823
1824         r = merge_verify_colnames(dbview, mergeview);
1825         if (r != ERROR_SUCCESS)
1826             goto done;
1827
1828         r = merge_verify_primary_keys(data->db, data->merge, name);
1829         if (r != ERROR_SUCCESS)
1830             goto done;
1831     }
1832
1833     r = msi_get_merge_table(data->merge, name, &table);
1834     if (r != ERROR_SUCCESS)
1835         goto done;
1836
1837     data->curtable = table;
1838     data->curview = mergeview;
1839     r = MSI_IterateRecords(mergeview, NULL, merge_diff_row, data);
1840     if (r != ERROR_SUCCESS)
1841     {
1842         free_merge_table(table);
1843         goto done;
1844     }
1845
1846     list_add_tail(data->tabledata, &table->entry);
1847
1848 done:
1849     msiobj_release(&dbview->hdr);
1850     msiobj_release(&mergeview->hdr);
1851     return r;
1852 }
1853
1854 static UINT gather_merge_data(MSIDATABASE *db, MSIDATABASE *merge,
1855                               struct list *tabledata)
1856 {
1857     UINT r;
1858     MSIQUERY *view;
1859     MERGEDATA data;
1860
1861     static const WCHAR query[] = {'S','E','L','E','C','T',' ','*',' ',
1862         'F','R','O','M',' ','`','_','T','a','b','l','e','s','`',0};
1863
1864     r = MSI_DatabaseOpenViewW(merge, query, &view);
1865     if (r != ERROR_SUCCESS)
1866         return r;
1867
1868     data.db = db;
1869     data.merge = merge;
1870     data.tabledata = tabledata;
1871     r = MSI_IterateRecords(view, NULL, merge_diff_tables, &data);
1872
1873     msiobj_release(&view->hdr);
1874     return r;
1875 }
1876
1877 static UINT merge_table(MSIDATABASE *db, MERGETABLE *table)
1878 {
1879     UINT r;
1880     MERGEROW *row;
1881     MSIVIEW *tv;
1882
1883     if (!TABLE_Exists(db, table->name))
1884     {
1885         r = msi_add_table_to_db(db, table->columns, table->types,
1886                table->labels, table->numlabels, table->numcolumns);
1887         if (r != ERROR_SUCCESS)
1888            return ERROR_FUNCTION_FAILED;
1889     }
1890
1891     LIST_FOR_EACH_ENTRY(row, &table->rows, MERGEROW, entry)
1892     {
1893         r = TABLE_CreateView(db, table->name, &tv);
1894         if (r != ERROR_SUCCESS)
1895             return r;
1896
1897         r = tv->ops->insert_row(tv, row->data, -1, FALSE);
1898         tv->ops->delete(tv);
1899
1900         if (r != ERROR_SUCCESS)
1901             return r;
1902     }
1903
1904     return ERROR_SUCCESS;
1905 }
1906
1907 static UINT update_merge_errors(MSIDATABASE *db, LPCWSTR error,
1908                                 LPWSTR table, DWORD numconflicts)
1909 {
1910     UINT r;
1911     MSIQUERY *view;
1912
1913     static const WCHAR create[] = {
1914         'C','R','E','A','T','E',' ','T','A','B','L','E',' ',
1915         '`','%','s','`',' ','(','`','T','a','b','l','e','`',' ',
1916         'C','H','A','R','(','2','5','5',')',' ','N','O','T',' ',
1917         'N','U','L','L',',',' ','`','N','u','m','R','o','w','M','e','r','g','e',
1918         'C','o','n','f','l','i','c','t','s','`',' ','S','H','O','R','T',' ',
1919         'N','O','T',' ','N','U','L','L',' ','P','R','I','M','A','R','Y',' ',
1920         'K','E','Y',' ','`','T','a','b','l','e','`',')',0};
1921     static const WCHAR insert[] = {
1922         'I','N','S','E','R','T',' ','I','N','T','O',' ',
1923         '`','%','s','`',' ','(','`','T','a','b','l','e','`',',',' ',
1924         '`','N','u','m','R','o','w','M','e','r','g','e',
1925         'C','o','n','f','l','i','c','t','s','`',')',' ','V','A','L','U','E','S',
1926         ' ','(','\'','%','s','\'',',',' ','%','d',')',0};
1927
1928     if (!TABLE_Exists(db, error))
1929     {
1930         r = MSI_OpenQuery(db, &view, create, error);
1931         if (r != ERROR_SUCCESS)
1932             return r;
1933
1934         r = MSI_ViewExecute(view, NULL);
1935         msiobj_release(&view->hdr);
1936         if (r != ERROR_SUCCESS)
1937             return r;
1938     }
1939
1940     r = MSI_OpenQuery(db, &view, insert, error, table, numconflicts);
1941     if (r != ERROR_SUCCESS)
1942         return r;
1943
1944     r = MSI_ViewExecute(view, NULL);
1945     msiobj_release(&view->hdr);
1946     return r;
1947 }
1948
1949 UINT WINAPI MsiDatabaseMergeW(MSIHANDLE hDatabase, MSIHANDLE hDatabaseMerge,
1950                               LPCWSTR szTableName)
1951 {
1952     struct list tabledata = LIST_INIT(tabledata);
1953     struct list *item, *cursor;
1954     MSIDATABASE *db, *merge;
1955     MERGETABLE *table;
1956     BOOL conflicts;
1957     UINT r;
1958
1959     TRACE("(%d, %d, %s)\n", hDatabase, hDatabaseMerge,
1960           debugstr_w(szTableName));
1961
1962     if (szTableName && !*szTableName)
1963         return ERROR_INVALID_TABLE;
1964
1965     db = msihandle2msiinfo(hDatabase, MSIHANDLETYPE_DATABASE);
1966     merge = msihandle2msiinfo(hDatabaseMerge, MSIHANDLETYPE_DATABASE);
1967     if (!db || !merge)
1968     {
1969         r = ERROR_INVALID_HANDLE;
1970         goto done;
1971     }
1972
1973     r = gather_merge_data(db, merge, &tabledata);
1974     if (r != ERROR_SUCCESS)
1975         goto done;
1976
1977     conflicts = FALSE;
1978     LIST_FOR_EACH_ENTRY(table, &tabledata, MERGETABLE, entry)
1979     {
1980         if (table->numconflicts)
1981         {
1982             conflicts = TRUE;
1983
1984             r = update_merge_errors(db, szTableName, table->name,
1985                                     table->numconflicts);
1986             if (r != ERROR_SUCCESS)
1987                 break;
1988         }
1989         else
1990         {
1991             r = merge_table(db, table);
1992             if (r != ERROR_SUCCESS)
1993                 break;
1994         }
1995     }
1996
1997     LIST_FOR_EACH_SAFE(item, cursor, &tabledata)
1998     {
1999         MERGETABLE *table = LIST_ENTRY(item, MERGETABLE, entry);
2000         list_remove(&table->entry);
2001         free_merge_table(table);
2002     }
2003
2004     if (conflicts)
2005         r = ERROR_FUNCTION_FAILED;
2006
2007 done:
2008     msiobj_release(&db->hdr);
2009     msiobj_release(&merge->hdr);
2010     return r;
2011 }
2012
2013 MSIDBSTATE WINAPI MsiGetDatabaseState( MSIHANDLE handle )
2014 {
2015     MSIDBSTATE ret = MSIDBSTATE_READ;
2016     MSIDATABASE *db;
2017
2018     TRACE("%d\n", handle);
2019
2020     db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
2021     if( !db )
2022     {
2023         IWineMsiRemoteDatabase *remote_database;
2024
2025         remote_database = (IWineMsiRemoteDatabase *)msi_get_remote( handle );
2026         if ( !remote_database )
2027             return MSIDBSTATE_ERROR;
2028
2029         IWineMsiRemoteDatabase_Release( remote_database );
2030         WARN("MsiGetDatabaseState not allowed during a custom action!\n");
2031
2032         return MSIDBSTATE_READ;
2033     }
2034
2035     if (db->mode != MSIDBOPEN_READONLY )
2036         ret = MSIDBSTATE_WRITE;
2037     msiobj_release( &db->hdr );
2038
2039     return ret;
2040 }
2041
2042 typedef struct _msi_remote_database_impl {
2043     IWineMsiRemoteDatabase IWineMsiRemoteDatabase_iface;
2044     MSIHANDLE database;
2045     LONG refs;
2046 } msi_remote_database_impl;
2047
2048 static inline msi_remote_database_impl *impl_from_IWineMsiRemoteDatabase( IWineMsiRemoteDatabase *iface )
2049 {
2050     return CONTAINING_RECORD(iface, msi_remote_database_impl, IWineMsiRemoteDatabase_iface);
2051 }
2052
2053 static HRESULT WINAPI mrd_QueryInterface( IWineMsiRemoteDatabase *iface,
2054                                           REFIID riid,LPVOID *ppobj)
2055 {
2056     if( IsEqualCLSID( riid, &IID_IUnknown ) ||
2057         IsEqualCLSID( riid, &IID_IWineMsiRemoteDatabase ) )
2058     {
2059         IUnknown_AddRef( iface );
2060         *ppobj = iface;
2061         return S_OK;
2062     }
2063
2064     return E_NOINTERFACE;
2065 }
2066
2067 static ULONG WINAPI mrd_AddRef( IWineMsiRemoteDatabase *iface )
2068 {
2069     msi_remote_database_impl* This = impl_from_IWineMsiRemoteDatabase( iface );
2070
2071     return InterlockedIncrement( &This->refs );
2072 }
2073
2074 static ULONG WINAPI mrd_Release( IWineMsiRemoteDatabase *iface )
2075 {
2076     msi_remote_database_impl* This = impl_from_IWineMsiRemoteDatabase( iface );
2077     ULONG r;
2078
2079     r = InterlockedDecrement( &This->refs );
2080     if (r == 0)
2081     {
2082         MsiCloseHandle( This->database );
2083         msi_free( This );
2084     }
2085     return r;
2086 }
2087
2088 static HRESULT WINAPI mrd_IsTablePersistent( IWineMsiRemoteDatabase *iface,
2089                                              LPCWSTR table, MSICONDITION *persistent )
2090 {
2091     msi_remote_database_impl *This = impl_from_IWineMsiRemoteDatabase( iface );
2092     *persistent = MsiDatabaseIsTablePersistentW(This->database, table);
2093     return S_OK;
2094 }
2095
2096 static HRESULT WINAPI mrd_GetPrimaryKeys( IWineMsiRemoteDatabase *iface,
2097                                           LPCWSTR table, MSIHANDLE *keys )
2098 {
2099     msi_remote_database_impl *This = impl_from_IWineMsiRemoteDatabase( iface );
2100     UINT r = MsiDatabaseGetPrimaryKeysW(This->database, table, keys);
2101     return HRESULT_FROM_WIN32(r);
2102 }
2103
2104 static HRESULT WINAPI mrd_GetSummaryInformation( IWineMsiRemoteDatabase *iface,
2105                                                 UINT updatecount, MSIHANDLE *suminfo )
2106 {
2107     msi_remote_database_impl *This = impl_from_IWineMsiRemoteDatabase( iface );
2108     UINT r = MsiGetSummaryInformationW(This->database, NULL, updatecount, suminfo);
2109     return HRESULT_FROM_WIN32(r);
2110 }
2111
2112 static HRESULT WINAPI mrd_OpenView( IWineMsiRemoteDatabase *iface,
2113                                     LPCWSTR query, MSIHANDLE *view )
2114 {
2115     msi_remote_database_impl *This = impl_from_IWineMsiRemoteDatabase( iface );
2116     UINT r = MsiDatabaseOpenViewW(This->database, query, view);
2117     return HRESULT_FROM_WIN32(r);
2118 }
2119
2120 static HRESULT WINAPI mrd_SetMsiHandle( IWineMsiRemoteDatabase *iface, MSIHANDLE handle )
2121 {
2122     msi_remote_database_impl* This = impl_from_IWineMsiRemoteDatabase( iface );
2123     This->database = handle;
2124     return S_OK;
2125 }
2126
2127 static const IWineMsiRemoteDatabaseVtbl msi_remote_database_vtbl =
2128 {
2129     mrd_QueryInterface,
2130     mrd_AddRef,
2131     mrd_Release,
2132     mrd_IsTablePersistent,
2133     mrd_GetPrimaryKeys,
2134     mrd_GetSummaryInformation,
2135     mrd_OpenView,
2136     mrd_SetMsiHandle,
2137 };
2138
2139 HRESULT create_msi_remote_database( IUnknown *pOuter, LPVOID *ppObj )
2140 {
2141     msi_remote_database_impl *This;
2142
2143     This = msi_alloc( sizeof *This );
2144     if (!This)
2145         return E_OUTOFMEMORY;
2146
2147     This->IWineMsiRemoteDatabase_iface.lpVtbl = &msi_remote_database_vtbl;
2148     This->database = 0;
2149     This->refs = 1;
2150
2151     *ppObj = This;
2152
2153     return S_OK;
2154 }