ReactOS 0.4.16-dev-598-gc07fba4
action.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 *
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
23#define COBJMACROS
24
25#include "windef.h"
26#include "winbase.h"
27#include "winerror.h"
28#include "winreg.h"
29#include "winsvc.h"
30#include "odbcinst.h"
31#include "wine/debug.h"
32#include "msidefs.h"
33#include "winuser.h"
34#include "shlobj.h"
35#include "objbase.h"
36#include "mscoree.h"
37#include "shlwapi.h"
38#include "imagehlp.h"
39#include "winver.h"
40
41#include "msipriv.h"
42#include "resource.h"
43
44#define REG_PROGRESS_VALUE 13200
45#define COMPONENT_PROGRESS_VALUE 24000
46
48
50{
54};
55
57{
58 MSIRECORD *row, *textrow;
59 INT rc;
60
61 textrow = MSI_QueryGetRecord(package->db, L"SELECT * FROM `ActionText` WHERE `Action` = '%s'", action);
62 if (textrow)
63 {
64 description = MSI_RecordGetString(textrow, 2);
65 template = MSI_RecordGetString(textrow, 3);
66 }
67
69 if (!row) return -1;
72 MSI_RecordSetStringW(row, 3, template);
74 if (textrow) msiobj_release(&textrow->hdr);
75 msiobj_release(&row->hdr);
76 return rc;
77}
78
79static void ui_actioninfo(MSIPACKAGE *package, const WCHAR *action, BOOL start, INT rc)
80{
82 WCHAR *template;
83
85
87 if (!row)
88 {
89 free(template);
90 return;
91 }
92 MSI_RecordSetStringW(row, 0, template);
96 msiobj_release(&row->hdr);
97 free(template);
98 if (!start) package->LastActionResult = rc;
99}
100
102{
107
108static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
109{
111 const WCHAR *p;
112 WCHAR *out = value;
113 BOOL ignore, in_quotes = FALSE;
114 int count = 0, len = 0;
115
116 for (p = str; *p; p++)
117 {
118 ignore = FALSE;
119 switch (state)
120 {
121 case state_whitespace:
122 switch (*p)
123 {
124 case ' ':
125 in_quotes = TRUE;
126 ignore = TRUE;
127 len++;
128 break;
129 case '"':
131 if (in_quotes && p[1] != '\"') count--;
132 else count++;
133 break;
134 default:
136 in_quotes = TRUE;
137 len++;
138 break;
139 }
140 break;
141
142 case state_token:
143 switch (*p)
144 {
145 case '"':
147 if (in_quotes) count--;
148 else count++;
149 break;
150 case ' ':
152 if (!count) goto done;
153 in_quotes = TRUE;
154 len++;
155 break;
156 default:
157 if (count) in_quotes = TRUE;
158 len++;
159 break;
160 }
161 break;
162
163 case state_quote:
164 switch (*p)
165 {
166 case '"':
167 if (in_quotes && p[1] != '\"') count--;
168 else count++;
169 break;
170 case ' ':
172 if (!count || (count > 1 && !len)) goto done;
173 in_quotes = TRUE;
174 len++;
175 break;
176 default:
178 if (count) in_quotes = TRUE;
179 len++;
180 break;
181 }
182 break;
183
184 default: break;
185 }
186 if (!ignore && value) *out++ = *p;
187 if (!count) in_quotes = FALSE;
188 }
189
190done:
191 if (value)
192 {
193 if (!len) *value = 0;
194 else *out = 0;
195 }
196
197 if(quotes) *quotes = count;
198 return p - str;
199}
200
201static void remove_quotes( WCHAR *str )
202{
203 WCHAR *p = str;
204 int len = lstrlenW( str );
205
206 while ((p = wcschr( p, '"' )))
207 {
208 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
209 p++;
210 }
211}
212
214 BOOL preserve_case )
215{
216 LPCWSTR ptr, ptr2;
217 int num_quotes;
218 DWORD len;
219 WCHAR *prop, *val;
220 UINT r;
221
222 if (!szCommandLine)
223 return ERROR_SUCCESS;
224
225 ptr = szCommandLine;
226 while (*ptr)
227 {
228 while (*ptr == ' ') ptr++;
229 if (!*ptr) break;
230
231 ptr2 = wcschr( ptr, '=' );
232 if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
233
234 len = ptr2 - ptr;
235 if (!len) return ERROR_INVALID_COMMAND_LINE;
236
237 while (ptr[len - 1] == ' ') len--;
238
239 prop = malloc( (len + 1) * sizeof(WCHAR) );
240 memcpy( prop, ptr, len * sizeof(WCHAR) );
241 prop[len] = 0;
242 if (!preserve_case) wcsupr( prop );
243
244 ptr2++;
245 while (*ptr2 == ' ') ptr2++;
246
247 num_quotes = 0;
248 val = malloc( (wcslen( ptr2 ) + 1) * sizeof(WCHAR) );
249 len = parse_prop( ptr2, val, &num_quotes );
250 if (num_quotes % 2)
251 {
252 WARN("unbalanced quotes\n");
253 free( val );
254 free( prop );
256 }
258 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
259
260 r = msi_set_property( package->db, prop, val, -1 );
261 if (r == ERROR_SUCCESS && !wcscmp( prop, L"SourceDir" ))
262 msi_reset_source_folders( package );
263
264 free( val );
265 free( prop );
266
267 ptr = ptr2 + len;
268 }
269
270 return ERROR_SUCCESS;
271}
272
274{
275 DWORD opt_len = lstrlenW(option);
276
277 if (!cmd)
278 return NULL;
279
280 while (*cmd)
281 {
282 BOOL found = FALSE;
283
284 while (*cmd == ' ') cmd++;
285 if (!*cmd) break;
286
287 if(!wcsnicmp(cmd, option, opt_len))
288 found = TRUE;
289
290 cmd = wcschr( cmd, '=' );
291 if(!cmd) break;
292 cmd++;
293 while (*cmd == ' ') cmd++;
294 if (!*cmd) break;
295
296 *len = parse_prop( cmd, NULL, NULL);
297 if (found) return cmd;
298 cmd += *len;
299 }
300
301 return NULL;
302}
303
305{
306 LPCWSTR pc;
307 LPWSTR p, *ret = NULL;
308 UINT count = 0;
309
310 if (!str)
311 return ret;
312
313 /* count the number of substrings */
314 for ( pc = str, count = 0; pc; count++ )
315 {
316 pc = wcschr( pc, sep );
317 if (pc)
318 pc++;
319 }
320
321 /* allocate space for an array of substring pointers and the substrings */
322 ret = malloc( (count + 1) * sizeof(WCHAR *) + (wcslen(str) + 1) * sizeof(WCHAR) );
323 if (!ret)
324 return ret;
325
326 /* copy the string and set the pointers */
327 p = (LPWSTR) &ret[count+1];
328 lstrcpyW( p, str );
329 for( count = 0; (ret[count] = p); count++ )
330 {
331 p = wcschr( p, sep );
332 if (p)
333 *p++ = 0;
334 }
335
336 return ret;
337}
338
340{
341 MSIQUERY *view;
342 DWORD count = 0;
343
344 if (!(MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `InstallUISequence` WHERE `Sequence` > 0", &view )))
345 {
346 MSI_IterateRecords( view, &count, NULL, package );
347 msiobj_release( &view->hdr );
348 }
349 return count != 0;
350}
351
353{
354 WCHAR *source, *check, *p, *db;
355 DWORD len;
356
357 if (!(db = msi_dup_property( package->db, L"OriginalDatabase" )))
358 return ERROR_OUTOFMEMORY;
359
360 if (!(p = wcsrchr( db, '\\' )) && !(p = wcsrchr( db, '/' )))
361 {
362 free(db);
363 return ERROR_SUCCESS;
364 }
365 len = p - db + 2;
366 source = malloc( len * sizeof(WCHAR) );
367 lstrcpynW( source, db, len );
368 free( db );
369
370 check = msi_dup_property( package->db, L"SourceDir" );
371 if (!check || replace)
372 {
373 UINT r = msi_set_property( package->db, L"SourceDir", source, -1 );
374 if (r == ERROR_SUCCESS)
375 msi_reset_source_folders( package );
376 }
377 free( check );
378
379 check = msi_dup_property( package->db, L"SOURCEDIR" );
380 if (!check || replace)
381 msi_set_property( package->db, L"SOURCEDIR", source, -1 );
382
383 free( check );
384 free( source );
385
386 return ERROR_SUCCESS;
387}
388
390{
392}
393
395{
396 UINT r = msi_locate_product( package->ProductCode, &package->Context );
397 if (r != ERROR_SUCCESS)
398 {
399 int num = msi_get_property_int( package->db, L"ALLUSERS", 0 );
400 if (num == 1 || num == 2)
402 else
404 }
405 return ERROR_SUCCESS;
406}
407
409{
410 UINT rc;
411 LPCWSTR cond, action;
412 MSIPACKAGE *package = param;
413
415 if (!action)
416 {
417 ERR("Error is retrieving action name\n");
419 }
420
421 /* check conditions */
422 cond = MSI_RecordGetString(row,2);
423
424 /* this is a hack to skip errors in the condition code */
425 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
426 {
427 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
428 return ERROR_SUCCESS;
429 }
430
431 rc = ACTION_PerformAction(package, action);
432
434
436 rc = ERROR_SUCCESS;
437
438 if (rc != ERROR_SUCCESS)
439 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
440
441 if (package->need_reboot_now)
442 {
443 TRACE("action %s asked for immediate reboot, suspending installation\n",
445 rc = ACTION_ForceReboot( package );
446 }
447 return rc;
448}
449
451{
452 MSIQUERY *view;
453 UINT r;
454
455 TRACE("%p %s\n", package, debugstr_w(table));
456
457 r = MSI_OpenQuery( package->db, &view, L"SELECT * FROM `%s` WHERE `Sequence` > 0 ORDER BY `Sequence`", table );
458 if (r == ERROR_SUCCESS)
459 {
461 msiobj_release(&view->hdr);
462 }
463 return r;
464}
465
467{
468 MSIQUERY *view;
469 UINT rc;
470
471 if (package->ExecuteSequenceRun)
472 {
473 TRACE("Execute Sequence already Run\n");
474 return ERROR_SUCCESS;
475 }
476
477 package->ExecuteSequenceRun = TRUE;
478
479 rc = MSI_OpenQuery(package->db, &view,
480 L"SELECT * FROM `InstallExecuteSequence` WHERE `Sequence` > 0 ORDER BY `Sequence`");
481 if (rc == ERROR_SUCCESS)
482 {
483 TRACE("Running the actions\n");
484
485 msi_set_property( package->db, L"SourceDir", NULL, -1 );
487 msiobj_release(&view->hdr);
488 }
489 return rc;
490}
491
493{
494 MSIQUERY *view;
495 UINT rc;
496
497 rc = MSI_DatabaseOpenViewW(package->db,
498 L"SELECT * FROM `InstallUISequence` WHERE `Sequence` > 0 ORDER BY `Sequence`",
499 &view);
500 if (rc == ERROR_SUCCESS)
501 {
502 TRACE("Running the actions\n");
504 msiobj_release(&view->hdr);
505 }
506 return rc;
507}
508
509/********************************************************
510 * ACTION helper functions and functions that perform the actions
511 *******************************************************/
513{
514 UINT arc;
515 INT uirc;
516
517 uirc = ui_actionstart(package, action, NULL, NULL);
518 if (uirc == IDCANCEL)
520 ui_actioninfo(package, action, TRUE, 0);
521 arc = ACTION_CustomAction(package, action);
522 uirc = !arc;
523
524 if (arc == ERROR_FUNCTION_NOT_CALLED && needs_ui_sequence(package))
525 {
526 uirc = ACTION_ShowDialog(package, action);
527 switch (uirc)
528 {
529 case -1:
530 return ERROR_SUCCESS; /* stop immediately */
531 case 0: arc = ERROR_FUNCTION_NOT_CALLED; break;
532 case 1: arc = ERROR_SUCCESS; break;
533 case 2: arc = ERROR_INSTALL_USEREXIT; break;
534 case 3: arc = ERROR_INSTALL_FAILURE; break;
535 case 4: arc = ERROR_INSTALL_SUSPEND; break;
536 case 5: arc = ERROR_MORE_DATA; break;
537 case 6: arc = ERROR_INVALID_HANDLE_STATE; break;
538 case 7: arc = ERROR_INVALID_DATA; break;
539 case 8: arc = ERROR_INSTALL_ALREADY_RUNNING; break;
540 case 9: arc = ERROR_INSTALL_PACKAGE_REJECTED; break;
541 default: arc = ERROR_FUNCTION_FAILED; break;
542 }
543 }
544
545 ui_actioninfo(package, action, FALSE, uirc);
546
547 return arc;
548}
549
551{
552 MSICOMPONENT *comp;
553
555 {
556 if (!wcscmp( Component, comp->Component )) return comp;
557 }
558 return NULL;
559}
560
562{
564
566 {
567 if (!wcscmp( Feature, feature->Feature )) return feature;
568 }
569 return NULL;
570}
571
573{
574 MSIFILE *file;
575
577 {
578 if (!wcscmp( key, file->File )) return file;
579 }
580 return NULL;
581}
582
584{
586
588 {
589 if (!wcscmp( dir, folder->Directory )) return folder;
590 }
591 return NULL;
592}
593
594void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
595{
596 MSIRECORD *row;
597
598 row = MSI_CreateRecord( 4 );
604 msiobj_release( &row->hdr );
605
607}
608
610{
611 if (!comp->Enabled)
612 {
613 TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
615 }
616 if (package->need_rollback) return comp->Installed;
617 if (comp->num_clients > 0 && comp->ActionRequest == INSTALLSTATE_ABSENT)
618 {
619 TRACE("%s has %u clients left\n", debugstr_w(comp->Component), comp->num_clients);
621 }
622 return comp->ActionRequest;
623}
624
626{
627 if (package->need_rollback) return feature->Installed;
628 return feature->ActionRequest;
629}
630
632{
633 MSIPACKAGE *package = param;
634 LPCWSTR dir, component, full_path;
635 MSIRECORD *uirow;
637 MSICOMPONENT *comp;
638
639 component = MSI_RecordGetString(row, 2);
640 if (!component)
641 return ERROR_SUCCESS;
642
643 comp = msi_get_loaded_component(package, component);
644 if (!comp)
645 return ERROR_SUCCESS;
646
647 comp->Action = msi_get_component_action( package, comp );
648 if (comp->Action != INSTALLSTATE_LOCAL)
649 {
650 TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
651 return ERROR_SUCCESS;
652 }
653
655 if (!dir)
656 {
657 ERR("Unable to get folder id\n");
658 return ERROR_SUCCESS;
659 }
660
661 uirow = MSI_CreateRecord(1);
662 MSI_RecordSetStringW(uirow, 1, dir);
664 msiobj_release(&uirow->hdr);
665
666 full_path = msi_get_target_folder( package, dir );
667 if (!full_path)
668 {
669 ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
670 return ERROR_SUCCESS;
671 }
672 TRACE("folder is %s\n", debugstr_w(full_path));
673
674 folder = msi_get_loaded_folder( package, dir );
675 if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( package, full_path );
677
678 return ERROR_SUCCESS;
679}
680
682{
683 MSIQUERY *view;
684 UINT rc;
685
686 if (package->script == SCRIPT_NONE)
687 return msi_schedule_action(package, SCRIPT_INSTALL, L"CreateFolders");
688
689 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `CreateFolder`", &view );
690 if (rc != ERROR_SUCCESS)
691 return ERROR_SUCCESS;
692
694 msiobj_release(&view->hdr);
695 return rc;
696}
697
699{
700 FolderList *fl;
701
703 {
704 remove_persistent_folder( fl->folder );
705 }
706 if (folder->persistent && folder->State != FOLDER_STATE_REMOVED)
707 {
708 if (RemoveDirectoryW( folder->ResolvedTarget )) folder->State = FOLDER_STATE_REMOVED;
709 }
710}
711
713{
714 MSIPACKAGE *package = param;
715 LPCWSTR dir, component, full_path;
716 MSIRECORD *uirow;
718 MSICOMPONENT *comp;
719
720 component = MSI_RecordGetString(row, 2);
721 if (!component)
722 return ERROR_SUCCESS;
723
724 comp = msi_get_loaded_component(package, component);
725 if (!comp)
726 return ERROR_SUCCESS;
727
728 comp->Action = msi_get_component_action( package, comp );
729 if (comp->Action != INSTALLSTATE_ABSENT)
730 {
731 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
732 return ERROR_SUCCESS;
733 }
734
736 if (!dir)
737 {
738 ERR("Unable to get folder id\n");
739 return ERROR_SUCCESS;
740 }
741
742 full_path = msi_get_target_folder( package, dir );
743 if (!full_path)
744 {
745 ERR("Unable to resolve folder %s\n", debugstr_w(dir));
746 return ERROR_SUCCESS;
747 }
748 TRACE("folder is %s\n", debugstr_w(full_path));
749
750 uirow = MSI_CreateRecord( 1 );
751 MSI_RecordSetStringW( uirow, 1, dir );
753 msiobj_release( &uirow->hdr );
754
755 folder = msi_get_loaded_folder( package, dir );
757 return ERROR_SUCCESS;
758}
759
761{
762 MSIQUERY *view;
763 UINT rc;
764
765 if (package->script == SCRIPT_NONE)
766 return msi_schedule_action(package, SCRIPT_INSTALL, L"RemoveFolders");
767
768 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `CreateFolder`", &view );
769 if (rc != ERROR_SUCCESS)
770 return ERROR_SUCCESS;
771
773 msiobj_release( &view->hdr );
774 return rc;
775}
776
778{
779 MSIPACKAGE *package = param;
780 MSICOMPONENT *comp;
781
782 comp = calloc( 1, sizeof(MSICOMPONENT) );
783 if (!comp)
785
786 list_add_tail( &package->components, &comp->entry );
787
788 /* fill in the data */
789 comp->Component = msi_dup_record_field( row, 1 );
790
791 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
792
793 comp->ComponentId = msi_dup_record_field( row, 2 );
794 comp->Directory = msi_dup_record_field( row, 3 );
795 comp->Attributes = MSI_RecordGetInteger(row,4);
796 comp->Condition = msi_dup_record_field( row, 5 );
797 comp->KeyPath = msi_dup_record_field( row, 6 );
798
799 comp->Installed = INSTALLSTATE_UNKNOWN;
800 comp->Action = INSTALLSTATE_UNKNOWN;
801 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
802
803 comp->assembly = msi_load_assembly( package, comp );
804 return ERROR_SUCCESS;
805}
806
808{
809 MSIQUERY *view;
810 UINT r;
811
812 if (!list_empty(&package->components))
813 return ERROR_SUCCESS;
814
815 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Component`", &view );
816 if (r != ERROR_SUCCESS)
817 return r;
818
820 msiobj_release(&view->hdr);
821 return r;
822}
823
825{
826 ComponentList *cl;
827
828 cl = malloc( sizeof(*cl) );
829 if ( !cl )
831 cl->component = comp;
832 list_add_tail( &feature->Components, &cl->entry );
833
834 return ERROR_SUCCESS;
835}
836
838{
840
841 fl = malloc( sizeof(*fl) );
842 if ( !fl )
844 fl->feature = child;
845 list_add_tail( &parent->Children, &fl->entry );
846
847 return ERROR_SUCCESS;
848}
849
851{
854};
855
857{
859 LPCWSTR component;
860 MSICOMPONENT *comp;
861
862 component = MSI_RecordGetString(row,1);
863
864 /* check to see if the component is already loaded */
866 if (!comp)
867 {
868 WARN("ignoring unknown component %s\n", debugstr_w(component));
869 return ERROR_SUCCESS;
870 }
872 comp->Enabled = TRUE;
873
874 return ERROR_SUCCESS;
875}
876
878{
879 MSIPACKAGE *package = param;
881 MSIQUERY *view;
883 UINT rc;
884
885 /* fill in the data */
886
887 feature = calloc( 1, sizeof(MSIFEATURE) );
888 if (!feature)
890
891 list_init( &feature->Children );
892 list_init( &feature->Components );
893
894 feature->Feature = msi_dup_record_field( row, 1 );
895
896 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
897
898 feature->Feature_Parent = msi_dup_record_field( row, 2 );
899 feature->Title = msi_dup_record_field( row, 3 );
900 feature->Description = msi_dup_record_field( row, 4 );
901
902 if (!MSI_RecordIsNull(row,5))
903 feature->Display = MSI_RecordGetInteger(row,5);
904
906 feature->Directory = msi_dup_record_field( row, 7 );
907 feature->Attributes = MSI_RecordGetInteger(row,8);
908
909 feature->Installed = INSTALLSTATE_UNKNOWN;
911 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
912
913 list_add_tail( &package->features, &feature->entry );
914
915 /* load feature components */
916
917 rc = MSI_OpenQuery( package->db, &view, L"SELECT `Component_` FROM `FeatureComponents` WHERE `Feature_` = '%s'",
918 feature->Feature );
919 if (rc != ERROR_SUCCESS)
920 return ERROR_SUCCESS;
921
922 package_feature.package = package;
924
926 msiobj_release(&view->hdr);
927 return rc;
928}
929
931{
932 MSIPACKAGE *package = param;
934
936 if (!child)
938
939 if (!child->Feature_Parent)
940 return ERROR_SUCCESS;
941
942 parent = msi_get_loaded_feature( package, child->Feature_Parent );
943 if (!parent)
945
947 return ERROR_SUCCESS;
948}
949
951{
952 MSIQUERY *view;
953 UINT r;
954
955 if (!list_empty(&package->features))
956 return ERROR_SUCCESS;
957
958 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Feature` ORDER BY `Display`", &view );
959 if (r != ERROR_SUCCESS)
960 return r;
961
962 r = MSI_IterateRecords( view, NULL, load_feature, package );
963 if (r != ERROR_SUCCESS)
964 {
965 msiobj_release( &view->hdr );
966 return r;
967 }
969 msiobj_release( &view->hdr );
970 return r;
971}
972
974{
975 if (!p)
976 return p;
977 p = wcschr(p, ch);
978 if (!p)
979 return p;
980 *p = 0;
981 return p+1;
982}
983
985{
986 MSIQUERY *view = NULL;
987 MSIRECORD *row = NULL;
988 UINT r;
989
990 TRACE("%s\n", debugstr_w(file->File));
991
992 r = MSI_OpenQuery(package->db, &view, L"SELECT * FROM `MsiFileHash` WHERE `File_` = '%s'", file->File);
993 if (r != ERROR_SUCCESS)
994 goto done;
995
997 if (r != ERROR_SUCCESS)
998 goto done;
999
1000 r = MSI_ViewFetch(view, &row);
1001 if (r != ERROR_SUCCESS)
1002 goto done;
1003
1004 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1005 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1006 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1007 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1008 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1009
1010done:
1011 if (view) msiobj_release(&view->hdr);
1012 if (row) msiobj_release(&row->hdr);
1013 return r;
1014}
1015
1017{
1018 MSIRECORD *row = MSI_QueryGetRecord( package->db, L"SELECT `DiskId` FROM `Media` WHERE `LastSequence` >= %d",
1019 file->Sequence );
1020 if (!row)
1021 {
1022 WARN("query failed\n");
1023 return ERROR_FUNCTION_FAILED;
1024 }
1025
1026 file->disk_id = MSI_RecordGetInteger( row, 1 );
1027 msiobj_release( &row->hdr );
1028 return ERROR_SUCCESS;
1029}
1030
1032{
1033 MSIPACKAGE* package = param;
1034 LPCWSTR component;
1035 MSIFILE *file;
1036
1037 /* fill in the data */
1038
1039 file = calloc( 1, sizeof(MSIFILE) );
1040 if (!file)
1042
1043 file->File = msi_dup_record_field( row, 1 );
1044
1045 component = MSI_RecordGetString( row, 2 );
1046 file->Component = msi_get_loaded_component( package, component );
1047
1048 if (!file->Component)
1049 {
1050 WARN("Component not found: %s\n", debugstr_w(component));
1051 free(file->File);
1052 free(file);
1053 return ERROR_SUCCESS;
1054 }
1055
1056 file->FileName = msi_dup_record_field( row, 3 );
1057 msi_reduce_to_long_filename( file->FileName );
1058
1059 file->ShortName = msi_dup_record_field( row, 3 );
1060 file->LongName = wcsdup( folder_split_path(file->ShortName, '|') );
1061
1062 file->FileSize = MSI_RecordGetInteger( row, 4 );
1063 file->Version = msi_dup_record_field( row, 5 );
1064 file->Language = msi_dup_record_field( row, 6 );
1065 file->Attributes = MSI_RecordGetInteger( row, 7 );
1066 file->Sequence = MSI_RecordGetInteger( row, 8 );
1067
1068 file->state = msifs_invalid;
1069
1070 /* if the compressed bits are not set in the file attributes,
1071 * then read the information from the package word count property
1072 */
1073 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1074 {
1075 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1076 }
1078 {
1079 file->IsCompressed = TRUE;
1080 }
1081 else if (file->Attributes & msidbFileAttributesNoncompressed)
1082 {
1083 file->IsCompressed = FALSE;
1084 }
1085 else file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1086
1087 load_file_hash(package, file);
1088 load_file_disk_id(package, file);
1089
1090 TRACE("File loaded (file %s sequence %u)\n", debugstr_w(file->File), file->Sequence);
1091
1092 list_add_tail( &package->files, &file->entry );
1093 return ERROR_SUCCESS;
1094}
1095
1097{
1098 MSIQUERY *view;
1099 UINT rc;
1100
1101 if (!list_empty(&package->files))
1102 return ERROR_SUCCESS;
1103
1104 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `File` ORDER BY `Sequence`", &view);
1105 if (rc != ERROR_SUCCESS)
1106 return ERROR_SUCCESS;
1107
1108 rc = MSI_IterateRecords(view, NULL, load_file, package);
1109 msiobj_release(&view->hdr);
1110 return rc;
1111}
1112
1114{
1115 MSIPACKAGE *package = param;
1116 UINT disk_id = MSI_RecordGetInteger( row, 1 );
1117 const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
1118
1119 /* FIXME: load external cabinets and directory sources too */
1120 if (!cabinet || cabinet[0] != '#' || disk_id >= MSI_INITIAL_MEDIA_TRANSFORM_DISKID)
1121 return ERROR_SUCCESS;
1122
1123 return msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
1124}
1125
1127{
1128 MSIQUERY *view;
1129 UINT r;
1130
1131 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Media` ORDER BY `DiskId`", &view );
1132 if (r != ERROR_SUCCESS)
1133 return ERROR_SUCCESS;
1134
1135 r = MSI_IterateRecords( view, NULL, load_media, package );
1136 msiobj_release( &view->hdr );
1137 return r;
1138}
1139
1141{
1142 MSIRECORD *rec = MSI_QueryGetRecord( package->db, L"SELECT `DiskId` FROM `Media` WHERE `LastSequence` >= %u",
1143 patch->Sequence );
1144 if (!rec)
1145 {
1146 WARN("query failed\n");
1147 return ERROR_FUNCTION_FAILED;
1148 }
1149
1150 patch->disk_id = MSI_RecordGetInteger( rec, 1 );
1151 msiobj_release( &rec->hdr );
1152 return ERROR_SUCCESS;
1153}
1154
1156{
1157 MSIPACKAGE *package = param;
1158 MSIFILEPATCH *patch;
1159 const WCHAR *file_key;
1160
1161 patch = calloc( 1, sizeof(MSIFILEPATCH) );
1162 if (!patch)
1164
1165 file_key = MSI_RecordGetString( row, 1 );
1166 patch->File = msi_get_loaded_file( package, file_key );
1167 if (!patch->File)
1168 {
1169 ERR("Failed to find target for patch in File table\n");
1170 free(patch);
1171 return ERROR_FUNCTION_FAILED;
1172 }
1173
1174 patch->Sequence = MSI_RecordGetInteger( row, 2 );
1175 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1176 patch->Attributes = MSI_RecordGetInteger( row, 4 );
1177
1178 /* FIXME:
1179 * Header field - for patch validation.
1180 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
1181 */
1182
1183 load_patch_disk_id( package, patch );
1184
1185 TRACE("Patch loaded (file %s sequence %u)\n", debugstr_w(patch->File->File), patch->Sequence);
1186
1187 list_add_tail( &package->filepatches, &patch->entry );
1188
1189 return ERROR_SUCCESS;
1190}
1191
1193{
1194 MSIQUERY *view;
1195 UINT rc;
1196
1197 if (!list_empty(&package->filepatches))
1198 return ERROR_SUCCESS;
1199
1200 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `Patch` ORDER BY `Sequence`", &view);
1201 if (rc != ERROR_SUCCESS)
1202 return ERROR_SUCCESS;
1203
1204 rc = MSI_IterateRecords(view, NULL, load_patch, package);
1205 msiobj_release(&view->hdr);
1206 return rc;
1207}
1208
1210{
1211 MSIPACKAGE *package = param;
1212 const WCHAR *name;
1213 MSICOMPONENT *c;
1214
1216 TRACE( "found patched component: %s\n", wine_dbgstr_w(name) );
1217 c = msi_get_loaded_component( package, name );
1218 if (!c)
1219 return ERROR_SUCCESS;
1220
1221 c->updated = 1;
1222 if (!wcscmp( MSI_RecordGetString( row, 2 ), L"INSERT" ))
1223 c->added = 1;
1224 return ERROR_SUCCESS;
1225}
1226
1228{
1229 static const WCHAR select[] = L"SELECT `Row`, `Column` FROM `_TransformView` WHERE `Table`='Component'";
1230 MSIQUERY *q;
1231 UINT r;
1232
1233 r = MSI_OpenQuery( package->db, &q, select );
1234 if (r != ERROR_SUCCESS)
1235 return;
1236
1238 msiobj_release( &q->hdr );
1239
1240 while (1)
1241 {
1242 r = MSI_OpenQuery( package->db, &q, L"ALTER TABLE `_TransformView` FREE" );
1243 if (r != ERROR_SUCCESS)
1244 return;
1245 r = MSI_ViewExecute( q, NULL );
1246 msiobj_release( &q->hdr );
1247 if (r != ERROR_SUCCESS)
1248 return;
1249 }
1250}
1251
1253{
1254 MSIQUERY *view;
1255
1256 folder->persistent = FALSE;
1257 if (!MSI_OpenQuery( package->db, &view, L"SELECT * FROM `CreateFolder` WHERE `Directory_` = '%s'",
1258 folder->Directory ))
1259 {
1260 if (!MSI_ViewExecute( view, NULL ))
1261 {
1262 MSIRECORD *rec;
1263 if (!MSI_ViewFetch( view, &rec ))
1264 {
1265 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory));
1266 folder->persistent = TRUE;
1267 msiobj_release( &rec->hdr );
1268 }
1269 }
1270 msiobj_release( &view->hdr );
1271 }
1272 return ERROR_SUCCESS;
1273}
1274
1276{
1277 MSIPACKAGE *package = param;
1278 static WCHAR szEmpty[] = L"";
1279 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1281
1282 if (!(folder = calloc( 1, sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY;
1283 list_init( &folder->children );
1284 folder->Directory = msi_dup_record_field( row, 1 );
1285 folder->Parent = msi_dup_record_field( row, 2 );
1287
1288 TRACE("%s\n", debugstr_w(folder->Directory));
1289
1290 /* split src and target dir */
1291 tgt_short = p;
1292 src_short = folder_split_path( p, ':' );
1293
1294 /* split the long and short paths */
1295 tgt_long = folder_split_path( tgt_short, '|' );
1296 src_long = folder_split_path( src_short, '|' );
1297
1298 /* check for no-op dirs */
1299 if (tgt_short && !wcscmp( L".", tgt_short ))
1300 tgt_short = szEmpty;
1301 if (src_short && !wcscmp( L".", src_short ))
1302 src_short = szEmpty;
1303
1304 if (!tgt_long)
1305 tgt_long = tgt_short;
1306
1307 if (!src_short) {
1308 src_short = tgt_short;
1309 src_long = tgt_long;
1310 }
1311
1312 if (!src_long)
1313 src_long = src_short;
1314
1315 /* FIXME: use the target short path too */
1316 folder->TargetDefault = wcsdup(tgt_long);
1317 folder->SourceShortPath = wcsdup(src_short);
1318 folder->SourceLongPath = wcsdup(src_long);
1319 free(p);
1320
1321 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1322 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1323 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1324
1325 load_folder_persistence( package, folder );
1326
1327 list_add_tail( &package->folders, &folder->entry );
1328 return ERROR_SUCCESS;
1329}
1330
1332{
1333 FolderList *fl;
1334
1335 if (!(fl = malloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
1336 fl->folder = child;
1337 list_add_tail( &parent->children, &fl->entry );
1338 return ERROR_SUCCESS;
1339}
1340
1342{
1343 MSIPACKAGE *package = param;
1345
1346 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
1347 return ERROR_FUNCTION_FAILED;
1348
1349 if (!child->Parent) return ERROR_SUCCESS;
1350
1351 if (!(parent = msi_get_loaded_folder( package, child->Parent )))
1352 return ERROR_FUNCTION_FAILED;
1353
1354 return add_folder_child( parent, child );
1355}
1356
1358{
1359 MSIQUERY *view;
1360 UINT r;
1361
1362 if (!list_empty(&package->folders))
1363 return ERROR_SUCCESS;
1364
1365 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Directory`", &view );
1366 if (r != ERROR_SUCCESS)
1367 return r;
1368
1369 r = MSI_IterateRecords( view, NULL, load_folder, package );
1370 if (r != ERROR_SUCCESS)
1371 {
1372 msiobj_release( &view->hdr );
1373 return r;
1374 }
1376 msiobj_release( &view->hdr );
1377 return r;
1378}
1379
1381{
1382 msi_set_property( package->db, L"CostingComplete", L"0", -1 );
1383 msi_set_property( package->db, L"ROOTDRIVE", L"C:\\", -1 );
1384
1385 load_all_folders( package );
1386 msi_load_all_components( package );
1387 msi_load_all_features( package );
1388 load_all_files( package );
1389 load_all_patches( package );
1390 mark_patched_components( package );
1391 load_all_media( package );
1392
1393 return ERROR_SUCCESS;
1394}
1395
1397{
1398 UINT i, rc = ERROR_SUCCESS;
1399
1400 TRACE("executing script %u\n", script);
1401
1402 package->script = script;
1403
1404 if (script == SCRIPT_ROLLBACK)
1405 {
1406 for (i = package->script_actions_count[script]; i > 0; i--)
1407 {
1408 rc = ACTION_PerformAction(package, package->script_actions[script][i-1]);
1409 if (rc != ERROR_SUCCESS)
1410 {
1411 ERR("Execution of script %i halted; action %s returned %u\n",
1412 script, debugstr_w(package->script_actions[script][i-1]), rc);
1413 break;
1414 }
1415 }
1416 }
1417 else
1418 {
1419 for (i = 0; i < package->script_actions_count[script]; i++)
1420 {
1421 rc = ACTION_PerformAction(package, package->script_actions[script][i]);
1422 if (rc != ERROR_SUCCESS)
1423 {
1424 ERR("Execution of script %i halted; action %s returned %u\n",
1425 script, debugstr_w(package->script_actions[script][i]), rc);
1426 break;
1427 }
1428 }
1429 }
1430
1431 package->script = SCRIPT_NONE;
1432
1434 return rc;
1435}
1436
1438{
1439 return ERROR_SUCCESS;
1440}
1441
1442static void get_client_counts( MSIPACKAGE *package )
1443{
1444 MSICOMPONENT *comp;
1445 HKEY hkey;
1446
1448 {
1449 if (!comp->ComponentId) continue;
1450
1451 if (MSIREG_OpenUserDataComponentKey( comp->ComponentId, L"S-1-5-18", &hkey, FALSE ) &&
1453 {
1454 comp->num_clients = 0;
1455 continue;
1456 }
1457 RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, NULL, (DWORD *)&comp->num_clients,
1458 NULL, NULL, NULL, NULL );
1459 RegCloseKey( hkey );
1460 }
1461}
1462
1464{
1465 MSICOMPONENT *comp;
1466 UINT r;
1467
1469 {
1470 if (!comp->ComponentId) continue;
1471
1474 &comp->Installed );
1475 if (r == ERROR_SUCCESS) continue;
1476
1479 &comp->Installed );
1480 if (r == ERROR_SUCCESS) continue;
1481
1484 &comp->Installed );
1485 if (r == ERROR_SUCCESS) continue;
1486
1488 }
1489}
1490
1492{
1494
1496 {
1498
1500 feature->Installed = INSTALLSTATE_ABSENT;
1501 else
1502 feature->Installed = state;
1503 }
1504}
1505
1507{
1508 return (feature->Level > 0 && feature->Level <= level);
1509}
1510
1513{
1514 LPWSTR override;
1516 BOOL remove = !wcscmp(property, L"REMOVE");
1517 BOOL reinstall = !wcscmp(property, L"REINSTALL");
1518
1519 override = msi_dup_property( package->db, property );
1520 if (!override)
1521 return FALSE;
1522
1524 {
1525 if (feature->Level <= 0)
1526 continue;
1527
1528 if (reinstall)
1529 state = (feature->Installed == INSTALLSTATE_ABSENT ? INSTALLSTATE_UNKNOWN : feature->Installed);
1530 else if (remove)
1532
1533 if (!wcsicmp( override, L"ALL" ))
1534 {
1535 feature->Action = state;
1536 feature->ActionRequest = state;
1537 }
1538 else
1539 {
1540 LPWSTR ptr = override;
1541 LPWSTR ptr2 = wcschr(override,',');
1542
1543 while (ptr)
1544 {
1545 int len = ptr2 - ptr;
1546
1547 if ((ptr2 && lstrlenW(feature->Feature) == len && !wcsncmp(ptr, feature->Feature, len))
1548 || (!ptr2 && !wcscmp(ptr, feature->Feature)))
1549 {
1550 feature->Action = state;
1551 feature->ActionRequest = state;
1552 break;
1553 }
1554 if (ptr2)
1555 {
1556 ptr=ptr2+1;
1557 ptr2 = wcschr(ptr,',');
1558 }
1559 else
1560 break;
1561 }
1562 }
1563 }
1564 free(override);
1565 return TRUE;
1566}
1567
1569{
1570 BOOL ret = FALSE;
1571
1572 /* all these activation/deactivation things happen in order and things
1573 * later on the list override things earlier on the list.
1574 *
1575 * 0 INSTALLLEVEL processing
1576 * 1 ADDLOCAL
1577 * 2 REMOVE
1578 * 3 ADDSOURCE
1579 * 4 ADDDEFAULT
1580 * 5 REINSTALL
1581 * 6 ADVERTISE
1582 * 7 COMPADDLOCAL
1583 * 8 COMPADDSOURCE
1584 * 9 FILEADDLOCAL
1585 * 10 FILEADDSOURCE
1586 * 11 FILEADDDEFAULT
1587 */
1588 ret |= process_state_property( package, level, L"ADDLOCAL", INSTALLSTATE_LOCAL );
1589 ret |= process_state_property( package, level, L"REMOVE", INSTALLSTATE_ABSENT );
1590 ret |= process_state_property( package, level, L"ADDSOURCE", INSTALLSTATE_SOURCE );
1591 ret |= process_state_property( package, level, L"REINSTALL", INSTALLSTATE_UNKNOWN );
1592 ret |= process_state_property( package, level, L"ADVERTISE", INSTALLSTATE_ADVERTISED );
1593
1594 if (ret)
1595 msi_set_property( package->db, L"Preselected", L"1", -1 );
1596
1597 return ret;
1598}
1599
1601{
1602 FeatureList *fl;
1603
1605 {
1607 {
1608 TRACE("child %s (level %d request %d) follows disabled parent %s (level %d request %d)\n",
1609 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1610 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1611
1612 fl->feature->Level = feature->Level;
1613 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1614 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1615 }
1616 disable_children( fl->feature, level );
1617 }
1618}
1619
1621{
1622 FeatureList *fl;
1623
1625 {
1626 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1627 {
1628 TRACE("child %s (level %d request %d) follows parent %s (level %d request %d)\n",
1629 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1630 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1631
1632 fl->feature->Action = feature->Action;
1633 fl->feature->ActionRequest = feature->ActionRequest;
1634 }
1635 follow_parent( fl->feature );
1636 }
1637}
1638
1640{
1641 int level;
1642 MSICOMPONENT* component;
1644
1645 TRACE("Checking Install Level\n");
1646
1647 level = msi_get_property_int(package->db, L"INSTALLLEVEL", 1);
1648
1649 if (msi_get_property_int( package->db, L"Preselected", 0 ))
1650 {
1652 {
1653 if (!is_feature_selected( feature, level )) continue;
1654
1655 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1656 {
1657 if (feature->Installed == INSTALLSTATE_ABSENT)
1658 {
1659 feature->Action = INSTALLSTATE_UNKNOWN;
1660 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1661 }
1662 else
1663 {
1664 feature->Action = feature->Installed;
1665 feature->ActionRequest = feature->Installed;
1666 }
1667 }
1668 }
1669 }
1670 else if (!msi_get_property_int( package->db, L"Installed", 0 ))
1671 {
1673 {
1674 if (!is_feature_selected( feature, level )) continue;
1675
1676 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1677 {
1679 {
1680 feature->Action = INSTALLSTATE_SOURCE;
1681 feature->ActionRequest = INSTALLSTATE_SOURCE;
1682 }
1683 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1684 {
1686 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1687 }
1688 else
1689 {
1690 feature->Action = INSTALLSTATE_LOCAL;
1691 feature->ActionRequest = INSTALLSTATE_LOCAL;
1692 }
1693 }
1694 }
1695 }
1696 else
1697 {
1699 {
1700 ComponentList *cl;
1701 MSIFEATURE *cur;
1702
1703 if (!is_feature_selected( feature, level )) continue;
1704 if (feature->ActionRequest != INSTALLSTATE_UNKNOWN) continue;
1705
1706 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1707 {
1708 if (!cl->component->updated && !cl->component->added)
1709 continue;
1710
1711 cur = feature;
1712 while (cur)
1713 {
1714 if (cur->ActionRequest != INSTALLSTATE_UNKNOWN)
1715 break;
1716
1717 if (cur->Installed != INSTALLSTATE_ABSENT)
1718 {
1719 cur->Action = cur->Installed;
1720 cur->ActionRequest = cur->Installed;
1721 }
1722 else if (!cl->component->added)
1723 {
1724 break;
1725 }
1726 else if (cur->Attributes & msidbFeatureAttributesFavorSource)
1727 {
1728 cur->Action = INSTALLSTATE_SOURCE;
1729 cur->ActionRequest = INSTALLSTATE_SOURCE;
1730 }
1731 else if (cur->Attributes & msidbFeatureAttributesFavorAdvertise)
1732 {
1733 cur->Action = INSTALLSTATE_ADVERTISED;
1734 cur->ActionRequest = INSTALLSTATE_ADVERTISED;
1735 }
1736 else
1737 {
1738 cur->Action = INSTALLSTATE_LOCAL;
1739 cur->ActionRequest = INSTALLSTATE_LOCAL;
1740 }
1741
1742 if (!cur->Feature_Parent)
1743 break;
1744 cur = msi_get_loaded_feature(package, cur->Feature_Parent);
1745 }
1746 }
1747 }
1748 }
1749
1750 /* disable child features of unselected parent or follow parent */
1752 {
1753 if (feature->Feature_Parent) continue;
1756 }
1757
1758 /* now we want to set component state based based on feature state */
1760 {
1761 ComponentList *cl;
1762
1763 TRACE("examining feature %s (level %d installed %d request %d action %d)\n",
1764 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1765 feature->ActionRequest, feature->Action);
1766
1767 /* features with components that have compressed files are made local */
1768 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1769 {
1770 if (cl->component->ForceLocalState &&
1771 feature->ActionRequest == INSTALLSTATE_SOURCE)
1772 {
1773 feature->Action = INSTALLSTATE_LOCAL;
1774 feature->ActionRequest = INSTALLSTATE_LOCAL;
1775 break;
1776 }
1777 }
1778
1779 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1780 {
1781 component = cl->component;
1782
1783 switch (feature->ActionRequest)
1784 {
1786 component->anyAbsent = 1;
1787 break;
1789 component->hasAdvertisedFeature = 1;
1790 break;
1792 component->hasSourceFeature = 1;
1793 break;
1794 case INSTALLSTATE_LOCAL:
1795 component->hasLocalFeature = 1;
1796 break;
1799 component->hasAdvertisedFeature = 1;
1800 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1801 component->hasSourceFeature = 1;
1802 else
1803 component->hasLocalFeature = 1;
1804 break;
1806 if (feature->Installed == INSTALLSTATE_ADVERTISED)
1807 component->hasAdvertisedFeature = 1;
1808 if (feature->Installed == INSTALLSTATE_SOURCE)
1809 component->hasSourceFeature = 1;
1810 if (feature->Installed == INSTALLSTATE_LOCAL)
1811 component->hasLocalFeature = 1;
1812 break;
1813 default:
1814 break;
1815 }
1816 }
1817 }
1818
1819 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1820 {
1821 /* check if it's local or source */
1822 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1823 (component->hasLocalFeature || component->hasSourceFeature))
1824 {
1826 !component->ForceLocalState)
1827 {
1828 component->Action = INSTALLSTATE_SOURCE;
1830 }
1831 else
1832 {
1833 component->Action = INSTALLSTATE_LOCAL;
1834 component->ActionRequest = INSTALLSTATE_LOCAL;
1835 }
1836 continue;
1837 }
1838
1839 /* if any feature is local, the component must be local too */
1840 if (component->hasLocalFeature)
1841 {
1842 component->Action = INSTALLSTATE_LOCAL;
1843 component->ActionRequest = INSTALLSTATE_LOCAL;
1844 continue;
1845 }
1846 if (component->hasSourceFeature)
1847 {
1848 component->Action = INSTALLSTATE_SOURCE;
1850 continue;
1851 }
1852 if (component->hasAdvertisedFeature)
1853 {
1854 component->Action = INSTALLSTATE_ADVERTISED;
1856 continue;
1857 }
1858 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1859 if (component->anyAbsent && component->ComponentId)
1860 {
1861 component->Action = INSTALLSTATE_ABSENT;
1863 }
1864 }
1865
1866 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1867 {
1868 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1869 {
1870 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1871 component->Action = INSTALLSTATE_LOCAL;
1872 component->ActionRequest = INSTALLSTATE_LOCAL;
1873 }
1874
1875 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
1876 component->Installed == INSTALLSTATE_SOURCE &&
1877 component->hasSourceFeature)
1878 {
1879 component->Action = INSTALLSTATE_UNKNOWN;
1881 }
1882
1883 if (component->Action == INSTALLSTATE_LOCAL || component->Action == INSTALLSTATE_SOURCE)
1884 component->num_clients++;
1885 else if (component->Action == INSTALLSTATE_ABSENT)
1886 {
1887 component->num_clients--;
1888
1889 if (component->num_clients > 0)
1890 {
1891 TRACE("multiple clients uses %s - disallowing uninstallation\n", debugstr_w(component->Component));
1892 component->Action = INSTALLSTATE_UNKNOWN;
1893 }
1894 }
1895
1896 TRACE("component %s (installed %d request %d action %d)\n",
1897 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
1898 }
1899
1900 return ERROR_SUCCESS;
1901}
1902
1904{
1905 MSIPACKAGE *package = param;
1906 LPCWSTR name;
1908
1910
1911 feature = msi_get_loaded_feature( package, name );
1912 if (!feature)
1913 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1914 else
1915 {
1918
1920 {
1922 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1923 feature->Level = level;
1924 }
1925 }
1926 return ERROR_SUCCESS;
1927}
1928
1930{
1931 DWORD ms, ls;
1932
1934
1935 if (fi->dwFileVersionMS > ms) return 1;
1936 else if (fi->dwFileVersionMS < ms) return -1;
1937 else if (fi->dwFileVersionLS > ls) return 1;
1938 else if (fi->dwFileVersionLS < ls) return -1;
1939 return 0;
1940}
1941
1942int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
1943{
1944 DWORD ms1, ms2;
1945
1946 msi_parse_version_string( ver1, &ms1, NULL );
1947 msi_parse_version_string( ver2, &ms2, NULL );
1948
1949 if (ms1 > ms2) return 1;
1950 else if (ms1 < ms2) return -1;
1951 return 0;
1952}
1953
1955{
1956 static UINT id;
1957 WCHAR *ret;
1958
1959 if (!db->tempfolder)
1960 {
1961 WCHAR tmp[MAX_PATH];
1962 DWORD len = ARRAY_SIZE( tmp );
1963
1964 if (msi_get_property( db, L"TempFolder", tmp, &len ) ||
1966 {
1967 GetTempPathW( MAX_PATH, tmp );
1968 }
1969 if (!(db->tempfolder = wcsdup( tmp ))) return NULL;
1970 }
1971
1972 if ((ret = malloc( (wcslen( db->tempfolder ) + 20) * sizeof(WCHAR) )))
1973 {
1974 for (;;)
1975 {
1976 if (!GetTempFileNameW( db->tempfolder, L"msi", ++id, ret ))
1977 {
1978 free( ret );
1979 return NULL;
1980 }
1981 if (CreateDirectoryW( ret, NULL )) break;
1982 }
1983 }
1984
1985 return ret;
1986}
1987
1988/*
1989 * msi_build_directory_name()
1990 *
1991 * This function is to save messing round with directory names
1992 * It handles adding backslashes between path segments,
1993 * and can add \ at the end of the directory name if told to.
1994 *
1995 * It takes a variable number of arguments.
1996 * It always allocates a new string for the result, so make sure
1997 * to free the return value when finished with it.
1998 *
1999 * The first arg is the number of path segments that follow.
2000 * The arguments following count are a list of path segments.
2001 * A path segment may be NULL.
2002 *
2003 * Path segments will be added with a \ separating them.
2004 * A \ will not be added after the last segment, however if the
2005 * last segment is NULL, then the last character will be a \
2006 */
2008{
2009 DWORD sz = 1, i;
2010 WCHAR *dir;
2011 va_list va;
2012
2013 va_start( va, count );
2014 for (i = 0; i < count; i++)
2015 {
2016 const WCHAR *str = va_arg( va, const WCHAR * );
2017 if (str) sz += lstrlenW( str ) + 1;
2018 }
2019 va_end( va );
2020
2021 dir = malloc( sz * sizeof(WCHAR) );
2022 dir[0] = 0;
2023
2024 va_start( va, count );
2025 for (i = 0; i < count; i++)
2026 {
2027 const WCHAR *str = va_arg( va, const WCHAR * );
2028 if (!str) continue;
2029 lstrcatW( dir, str );
2030 if ( i + 1 != count && dir[0] && dir[lstrlenW( dir ) - 1] != '\\') lstrcatW( dir, L"\\" );
2031 }
2032 va_end( va );
2033 return dir;
2034}
2035
2037{
2038 return comp->assembly && !comp->assembly->application;
2039}
2040
2041static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2042{
2043 free( file->TargetPath );
2044 if (msi_is_global_assembly( file->Component ))
2045 {
2046 MSIASSEMBLY *assembly = file->Component->assembly;
2047
2048 if (!assembly->tempdir) assembly->tempdir = create_temp_dir( package->db );
2049 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
2050 }
2051 else
2052 {
2053 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2054 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2055 }
2056
2057 TRACE("file %s resolves to %s\n", debugstr_w(file->File), debugstr_w(file->TargetPath));
2058}
2059
2061{
2062 VS_FIXEDFILEINFO *file_version;
2063 WCHAR *font_version;
2064 MSIFILE *file;
2065
2067 {
2068 MSICOMPONENT *comp = file->Component;
2070
2071 if (!comp->Enabled) continue;
2072
2073 if (file->IsCompressed)
2074 comp->ForceLocalState = TRUE;
2075
2076 set_target_path( package, file );
2077
2078 if (msi_get_file_attributes( package, file->TargetPath ) == INVALID_FILE_ATTRIBUTES)
2079 {
2080 comp->cost += cost_from_size( file->FileSize );
2081 continue;
2082 }
2083 file_size = msi_get_disk_file_size( package, file->TargetPath );
2084 TRACE("%s (size %lu)\n", debugstr_w(file->TargetPath), file_size);
2085
2086 if (file->Version)
2087 {
2088 if ((file_version = msi_get_disk_file_version( package, file->TargetPath )))
2089 {
2090 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2091 {
2092 comp->cost += cost_from_size( file->FileSize - file_size );
2093 }
2094 free( file_version );
2095 continue;
2096 }
2097 else if ((font_version = msi_get_font_file_version( package, file->TargetPath )))
2098 {
2099 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2100 {
2101 comp->cost += cost_from_size( file->FileSize - file_size );
2102 }
2103 free( font_version );
2104 continue;
2105 }
2106 }
2107 if (file_size != file->FileSize)
2108 {
2109 comp->cost += cost_from_size( file->FileSize - file_size );
2110 }
2111 }
2112
2113 return ERROR_SUCCESS;
2114}
2115
2117{
2118 const WCHAR *p = in;
2119 WCHAR *q, *ret;
2120 int n, len = lstrlenW( in ) + 2;
2121
2122 if (!(q = ret = malloc( len * sizeof(WCHAR) ))) return NULL;
2123
2124 len = 0;
2125 while (1)
2126 {
2127 /* copy until the end of the string or a space */
2128 while (*p != ' ' && (*q = *p))
2129 {
2130 p++, len++;
2131 /* reduce many backslashes to one */
2132 if (*p != '\\' || *q != '\\')
2133 q++;
2134 }
2135
2136 /* quit at the end of the string */
2137 if (!*p)
2138 break;
2139
2140 /* count the number of spaces */
2141 n = 0;
2142 while (p[n] == ' ')
2143 n++;
2144
2145 /* if it's leading or trailing space, skip it */
2146 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
2147 p += n;
2148 else /* copy n spaces */
2149 while (n && (*q++ = *p++)) n--;
2150 }
2151 while (q - ret > 0 && q[-1] == ' ') q--;
2152 if (q - ret > 0 && q[-1] != '\\')
2153 {
2154 q[0] = '\\';
2155 q[1] = 0;
2156 }
2157 return ret;
2158}
2159
2161{
2162 HKEY hkey;
2163 WCHAR *path;
2164
2165 if (!package->ProductCode) return NULL;
2166 if (MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE )) return NULL;
2167 if ((path = msi_reg_get_val_str( hkey, L"InstallLocation" )) && !path[0])
2168 {
2169 free( path );
2170 path = NULL;
2171 }
2172 RegCloseKey( hkey );
2173 return path;
2174}
2175
2176void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2177{
2178 FolderList *fl;
2180 WCHAR *path, *normalized_path;
2181
2182 TRACE("resolving %s\n", debugstr_w(name));
2183
2184 if (!(folder = msi_get_loaded_folder( package, name ))) return;
2185
2186 if (!wcscmp( folder->Directory, L"TARGETDIR" )) /* special resolving for target root dir */
2187 {
2188 if (!(path = get_install_location( package )) &&
2189 (!load_prop || !(path = msi_dup_property( package->db, L"TARGETDIR" ))))
2190 {
2191 path = msi_dup_property( package->db, L"ROOTDRIVE" );
2192 }
2193 }
2194 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2195 {
2196 if (folder->Parent && wcscmp( folder->Directory, folder->Parent ))
2197 {
2198 parent = msi_get_loaded_folder( package, folder->Parent );
2199 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2200 }
2201 else
2202 path = msi_build_directory_name( 2, folder->TargetDefault, NULL );
2203 }
2204
2205 normalized_path = msi_normalize_path( path );
2206 msi_set_property( package->db, folder->Directory, normalized_path, -1 );
2207 free( path );
2208
2209 free( folder->ResolvedTarget );
2210 folder->ResolvedTarget = normalized_path;
2211
2213 {
2214 child = fl->folder;
2215 msi_resolve_target_folder( package, child->Directory, load_prop );
2216 }
2217 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2218}
2219
2221{
2222 MSICOMPONENT *comp;
2223 ULONGLONG ret = 0;
2224
2226 {
2227 if (comp->Action == INSTALLSTATE_LOCAL) ret += comp->cost;
2228 }
2229 return ret;
2230}
2231
2233{
2234 MSICOMPONENT *comp;
2235 MSIQUERY *view;
2236 WCHAR *level, *primary_key, *primary_folder;
2237 UINT rc;
2238
2239 TRACE("Building directory properties\n");
2240 msi_resolve_target_folder( package, L"TARGETDIR", TRUE );
2241
2242 TRACE("Evaluating component conditions\n");
2244 {
2245 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2246 {
2247 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2248 comp->Enabled = FALSE;
2249 }
2250 else
2251 comp->Enabled = TRUE;
2252 }
2253 get_client_counts( package );
2254
2255 /* read components states from the registry */
2258
2259 if (!process_overrides( package, msi_get_property_int( package->db, L"INSTALLLEVEL", 1 ) ))
2260 {
2261 TRACE("Evaluating feature conditions\n");
2262
2263 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Condition`", &view );
2264 if (rc == ERROR_SUCCESS)
2265 {
2267 msiobj_release( &view->hdr );
2268 if (rc != ERROR_SUCCESS)
2269 return rc;
2270 }
2271 }
2272
2273 TRACE("Calculating file cost\n");
2274 calculate_file_cost( package );
2275
2276 msi_set_property( package->db, L"CostingComplete", L"1", -1 );
2277 /* set default run level if not set */
2278 level = msi_dup_property( package->db, L"INSTALLLEVEL" );
2279 if (!level) msi_set_property( package->db, L"INSTALLLEVEL", L"1", -1 );
2280 free(level);
2281
2282 if ((rc = MSI_SetFeatureStates( package ))) return rc;
2283
2284 if ((primary_key = msi_dup_property( package->db, L"PRIMARYFOLDER" )))
2285 {
2286 if ((primary_folder = msi_dup_property( package->db, primary_key )))
2287 {
2288 if (((primary_folder[0] >= 'A' && primary_folder[0] <= 'Z') ||
2289 (primary_folder[0] >= 'a' && primary_folder[0] <= 'z')) && primary_folder[1] == ':')
2290 {
2292 ULONGLONG required;
2293 WCHAR buf[21];
2294
2295 primary_folder[2] = 0;
2296 if (GetDiskFreeSpaceExW( primary_folder, &free, NULL, NULL ))
2297 {
2298#ifdef __REACTOS__
2299 swprintf(buf, ARRAY_SIZE(buf), L"%I64u", free.QuadPart / 512);
2300#else
2301 swprintf( buf, ARRAY_SIZE(buf), L"%lu", free.QuadPart / 512 );
2302#endif
2303 msi_set_property( package->db, L"PrimaryVolumeSpaceAvailable", buf, -1 );
2304 }
2305 required = get_volume_space_required( package );
2306#ifdef __REACTOS__
2307 swprintf( buf, ARRAY_SIZE(buf), L"%I64u", required );
2308#else
2309 swprintf( buf, ARRAY_SIZE(buf), L"%lu", required );
2310#endif
2311 msi_set_property( package->db, L"PrimaryVolumeSpaceRequired", buf, -1 );
2312
2313#ifdef __REACTOS__
2314 swprintf( buf, ARRAY_SIZE(buf), L"%I64u", (free.QuadPart / 512) - required );
2315#else
2316 swprintf( buf, ARRAY_SIZE(buf), L"%lu", (free.QuadPart / 512) - required );
2317#endif
2318 msi_set_property( package->db, L"PrimaryVolumeSpaceRemaining", buf, -1 );
2319 msi_set_property( package->db, L"PrimaryVolumePath", primary_folder, 2 );
2320 }
2321 free( primary_folder );
2322 }
2323 free( primary_key );
2324 }
2325
2326 /* FIXME: check volume disk space */
2327 msi_set_property( package->db, L"OutOfDiskSpace", L"0", -1 );
2328 msi_set_property( package->db, L"OutOfNoRbDiskSpace", L"0", -1 );
2329
2330 return ERROR_SUCCESS;
2331}
2332
2334{
2335 BYTE *data;
2336
2337 if (!value)
2338 {
2339 *size = sizeof(WCHAR);
2340 *type = REG_SZ;
2341 if ((data = malloc( *size ))) *(WCHAR *)data = 0;
2342 return data;
2343 }
2344 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2345 {
2346 if (value[1]=='x')
2347 {
2348 LPWSTR ptr;
2349 CHAR byte[5];
2350 LPWSTR deformated = NULL;
2351 int count;
2352
2353 deformat_string(package, &value[2], &deformated);
2354
2355 /* binary value type */
2356 ptr = deformated;
2357 *type = REG_BINARY;
2358 if (lstrlenW(ptr)%2)
2359 *size = (lstrlenW(ptr)/2)+1;
2360 else
2361 *size = lstrlenW(ptr)/2;
2362
2363 data = malloc(*size);
2364
2365 byte[0] = '0';
2366 byte[1] = 'x';
2367 byte[4] = 0;
2368 count = 0;
2369 /* if uneven pad with a zero in front */
2370 if (lstrlenW(ptr)%2)
2371 {
2372 byte[2]= '0';
2373 byte[3]= *ptr;
2374 ptr++;
2375 data[count] = (BYTE)strtol(byte,NULL,0);
2376 count ++;
2377 TRACE("Uneven byte count\n");
2378 }
2379 while (*ptr)
2380 {
2381 byte[2]= *ptr;
2382 ptr++;
2383 byte[3]= *ptr;
2384 ptr++;
2385 data[count] = (BYTE)strtol(byte,NULL,0);
2386 count ++;
2387 }
2388 free(deformated);
2389
2390 TRACE( "data %lu bytes(%u)\n", *size, count );
2391 }
2392 else
2393 {
2394 LPWSTR deformated;
2395 LPWSTR p;
2396 DWORD d = 0;
2397 deformat_string(package, &value[1], &deformated);
2398
2399 *type=REG_DWORD;
2400 *size = sizeof(DWORD);
2401 data = malloc(*size);
2402 p = deformated;
2403 if (*p == '-')
2404 p++;
2405 while (*p)
2406 {
2407 if ( (*p < '0') || (*p > '9') )
2408 break;
2409 d *= 10;
2410 d += (*p - '0');
2411 p++;
2412 }
2413 if (deformated[0] == '-')
2414 d = -d;
2415 *(DWORD *)data = d;
2416 TRACE( "DWORD %lu\n", *(DWORD *)data);
2417
2418 free(deformated);
2419 }
2420 }
2421 else
2422 {
2423 const WCHAR *ptr = value;
2424
2425 *type = REG_SZ;
2426 if (value[0] == '#')
2427 {
2428 ptr++; len--;
2429 if (value[1] == '%')
2430 {
2431 ptr++; len--;
2433 }
2434 }
2435 data = (BYTE *)msi_strdupW( ptr, len );
2436 if (len > lstrlenW( (const WCHAR *)data )) *type = REG_MULTI_SZ;
2437 *size = (len + 1) * sizeof(WCHAR);
2438 }
2439 return data;
2440}
2441
2442static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2443{
2444 const WCHAR *ret;
2445
2446 switch (root)
2447 {
2448 case -1:
2449 if (msi_get_property_int( package->db, L"ALLUSERS", 0 ))
2450 {
2451 *root_key = HKEY_LOCAL_MACHINE;
2452 ret = L"HKEY_LOCAL_MACHINE\\";
2453 }
2454 else
2455 {
2456 *root_key = HKEY_CURRENT_USER;
2457 ret = L"HKEY_CURRENT_USER\\";
2458 }
2459 break;
2460 case 0:
2461 *root_key = HKEY_CLASSES_ROOT;
2462 ret = L"HKEY_CLASSES_ROOT\\";
2463 break;
2464 case 1:
2465 *root_key = HKEY_CURRENT_USER;
2466 ret = L"HKEY_CURRENT_USER\\";
2467 break;
2468 case 2:
2469 *root_key = HKEY_LOCAL_MACHINE;
2470 ret = L"HKEY_LOCAL_MACHINE\\";
2471 break;
2472 case 3:
2473 *root_key = HKEY_USERS;
2474 ret = L"HKEY_USERS\\";
2475 break;
2476 default:
2477 ERR("Unknown root %i\n", root);
2478 return NULL;
2479 }
2480
2481 return ret;
2482}
2483
2484static inline REGSAM get_registry_view( const MSICOMPONENT *comp )
2485{
2486 REGSAM view = 0;
2487 if (is_wow64 || is_64bit)
2489 return view;
2490}
2491
2493{
2494 WCHAR *subkey, *p, *q;
2495 HKEY hkey, ret = NULL;
2496 LONG res;
2497
2498 access |= get_registry_view( comp );
2499
2500 if (!(subkey = wcsdup( path ))) return NULL;
2501 p = subkey;
2502 if ((q = wcschr( p, '\\' ))) *q = 0;
2503 if (create)
2504 res = RegCreateKeyExW( root, subkey, 0, NULL, 0, access, NULL, &hkey, NULL );
2505 else
2506 res = RegOpenKeyExW( root, subkey, 0, access, &hkey );
2507 if (res)
2508 {
2509 TRACE( "failed to open key %s (%ld)\n", debugstr_w(subkey), res );
2510 free( subkey );
2511 return NULL;
2512 }
2513 if (q && q[1])
2514 {
2515 ret = open_key( comp, hkey, q + 1, create, access );
2516 RegCloseKey( hkey );
2517 }
2518 else ret = hkey;
2519 free( subkey );
2520 return ret;
2521}
2522
2524{
2525 return (name && (name[0] == '*' || name[0] == '+') && !name[1]);
2526}
2527
2529{
2530 const WCHAR *p = str;
2531 WCHAR **ret;
2532 int i = 0;
2533
2534 *count = 0;
2535 if (!str) return NULL;
2536 while ((p - str) < len)
2537 {
2538 p += lstrlenW( p ) + 1;
2539 (*count)++;
2540 }
2541 if (!(ret = malloc( *count * sizeof(WCHAR *) ))) return NULL;
2542 p = str;
2543 while ((p - str) < len)
2544 {
2545 if (!(ret[i] = wcsdup( p )))
2546 {
2547 for (; i >= 0; i--) free( ret[i] );
2548 free( ret );
2549 return NULL;
2550 }
2551 p += lstrlenW( p ) + 1;
2552 i++;
2553 }
2554 return ret;
2555}
2556
2558 WCHAR **right, DWORD right_count, DWORD *size )
2559{
2560 WCHAR *ret, *p;
2561 unsigned int i;
2562
2563 *size = sizeof(WCHAR);
2564 for (i = 0; i < left_count; i++) *size += (lstrlenW( left[i] ) + 1) * sizeof(WCHAR);
2565 for (i = 0; i < right_count; i++) *size += (lstrlenW( right[i] ) + 1) * sizeof(WCHAR);
2566
2567 if (!(ret = p = malloc( *size ))) return NULL;
2568
2569 for (i = 0; i < left_count; i++)
2570 {
2571 lstrcpyW( p, left[i] );
2572 p += lstrlenW( p ) + 1;
2573 }
2574 for (i = 0; i < right_count; i++)
2575 {
2576 lstrcpyW( p, right[i] );
2577 p += lstrlenW( p ) + 1;
2578 }
2579 *p = 0;
2580 return ret;
2581}
2582
2583static DWORD remove_duplicate_values( WCHAR **old, DWORD old_count,
2584 WCHAR **new, DWORD new_count )
2585{
2586 DWORD ret = old_count;
2587 unsigned int i, j, k;
2588
2589 for (i = 0; i < new_count; i++)
2590 {
2591 for (j = 0; j < old_count; j++)
2592 {
2593 if (old[j] && !wcscmp( new[i], old[j] ))
2594 {
2595 free( old[j] );
2596 for (k = j; k < old_count - 1; k++) { old[k] = old[k + 1]; }
2597 old[k] = NULL;
2598 ret--;
2599 }
2600 }
2601 }
2602 return ret;
2603}
2604
2606{
2611
2612static WCHAR *join_multi_string_values( enum join_op op, WCHAR **old, DWORD old_count,
2613 WCHAR **new, DWORD new_count, DWORD *size )
2614{
2615 switch (op)
2616 {
2617 case JOIN_OP_APPEND:
2618 old_count = remove_duplicate_values( old, old_count, new, new_count );
2619 return flatten_multi_string_values( old, old_count, new, new_count, size );
2620
2621 case JOIN_OP_PREPEND:
2622 old_count = remove_duplicate_values( old, old_count, new, new_count );
2623 return flatten_multi_string_values( new, new_count, old, old_count, size );
2624
2625 case JOIN_OP_REPLACE:
2626 return flatten_multi_string_values( new, new_count, NULL, 0, size );
2627
2628 default:
2629 ERR("unhandled join op %u\n", op);
2630 return NULL;
2631 }
2632}
2633
2635 BYTE *new_value, DWORD new_size, DWORD *size )
2636{
2637 DWORD i, old_len = 0, new_len = 0, old_count = 0, new_count = 0;
2638 const WCHAR *new_ptr = NULL, *old_ptr = NULL;
2639 enum join_op op = JOIN_OP_REPLACE;
2640 WCHAR **old = NULL, **new = NULL;
2641 BYTE *ret;
2642
2643 if (new_size / sizeof(WCHAR) - 1 > 1)
2644 {
2645 new_ptr = (const WCHAR *)new_value;
2646 new_len = new_size / sizeof(WCHAR) - 1;
2647
2648 if (!new_ptr[0] && new_ptr[new_len - 1])
2649 {
2651 new_len--;
2652 new_ptr++;
2653 }
2654 else if (new_ptr[0] && !new_ptr[new_len - 1])
2655 {
2657 new_len--;
2658 }
2659 else if (new_len > 2 && !new_ptr[0] && !new_ptr[new_len - 1])
2660 {
2662 new_len -= 2;
2663 new_ptr++;
2664 }
2665 new = split_multi_string_values( new_ptr, new_len, &new_count );
2666 }
2667 if (old_size / sizeof(WCHAR) - 1 > 1)
2668 {
2669 old_ptr = (const WCHAR *)old_value;
2670 old_len = old_size / sizeof(WCHAR) - 1;
2671 old = split_multi_string_values( old_ptr, old_len, &old_count );
2672 }
2673 ret = (BYTE *)join_multi_string_values( op, old, old_count, new, new_count, size );
2674 for (i = 0; i < old_count; i++) free( old[i] );
2675 for (i = 0; i < new_count; i++) free( new[i] );
2676 free( old );
2677 free( new );
2678 return ret;
2679}
2680
2681static BYTE *reg_get_value( HKEY hkey, const WCHAR *name, DWORD *type, DWORD *size )
2682{
2683 BYTE *ret;
2684 if (RegQueryValueExW( hkey, name, NULL, NULL, NULL, size )) return NULL;
2685 if (!(ret = malloc( *size ))) return NULL;
2686 RegQueryValueExW( hkey, name, NULL, type, ret, size );
2687 return ret;
2688}
2689
2691{
2692 MSIPACKAGE *package = param;
2693 BYTE *new_value, *old_value = NULL;
2694 HKEY root_key, hkey;
2695 DWORD type, old_type, new_size, old_size = 0;
2696 LPWSTR deformated, uikey;
2697 const WCHAR *szRoot, *component, *name, *key, *str;
2698 MSICOMPONENT *comp;
2699 MSIRECORD * uirow;
2700 INT root;
2701 BOOL check_first = FALSE;
2702 int len;
2703
2704 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2705
2706 component = MSI_RecordGetString(row, 6);
2707 comp = msi_get_loaded_component(package,component);
2708 if (!comp)
2709 return ERROR_SUCCESS;
2710
2711 comp->Action = msi_get_component_action( package, comp );
2712 if (comp->Action != INSTALLSTATE_LOCAL && comp->Action != INSTALLSTATE_SOURCE)
2713 {
2714 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2715 return ERROR_SUCCESS;
2716 }
2717
2719 if( MSI_RecordIsNull(row,5) && name )
2720 {
2721 /* null values can have special meanings */
2722 if (name[0]=='-' && name[1] == 0)
2723 return ERROR_SUCCESS;
2724 if ((name[0] == '+' || name[0] == '*') && !name[1])
2725 check_first = TRUE;
2726 }
2727
2730
2731 szRoot = get_root_key( package, root, &root_key );
2732 if (!szRoot)
2733 return ERROR_SUCCESS;
2734
2735 deformat_string(package, key , &deformated);
2736 uikey = malloc( (wcslen(deformated) + wcslen(szRoot) + 1) * sizeof(WCHAR) );
2737 lstrcpyW(uikey,szRoot);
2738 lstrcatW(uikey,deformated);
2739
2740 if (!(hkey = open_key( comp, root_key, deformated, TRUE, KEY_QUERY_VALUE | KEY_SET_VALUE )))
2741 {
2742 ERR("Could not create key %s\n", debugstr_w(deformated));
2743 free(uikey);
2744 free(deformated);
2745 return ERROR_FUNCTION_FAILED;
2746 }
2747 free( deformated );
2749 len = deformat_string( package, str, &deformated );
2750 new_value = parse_value( package, deformated, len, &type, &new_size );
2751
2752 free( deformated );
2753 deformat_string(package, name, &deformated);
2754
2755 if (!is_special_entry( name ))
2756 {
2757 old_value = reg_get_value( hkey, deformated, &old_type, &old_size );
2758 if (type == REG_MULTI_SZ)
2759 {
2760 BYTE *new;
2761 if (old_value && old_type != REG_MULTI_SZ)
2762 {
2763 free( old_value );
2764 old_value = NULL;
2765 old_size = 0;
2766 }
2768 free( new_value );
2769 new_value = new;
2770 }
2771 if (!check_first)
2772 {
2773 TRACE( "setting value %s of %s type %lu\n", debugstr_w(deformated), debugstr_w(uikey), type );
2774 RegSetValueExW( hkey, deformated, 0, type, new_value, new_size );
2775 }
2776 else if (!old_value)
2777 {
2778 if (deformated || new_size)
2779 {
2780 TRACE( "setting value %s of %s type %lu\n", debugstr_w(deformated), debugstr_w(uikey), type );
2781 RegSetValueExW( hkey, deformated, 0, type, new_value, new_size );
2782 }
2783 }
2784 else TRACE("not overwriting existing value %s of %s\n", debugstr_w(deformated), debugstr_w(uikey));
2785 }
2786 RegCloseKey(hkey);
2787
2788 uirow = MSI_CreateRecord(3);
2789 MSI_RecordSetStringW(uirow,2,deformated);
2790 MSI_RecordSetStringW(uirow,1,uikey);
2791 if (type == REG_SZ || type == REG_EXPAND_SZ)
2792 MSI_RecordSetStringW(uirow, 3, (LPWSTR)new_value);
2794 msiobj_release( &uirow->hdr );
2795
2796 free(new_value);
2797 free(old_value);
2798 free(deformated);
2799 free(uikey);
2800
2801 return ERROR_SUCCESS;
2802}
2803
2805{
2806 MSIQUERY *view;
2807 UINT rc;
2808
2809 if (package->script == SCRIPT_NONE)
2810 return msi_schedule_action(package, SCRIPT_INSTALL, L"WriteRegistryValues");
2811
2812 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `Registry`", &view);
2813 if (rc != ERROR_SUCCESS)
2814 return ERROR_SUCCESS;
2815
2817 msiobj_release(&view->hdr);
2818 return rc;
2819}
2820
2821static int is_key_empty(const MSICOMPONENT *comp, HKEY root, const WCHAR *path)
2822{
2823 DWORD subkeys, values;
2824 HKEY key;
2825 LONG res;
2826
2827 key = open_key(comp, root, path, FALSE, KEY_READ);
2828 if (!key) return 0;
2829
2830 res = RegQueryInfoKeyW(key, 0, 0, 0, &subkeys, 0, 0, &values, 0, 0, 0, 0);
2832
2833 return !res && !subkeys && !values;
2834}
2835
2836static void delete_key( const MSICOMPONENT *comp, HKEY root, const WCHAR *path )
2837{
2840 WCHAR *subkey, *p;
2841 HKEY hkey;
2842
2843 if (!(subkey = wcsdup( path ))) return;
2844 do
2845 {
2846 if ((p = wcsrchr( subkey, '\\' )))
2847 {
2848 *p = 0;
2849 if (!p[1]) continue; /* trailing backslash */
2850 hkey = open_key( comp, root, subkey, FALSE, READ_CONTROL );
2851 if (!hkey) break;
2852 if (!is_key_empty(comp, hkey, p + 1))
2853 {
2854 RegCloseKey(hkey);
2855 break;
2856 }
2857 res = RegDeleteKeyExW( hkey, p + 1, access, 0 );
2858 RegCloseKey( hkey );
2859 }
2860 else if (is_key_empty(comp, root, subkey))
2861 res = RegDeleteKeyExW( root, subkey, access, 0 );
2862 if (res)
2863 {
2864 TRACE( "failed to delete key %s (%ld)\n", debugstr_w(subkey), res );
2865 break;
2866 }
2867 } while (p);
2868 free( subkey );
2869}
2870
2871static void delete_value( const MSICOMPONENT *comp, HKEY root, const WCHAR *path, const WCHAR *value )
2872{
2873 LONG res;
2874 HKEY hkey;
2875
2876 if ((hkey = open_key( comp, root, path, FALSE, KEY_SET_VALUE | KEY_QUERY_VALUE )))
2877 {
2878 if ((res = RegDeleteValueW( hkey, value )))
2879 TRACE( "failed to delete value %s (%ld)\n", debugstr_w(value), res );
2880
2881 RegCloseKey( hkey );
2882 if (is_key_empty(comp, root, path))
2883 {
2884 TRACE("removing empty key %s\n", debugstr_w(path));
2885 delete_key( comp, root, path );
2886 }
2887 }
2888}
2889
2890static void delete_tree( const MSICOMPONENT *comp, HKEY root, const WCHAR *path )
2891{
2892 LONG res;
2893 HKEY hkey;
2894
2895 if (!(hkey = open_key( comp, root, path, FALSE, KEY_ALL_ACCESS ))) return;
2896 res = RegDeleteTreeW( hkey, NULL );
2897 if (res) TRACE( "failed to delete subtree of %s (%ld)\n", debugstr_w(path), res );
2898 delete_key( comp, root, path );
2899 RegCloseKey( hkey );
2900}
2901
2903{
2904 MSIPACKAGE *package = param;
2905 LPCWSTR component, name, key_str, root_key_str;
2906 LPWSTR deformated_key, deformated_name, ui_key_str;
2907 MSICOMPONENT *comp;
2908 MSIRECORD *uirow;
2910 HKEY hkey_root;
2911 UINT size;
2912 INT root;
2913
2914 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2915
2916 component = MSI_RecordGetString( row, 6 );
2917 comp = msi_get_loaded_component( package, component );
2918 if (!comp)
2919 return ERROR_SUCCESS;
2920
2921 comp->Action = msi_get_component_action( package, comp );
2922 if (comp->Action != INSTALLSTATE_ABSENT)
2923 {
2924 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2925 return ERROR_SUCCESS;
2926 }
2927
2929 if (MSI_RecordIsNull( row, 5 ) && name )
2930 {
2931 if (name[0] == '+' && !name[1])
2932 return ERROR_SUCCESS;
2933 if ((name[0] == '-' || name[0] == '*') && !name[1])
2934 {
2935 delete_key = TRUE;
2936 name = NULL;
2937 }
2938 }
2939
2941 key_str = MSI_RecordGetString( row, 3 );
2942
2943 root_key_str = get_root_key( package, root, &hkey_root );
2944 if (!root_key_str)
2945 return ERROR_SUCCESS;
2946
2947 deformat_string( package, key_str, &deformated_key );
2948 size = lstrlenW( deformated_key ) + lstrlenW( root_key_str ) + 1;
2949 ui_key_str = malloc( size * sizeof(WCHAR) );
2950 lstrcpyW( ui_key_str, root_key_str );
2951 lstrcatW( ui_key_str, deformated_key );
2952
2953 deformat_string( package, name, &deformated_name );
2954
2955 if (delete_key) delete_tree( comp, hkey_root, deformated_key );
2956 else delete_value( comp, hkey_root, deformated_key, deformated_name );
2957 free( deformated_key );
2958
2959 uirow = MSI_CreateRecord( 2 );
2960 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2961 MSI_RecordSetStringW( uirow, 2, deformated_name );
2963 msiobj_release( &uirow->hdr );
2964
2965 free( ui_key_str );
2966 free( deformated_name );
2967 return ERROR_SUCCESS;
2968}
2969
2971{
2972 MSIPACKAGE *package = param;
2973 LPCWSTR component, name, key_str, root_key_str;
2974 LPWSTR deformated_key, deformated_name, ui_key_str;
2975 MSICOMPONENT *comp;
2976 MSIRECORD *uirow;
2978 HKEY hkey_root;
2979 UINT size;
2980 INT root;
2981
2982 component = MSI_RecordGetString( row, 5 );
2983 comp = msi_get_loaded_component( package, component );
2984 if (!comp)
2985 return ERROR_SUCCESS;
2986
2987 comp->Action = msi_get_component_action( package, comp );
2988 if (comp->Action != INSTALLSTATE_LOCAL)
2989 {
2990 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2991 return ERROR_SUCCESS;
2992 }
2993
2994 if ((name = MSI_RecordGetString( row, 4 )))
2995 {
2996 if (name[0] == '-' && !name[1])
2997 {
2998 delete_key = TRUE;
2999 name = NULL;
3000 }
3001 }
3002
3004 key_str = MSI_RecordGetString( row, 3 );
3005
3006 root_key_str = get_root_key( package, root, &hkey_root );
3007 if (!root_key_str)
3008 return ERROR_SUCCESS;
3009
3010 deformat_string( package, key_str, &deformated_key );
3011 size = lstrlenW( deformated_key ) + lstrlenW( root_key_str ) + 1;
3012 ui_key_str = malloc( size * sizeof(WCHAR) );
3013 lstrcpyW( ui_key_str, root_key_str );
3014 lstrcatW( ui_key_str, deformated_key );
3015
3016 deformat_string( package, name, &deformated_name );
3017
3018 if (delete_key) delete_tree( comp, hkey_root, deformated_key );
3019 else delete_value( comp, hkey_root, deformated_key, deformated_name );
3020 free( deformated_key );
3021
3022 uirow = MSI_CreateRecord( 2 );
3023 MSI_RecordSetStringW( uirow, 1, ui_key_str );
3024 MSI_RecordSetStringW( uirow, 2, deformated_name );
3026 msiobj_release( &uirow->hdr );
3027
3028 free( ui_key_str );
3029 free( deformated_name );
3030 return ERROR_SUCCESS;
3031}
3032
3034{
3035 MSIQUERY *view;
3036 UINT rc;
3037
3038 if (package->script == SCRIPT_NONE)
3039 return msi_schedule_action(package, SCRIPT_INSTALL, L"RemoveRegistryValues");
3040
3041 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Registry`", &view );
3042 if (rc == ERROR_SUCCESS)
3043 {
3045 msiobj_release( &view->hdr );
3046 if (rc != ERROR_SUCCESS)
3047 return rc;
3048 }
3049 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `RemoveRegistry`", &view );
3050 if (rc == ERROR_SUCCESS)
3051 {
3053 msiobj_release( &view->hdr );
3054 if (rc != ERROR_SUCCESS)
3055 return rc;
3056 }
3057 return ERROR_SUCCESS;
3058}
3059
3061{
3062 return ERROR_SUCCESS;
3063}
3064
3065
3067{
3068 MSICOMPONENT *comp;
3069 DWORD total = 0, count = 0;
3070 MSIQUERY *view;
3072 MSIFILE *file;
3073 UINT rc;
3074
3075 TRACE("InstallValidate\n");
3076
3077 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Registry`", &view );
3078 if (rc == ERROR_SUCCESS)
3079 {
3080 rc = MSI_IterateRecords( view, &count, NULL, package );
3081 msiobj_release( &view->hdr );
3082 if (rc != ERROR_SUCCESS)
3083 return rc;
3085 }
3088
3090 total += file->FileSize;
3091
3092 msi_ui_progress( package, 0, total, 0, 0 );
3093
3095 {
3096 TRACE("Feature: %s Installed %d Request %d Action %d\n",
3097 debugstr_w(feature->Feature), feature->Installed,
3098 feature->ActionRequest, feature->Action);
3099 }
3100 return ERROR_SUCCESS;
3101}
3102
3104{
3105 MSIPACKAGE* package = param;
3106 const WCHAR *cond, *message;
3107 UINT r;
3108
3109 cond = MSI_RecordGetString(row, 1);
3110 r = MSI_EvaluateConditionW(package, cond);
3111 if (r == MSICONDITION_FALSE)
3112 {
3113 if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
3114 {
3115 WCHAR *deformated;
3117 deformat_string(package, message, &deformated);
3118 MessageBoxW(NULL, deformated, L"Install Failed", MB_OK);
3119 free(deformated);
3120 }
3121
3122 return ERROR_INSTALL_FAILURE;
3123 }
3124
3125 return ERROR_SUCCESS;
3126}
3127
3129{
3130 MSIQUERY *view;
3131 UINT rc;
3132
3133 TRACE("Checking launch conditions\n");
3134
3135 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `LaunchCondition`", &view);
3136 if (rc != ERROR_SUCCESS)
3137 return ERROR_SUCCESS;
3138
3140 msiobj_release(&view->hdr);
3141 return rc;
3142}
3143
3145{
3146
3147 if (!cmp->KeyPath)
3148 return wcsdup( msi_get_target_folder( package, cmp->Directory ) );
3149
3151 {
3152 MSIRECORD *row;
3153 UINT root, len;
3154 LPWSTR deformated, buffer, deformated_name;
3155 LPCWSTR key, name;
3156
3157 row = MSI_QueryGetRecord(package->db, L"SELECT * FROM `Registry` WHERE `Registry` = '%s'", cmp->KeyPath);
3158 if (!row)
3159 return NULL;
3160
3164 deformat_string(package, key , &deformated);
3165 deformat_string(package, name, &deformated_name);
3166
3167 len = lstrlenW(deformated) + 6;
3168 if (deformated_name)
3169 len+=lstrlenW(deformated_name);
3170
3171 buffer = malloc(len * sizeof(WCHAR));
3172
3173 if (deformated_name)
3174 swprintf(buffer, len, L"%02d:\\%s\\%s", root, deformated, deformated_name);
3175 else
3176 swprintf(buffer, len, L"%02d:\\%s\\", root, deformated);
3177
3178 free(deformated);
3179 free(deformated_name);
3180 msiobj_release(&row->hdr);
3181
3182 return buffer;
3183 }
3184 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3185 {
3186 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3187 return NULL;
3188 }
3189 else
3190 {
3191 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3192
3193 if (file)
3194 return wcsdup( file->TargetPath );
3195 }
3196 return NULL;
3197}
3198
3200{
3201 return open_key( comp, HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\SharedDLLs",
3202 create, access );
3203}
3204
3206{
3207 DWORD count, type, sz = sizeof(count);
3208 HKEY hkey = open_shared_dlls_key( comp, FALSE, KEY_READ );
3209 if (RegQueryValueExW( hkey, comp->FullKeypath, NULL, &type, (BYTE *)&count, &sz )) count = 0;
3210 RegCloseKey( hkey );
3211 return count;
3212}
3213
3215{
3217 if (count > 0)
3219 else
3220 RegDeleteValueW( hkey, path );
3221 RegCloseKey(hkey);
3222}
3223
3224static void refcount_component( MSIPACKAGE *package, MSICOMPONENT *comp )
3225{
3227 INT count = 0;
3228 BOOL write = FALSE;
3229
3230 /* only refcount DLLs */
3231 if (!comp->KeyPath || comp->assembly || comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3233 write = FALSE;
3234 else
3235 {
3236 count = get_shared_dlls_count( comp );
3237 write = (count > 0);
3239 write = TRUE;
3240 }
3241
3242 /* increment counts */
3244 {
3245 ComponentList *cl;
3246
3248 continue;
3249
3250 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3251 {
3252 if ( cl->component == comp )
3253 count++;
3254 }
3255 }
3256
3257 /* decrement counts */
3259 {
3260 ComponentList *cl;
3261
3263 continue;
3264
3265 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3266 {
3267 if ( cl->component == comp )
3268 count--;
3269 }
3270 }
3271
3272 /* ref count all the files in the component */
3273 if (write)
3274 {
3275 MSIFILE *file;
3276
3278 {
3279 if (file->Component == comp)
3280 write_shared_dlls_count( comp, file->TargetPath, count );
3281 }
3282 }
3283
3284 /* add a count for permanent */
3286 count ++;
3287
3288 comp->RefCount = count;
3289
3290 if (write)
3291 write_shared_dlls_count( comp, comp->FullKeypath, comp->RefCount );
3292}
3293
3295{
3296 if (comp->assembly)
3297 {
3298 DWORD len = lstrlenW( L"<\\" ) + lstrlenW( comp->assembly->display_name );
3299 WCHAR *keypath = malloc( (len + 1) * sizeof(WCHAR) );
3300
3301 if (keypath)
3302 {
3303 lstrcpyW( keypath, L"<\\" );
3304 lstrcatW( keypath, comp->assembly->display_name );
3305 }
3306 return keypath;
3307 }
3308 return resolve_keypath( package, comp );
3309}
3310
3312{
3313 WCHAR squashed_pc[SQUASHED_GUID_SIZE], squashed_cc[SQUASHED_GUID_SIZE];
3314 UINT rc;
3315 MSICOMPONENT *comp;
3316 HKEY hkey;
3317
3318 TRACE("\n");
3319
3321
3322 if (package->script == SCRIPT_NONE)
3323 return msi_schedule_action(package, SCRIPT_INSTALL, L"ProcessComponents");
3324
3325 squash_guid( package->ProductCode, squashed_pc );
3326
3328 {
3329 MSIRECORD *uirow;
3331
3332 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3333 if (!comp->ComponentId)
3334 continue;
3335
3336 squash_guid( comp->ComponentId, squashed_cc );
3337 free( comp->FullKeypath );
3338 comp->FullKeypath = build_full_keypath( package, comp );
3339
3340 refcount_component( package, comp );
3341
3342 if (package->need_rollback) action = comp->Installed;
3343 else action = comp->ActionRequest;
3344
3345 TRACE("Component %s (%s) Keypath=%s RefCount=%u Clients=%u Action=%u\n",
3346 debugstr_w(comp->Component), debugstr_w(squashed_cc),
3347 debugstr_w(comp->FullKeypath), comp->RefCount, comp->num_clients, action);
3348
3350 {
3351 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3352 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, L"S-1-5-18", &hkey, TRUE);
3353 else
3355
3356 if (rc != ERROR_SUCCESS)
3357 continue;
3358
3360 {
3361 msi_reg_set_val_str(hkey, L"00000000000000000000000000000000", comp->FullKeypath);
3362 }
3364 msi_reg_set_val_str( hkey, squashed_pc, comp->FullKeypath );
3365 else
3366 {
3367 MSIFILE *file;
3368 MSIRECORD *row;
3369 LPWSTR ptr, ptr2;
3372 LPWSTR sourcepath;
3373
3374 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3375 continue;
3376
3377 if (!(row = MSI_QueryGetRecord(package->db, L"SELECT * FROM `Media` WHERE `LastSequence` >= %d "
3378 L"ORDER BY `DiskId`", file->Sequence)))
3379 return ERROR_FUNCTION_FAILED;
3380
3382 ptr2 = wcsrchr(source, '\\') + 1;
3383 msiobj_release(&row->hdr);
3384
3385 lstrcpyW(base, package->PackagePath);
3386 ptr = wcsrchr(base, '\\');
3387 *(ptr + 1) = '\0';
3388
3389 sourcepath = msi_resolve_file_source(package, file);
3390 ptr = sourcepath + lstrlenW(base);
3391 lstrcpyW(ptr2, ptr);
3392 free(sourcepath);
3393
3394 msi_reg_set_val_str( hkey, squashed_pc, source );
3395 }
3396 RegCloseKey(hkey);
3397 }
3398 else if (action == INSTALLSTATE_ABSENT)
3399 {
3400 if (comp->num_clients <= 0)
3401 {
3402 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3403 rc = MSIREG_DeleteUserDataComponentKey( comp->ComponentId, L"S-1-5-18" );
3404 else
3406
3407 if (rc != ERROR_SUCCESS) WARN( "failed to delete component key %u\n", rc );
3408 }
3409 else
3410 {
3411 LONG res;
3412
3413 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3414 rc = MSIREG_OpenUserDataComponentKey( comp->ComponentId, L"S-1-5-18", &hkey, FALSE );
3415 else
3417
3418 if (rc != ERROR_SUCCESS)
3419 {
3420 WARN( "failed to open component key %u\n", rc );
3421 continue;
3422 }
3423 res = RegDeleteValueW( hkey, squashed_pc );
3424 RegCloseKey(hkey);
3425 if (res) WARN( "failed to delete component value %ld\n", res );
3426 }
3427 }
3428
3429 /* UI stuff */
3430 uirow = MSI_CreateRecord(3);
3431 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3432 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3433 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3435 msiobj_release( &uirow->hdr );
3436 }
3437 return ERROR_SUCCESS;
3438}
3439
3441{
3446};
3447
3449 LPWSTR lpszName, LONG_PTR lParam)
3450{
3451 TLIBATTR *attr;
3452 struct typelib *tl_struct = (struct typelib *)lParam;
3453 int sz;
3454 HRESULT res;
3455
3456 if (!IS_INTRESOURCE(lpszName))
3457 {
3458 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3459 return TRUE;
3460 }
3461
3462 sz = lstrlenW(tl_struct->source)+4;
3463
3464 if ((INT_PTR)lpszName == 1)
3465 tl_struct->path = wcsdup(tl_struct->source);
3466 else
3467 {
3468 tl_struct->path = malloc(sz * sizeof(WCHAR));
3469#ifdef __REACTOS__
3470 swprintf(tl_struct->path, sz, L"%s\\%d", tl_struct->source, (WORD)(INT_PTR)lpszName);
3471#else
3472 swprintf(tl_struct->path, sz, L"%s\\%d", tl_struct->source, lpszName);
3473#endif
3474 }
3475
3476 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3477 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3478 if (FAILED(res))
3479 {
3480 free(tl_struct->path);
3481 tl_struct->path = NULL;
3482
3483 return TRUE;
3484 }
3485
3486 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3487 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3488 {
3489 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3490 return FALSE;
3491 }
3492
3493 free(tl_struct->path);
3494 tl_struct->path = NULL;
3495
3496 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3497 ITypeLib_Release(tl_struct->ptLib);
3498
3499 return TRUE;
3500}
3501
3503{
3505 msi_disable_fs_redirection( package );
3507 msi_revert_fs_redirection( package );
3508 return module;
3509}
3510
3511static HRESULT load_typelib( MSIPACKAGE *package, const WCHAR *filename, REGKIND kind, ITypeLib **lib )
3512{
3513 HRESULT hr;
3514 msi_disable_fs_redirection( package );
3515 hr = LoadTypeLibEx( filename, kind, lib );
3516 msi_revert_fs_redirection( package );
3517 return hr;
3518}
3519
3521{
3522 MSIPACKAGE* package = param;
3523 LPCWSTR component;
3524 MSICOMPONENT *comp;
3525 MSIFILE *file;
3526 struct typelib tl_struct;
3527 ITypeLib *tlib;
3529 HRESULT hr;
3530
3531 component = MSI_RecordGetString(row,3);
3532 comp = msi_get_loaded_component(package,component);
3533 if (!comp)
3534 return ERROR_SUCCESS;
3535
3536 comp->Action = msi_get_component_action( package, comp );
3537 if (comp->Action != INSTALLSTATE_LOCAL)
3538 {
3539 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3540 return ERROR_SUCCESS;
3541 }
3542
3543 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3544 {
3545 TRACE("component has no key path\n");
3546 return ERROR_SUCCESS;
3547 }
3549
3550 module = load_library( package, file->TargetPath, LOAD_LIBRARY_AS_DATAFILE );
3551 if (module)
3552 {
3553 LPCWSTR guid;
3555 CLSIDFromString( guid, &tl_struct.clsid);
3556 tl_struct.source = wcsdup( file->TargetPath );
3557 tl_struct.path = NULL;
3558
3560 (LONG_PTR)&tl_struct);
3561
3562 if (tl_struct.path)
3563 {
3564 LPCWSTR helpid, help_path = NULL;
3565 HRESULT res;
3566
3567 helpid = MSI_RecordGetString(row,6);
3568
3569 if (helpid) help_path = msi_get_target_folder( package, helpid );
3570 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3571
3572 if (FAILED(res))
3573 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3574 else
3575 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3576
3577 ITypeLib_Release(tl_struct.ptLib);
3578 free(tl_struct.path);
3579 }
3580 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3581
3583 free(tl_struct.source);
3584 }
3585 else
3586 {
3587 hr = load_typelib( package, file->TargetPath, REGKIND_REGISTER, &tlib );
3588 if (FAILED(hr))
3589 {
3590 ERR( "failed to load type library: %#lx\n", hr );
3591 return ERROR_INSTALL_FAILURE;
3592 }
3593
3594 ITypeLib_Release(tlib);
3595 }
3596
3597 return ERROR_SUCCESS;
3598}
3599
3601{
3602 MSIQUERY *view;
3603 UINT rc;
3604
3605 if (package->script == SCRIPT_NONE)
3606 return msi_schedule_action(package, SCRIPT_INSTALL, L"RegisterTypeLibraries");
3607
3608 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `TypeLib`", &view);
3609 if (rc != ERROR_SUCCESS)
3610 return ERROR_SUCCESS;
3611
3613 msiobj_release(&view->hdr);
3614 return rc;
3615}
3616
3618{
3619 MSIPACKAGE *package = param;
3620 LPCWSTR component, guid;
3621 MSICOMPONENT *comp;
3622 GUID libid;
3623 UINT version;
3624 LCID language;
3625 SYSKIND syskind;
3626 HRESULT hr;
3627
3628 component = MSI_RecordGetString( row, 3 );
3629 comp = msi_get_loaded_component( package, component );
3630 if (!comp)
3631 return ERROR_SUCCESS;
3632
3633 comp->Action = msi_get_component_action( package, comp );
3634 if (comp->Action != INSTALLSTATE_ABSENT)
3635 {
3636 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3637 return ERROR_SUCCESS;
3638 }
3640
3642 CLSIDFromString( guid, &libid );
3644 language = MSI_RecordGetInteger( row, 2 );
3645
3646#ifdef _WIN64
3647 syskind = SYS_WIN64;
3648#else
3649 syskind = SYS_WIN32;
3650#endif
3651
3652 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3653 if (FAILED(hr))
3654 {
3655 WARN( "failed to unregister typelib: %#lx\n", hr );
3656 }
3657
3658 return ERROR_SUCCESS;
3659}
3660
3662{
3663 MSIQUERY *view;
3664 UINT rc;
3665
3666 if (package->script == SCRIPT_NONE)
3667 return msi_schedule_action(package, SCRIPT_INSTALL, L"UnregisterTypeLibraries");
3668
3669 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `TypeLib`", &view );
3670 if (rc != ERROR_SUCCESS)
3671 return ERROR_SUCCESS;
3672
3674 msiobj_release( &view->hdr );
3675 return rc;
3676}
3677
3679{
3680 LPCWSTR directory, extension, link_folder;
3681 WCHAR *link_file = NULL, *filename, *new_filename;
3682
3684 link_folder = msi_get_target_folder( package, directory );
3685 if (!link_folder)
3686 {
3687 ERR("unable to resolve folder %s\n", debugstr_w(directory));
3688 return NULL;
3689 }
3690 /* may be needed because of a bug somewhere else */
3691 msi_create_full_path( package, link_folder );
3692
3694 if (!filename) return NULL;
3696
3697 extension = wcsrchr( filename, '.' );
3698 if (!extension || wcsicmp( extension, L".lnk" ))
3699 {
3700 int len = lstrlenW( filename );
3701 new_filename = realloc( filename, len * sizeof(WCHAR) + sizeof(L".lnk") );
3702 if (!new_filename) goto done;
3703 filename = new_filename;
3704 memcpy( filename + len, L".lnk", sizeof(L".lnk") );
3705 }
3706 link_file = msi_build_directory_name( 2, link_folder, filename );
3707
3708done:
3709 free( filename );
3710 return link_file;
3711}
3712
3713WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3714{
3715 WCHAR *folder, *dest, *path;
3716
3717 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3718 folder = msi_dup_property( package->db, L"WindowsFolder" );
3719 else
3720 {
3721 WCHAR *appdata = msi_dup_property( package->db, L"AppDataFolder" );
3722 folder = msi_build_directory_name( 2, appdata, L"Microsoft\\" );
3723 free( appdata );
3724 }
3725 dest = msi_build_directory_name( 3, folder, L"Installer\\", package->ProductCode );
3726 msi_create_full_path( package, dest );
3727 path = msi_build_directory_name( 2, dest, icon_name );
3728 free( folder );
3729 free( dest );
3730 return path;
3731}
3732
3734{
3735 MSIPACKAGE *package = param;
3736 LPWSTR link_file, deformated, path;
3737 LPCWSTR component, target;
3738 MSICOMPONENT *comp;
3739 IShellLinkW *sl = NULL;
3740 IPersistFile *pf = NULL;
3741 HRESULT res;
3742
3743 component = MSI_RecordGetString(row, 4);
3744 comp = msi_get_loaded_component(package, component);
3745 if (!comp)
3746 return ERROR_SUCCESS;
3747
3748 comp->Action = msi_get_component_action( package, comp );
3749 if (comp->Action != INSTALLSTATE_LOCAL)
3750 {
3751 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3752 return ERROR_SUCCESS;
3753 }
3755
3756 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3757 &IID_IShellLinkW, (LPVOID *) &sl );
3758
3759 if (FAILED( res ))
3760 {
3761 ERR("CLSID_ShellLink not available\n");
3762 goto err;
3763 }
3764
3765 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3766 if (FAILED( res ))
3767 {
3768 ERR("QueryInterface(IID_IPersistFile) failed\n");
3769 goto err;
3770 }
3771
3773 if (wcschr(target, '['))
3774 {
3775 deformat_string( package, target, &path );
3776 TRACE("target path is %s\n", debugstr_w(path));
3777 IShellLinkW_SetPath( sl, path );
3778 free( path );
3779 }
3780 else
3781 {
3782 FIXME("poorly handled shortcut format, advertised shortcut\n");
3783 path = resolve_keypath( package, comp );
3784 IShellLinkW_SetPath( sl, path );
3785 free( path );
3786 }
3787
3788 if (!MSI_RecordIsNull(row,6))
3789 {
3790 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3791 deformat_string(package, arguments, &deformated);
3792 IShellLinkW_SetArguments(sl,deformated);
3793 free(deformated);
3794 }
3795
3796 if (!MSI_RecordIsNull(row,7))
3797 {
3799 IShellLinkW_SetDescription(sl, description);
3800 }
3801
3802 if (!MSI_RecordIsNull(row,8))
3803 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3804
3805 if (!MSI_RecordIsNull(row,9))
3806 {
3807 INT index;
3808 LPCWSTR icon = MSI_RecordGetString(row, 9);
3809
3810 path = msi_build_icon_path(package, icon);