ReactOS  0.4.15-dev-4863-gba0d16f
patch.c
Go to the documentation of this file.
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2004,2005 Aric Stewart for CodeWeavers
5  * Copyright 2011 Hans Leidekker for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include <stdarg.h>
23 #define COBJMACROS
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winreg.h"
27 #include "objbase.h"
28 #include "shlwapi.h"
29 #include "wine/debug.h"
30 #include "msipriv.h"
31 
33 
35 {
36  UINT i;
37 
38  if (!package->num_langids || !langid) return TRUE;
39  for (i = 0; i < package->num_langids; i++)
40  {
41  if (package->langids[i] == langid) return TRUE;
42  }
43  return FALSE;
44 }
45 
47 {
53 };
54 
55 static void free_transform_desc( struct transform_desc *desc )
56 {
57  msi_free( desc->product_code_from );
58  msi_free( desc->product_code_to );
59  msi_free( desc->version_from );
60  msi_free( desc->version_to );
61  msi_free( desc->upgrade_code );
62  msi_free( desc );
63 }
64 
65 static struct transform_desc *parse_transform_desc( const WCHAR *str )
66 {
67  struct transform_desc *ret;
68  const WCHAR *p = str, *q;
69  UINT len;
70 
71  if (!(ret = msi_alloc_zero( sizeof(*ret) ))) return NULL;
72 
73  q = wcschr( p, '}' );
74  if (*p != '{' || !q) goto error;
75 
76  len = q - p + 1;
77  if (!(ret->product_code_from = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error;
78  memcpy( ret->product_code_from, p, len * sizeof(WCHAR) );
79  ret->product_code_from[len] = 0;
80 
81  p = q + 1;
82  if (!(q = wcschr( p, ';' ))) goto error;
83  len = q - p;
84  if (!(ret->version_from = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error;
85  memcpy( ret->version_from, p, len * sizeof(WCHAR) );
86  ret->version_from[len] = 0;
87 
88  p = q + 1;
89  q = wcschr( p, '}' );
90  if (*p != '{' || !q) goto error;
91 
92  len = q - p + 1;
93  if (!(ret->product_code_to = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error;
94  memcpy( ret->product_code_to, p, len * sizeof(WCHAR) );
95  ret->product_code_to[len] = 0;
96 
97  p = q + 1;
98  if (!(q = wcschr( p, ';' ))) goto error;
99  len = q - p;
100  if (!(ret->version_to = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error;
101  memcpy( ret->version_to, p, len * sizeof(WCHAR) );
102  ret->version_to[len] = 0;
103 
104  p = q + 1;
105  q = wcschr( p, '}' );
106  if (*p != '{' || !q) goto error;
107 
108  len = q - p + 1;
109  if (!(ret->upgrade_code = msi_alloc( (len + 1) * sizeof(WCHAR) ))) goto error;
110  memcpy( ret->upgrade_code, p, len * sizeof(WCHAR) );
111  ret->upgrade_code[len] = 0;
112 
113  return ret;
114 
115 error:
117  return NULL;
118 }
119 
121 {
122  static const UINT supported_flags =
126  MSISUMMARYINFO *si;
127  UINT r, valid_flags = 0, wanted_flags = 0;
128  WCHAR *template, *product, *p;
129  struct transform_desc *desc;
130 
131  r = msi_get_suminfo( transform, 0, &si );
132  if (r != ERROR_SUCCESS)
133  {
134  WARN("no summary information!\n");
135  return r;
136  }
137  wanted_flags = msi_suminfo_get_int32( si, PID_CHARCOUNT );
138  wanted_flags &= 0xffff; /* mask off error condition flags */
139  TRACE("validation flags 0x%04x\n", wanted_flags);
140 
141  /* native is not validating platform */
142  wanted_flags &= ~MSITRANSFORM_VALIDATE_PLATFORM;
143 
144  if (wanted_flags & ~supported_flags)
145  {
146  FIXME("unsupported validation flags 0x%04x\n", wanted_flags);
147  msiobj_release( &si->hdr );
148  return ERROR_FUNCTION_FAILED;
149  }
150  if (!(template = msi_suminfo_dup_string( si, PID_TEMPLATE )))
151  {
152  WARN("no template property!\n");
153  msiobj_release( &si->hdr );
154  return ERROR_FUNCTION_FAILED;
155  }
156  TRACE("template property: %s\n", debugstr_w(template));
157  if (!(product = msi_get_suminfo_product( transform )))
158  {
159  WARN("no product property!\n");
160  msi_free( template );
161  msiobj_release( &si->hdr );
162  return ERROR_FUNCTION_FAILED;
163  }
164  TRACE("product property: %s\n", debugstr_w(product));
165  if (!(desc = parse_transform_desc( product )))
166  {
167  msi_free( template );
168  msiobj_release( &si->hdr );
169  return ERROR_FUNCTION_FAILED;
170  }
171  msi_free( product );
172 
173  if (wanted_flags & MSITRANSFORM_VALIDATE_LANGUAGE)
174  {
175  if (!template[0] || ((p = wcschr( template, ';' )) && match_language( package, wcstol( p + 1, NULL, 10 ) )))
176  {
177  valid_flags |= MSITRANSFORM_VALIDATE_LANGUAGE;
178  }
179  }
180  if (wanted_flags & MSITRANSFORM_VALIDATE_PRODUCT)
181  {
182  WCHAR *product_code_installed = msi_dup_property( package->db, L"ProductCode" );
183 
184  if (!product_code_installed)
185  {
186  msi_free( template );
188  msiobj_release( &si->hdr );
190  }
191  if (!wcscmp( desc->product_code_from, product_code_installed ))
192  {
193  valid_flags |= MSITRANSFORM_VALIDATE_PRODUCT;
194  }
195  msi_free( product_code_installed );
196  }
197  msi_free( template );
198  if (wanted_flags & MSITRANSFORM_VALIDATE_MAJORVERSION)
199  {
200  WCHAR *product_version_installed = msi_dup_property( package->db, L"ProductVersion" );
201  DWORD major_installed, minor_installed, major, minor;
202 
203  if (!product_version_installed)
204  {
206  msiobj_release( &si->hdr );
208  }
209  msi_parse_version_string( product_version_installed, &major_installed, &minor_installed );
210  msi_parse_version_string( desc->version_from, &major, &minor );
211 
212  if (major_installed == major)
213  {
214  valid_flags |= MSITRANSFORM_VALIDATE_MAJORVERSION;
215  wanted_flags &= ~MSITRANSFORM_VALIDATE_MINORVERSION;
216  }
217  msi_free( product_version_installed );
218  }
219  else if (wanted_flags & MSITRANSFORM_VALIDATE_MINORVERSION)
220  {
221  WCHAR *product_version_installed = msi_dup_property( package->db, L"ProductVersion" );
222  DWORD major_installed, minor_installed, major, minor;
223 
224  if (!product_version_installed)
225  {
227  msiobj_release( &si->hdr );
229  }
230  msi_parse_version_string( product_version_installed, &major_installed, &minor_installed );
231  msi_parse_version_string( desc->version_from, &major, &minor );
232 
233  if (major_installed == major && minor_installed == minor)
234  valid_flags |= MSITRANSFORM_VALIDATE_MINORVERSION;
235  msi_free( product_version_installed );
236  }
237  if (wanted_flags & MSITRANSFORM_VALIDATE_UPGRADECODE)
238  {
239  WCHAR *upgrade_code_installed = msi_dup_property( package->db, L"UpgradeCode" );
240 
241  if (!upgrade_code_installed)
242  {
244  msiobj_release( &si->hdr );
246  }
247  if (!wcscmp( desc->upgrade_code, upgrade_code_installed ))
248  valid_flags |= MSITRANSFORM_VALIDATE_UPGRADECODE;
249  msi_free( upgrade_code_installed );
250  }
251 
253  msiobj_release( &si->hdr );
254  if ((valid_flags & wanted_flags) != wanted_flags) return ERROR_FUNCTION_FAILED;
255  TRACE("applicable transform\n");
256  return ERROR_SUCCESS;
257 }
258 
260 {
262  IStorage *stg = NULL;
263  HRESULT r;
264 
265  TRACE("%p %s\n", package, debugstr_w(name));
266 
267  if (*name++ != ':')
268  {
269  ERR("expected a colon in %s\n", debugstr_w(name));
270  return ERROR_FUNCTION_FAILED;
271  }
272  r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
273  if (SUCCEEDED(r))
274  {
275  ret = check_transform_applicable( package, stg );
276  if (ret == ERROR_SUCCESS)
277  {
279  msi_table_apply_transform( package->db, stg, 0 );
280  }
281  else
282  {
283  TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
284  }
285  IStorage_Release( stg );
286  }
287  else
288  {
289  ERR("failed to open substorage %s\n", debugstr_w(name));
290  }
291  return ERROR_SUCCESS;
292 }
293 
295 {
296  LPWSTR guid_list, *guids, product_code;
298 
299  product_code = msi_dup_property( package->db, L"ProductCode" );
300  if (!product_code)
301  {
302  /* FIXME: the property ProductCode should be written into the DB somewhere */
303  ERR("no product code to check\n");
304  return ERROR_SUCCESS;
305  }
307  guids = msi_split_string( guid_list, ';' );
308  for (i = 0; guids[i] && ret != ERROR_SUCCESS; i++)
309  {
310  if (!wcscmp( guids[i], product_code )) ret = ERROR_SUCCESS;
311  }
312  msi_free( guids );
313  msi_free( guid_list );
314  msi_free( product_code );
315  return ret;
316 }
317 
319 {
320  MSIPATCHINFO *pi;
321  UINT r = ERROR_SUCCESS;
322  WCHAR *p;
323 
324  if (!(pi = msi_alloc_zero( sizeof(MSIPATCHINFO) )))
325  {
326  return ERROR_OUTOFMEMORY;
327  }
328  if (!(pi->patchcode = msi_suminfo_dup_string( si, PID_REVNUMBER )))
329  {
330  msi_free( pi );
331  return ERROR_OUTOFMEMORY;
332  }
333  p = pi->patchcode;
334  if (*p != '{')
335  {
336  msi_free( pi->patchcode );
337  msi_free( pi );
339  }
340  if (!(p = wcschr( p + 1, '}' )))
341  {
342  msi_free( pi->patchcode );
343  msi_free( pi );
345  }
346  if (p[1])
347  {
348  FIXME("patch obsoletes %s\n", debugstr_w(p + 1));
349  p[1] = 0;
350  }
351  TRACE("patch code %s\n", debugstr_w(pi->patchcode));
352  if (!(pi->products = msi_suminfo_dup_string( si, PID_TEMPLATE )))
353  {
354  msi_free( pi->patchcode );
355  msi_free( pi );
356  return ERROR_OUTOFMEMORY;
357  }
358  if (!(pi->transforms = msi_suminfo_dup_string( si, PID_LASTAUTHOR )))
359  {
360  msi_free( pi->patchcode );
361  msi_free( pi->products );
362  msi_free( pi );
363  return ERROR_OUTOFMEMORY;
364  }
365  *patch = pi;
366  return r;
367 }
368 
370 {
371  MSIQUERY *view;
372  MSIRECORD *rec;
373  const WCHAR *property;
374  WCHAR *patch;
375  UINT r;
376 
377  r = MSI_DatabaseOpenViewW( package->db, L"SELECT `Source` FROM `Media` WHERE `Source` IS NOT NULL", &view );
378  if (r != ERROR_SUCCESS)
379  return r;
380 
381  r = MSI_ViewExecute( view, 0 );
382  if (r != ERROR_SUCCESS)
383  goto done;
384 
385  if (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
386  {
387  property = MSI_RecordGetString( rec, 1 );
388  patch = msi_dup_property( package->db, L"PATCH" );
389  msi_set_property( package->db, property, patch, -1 );
390  msi_free( patch );
391  msiobj_release( &rec->hdr );
392  }
393 
394 done:
395  msiobj_release( &view->hdr );
396  return r;
397 }
398 
400 {
401  struct list entry;
404 };
405 
407 {
408  struct list files;
409  struct list patches;
412 };
413 
415 {
416  struct patch_offset_list *pos = msi_alloc( sizeof(struct patch_offset_list) );
417  list_init( &pos->files );
418  list_init( &pos->patches );
419  pos->count = pos->max = 0;
420  pos->min = 999999;
421  return pos;
422 }
423 
425 {
426  struct patch_offset *po, *po2;
427 
428  LIST_FOR_EACH_ENTRY_SAFE( po, po2, &pos->files, struct patch_offset, entry )
429  {
430  msi_free( po->name );
431  msi_free( po );
432  }
433  LIST_FOR_EACH_ENTRY_SAFE( po, po2, &pos->patches, struct patch_offset, entry )
434  {
435  msi_free( po->name );
436  msi_free( po );
437  }
438  msi_free( pos );
439 }
440 
441 static void patch_offset_get_filepatches( MSIDATABASE *db, UINT last_sequence, struct patch_offset_list *pos )
442 {
443  MSIQUERY *view;
444  MSIRECORD *rec;
445  UINT r;
446 
447  r = MSI_DatabaseOpenViewW( db, L"SELECT * FROM `Patch` WHERE `Sequence` <= ? ORDER BY `Sequence`", &view );
448  if (r != ERROR_SUCCESS)
449  return;
450 
451  rec = MSI_CreateRecord( 1 );
452  MSI_RecordSetInteger( rec, 1, last_sequence );
453 
454  r = MSI_ViewExecute( view, rec );
455  msiobj_release( &rec->hdr );
456  if (r != ERROR_SUCCESS)
457  return;
458 
459  while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
460  {
461  struct patch_offset *po = msi_alloc( sizeof(struct patch_offset) );
462 
463  po->name = msi_dup_record_field( rec, 1 );
464  po->sequence = MSI_RecordGetInteger( rec, 2 );
465  pos->min = min( pos->min, po->sequence );
466  pos->max = max( pos->max, po->sequence );
467  list_add_tail( &pos->patches, &po->entry );
468  pos->count++;
469 
470  msiobj_release( &rec->hdr );
471  }
472  msiobj_release( &view->hdr );
473 }
474 
475 static void patch_offset_get_files( MSIDATABASE *db, UINT last_sequence, struct patch_offset_list *pos )
476 {
477  MSIQUERY *view;
478  MSIRECORD *rec;
479  UINT r;
480 
481  r = MSI_DatabaseOpenViewW( db, L"SELECT * FROM `File` WHERE `Sequence` <= ? ORDER BY `Sequence`", &view );
482  if (r != ERROR_SUCCESS)
483  return;
484 
485  rec = MSI_CreateRecord( 1 );
486  MSI_RecordSetInteger( rec, 1, last_sequence );
487 
488  r = MSI_ViewExecute( view, rec );
489  msiobj_release( &rec->hdr );
490  if (r != ERROR_SUCCESS)
491  return;
492 
493  while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
494  {
495  UINT attributes = MSI_RecordGetInteger( rec, 7 );
496  if (attributes & msidbFileAttributesPatchAdded)
497  {
498  struct patch_offset *po = msi_alloc( sizeof(struct patch_offset) );
499 
500  po->name = msi_dup_record_field( rec, 1 );
501  po->sequence = MSI_RecordGetInteger( rec, 8 );
502  pos->min = min( pos->min, po->sequence );
503  pos->max = max( pos->max, po->sequence );
504  list_add_tail( &pos->files, &po->entry );
505  pos->count++;
506  }
507  msiobj_release( &rec->hdr );
508  }
509  msiobj_release( &view->hdr );
510 }
511 
513  MSIQUERY *view, MSIRECORD *rec )
514 {
515  struct patch_offset *po;
516  const WCHAR *file = MSI_RecordGetString( rec, 1 );
517  UINT r = ERROR_SUCCESS, seq = MSI_RecordGetInteger( rec, 8 );
518 
519  LIST_FOR_EACH_ENTRY( po, &pos->files, struct patch_offset, entry )
520  {
521  if (!wcsicmp( file, po->name ))
522  {
523  MSI_RecordSetInteger( rec, 8, seq + pos->offset_to_apply );
525  if (r != ERROR_SUCCESS)
526  ERR("Failed to update offset for file %s (%u)\n", debugstr_w(file), r);
527  break;
528  }
529  }
530  return r;
531 }
532 
534  MSIQUERY *view, MSIRECORD *rec )
535 {
536  struct patch_offset *po;
537  const WCHAR *file = MSI_RecordGetString( rec, 1 );
538  UINT r = ERROR_SUCCESS, seq = MSI_RecordGetInteger( rec, 2 );
539 
540  LIST_FOR_EACH_ENTRY( po, &pos->patches, struct patch_offset, entry )
541  {
542  if (seq == po->sequence && !wcsicmp( file, po->name ))
543  {
544  MSIQUERY *delete_view, *insert_view;
545  MSIRECORD *rec2;
546 
547  r = MSI_DatabaseOpenViewW( db, L"DELETE FROM `Patch` WHERE `File_` = ? AND `Sequence` = ?", &delete_view );
548  if (r != ERROR_SUCCESS) return r;
549 
550  rec2 = MSI_CreateRecord( 2 );
551  MSI_RecordSetStringW( rec2, 1, po->name );
552  MSI_RecordSetInteger( rec2, 2, po->sequence );
553  r = MSI_ViewExecute( delete_view, rec2 );
554  msiobj_release( &delete_view->hdr );
555  msiobj_release( &rec2->hdr );
556  if (r != ERROR_SUCCESS) return r;
557 
558  r = MSI_DatabaseOpenViewW( db, L"INSERT INTO `Patch` (`File_`,`Sequence`,`PatchSize`,`Attributes`,"
559  L"`Header`,`StreamRef_`) VALUES (?,?,?,?,?,?)", &insert_view );
560  if (r != ERROR_SUCCESS) return r;
561 
562  MSI_RecordSetInteger( rec, 2, po->sequence + pos->offset_to_apply );
563 
564  r = MSI_ViewExecute( insert_view, rec );
565  msiobj_release( &insert_view->hdr );
566  if (r != ERROR_SUCCESS)
567  ERR("Failed to update offset for filepatch %s (%u)\n", debugstr_w(file), r);
568  break;
569  }
570  }
571  return r;
572 }
573 
575 {
576  MSIRECORD *rec;
577  MSIQUERY *view;
578  UINT r, min = pos->min, max = pos->max, r_fetch;
579 
580  r = MSI_DatabaseOpenViewW( db,
581  L"SELECT * FROM `File` WHERE `Sequence` >= ? AND `Sequence` <= ? ORDER BY `Sequence`",
582  &view );
583  if (r != ERROR_SUCCESS)
584  return ERROR_SUCCESS;
585 
586  rec = MSI_CreateRecord( 2 );
587  MSI_RecordSetInteger( rec, 1, min );
588  MSI_RecordSetInteger( rec, 2, max );
589 
590  r = MSI_ViewExecute( view, rec );
591  msiobj_release( &rec->hdr );
592  if (r != ERROR_SUCCESS)
593  goto done;
594 
595  while ((r_fetch = MSI_ViewFetch( view, &rec )) == ERROR_SUCCESS)
596  {
597  r = patch_update_file_sequence( db, pos, view, rec );
598  msiobj_release( &rec->hdr );
599  if (r != ERROR_SUCCESS) goto done;
600  }
601  msiobj_release( &view->hdr );
602 
603  r = MSI_DatabaseOpenViewW( db,
604  L"SELECT *FROM `Patch` WHERE `Sequence` >= ? AND `Sequence` <= ? ORDER BY `Sequence`",
605  &view );
606  if (r != ERROR_SUCCESS)
607  return ERROR_SUCCESS;
608 
609  rec = MSI_CreateRecord( 2 );
610  MSI_RecordSetInteger( rec, 1, min );
611  MSI_RecordSetInteger( rec, 2, max );
612 
613  r = MSI_ViewExecute( view, rec );
614  msiobj_release( &rec->hdr );
615  if (r != ERROR_SUCCESS)
616  goto done;
617 
618  while ((r_fetch = MSI_ViewFetch( view, &rec )) == ERROR_SUCCESS)
619  {
620  r = patch_update_filepatch_sequence( db, pos, view, rec );
621  msiobj_release( &rec->hdr );
622  if (r != ERROR_SUCCESS) goto done;
623  }
624 
625 done:
626  msiobj_release( &view->hdr );
627  return r;
628 }
629 
630 static const WCHAR patch_media_query[] =
631  L"SELECT * FROM `Media` WHERE `Source` IS NOT NULL AND `Cabinet` IS NOT NULL ORDER BY `DiskId`";
632 
634 {
635  struct list entry;
642 };
643 
644 static UINT patch_add_media( MSIPACKAGE *package, IStorage *storage, MSIPATCHINFO *patch )
645 {
646  MSIQUERY *view;
647  MSIRECORD *rec;
648  UINT r, disk_id;
649  struct list media_list;
650  struct patch_media *media, *next;
651 
653  if (r != ERROR_SUCCESS) return r;
654 
655  r = MSI_ViewExecute( view, 0 );
656  if (r != ERROR_SUCCESS)
657  {
658  msiobj_release( &view->hdr );
659  TRACE("query failed %u\n", r);
660  return r;
661  }
662  list_init( &media_list );
663  while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
664  {
665  disk_id = MSI_RecordGetInteger( rec, 1 );
666  TRACE("disk_id %u\n", disk_id);
667  if (disk_id >= MSI_INITIAL_MEDIA_TRANSFORM_DISKID)
668  {
669  msiobj_release( &rec->hdr );
670  continue;
671  }
672  if (!(media = msi_alloc( sizeof( *media ))))
673  {
674  msiobj_release( &rec->hdr );
675  goto done;
676  }
677  media->disk_id = disk_id;
678  media->last_sequence = MSI_RecordGetInteger( rec, 2 );
679  media->prompt = msi_dup_record_field( rec, 3 );
680  media->cabinet = msi_dup_record_field( rec, 4 );
681  media->volume = msi_dup_record_field( rec, 5 );
682  media->source = msi_dup_record_field( rec, 6 );
683 
684  list_add_tail( &media_list, &media->entry );
685  msiobj_release( &rec->hdr );
686  }
687  LIST_FOR_EACH_ENTRY( media, &media_list, struct patch_media, entry )
688  {
689  MSIQUERY *delete_view, *insert_view;
690 
691  r = MSI_DatabaseOpenViewW( package->db, L"DELETE FROM `Media` WHERE `DiskId`=?", &delete_view );
692  if (r != ERROR_SUCCESS) goto done;
693 
694  rec = MSI_CreateRecord( 1 );
695  MSI_RecordSetInteger( rec, 1, media->disk_id );
696 
697  r = MSI_ViewExecute( delete_view, rec );
698  msiobj_release( &delete_view->hdr );
699  msiobj_release( &rec->hdr );
700  if (r != ERROR_SUCCESS) goto done;
701 
702  r = MSI_DatabaseOpenViewW( package->db, L"INSERT INTO `Media` (`DiskId`,`LastSequence`,`DiskPrompt`,"
703  L"`Cabinet`,`VolumeLabel`,`Source`) VALUES (?,?,?,?,?,?)",
704  &insert_view );
705  if (r != ERROR_SUCCESS) goto done;
706 
707  disk_id = package->db->media_transform_disk_id;
708  TRACE("disk id %u\n", disk_id);
709  TRACE("last sequence %u\n", media->last_sequence);
710  TRACE("prompt %s\n", debugstr_w(media->prompt));
711  TRACE("cabinet %s\n", debugstr_w(media->cabinet));
712  TRACE("volume %s\n", debugstr_w(media->volume));
713  TRACE("source %s\n", debugstr_w(media->source));
714 
715  rec = MSI_CreateRecord( 6 );
716  MSI_RecordSetInteger( rec, 1, disk_id );
717  MSI_RecordSetInteger( rec, 2, media->last_sequence );
718  MSI_RecordSetStringW( rec, 3, media->prompt );
719  MSI_RecordSetStringW( rec, 4, media->cabinet );
720  MSI_RecordSetStringW( rec, 5, media->volume );
721  MSI_RecordSetStringW( rec, 6, media->source );
722 
723  r = MSI_ViewExecute( insert_view, rec );
724  msiobj_release( &insert_view->hdr );
725  msiobj_release( &rec->hdr );
726  if (r != ERROR_SUCCESS) goto done;
727 
728  r = msi_add_cabinet_stream( package, disk_id, storage, media->cabinet );
729  if (r != ERROR_SUCCESS) ERR("failed to add cabinet stream %u\n", r);
730  else
731  {
732  patch->disk_id = disk_id;
733  package->db->media_transform_disk_id++;
734  }
735  }
736 
737 done:
738  msiobj_release( &view->hdr );
739  LIST_FOR_EACH_ENTRY_SAFE( media, next, &media_list, struct patch_media, entry )
740  {
741  list_remove( &media->entry );
742  msi_free( media->prompt );
743  msi_free( media->cabinet );
744  msi_free( media->volume );
745  msi_free( media->source );
746  msi_free( media );
747  }
748  return r;
749 }
750 
752 {
753  MSIQUERY *view;
754  MSIRECORD *rec;
755  UINT r;
756 
758  if (r != ERROR_SUCCESS)
759  return r;
760 
761  r = MSI_ViewExecute( view, 0 );
762  if (r != ERROR_SUCCESS)
763  goto done;
764 
765  while (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
766  {
767  UINT offset, last_sequence = MSI_RecordGetInteger( rec, 2 );
768  struct patch_offset_list *pos;
769 
770  /* FIXME: set/check Source field instead? */
771  if (last_sequence >= MSI_INITIAL_MEDIA_TRANSFORM_OFFSET)
772  {
773  msiobj_release( &rec->hdr );
774  continue;
775  }
777  patch_offset_get_files( db, last_sequence, pos );
778  patch_offset_get_filepatches( db, last_sequence, pos );
779 
780  offset = db->media_transform_offset - pos->min;
781  last_sequence = offset + pos->max;
782 
783  last_sequence += pos->min;
784  pos->offset_to_apply = offset;
785  if (pos->count)
786  {
787  r = patch_offset_modify_db( db, pos );
788  if (r != ERROR_SUCCESS)
789  ERR("Failed to set offsets, expect breakage (%u)\n", r);
790  }
791  MSI_RecordSetInteger( rec, 2, last_sequence );
793  if (r != ERROR_SUCCESS)
794  ERR("Failed to update Media table entry, expect breakage (%u)\n", r);
795 
796  db->media_transform_offset = last_sequence + 1;
797 
799  msiobj_release( &rec->hdr );
800  }
801 
802 done:
803  msiobj_release( &view->hdr );
804  return r;
805 }
806 
808 {
809  MSIQUERY *view;
810  MSIRECORD *rec;
811  DWORD ret = 0;
812 
813  if (MSI_DatabaseOpenViewW( db, L"SELECT `Value` FROM `MsiPatchMetadata` WHERE `Company` IS NULL "
814  L"AND `Property`='AllowRemoval'", &view ) != ERROR_SUCCESS) return 0;
815  if (MSI_ViewExecute( view, 0 ) != ERROR_SUCCESS)
816  {
817  msiobj_release( &view->hdr );
818  return 0;
819  }
820 
821  if (MSI_ViewFetch( view, &rec ) == ERROR_SUCCESS)
822  {
823  const WCHAR *value = MSI_RecordGetString( rec, 1 );
824  ret = wcstol( value, NULL, 10 );
825  msiobj_release( &rec->hdr );
826  }
827 
828  FIXME( "check other criteria\n" );
829 
830  msiobj_release( &view->hdr );
831  return ret;
832 }
833 
834 static UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch )
835 {
836  UINT i, r = ERROR_SUCCESS;
837  WCHAR **substorage;
838 
839  /* apply substorage transforms */
840  substorage = msi_split_string( patch->transforms, ';' );
841  for (i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++)
842  {
843  r = apply_substorage_transform( package, patch_db, substorage[i] );
844  if (r == ERROR_SUCCESS)
845  {
846  r = patch_set_offsets( package->db, patch );
847  if (r == ERROR_SUCCESS)
848  r = patch_add_media( package, patch_db->storage, patch );
849  }
850  }
851  msi_free( substorage );
852  if (r != ERROR_SUCCESS)
853  return r;
854 
855  r = patch_set_media_source_prop( package );
856  if (r != ERROR_SUCCESS)
857  return r;
858 
859  patch->uninstallable = is_uninstallable( patch_db );
860  patch->state = MSIPATCHSTATE_APPLIED;
861  list_add_tail( &package->patches, &patch->entry );
862  return ERROR_SUCCESS;
863 }
864 
866 {
867  msi_free( patch->patchcode );
868  msi_free( patch->products );
869  msi_free( patch->transforms );
870  msi_free( patch->filename );
871  msi_free( patch->localfile );
872  msi_free( patch );
873 }
874 
876 {
877  MSIDATABASE *patch_db = NULL;
878  WCHAR localfile[MAX_PATH];
879  MSISUMMARYINFO *si;
880  MSIPATCHINFO *patch = NULL;
881  UINT r;
882 
883  TRACE("%p, %s\n", package, debugstr_w(file));
884 
886  if (r != ERROR_SUCCESS)
887  {
888  ERR("failed to open patch collection %s\n", debugstr_w( file ) );
889  return r;
890  }
891  r = msi_get_suminfo( patch_db->storage, 0, &si );
892  if (r != ERROR_SUCCESS)
893  {
894  msiobj_release( &patch_db->hdr );
895  return r;
896  }
897  r = msi_check_patch_applicable( package, si );
898  if (r != ERROR_SUCCESS)
899  {
900  TRACE("patch not applicable\n");
901  r = ERROR_SUCCESS;
902  goto done;
903  }
904  r = msi_parse_patch_summary( si, &patch );
905  if ( r != ERROR_SUCCESS )
906  goto done;
907 
908  r = msi_create_empty_local_file( localfile, L".msp" );
909  if ( r != ERROR_SUCCESS )
910  goto done;
911 
913  patch->registered = FALSE;
914  if (!(patch->filename = strdupW( file ))) goto done;
915  if (!(patch->localfile = strdupW( localfile ))) goto done;
916 
917  r = msi_apply_patch_db( package, patch_db, patch );
918  if (r != ERROR_SUCCESS) WARN("patch failed to apply %u\n", r);
919 
920 done:
921  msiobj_release( &si->hdr );
922  msiobj_release( &patch_db->hdr );
923  if (patch && r != ERROR_SUCCESS)
924  {
925  DeleteFileW( patch->localfile );
926  msi_free_patchinfo( patch );
927  }
928  return r;
929 }
930 
931 /* get the PATCH property, and apply all the patches it specifies */
933 {
934  LPWSTR patch_list, *patches;
935  UINT i, r = ERROR_SUCCESS;
936 
937  patch_list = msi_dup_property( package->db, L"PATCH" );
938 
939  TRACE("patches to be applied: %s\n", debugstr_w(patch_list));
940 
941  patches = msi_split_string( patch_list, ';' );
942  for (i = 0; patches && patches[i] && r == ERROR_SUCCESS; i++)
943  r = msi_apply_patch_package( package, patches[i] );
944 
945  msi_free( patches );
946  msi_free( patch_list );
947  return r;
948 }
949 
951 {
952  LPWSTR xform_list, *xforms;
953  UINT i, r = ERROR_SUCCESS;
954 
955  xform_list = msi_dup_property( package->db, L"TRANSFORMS" );
956  xforms = msi_split_string( xform_list, ';' );
957 
958  for (i = 0; xforms && xforms[i] && r == ERROR_SUCCESS; i++)
959  {
960  if (xforms[i][0] == ':')
961  r = apply_substorage_transform( package, package->db, xforms[i] );
962  else
963  {
964  WCHAR *transform;
965 
966  if (!PathIsRelativeW( xforms[i] )) transform = xforms[i];
967  else
968  {
969  WCHAR *p = wcsrchr( package->PackagePath, '\\' );
970  DWORD len = p - package->PackagePath + 1;
971 
972  if (!(transform = msi_alloc( (len + lstrlenW( xforms[i] ) + 1) * sizeof(WCHAR)) ))
973  {
974  msi_free( xforms );
975  msi_free( xform_list );
976  return ERROR_OUTOFMEMORY;
977  }
978  memcpy( transform, package->PackagePath, len * sizeof(WCHAR) );
979  memcpy( transform + len, xforms[i], (lstrlenW( xforms[i] ) + 1) * sizeof(WCHAR) );
980  }
981  r = MSI_DatabaseApplyTransformW( package->db, transform, 0 );
982  if (transform != xforms[i]) msi_free( transform );
983  }
984  }
985  msi_free( xforms );
986  msi_free( xform_list );
987  return r;
988 }
989 
991 {
992  UINT r;
993  DWORD len;
995  MSIDATABASE *patch_db;
996  MSIPATCHINFO *patch_info;
997  MSISUMMARYINFO *si;
998 
999  TRACE("%p, %s\n", package, debugstr_w(patch_code));
1000 
1001  len = ARRAY_SIZE( patch_file );
1002  r = MsiGetPatchInfoExW( patch_code, package->ProductCode, NULL, package->Context,
1004  if (r != ERROR_SUCCESS)
1005  {
1006  ERR("failed to get patch filename %u\n", r);
1007  return r;
1008  }
1010  if (r != ERROR_SUCCESS)
1011  {
1012  ERR("failed to open patch database %s\n", debugstr_w( patch_file ));
1013  return r;
1014  }
1015  r = msi_get_suminfo( patch_db->storage, 0, &si );
1016  if (r != ERROR_SUCCESS)
1017  {
1018  msiobj_release( &patch_db->hdr );
1019  return r;
1020  }
1021  r = msi_parse_patch_summary( si, &patch_info );
1022  msiobj_release( &si->hdr );
1023  if (r != ERROR_SUCCESS)
1024  {
1025  ERR("failed to parse patch summary %u\n", r);
1026  msiobj_release( &patch_db->hdr );
1027  return r;
1028  }
1029  patch_info->registered = TRUE;
1030  patch_info->localfile = strdupW( patch_file );
1031  if (!patch_info->localfile)
1032  {
1033  msiobj_release( &patch_db->hdr );
1034  msi_free_patchinfo( patch_info );
1035  return ERROR_OUTOFMEMORY;
1036  }
1037  r = msi_apply_patch_db( package, patch_db, patch_info );
1038  msiobj_release( &patch_db->hdr );
1039  if (r != ERROR_SUCCESS)
1040  {
1041  ERR("failed to apply patch %u\n", r);
1042  msi_free_patchinfo( patch_info );
1043  }
1044  return r;
1045 }
LPWSTR msi_suminfo_dup_string(MSISUMMARYINFO *si, UINT uiProperty) DECLSPEC_HIDDEN
Definition: suminfo.c:696
LPWSTR ProductCode
Definition: msipriv.h:448
#define PID_TEMPLATE
Definition: suminfo.c:49
#define MSIDBOPEN_READONLY
Definition: msiquery.h:66
#define max(a, b)
Definition: svc.c:63
void msi_free_patchinfo(MSIPATCHINFO *patch)
Definition: patch.c:865
Definition: pdh_main.c:93
BOOL WINAPI PathIsRelativeW(LPCWSTR lpszPath)
Definition: path.c:1578
UINT MSI_RecordSetStringW(MSIRECORD *, UINT, LPCWSTR) DECLSPEC_HIDDEN
Definition: record.c:597
#define PID_CHARCOUNT
Definition: suminfo.c:58
static UINT msi_parse_patch_summary(MSISUMMARYINFO *si, MSIPATCHINFO **patch)
Definition: patch.c:318
UINT msi_check_patch_applicable(MSIPACKAGE *package, MSISUMMARYINFO *si)
Definition: patch.c:294
LPWSTR transforms
Definition: msipriv.h:203
#define ERROR_SUCCESS
Definition: deptool.c:10
#define MSIDBOPEN_PATCHFILE
Definition: msiquery.h:79
WCHAR * source
Definition: patch.c:641
#define error(str)
Definition: mkdosfs.c:1605
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#define MSI_INITIAL_MEDIA_TRANSFORM_DISKID
Definition: msipriv.h:84
#define STGM_SHARE_EXCLUSIVE
Definition: objbase.h:922
WCHAR * prompt
Definition: patch.c:638
WCHAR * product_code_to
Definition: patch.c:49
UINT MSI_ViewModify(MSIQUERY *, MSIMODIFY, MSIRECORD *) DECLSPEC_HIDDEN
Definition: msiquery.c:698
#define TRUE
Definition: types.h:120
static WCHAR * strdupW(const WCHAR *src)
Definition: main.c:92
MSIOBJECTHDR hdr
Definition: msipriv.h:151
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLuint GLuint GLsizei count
Definition: gl.h:1545
UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
Definition: database.c:140
LPWSTR PackagePath
Definition: msipriv.h:447
#define WARN(fmt,...)
Definition: debug.h:112
UINT MSI_ViewExecute(MSIQUERY *, MSIRECORD *) DECLSPEC_HIDDEN
Definition: msiquery.c:502
static UINT patch_set_media_source_prop(MSIPACKAGE *package)
Definition: patch.c:369
WCHAR * name
Definition: patch.c:402
static UINT msi_apply_patch_db(MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch)
Definition: patch.c:834
MSIPATCHSTATE state
Definition: msipriv.h:206
static void msi_free(void *mem)
Definition: msipriv.h:1159
WORD LANGID
Definition: typedefs.h:81
DWORD uninstallable
Definition: msipriv.h:207
_Check_return_ long __cdecl wcstol(_In_z_ const wchar_t *_Str, _Out_opt_ _Deref_post_z_ wchar_t **_EndPtr, _In_ int _Radix)
#define PID_REVNUMBER
Definition: suminfo.c:51
#define MSI_INITIAL_MEDIA_TRANSFORM_OFFSET
Definition: msipriv.h:83
static BOOL match_language(MSIPACKAGE *package, LANGID langid)
Definition: patch.c:34
UINT msi_apply_transforms(MSIPACKAGE *package)
Definition: patch.c:950
LANGID langid
Definition: msctf.idl:605
UINT sequence
Definition: patch.c:403
#define lstrlenW
Definition: compat.h:609
static const WCHAR INSTALLPROPERTY_LOCALPACKAGEW[]
Definition: msi.h:343
static void * msi_alloc_zero(size_t len) __WINE_ALLOC_SIZE(1)
Definition: msipriv.h:1148
static UINT patch_add_media(MSIPACKAGE *package, IStorage *storage, MSIPATCHINFO *patch)
Definition: patch.c:644
static void patch_offset_get_filepatches(MSIDATABASE *db, UINT last_sequence, struct patch_offset_list *pos)
Definition: patch.c:441
WCHAR * cabinet
Definition: patch.c:639
__WINE_SERVER_LIST_INLINE void list_add_tail(struct list *list, struct list *elem)
Definition: list.h:102
#define LIST_FOR_EACH_ENTRY(elem, list, type, field)
Definition: list.h:198
BOOL registered
Definition: msipriv.h:209
#define L(x)
Definition: ntvdm.h:50
UINT MSI_RecordSetInteger(MSIRECORD *, UINT, int) DECLSPEC_HIDDEN
Definition: record.c:280
LPWSTR msi_get_suminfo_product(IStorage *stg) DECLSPEC_HIDDEN
Definition: suminfo.c:720
static UINT patch_update_file_sequence(MSIDATABASE *db, const struct patch_offset_list *pos, MSIQUERY *view, MSIRECORD *rec)
Definition: patch.c:512
static void patch_offset_get_files(MSIDATABASE *db, UINT last_sequence, struct patch_offset_list *pos)
Definition: patch.c:475
#define ERROR_FUNCTION_FAILED
Definition: winerror.h:985
UINT MSI_ViewFetch(MSIQUERY *, MSIRECORD **) DECLSPEC_HIDDEN
Definition: msiquery.c:377
#define FALSE
Definition: types.h:117
#define PID_LASTAUTHOR
Definition: suminfo.c:50
unsigned int BOOL
Definition: ntddk_ex.h:94
static const WCHAR desc[]
Definition: protectdata.c:36
if SUCCEEDED(hr)
static void free_transform_desc(struct transform_desc *desc)
Definition: patch.c:55
#define debugstr_w
Definition: kernel32.h:32
#define ERROR_PATCH_PACKAGE_INVALID
Definition: winerror.h:994
#define FIXME(fmt,...)
Definition: debug.h:111
BOOL WINAPI DeleteFileW(IN LPCWSTR lpFileName)
Definition: delete.c:39
const WCHAR * str
static const WCHAR patch_media_query[]
Definition: patch.c:630
LPWSTR filename
Definition: msipriv.h:204
ULONG major
UINT msi_get_suminfo(IStorage *stg, UINT uiUpdateCount, MSISUMMARYINFO **si) DECLSPEC_HIDDEN
Definition: suminfo.c:457
const WCHAR * MSI_RecordGetString(const MSIRECORD *, UINT) DECLSPEC_HIDDEN
Definition: record.c:433
void msi_parse_version_string(LPCWSTR verStr, PDWORD ms, PDWORD ls)
Definition: appsearch.c:52
LPWSTR products
Definition: msipriv.h:202
__WINE_SERVER_LIST_INLINE void list_remove(struct list *elem)
Definition: list.h:108
__u8 media
Definition: mkdosfs.c:367
#define TRACE(s)
Definition: solgame.cpp:4
struct list entry
Definition: patch.c:401
#define ERROR_INSTALL_PACKAGE_INVALID
Definition: winerror.h:978
_CONST_RETURN wchar_t *__cdecl wcschr(_In_z_ const wchar_t *_Str, wchar_t _Ch)
__wchar_t WCHAR
Definition: xmlstorage.h:180
static refpint_t pi[]
Definition: server.c:96
LONG HRESULT
Definition: typedefs.h:79
GLintptr offset
Definition: glext.h:5920
#define MAX_PATH
Definition: compat.h:34
WCHAR * upgrade_code
Definition: patch.c:52
unsigned long DWORD
Definition: ntddk_ex.h:95
MSIDATABASE * db
Definition: msipriv.h:394
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
MSIOBJECTHDR hdr
Definition: msipriv.h:129
LANGID * langids
Definition: msipriv.h:398
MSIOBJECTHDR hdr
Definition: msipriv.h:486
int msiobj_release(MSIOBJECTHDR *info)
Definition: handle.c:241
#define wcsicmp
Definition: compat.h:15
int ret
MSIRECORD * MSI_CreateRecord(UINT) DECLSPEC_HIDDEN
Definition: record.c:76
uint32_t entry
Definition: isohybrid.c:63
static struct patch_offset_list * patch_offset_list_create(void)
Definition: patch.c:414
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
static UINT check_transform_applicable(MSIPACKAGE *package, IStorage *transform)
Definition: patch.c:120
Definition: _list.h:228
static UINT msi_apply_patch_package(MSIPACKAGE *package, const WCHAR *file)
Definition: patch.c:875
struct list entry
Definition: msipriv.h:200
LPWSTR patchcode
Definition: msipriv.h:201
#define wcsrchr
Definition: compat.h:16
WCHAR * volume
Definition: patch.c:640
static DWORD is_uninstallable(MSIDATABASE *db)
Definition: patch.c:807
int MSI_RecordGetInteger(MSIRECORD *, UINT) DECLSPEC_HIDDEN
Definition: record.c:213
#define ERR(fmt,...)
Definition: debug.h:110
UINT disk_id
Definition: patch.c:636
UINT msi_apply_registered_patch(MSIPACKAGE *package, LPCWSTR patch_code)
Definition: patch.c:990
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
UINT num_langids
Definition: msipriv.h:397
static unsigned __int64 next
Definition: rand_nt.c:6
WINE_DEFAULT_DEBUG_CHANNEL(msi)
#define LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, list, type, field)
Definition: list.h:204
WCHAR ** msi_split_string(const WCHAR *str, WCHAR sep)
Definition: action.c:305
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
static struct transform_desc * parse_transform_desc(const WCHAR *str)
Definition: patch.c:65
#define ARRAY_SIZE(a)
Definition: main.h:24
WCHAR * msi_dup_record_field(MSIRECORD *row, INT index) DECLSPEC_HIDDEN
Definition: record.c:1002
static UINT patch_set_offsets(MSIDATABASE *db, MSIPATCHINFO *patch)
Definition: patch.c:751
WCHAR * version_to
Definition: patch.c:51
UINT msi_apply_patches(MSIPACKAGE *package)
Definition: patch.c:932
#define min(a, b)
Definition: monoChain.cc:55
static UINT apply_substorage_transform(MSIPACKAGE *package, MSIDATABASE *patch_db, LPCWSTR name)
Definition: patch.c:259
unsigned int UINT
Definition: ndis.h:50
#define NULL
Definition: types.h:112
UINT offset_to_apply
Definition: patch.c:411
UINT msi_set_property(MSIDATABASE *, const WCHAR *, const WCHAR *, int) DECLSPEC_HIDDEN
Definition: package.c:2044
UINT msi_create_empty_local_file(LPWSTR path, LPCWSTR suffix) DECLSPEC_HIDDEN
Definition: package.c:1063
LPWSTR localfile
Definition: msipriv.h:205
UINT Context
Definition: msipriv.h:459
UINT msi_table_apply_transform(MSIDATABASE *db, IStorage *stg, int err_cond) DECLSPEC_HIDDEN
Definition: table.c:3371
UINT media_transform_disk_id
Definition: msipriv.h:117
Definition: name.c:38
__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:1142
static const GUID * guid_list[]
Definition: metadata.c:2260
INT msi_suminfo_get_int32(MSISUMMARYINFO *si, UINT uiProperty) DECLSPEC_HIDDEN
Definition: suminfo.c:708
UINT msi_add_cabinet_stream(MSIPACKAGE *package, UINT disk_id, IStorage *storage, const WCHAR *name)
Definition: media.c:935
static IOleDocumentView * view
Definition: activex.c:1749
GLuint GLenum GLenum transform
Definition: glext.h:9407
UINT last_sequence
Definition: patch.c:637
IStorage * storage
Definition: msipriv.h:109
static UINT patch_update_filepatch_sequence(MSIDATABASE *db, const struct patch_offset_list *pos, MSIQUERY *view, MSIRECORD *rec)
Definition: patch.c:533
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
static void patch_offset_list_free(struct patch_offset_list *pos)
Definition: patch.c:424
ULONG minor
MSIOBJECTHDR hdr
Definition: msipriv.h:108
WCHAR * product_code_from
Definition: patch.c:48
UINT media_transform_offset
Definition: msipriv.h:116
struct list patches
Definition: msipriv.h:400
#define ERROR_OUTOFMEMORY
Definition: deptool.c:13
UINT WINAPI MsiGetPatchInfoExW(LPCWSTR szPatchCode, LPCWSTR szProductCode, LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext, LPCWSTR szProperty, LPWSTR lpValue, DWORD *pcchValue)
Definition: msi.c:1659
WCHAR * version_from
Definition: patch.c:50
UINT MSI_DatabaseApplyTransformW(MSIDATABASE *db, LPCWSTR szTransformFile, int iErrorCond) DECLSPEC_HIDDEN
static UINT patch_offset_modify_db(MSIDATABASE *db, struct patch_offset_list *pos)
Definition: patch.c:574
Definition: fci.c:126
LPWSTR msi_dup_property(MSIDATABASE *db, LPCWSTR prop) DECLSPEC_HIDDEN
Definition: package.c:2227
static UINT patch_file(MSIPACKAGE *package, MSIFILEPATCH *patch)
Definition: files.c:712
UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY **) DECLSPEC_HIDDEN