ReactOS 0.4.15-dev-7918-g2a2556c
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
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
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
115error:
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 );
149 }
150 if (!(template = msi_suminfo_dup_string( si, PID_TEMPLATE )))
151 {
152 WARN("no template property!\n");
153 msiobj_release( &si->hdr );
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 );
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 );
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 {
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)
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 ))
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));
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 );
314 msi_free( product_code );
315 return ret;
316}
317
319{
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
394done:
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
441static 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
475static 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
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
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 {
621 msiobj_release( &rec->hdr );
622 if (r != ERROR_SUCCESS) goto done;
623 }
624
625done:
626 msiobj_release( &view->hdr );
627 return r;
628}
629
630static 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
644static 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);
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
737done:
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 {
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
802done:
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;
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
834static UINT msi_apply_patch_db( MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch )
835{
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 );
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");
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
920done:
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;
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;
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 {
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
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}
void msi_parse_version_string(LPCWSTR verStr, PDWORD ms, PDWORD ls)
Definition: appsearch.c:52
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
static WCHAR * strdupW(const WCHAR *src)
Definition: main.c:92
#define ARRAY_SIZE(A)
Definition: main.h:33
static void list_remove(struct list_entry *entry)
Definition: list.h:90
static void list_add_tail(struct list_entry *head, struct list_entry *entry)
Definition: list.h:83
static void list_init(struct list_entry *head)
Definition: list.h:51
#define FIXME(fmt,...)
Definition: debug.h:111
#define WARN(fmt,...)
Definition: debug.h:112
#define ERR(fmt,...)
Definition: debug.h:110
Definition: list.h:37
#define ERROR_OUTOFMEMORY
Definition: deptool.c:13
#define ERROR_SUCCESS
Definition: deptool.c:10
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define wcschr
Definition: compat.h:17
#define wcsrchr
Definition: compat.h:16
#define MAX_PATH
Definition: compat.h:34
#define wcsicmp
Definition: compat.h:15
#define lstrlenW
Definition: compat.h:750
BOOL WINAPI DeleteFileW(IN LPCWSTR lpFileName)
Definition: delete.c:39
WCHAR ** msi_split_string(const WCHAR *str, WCHAR sep)
Definition: action.c:305
UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
Definition: database.c:140
static UINT patch_file(MSIPACKAGE *package, MSIFILEPATCH *patch)
Definition: files.c:712
int msiobj_release(MSIOBJECTHDR *info)
Definition: handle.c:241
UINT msi_add_cabinet_stream(MSIPACKAGE *package, UINT disk_id, IStorage *storage, const WCHAR *name)
Definition: media.c:935
UINT WINAPI MsiGetPatchInfoExW(LPCWSTR szPatchCode, LPCWSTR szProductCode, LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext, LPCWSTR szProperty, LPWSTR lpValue, DWORD *pcchValue)
Definition: msi.c:1659
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
static void patch_offset_get_filepatches(MSIDATABASE *db, UINT last_sequence, struct patch_offset_list *pos)
Definition: patch.c:441
static struct patch_offset_list * patch_offset_list_create(void)
Definition: patch.c:414
static void patch_offset_get_files(MSIDATABASE *db, UINT last_sequence, struct patch_offset_list *pos)
Definition: patch.c:475
static UINT patch_update_file_sequence(MSIDATABASE *db, const struct patch_offset_list *pos, MSIQUERY *view, MSIRECORD *rec)
Definition: patch.c:512
static UINT msi_apply_patch_db(MSIPACKAGE *package, MSIDATABASE *patch_db, MSIPATCHINFO *patch)
Definition: patch.c:834
UINT msi_apply_patches(MSIPACKAGE *package)
Definition: patch.c:932
static UINT msi_apply_patch_package(MSIPACKAGE *package, const WCHAR *file)
Definition: patch.c:875
static UINT patch_update_filepatch_sequence(MSIDATABASE *db, const struct patch_offset_list *pos, MSIQUERY *view, MSIRECORD *rec)
Definition: patch.c:533
static UINT patch_add_media(MSIPACKAGE *package, IStorage *storage, MSIPATCHINFO *patch)
Definition: patch.c:644
UINT msi_apply_registered_patch(MSIPACKAGE *package, LPCWSTR patch_code)
Definition: patch.c:990
static struct transform_desc * parse_transform_desc(const WCHAR *str)
Definition: patch.c:65
static void free_transform_desc(struct transform_desc *desc)
Definition: patch.c:55
void msi_free_patchinfo(MSIPATCHINFO *patch)
Definition: patch.c:865
static const WCHAR patch_media_query[]
Definition: patch.c:630
static UINT patch_offset_modify_db(MSIDATABASE *db, struct patch_offset_list *pos)
Definition: patch.c:574
static UINT patch_set_offsets(MSIDATABASE *db, MSIPATCHINFO *patch)
Definition: patch.c:751
static UINT apply_substorage_transform(MSIPACKAGE *package, MSIDATABASE *patch_db, LPCWSTR name)
Definition: patch.c:259
static BOOL match_language(MSIPACKAGE *package, LANGID langid)
Definition: patch.c:34
UINT msi_apply_transforms(MSIPACKAGE *package)
Definition: patch.c:950
static void patch_offset_list_free(struct patch_offset_list *pos)
Definition: patch.c:424
static UINT check_transform_applicable(MSIPACKAGE *package, IStorage *transform)
Definition: patch.c:120
static DWORD is_uninstallable(MSIDATABASE *db)
Definition: patch.c:807
static UINT patch_set_media_source_prop(MSIPACKAGE *package)
Definition: patch.c:369
BOOL WINAPI PathIsRelativeW(LPCWSTR lpszPath)
Definition: path.c:1579
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
GLuint GLenum GLenum transform
Definition: glext.h:9407
GLfloat GLfloat p
Definition: glext.h:8902
GLenum GLsizei len
Definition: glext.h:6722
GLintptr offset
Definition: glext.h:5920
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
_Check_return_ long __cdecl wcstol(_In_z_ const wchar_t *_Str, _Out_opt_ _Deref_post_z_ wchar_t **_EndPtr, _In_ int _Radix)
#define SUCCEEDED(hr)
Definition: intsafe.h:50
uint32_t entry
Definition: isohybrid.c:63
#define debugstr_w
Definition: kernel32.h:32
USHORT LANGID
Definition: mui.h:9
__u8 media
Definition: mkdosfs.c:9
#define error(str)
Definition: mkdosfs.c:1605
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
static const WCHAR desc[]
Definition: protectdata.c:36
#define PID_TEMPLATE
Definition: suminfo.c:49
#define PID_CHARCOUNT
Definition: suminfo.c:58
#define PID_LASTAUTHOR
Definition: suminfo.c:50
#define PID_REVNUMBER
Definition: suminfo.c:51
static refpint_t pi[]
Definition: server.c:96
static const GUID * guid_list[]
Definition: metadata.c:2260
#define min(a, b)
Definition: monoChain.cc:55
LANGID langid
Definition: msctf.idl:644
@ MSIPATCHSTATE_APPLIED
Definition: msi.h:54
static const WCHAR INSTALLPROPERTY_LOCALPACKAGEW[]
Definition: msi.h:343
@ msidbFileAttributesPatchAdded
Definition: msidefs.h:37
#define MSI_INITIAL_MEDIA_TRANSFORM_DISKID
Definition: msipriv.h:84
INT msi_suminfo_get_int32(MSISUMMARYINFO *si, UINT uiProperty) DECLSPEC_HIDDEN
Definition: suminfo.c:708
WCHAR * msi_dup_record_field(MSIRECORD *row, INT index) DECLSPEC_HIDDEN
Definition: record.c:1002
UINT msi_set_property(MSIDATABASE *, const WCHAR *, const WCHAR *, int) DECLSPEC_HIDDEN
Definition: package.c:2100
static void * msi_alloc_zero(size_t len) __WINE_ALLOC_SIZE(1)
Definition: msipriv.h:1148
LPWSTR msi_suminfo_dup_string(MSISUMMARYINFO *si, UINT uiProperty) DECLSPEC_HIDDEN
Definition: suminfo.c:696
UINT MSI_ViewFetch(MSIQUERY *, MSIRECORD **) DECLSPEC_HIDDEN
Definition: msiquery.c:377
static void msi_free(void *mem)
Definition: msipriv.h:1159
UINT msi_table_apply_transform(MSIDATABASE *db, IStorage *stg, int err_cond) DECLSPEC_HIDDEN
Definition: table.c:3371
int MSI_RecordGetInteger(MSIRECORD *, UINT) DECLSPEC_HIDDEN
Definition: record.c:213
UINT MSI_ViewModify(MSIQUERY *, MSIMODIFY, MSIRECORD *) DECLSPEC_HIDDEN
Definition: msiquery.c:698
UINT MSI_DatabaseApplyTransformW(MSIDATABASE *db, LPCWSTR szTransformFile, int iErrorCond) DECLSPEC_HIDDEN
UINT MSI_RecordSetInteger(MSIRECORD *, UINT, int) DECLSPEC_HIDDEN
Definition: record.c:280
const WCHAR * MSI_RecordGetString(const MSIRECORD *, UINT) DECLSPEC_HIDDEN
Definition: record.c:433
static void * msi_alloc(size_t len) __WINE_ALLOC_SIZE(1)
Definition: msipriv.h:1142
MSIRECORD * MSI_CreateRecord(UINT) DECLSPEC_HIDDEN
Definition: record.c:76
#define MSI_INITIAL_MEDIA_TRANSFORM_OFFSET
Definition: msipriv.h:83
UINT msi_get_suminfo(IStorage *stg, UINT uiUpdateCount, MSISUMMARYINFO **si) DECLSPEC_HIDDEN
Definition: suminfo.c:457
LPWSTR msi_dup_property(MSIDATABASE *db, LPCWSTR prop) DECLSPEC_HIDDEN
Definition: package.c:2283
LPWSTR msi_get_suminfo_product(IStorage *stg) DECLSPEC_HIDDEN
Definition: suminfo.c:720
UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY **) DECLSPEC_HIDDEN
UINT msi_create_empty_local_file(LPWSTR path, LPCWSTR suffix) DECLSPEC_HIDDEN
Definition: package.c:1063
UINT MSI_RecordSetStringW(MSIRECORD *, UINT, LPCWSTR) DECLSPEC_HIDDEN
Definition: record.c:597
UINT MSI_ViewExecute(MSIQUERY *, MSIRECORD *) DECLSPEC_HIDDEN
Definition: msiquery.c:502
@ MSIMODIFY_UPDATE
Definition: msiquery.h:53
#define MSIDBOPEN_PATCHFILE
Definition: msiquery.h:79
@ MSITRANSFORM_ERROR_VIEWTRANSFORM
Definition: msiquery.h:156
#define MSIDBOPEN_READONLY
Definition: msiquery.h:66
@ MSITRANSFORM_VALIDATE_LANGUAGE
Definition: msiquery.h:161
@ MSITRANSFORM_VALIDATE_PLATFORM
Definition: msiquery.h:163
@ MSITRANSFORM_VALIDATE_UPGRADECODE
Definition: msiquery.h:172
@ MSITRANSFORM_VALIDATE_MAJORVERSION
Definition: msiquery.h:164
@ MSITRANSFORM_VALIDATE_PRODUCT
Definition: msiquery.h:162
@ MSITRANSFORM_VALIDATE_MINORVERSION
Definition: msiquery.h:165
unsigned int UINT
Definition: ndis.h:50
#define L(x)
Definition: ntvdm.h:50
#define STGM_SHARE_EXCLUSIVE
Definition: objbase.h:923
#define minor(rdev)
Definition: propsheet.cpp:929
#define major(rdev)
Definition: propsheet.cpp:928
static unsigned __int64 next
Definition: rand_nt.c:6
const WCHAR * str
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
#define LIST_FOR_EACH_ENTRY(elem, list, type, field)
Definition: list.h:198
#define LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, list, type, field)
Definition: list.h:204
#define TRACE(s)
Definition: solgame.cpp:4
Definition: fci.c:127
Definition: name.c:39
UINT last_sequence
Definition: patch.c:637
WCHAR * cabinet
Definition: patch.c:639
struct list entry
Definition: patch.c:635
WCHAR * prompt
Definition: patch.c:638
UINT disk_id
Definition: patch.c:636
WCHAR * volume
Definition: patch.c:640
WCHAR * source
Definition: patch.c:641
struct list files
Definition: patch.c:408
struct list patches
Definition: patch.c:409
UINT offset_to_apply
Definition: patch.c:411
UINT sequence
Definition: patch.c:403
struct list entry
Definition: patch.c:401
WCHAR * name
Definition: patch.c:402
UINT media_transform_disk_id
Definition: msipriv.h:117
MSIOBJECTHDR hdr
Definition: msipriv.h:108
IStorage * storage
Definition: msipriv.h:109
UINT media_transform_offset
Definition: msipriv.h:116
MSIDATABASE * db
Definition: msipriv.h:394
UINT num_langids
Definition: msipriv.h:397
LPWSTR ProductCode
Definition: msipriv.h:448
LPWSTR PackagePath
Definition: msipriv.h:447
UINT Context
Definition: msipriv.h:459
LANGID * langids
Definition: msipriv.h:398
struct list patches
Definition: msipriv.h:400
BOOL registered
Definition: msipriv.h:209
DWORD uninstallable
Definition: msipriv.h:207
LPWSTR patchcode
Definition: msipriv.h:201
LPWSTR transforms
Definition: msipriv.h:203
struct list entry
Definition: msipriv.h:200
MSIPATCHSTATE state
Definition: msipriv.h:206
LPWSTR localfile
Definition: msipriv.h:205
LPWSTR products
Definition: msipriv.h:202
LPWSTR filename
Definition: msipriv.h:204
MSIOBJECTHDR hdr
Definition: msipriv.h:129
MSIOBJECTHDR hdr
Definition: msipriv.h:151
MSIOBJECTHDR hdr
Definition: msipriv.h:486
WCHAR * version_from
Definition: patch.c:50
WCHAR * upgrade_code
Definition: patch.c:52
WCHAR * version_to
Definition: patch.c:51
WCHAR * product_code_to
Definition: patch.c:49
WCHAR * product_code_from
Definition: patch.c:48
#define max(a, b)
Definition: svc.c:63
Definition: pdh_main.c:94
int ret
#define ERROR_INSTALL_PACKAGE_INVALID
Definition: winerror.h:978
#define ERROR_PATCH_PACKAGE_INVALID
Definition: winerror.h:994
#define ERROR_FUNCTION_FAILED
Definition: winerror.h:985
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185