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