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