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