ReactOS  0.4.15-dev-4853-g3a72a52
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 
68  row = MSI_CreateRecord(3);
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 
79 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start,
80  INT rc)
81 {
82  MSIRECORD *row;
83  WCHAR *template;
84 
86 
87  row = MSI_CreateRecord(2);
88  if (!row)
89  {
90  msi_free(template);
91  return;
92  }
93  MSI_RecordSetStringW(row, 0, template);
95  MSI_RecordSetInteger(row, 2, start ? package->LastActionResult : rc);
97  msiobj_release(&row->hdr);
98  msi_free(template);
99  if (!start) package->LastActionResult = rc;
100 }
101 
103 {
107 };
108 
109 static 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 '"':
131  state = state_quote;
132  if (in_quotes && p[1] != '\"') count--;
133  else count++;
134  break;
135  default:
136  state = state_token;
137  in_quotes = TRUE;
138  len++;
139  break;
140  }
141  break;
142 
143  case state_token:
144  switch (*p)
145  {
146  case '"':
147  state = state_quote;
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:
178  state = state_token;
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 
191 done:
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 
202 static 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  }
258  remove_quotes( val );
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 {
393  return (package->ui_level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
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");
420  return ERROR_FUNCTION_FAILED;
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 
437  if (rc == ERROR_FUNCTION_NOT_CALLED)
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",
446  debugstr_w(action));
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  {
462  r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
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 );
488  rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
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");
505  rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
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)
521  return ERROR_INSTALL_USEREXIT;
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 
556  LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
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 
578  LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
579  {
580  if (!wcscmp( key, file->File )) return file;
581  }
582  return NULL;
583 }
584 
586 {
587  MSIFOLDER *folder;
588 
590  {
591  if (!wcscmp( dir, folder->Directory )) return folder;
592  }
593  return NULL;
594 }
595 
596 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
597 {
598  MSIRECORD *row;
599 
600  row = MSI_CreateRecord( 4 );
601  MSI_RecordSetInteger( row, 1, a );
602  MSI_RecordSetInteger( row, 2, b );
603  MSI_RecordSetInteger( row, 3, c );
604  MSI_RecordSetInteger( row, 4, d );
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));
616  return INSTALLSTATE_UNKNOWN;
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);
622  return INSTALLSTATE_UNKNOWN;
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;
638  MSIFOLDER *folder;
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 );
678  folder->State = FOLDER_STATE_CREATED;
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 
704  LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
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;
719  MSIFOLDER *folder;
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 
737  dir = MSI_RecordGetString( row, 1 );
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)
786  return ERROR_FUNCTION_FAILED;
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 
826 typedef 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 {
846  FeatureList *fl;
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 
906  feature->Level= MSI_RecordGetInteger(row,6);
907  feature->Directory = msi_dup_record_field( row, 7 );
908  feature->Attributes = MSI_RecordGetInteger(row,8);
909 
910  feature->Installed = INSTALLSTATE_UNKNOWN;
911  feature->Action = 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)
938  return ERROR_FUNCTION_FAILED;
939 
940  if (!child->Feature_Parent)
941  return ERROR_SUCCESS;
942 
943  parent = msi_get_loaded_feature( package, child->Feature_Parent );
944  if (!parent)
945  return ERROR_FUNCTION_FAILED;
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 
1011 done:
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)
1042  return ERROR_NOT_ENOUGH_MEMORY;
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 
1127 static UINT load_all_media( MSIPACKAGE *package )
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)
1164  return ERROR_NOT_ENOUGH_MEMORY;
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 
1216  name = MSI_RecordGetString( row, 1 );
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 
1228 static void mark_patched_components( MSIPACKAGE *package )
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;
1281  MSIFOLDER *folder;
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 );
1287  p = msi_dup_record_field(row, 3);
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;
1345  MSIFOLDER *parent, *child;
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 
1434  msi_free_action_script(package, script);
1435  return rc;
1436 }
1437 
1439 {
1440  return ERROR_SUCCESS;
1441 }
1442 
1443 static void get_client_counts( MSIPACKAGE *package )
1444 {
1445  MSICOMPONENT *comp;
1446  HKEY hkey;
1447 
1448  LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
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 
1569 static BOOL process_overrides( MSIPACKAGE *package, int level )
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  {
1679  if (feature->Attributes & msidbFeatureAttributesFavorSource)
1680  {
1681  feature->Action = INSTALLSTATE_SOURCE;
1682  feature->ActionRequest = INSTALLSTATE_SOURCE;
1683  }
1684  else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1685  {
1686  feature->Action = INSTALLSTATE_ADVERTISED;
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  {
1786  case INSTALLSTATE_ABSENT:
1787  component->anyAbsent = 1;
1788  break;
1790  component->hasAdvertisedFeature = 1;
1791  break;
1792  case INSTALLSTATE_SOURCE:
1793  component->hasSourceFeature = 1;
1794  break;
1795  case INSTALLSTATE_LOCAL:
1796  component->hasLocalFeature = 1;
1797  break;
1798  case INSTALLSTATE_DEFAULT:
1800  component->hasAdvertisedFeature = 1;
1801  else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1802  component->hasSourceFeature = 1;
1803  else
1804  component->hasLocalFeature = 1;
1805  break;
1806  case INSTALLSTATE_UNKNOWN:
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  {
1826  if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1827  !component->ForceLocalState)
1828  {
1829  component->Action = INSTALLSTATE_SOURCE;
1830  component->ActionRequest = 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;
1850  component->ActionRequest = 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;
1863  component->ActionRequest = 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;
1881  component->ActionRequest = 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 
1910  name = MSI_RecordGetString( row, 1 );
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  {
1922  int level = MSI_RecordGetInteger(row,2);
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 
1943 int 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 
2042 static 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 
2067  LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2068  {
2069  MSICOMPONENT *comp = file->Component;
2070  DWORD file_size;
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 
2178 void 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 
2214  LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
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 
2227  LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
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");
2245  LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
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 
2335 static BYTE *parse_value( MSIPACKAGE *package, const WCHAR *value, DWORD len, DWORD *type, DWORD *size )
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--;
2434  *type = REG_EXPAND_SZ;
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 
2444 static 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 
2486 static 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 
2585 static 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 {
2612 };
2613 
2614 static 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  {
2652  op = JOIN_OP_APPEND;
2653  new_len--;
2654  new_ptr++;
2655  }
2656  else if (new_ptr[0] && !new_ptr[new_len - 1])
2657  {
2658  op = JOIN_OP_PREPEND;
2659  new_len--;
2660  }
2661  else if (new_len > 2 && !new_ptr[0] && !new_ptr[new_len - 1])
2662  {
2663  op = JOIN_OP_REPLACE;
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 
2683 static 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 
2731  key = MSI_RecordGetString(row, 3);
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 );
2750  str = msi_record_get_string( row, 5, NULL );
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  {
2765  msi_free( old_value );
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 
2823 static 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);
2833  RegCloseKey(key);
2834 
2835  return !res && !subkeys && !values;
2836 }
2837 
2838 static void delete_key( const MSICOMPONENT *comp, HKEY root, const WCHAR *path )
2839 {
2841  REGSAM access = get_registry_view( comp );
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 
2873 static 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 
2892 static 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;
2911  BOOL delete_key = FALSE;
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 
2930  name = MSI_RecordGetString( row, 4 );
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 
2942  root = MSI_RecordGetInteger( row, 2 );
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;
2979  BOOL delete_key = FALSE;
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 
3005  root = MSI_RecordGetInteger( row, 2 );
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  }
3088  LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3090 
3091  LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
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 
3152  if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
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 
3164  key = MSI_RecordGetString(row, 3);
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 {
3218  HKEY hkey = open_shared_dlls_key( comp, TRUE, KEY_SET_VALUE );
3219  if (count > 0)
3220  msi_reg_set_val_dword( hkey, path, count );
3221  else
3222  RegDeleteValueW( hkey, path );
3223  RegCloseKey(hkey);
3224 }
3225 
3226 static 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 
3279  LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
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 
3322  msi_set_sourcedir_props(package, FALSE);
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 
3329  LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
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  }
3365  if (action == INSTALLSTATE_LOCAL)
3366  msi_reg_set_val_str( hkey, squashed_pc, comp->FullKeypath );
3367  else
3368  {
3369  MSIFILE *file;
3370  MSIRECORD *row;
3371  LPWSTR ptr, ptr2;
3373  WCHAR base[MAX_PATH];
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
3418  rc = MSIREG_OpenUserDataComponentKey( comp->ComponentId, NULL, &hkey, FALSE );
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 
3442 typedef struct {
3445 
3448 } typelib_struct;
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 {
3506  HMODULE module;
3507  msi_disable_fs_redirection( package );
3509  msi_revert_fs_redirection( package );
3510  return module;
3511 }
3512 
3513 static 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;
3530  HMODULE module;
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 
3643  guid = MSI_RecordGetString( row, 1 );
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 
3711 WCHAR *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,MSI_RecordGetInteger(row,11));
3821 
3822  if (!MSI_RecordIsNull(row,12))
3823  {
3824  LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3825  full_path = msi_get_target_folder( package, wkdir );
3826  if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3827  }
3828 
3829  link_file = get_link_file(package, row);
3830  TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3831 
3832  msi_disable_fs_redirection( package );
3833  IPersistFile_Save(pf, link_file, FALSE);
3834  msi_revert_fs_redirection( package );
3835 
3836  msi_free(link_file);
3837 
3838 err:
3839  if (pf)
3840  IPersistFile_Release( pf );
3841  if (sl)
3842  IShellLinkW_Release( sl );
3843 
3844  return ERROR_SUCCESS;
3845 }
3846 
3848 {
3849  MSIQUERY *view;
3850  HRESULT res;
3851  UINT rc;
3852 
3853  if (package->script == SCRIPT_NONE)
3854  return msi_schedule_action(package, SCRIPT_INSTALL, L"CreateShortcuts");
3855 
3856  rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `Shortcut`", &view);
3857  if (rc != ERROR_SUCCESS)
3858  return ERROR_SUCCESS;
3859 
3860  res = CoInitialize( NULL );
3861 
3863  msiobj_release(&view->hdr);
3864 
3865  if (SUCCEEDED(res)) CoUninitialize();
3866  return rc;
3867 }
3868 
3870 {
3871  MSIPACKAGE *package = param;
3872  LPWSTR link_file;
3873  LPCWSTR component;
3874  MSICOMPONENT *comp;
3875 
3876  component = MSI_RecordGetString( row, 4 );
3877  comp = msi_get_loaded_component( package, component );
3878  if (!comp)
3879  return ERROR_SUCCESS;
3880 
3881  comp->Action = msi_get_component_action( package, comp );
3882  if (comp->Action != INSTALLSTATE_ABSENT)
3883  {
3884  TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3885  return ERROR_SUCCESS;
3886  }
3888 
3889  link_file = get_link_file( package, row );
3890  TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3891  if (!msi_delete_file( package, link_file )) WARN( "failed to remove shortcut file %lu\n", GetLastError() );
3892  msi_free( link_file );
3893 
3894  return ERROR_SUCCESS;
3895 }
3896 
3898 {
3899  MSIQUERY *view;
3900  UINT rc;
3901 
3902  if (package->script == SCRIPT_NONE)
3903  return msi_schedule_action(package, SCRIPT_INSTALL, L"RemoveShortcuts");
3904 
3905  rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Shortcut`", &view );
3906  if (rc != ERROR_SUCCESS)
3907  return ERROR_SUCCESS;
3908 
3910  msiobj_release( &view->hdr );
3911  return rc;
3912 }
3913 
3915 {
3916  MSIPACKAGE *package = param;
3917  HANDLE handle;
3918  WCHAR *icon_path;
3919  const WCHAR *filename;
3920  char buffer[1024];
3921  DWORD sz;
3922  UINT rc;
3923 
3925  if (!filename)
3926  {
3927  ERR("Unable to get filename\n");
3928  return ERROR_SUCCESS;
3929  }
3930 
3931  icon_path = msi_build_icon_path( package, filename );
3932 
3933  TRACE("Creating icon file at %s\n", debugstr_w(icon_path));
3934 
3937  {
3938  ERR("Unable to create file %s\n", debugstr_w(icon_path));
3939  msi_free( icon_path );
3940  return ERROR_SUCCESS;
3941  }
3942 
3943  do
3944  {
3945  DWORD count;
3946  sz = 1024;
3947  rc = MSI_RecordReadStream( row, 2, buffer, &sz );
3948  if (rc != ERROR_SUCCESS)
3949  {
3950  ERR("Failed to get stream\n");
3951  msi_delete_file( package, icon_path );
3952  break;
3953  }
3954  WriteFile( handle, buffer, sz, &count, NULL );
3955  } while (sz == 1024);
3956 
3957  msi_free( icon_path );
3958  CloseHandle( handle );
3959 
3960  return ERROR_SUCCESS;
3961 }
3962 
3964 {
3965  MSIQUERY *view;
3966  UINT r;
3967 
3968  r = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `Icon`", &view);
3969  if (r == ERROR_SUCCESS)
3970  {
3972  msiobj_release(&view->hdr);
3973  if (r != ERROR_SUCCESS)
3974  return r;
3975  }
3976  return ERROR_SUCCESS;
3977 }
3978 
3980 {
3981  UINT r;
3982  HKEY source;
3983  LPWSTR buffer;
3984  MSIMEDIADISK *disk;
3986 
3987  r = RegCreateKeyW(hkey, L"SourceList", &source);
3988  if (r != ERROR_SUCCESS)
3989  return r;
3990 
3992 
3993  buffer = wcsrchr(package->PackagePath, '\\') + 1;
3995  package->Context, MSICODE_PRODUCT,
3997  if (r != ERROR_SUCCESS)
3998  return r;
3999 
4001  package->Context, MSICODE_PRODUCT,
4003  if (r != ERROR_SUCCESS)
4004  return r;
4005 
4007  package->Context, MSICODE_PRODUCT,
4009  if (r != ERROR_SUCCESS)
4010  return r;
4011 
4013  {
4014  if (!wcscmp( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
4015  msi_set_last_used_source(package->ProductCode, NULL, info->context,
4016  info->options, info->value);
4017  else
4019  info->context, info->options,
4020  info->property, info->value);
4021  }
4022 
4024  {
4026  disk->context, disk->options,
4027  disk->disk_id, disk->volume_label, disk->disk_prompt);
4028  }
4029 
4030  return ERROR_SUCCESS;
4031 }
4032 
4034 {
4035  WCHAR *buffer, *ptr, *guids, packcode[SQUASHED_GUID_SIZE];
4036  DWORD langid;
4037 
4040  msi_free(buffer);
4041 
4042  langid = msi_get_property_int(package->db, L"ProductLanguage", 0);
4044 
4045  /* FIXME */
4047 
4048  buffer = msi_dup_property(package->db, L"ARPPRODUCTICON");
4049  if (buffer)
4050  {
4051  LPWSTR path = msi_build_icon_path(package, buffer);
4053  msi_free(path);
4054  msi_free(buffer);
4055  }
4056 
4057  buffer = msi_dup_property(package->db, L"ProductVersion");
4058  if (buffer)
4059  {
4062  msi_free(buffer);
4063  }
4064 
4065  msi_reg_set_val_dword(hkey, L"Assignment", 0);
4066  msi_reg_set_val_dword(hkey, L"AdvertiseFlags", 0x184);
4068  msi_reg_set_val_multi_str(hkey, L"Clients", L":\0");
4069 
4070  if (!(guids = msi_get_package_code(package->db))) return ERROR_OUTOFMEMORY;
4071  if ((ptr = wcschr(guids, ';'))) *ptr = 0;
4072  squash_guid(guids, packcode);
4073  msi_free( guids);
4075 
4076  return ERROR_SUCCESS;
4077 }
4078 
4080 {
4081  UINT r;
4082  HKEY hkey;
4083  WCHAR *upgrade, squashed_pc[SQUASHED_GUID_SIZE];
4084 
4085  upgrade = msi_dup_property(package->db, L"UpgradeCode");
4086  if (!upgrade)
4087  return ERROR_SUCCESS;
4088 
4089  if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4090  r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
4091  else
4092  r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4093 
4094  if (r != ERROR_SUCCESS)
4095  {
4096  WARN("failed to open upgrade code key\n");
4097  msi_free(upgrade);
4098  return ERROR_SUCCESS;
4099  }
4100  squash_guid(package->ProductCode, squashed_pc);
4101  msi_reg_set_val_str(hkey, squashed_pc, NULL);
4102  RegCloseKey(hkey);
4103  msi_free(upgrade);
4104  return ERROR_SUCCESS;
4105 }
4106 
4108 {
4110 
4112  {
4113  feature->Action = msi_get_feature_action( package, feature );
4114  if (feature->Action == INSTALLSTATE_LOCAL || feature->Action == INSTALLSTATE_SOURCE)
4115  return TRUE;
4116  }
4117 
4118  return FALSE;
4119 }
4120 
4122 {
4124 
4125  LIST_FOR_EACH_ENTRY(feature, &package->features,