1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
3 *
4 * Copyright 2004,2005 Aric Stewart for CodeWeavers
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winerror.h"
28 #include "winreg.h"
29 #include "winsvc.h"
30 #include "odbcinst.h"
31 #include "wine/debug.h"
32 #include "msidefs.h"
33 #include "winuser.h"
34 #include "shlobj.h"
35 #include "objbase.h"
36 #include "mscoree.h"
37 #include "shlwapi.h"
38 #include "imagehlp.h"
39 #include "winver.h"
40
41 #include "msipriv.h"
42 #include "resource.h"
43
44 #define REG_PROGRESS_VALUE 13200
45 #define COMPONENT_PROGRESS_VALUE 24000
46
47 WINE_DEFAULT_DEBUG_CHANNEL(msi);
48
49 struct dummy_thread
50 {
51 HANDLE started;
52 HANDLE stopped;
53 HANDLE thread;
54 };
55
ui_actionstart(MSIPACKAGE * package,LPCWSTR action,LPCWSTR description,LPCWSTR template)56 static INT ui_actionstart(MSIPACKAGE *package, LPCWSTR action, LPCWSTR description, LPCWSTR template)
57 {
58 MSIRECORD *row, *textrow;
59 INT rc;
60
61 textrow = MSI_QueryGetRecord(package->db, L"SELECT * FROM `ActionText` WHERE `Action` = '%s'", action);
62 if (textrow)
63 {
64 description = MSI_RecordGetString(textrow, 2);
65 template = MSI_RecordGetString(textrow, 3);
66 }
67
68 row = MSI_CreateRecord(3);
69 if (!row) return -1;
70 MSI_RecordSetStringW(row, 1, action);
71 MSI_RecordSetStringW(row, 2, description);
72 MSI_RecordSetStringW(row, 3, template);
73 rc = MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
74 if (textrow) msiobj_release(&textrow->hdr);
75 msiobj_release(&row->hdr);
76 return rc;
77 }
78
ui_actioninfo(MSIPACKAGE * package,const WCHAR * action,BOOL start,INT rc)79 static void ui_actioninfo(MSIPACKAGE *package, const WCHAR *action, BOOL start, INT rc)
80 {
81 MSIRECORD *row;
82 WCHAR *template;
83
84 template = msi_get_error_message(package->db, start ? MSIERR_INFO_ACTIONSTART : MSIERR_INFO_ACTIONENDED);
85
86 row = MSI_CreateRecord(2);
87 if (!row)
88 {
89 free(template);
90 return;
91 }
92 MSI_RecordSetStringW(row, 0, template);
93 MSI_RecordSetStringW(row, 1, action);
94 MSI_RecordSetInteger(row, 2, start ? package->LastActionResult : rc);
95 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
96 msiobj_release(&row->hdr);
97 free(template);
98 if (!start) package->LastActionResult = rc;
99 }
100
101 enum parse_state
102 {
103 state_whitespace,
104 state_token,
105 state_quote
106 };
107
parse_prop(const WCHAR * str,WCHAR * value,int * quotes)108 static int parse_prop( const WCHAR *str, WCHAR *value, int *quotes )
109 {
110 enum parse_state state = state_quote;
111 const WCHAR *p;
112 WCHAR *out = value;
113 BOOL ignore, in_quotes = FALSE;
114 int count = 0, len = 0;
115
116 for (p = str; *p; p++)
117 {
118 ignore = FALSE;
119 switch (state)
120 {
121 case state_whitespace:
122 switch (*p)
123 {
124 case ' ':
125 in_quotes = TRUE;
126 ignore = TRUE;
127 len++;
128 break;
129 case '"':
130 state = state_quote;
131 if (in_quotes && p[1] != '\"') count--;
132 else count++;
133 break;
134 default:
135 state = state_token;
136 in_quotes = TRUE;
137 len++;
138 break;
139 }
140 break;
141
142 case state_token:
143 switch (*p)
144 {
145 case '"':
146 state = state_quote;
147 if (in_quotes) count--;
148 else count++;
149 break;
150 case ' ':
151 state = state_whitespace;
152 if (!count) goto done;
153 in_quotes = TRUE;
154 len++;
155 break;
156 default:
157 if (count) in_quotes = TRUE;
158 len++;
159 break;
160 }
161 break;
162
163 case state_quote:
164 switch (*p)
165 {
166 case '"':
167 if (in_quotes && p[1] != '\"') count--;
168 else count++;
169 break;
170 case ' ':
171 state = state_whitespace;
172 if (!count || (count > 1 && !len)) goto done;
173 in_quotes = TRUE;
174 len++;
175 break;
176 default:
177 state = state_token;
178 if (count) in_quotes = TRUE;
179 len++;
180 break;
181 }
182 break;
183
184 default: break;
185 }
186 if (!ignore && value) *out++ = *p;
187 if (!count) in_quotes = FALSE;
188 }
189
190 done:
191 if (value)
192 {
193 if (!len) *value = 0;
194 else *out = 0;
195 }
196
197 if(quotes) *quotes = count;
198 return p - str;
199 }
200
remove_quotes(WCHAR * str)201 static void remove_quotes( WCHAR *str )
202 {
203 WCHAR *p = str;
204 int len = lstrlenW( str );
205
206 while ((p = wcschr( p, '"' )))
207 {
208 memmove( p, p + 1, (len - (p - str)) * sizeof(WCHAR) );
209 p++;
210 }
211 }
212
msi_parse_command_line(MSIPACKAGE * package,LPCWSTR szCommandLine,BOOL preserve_case)213 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
214 BOOL preserve_case )
215 {
216 LPCWSTR ptr, ptr2;
217 int num_quotes;
218 DWORD len;
219 WCHAR *prop, *val;
220 UINT r;
221
222 if (!szCommandLine)
223 return ERROR_SUCCESS;
224
225 ptr = szCommandLine;
226 while (*ptr)
227 {
228 while (*ptr == ' ') ptr++;
229 if (!*ptr) break;
230
231 ptr2 = wcschr( ptr, '=' );
232 if (!ptr2) return ERROR_INVALID_COMMAND_LINE;
233
234 len = ptr2 - ptr;
235 if (!len) return ERROR_INVALID_COMMAND_LINE;
236
237 while (ptr[len - 1] == ' ') len--;
238
239 prop = malloc( (len + 1) * sizeof(WCHAR) );
240 memcpy( prop, ptr, len * sizeof(WCHAR) );
241 prop[len] = 0;
242 if (!preserve_case) wcsupr( prop );
243
244 ptr2++;
245 while (*ptr2 == ' ') ptr2++;
246
247 num_quotes = 0;
248 val = malloc( (wcslen( ptr2 ) + 1) * sizeof(WCHAR) );
249 len = parse_prop( ptr2, val, &num_quotes );
250 if (num_quotes % 2)
251 {
252 WARN("unbalanced quotes\n");
253 free( val );
254 free( prop );
255 return ERROR_INVALID_COMMAND_LINE;
256 }
257 remove_quotes( val );
258 TRACE("Found commandline property %s = %s\n", debugstr_w(prop), debugstr_w(val));
259
260 r = msi_set_property( package->db, prop, val, -1 );
261 if (r == ERROR_SUCCESS && !wcscmp( prop, L"SourceDir" ))
262 msi_reset_source_folders( package );
263
264 free( val );
265 free( prop );
266
267 ptr = ptr2 + len;
268 }
269
270 return ERROR_SUCCESS;
271 }
272
msi_get_command_line_option(const WCHAR * cmd,const WCHAR * option,UINT * len)273 const WCHAR *msi_get_command_line_option(const WCHAR *cmd, const WCHAR *option, UINT *len)
274 {
275 DWORD opt_len = lstrlenW(option);
276
277 if (!cmd)
278 return NULL;
279
280 while (*cmd)
281 {
282 BOOL found = FALSE;
283
284 while (*cmd == ' ') cmd++;
285 if (!*cmd) break;
286
287 if(!wcsnicmp(cmd, option, opt_len))
288 found = TRUE;
289
290 cmd = wcschr( cmd, '=' );
291 if(!cmd) break;
292 cmd++;
293 while (*cmd == ' ') cmd++;
294 if (!*cmd) break;
295
296 *len = parse_prop( cmd, NULL, NULL);
297 if (found) return cmd;
298 cmd += *len;
299 }
300
301 return NULL;
302 }
303
msi_split_string(const WCHAR * str,WCHAR sep)304 WCHAR **msi_split_string( const WCHAR *str, WCHAR sep )
305 {
306 LPCWSTR pc;
307 LPWSTR p, *ret = NULL;
308 UINT count = 0;
309
310 if (!str)
311 return ret;
312
313 /* count the number of substrings */
314 for ( pc = str, count = 0; pc; count++ )
315 {
316 pc = wcschr( pc, sep );
317 if (pc)
318 pc++;
319 }
320
321 /* allocate space for an array of substring pointers and the substrings */
322 ret = malloc( (count + 1) * sizeof(WCHAR *) + (wcslen(str) + 1) * sizeof(WCHAR) );
323 if (!ret)
324 return ret;
325
326 /* copy the string and set the pointers */
327 p = (LPWSTR) &ret[count+1];
328 lstrcpyW( p, str );
329 for( count = 0; (ret[count] = p); count++ )
330 {
331 p = wcschr( p, sep );
332 if (p)
333 *p++ = 0;
334 }
335
336 return ret;
337 }
338
ui_sequence_exists(MSIPACKAGE * package)339 static BOOL ui_sequence_exists( MSIPACKAGE *package )
340 {
341 MSIQUERY *view;
342 DWORD count = 0;
343
344 if (!(MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `InstallUISequence` WHERE `Sequence` > 0", &view )))
345 {
346 MSI_IterateRecords( view, &count, NULL, package );
347 msiobj_release( &view->hdr );
348 }
349 return count != 0;
350 }
351
msi_set_sourcedir_props(MSIPACKAGE * package,BOOL replace)352 UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
353 {
354 WCHAR *source, *check, *p, *db;
355 DWORD len;
356
357 if (!(db = msi_dup_property( package->db, L"OriginalDatabase" )))
358 return ERROR_OUTOFMEMORY;
359
360 if (!(p = wcsrchr( db, '\\' )) && !(p = wcsrchr( db, '/' )))
361 {
362 free(db);
363 return ERROR_SUCCESS;
364 }
365 len = p - db + 2;
366 source = malloc( len * sizeof(WCHAR) );
367 lstrcpynW( source, db, len );
368 free( db );
369
370 check = msi_dup_property( package->db, L"SourceDir" );
371 if (!check || replace)
372 {
373 UINT r = msi_set_property( package->db, L"SourceDir", source, -1 );
374 if (r == ERROR_SUCCESS)
375 msi_reset_source_folders( package );
376 }
377 free( check );
378
379 check = msi_dup_property( package->db, L"SOURCEDIR" );
380 if (!check || replace)
381 msi_set_property( package->db, L"SOURCEDIR", source, -1 );
382
383 free( check );
384 free( source );
385
386 return ERROR_SUCCESS;
387 }
388
needs_ui_sequence(MSIPACKAGE * package)389 static BOOL needs_ui_sequence(MSIPACKAGE *package)
390 {
391 return (package->ui_level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
392 }
393
msi_set_context(MSIPACKAGE * package)394 UINT msi_set_context(MSIPACKAGE *package)
395 {
396 UINT r = msi_locate_product( package->ProductCode, &package->Context );
397 if (r != ERROR_SUCCESS)
398 {
399 int num = msi_get_property_int( package->db, L"ALLUSERS", 0 );
400 if (num == 1 || num == 2)
401 package->Context = MSIINSTALLCONTEXT_MACHINE;
402 else
403 package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
404 }
405 return ERROR_SUCCESS;
406 }
407
ITERATE_Actions(MSIRECORD * row,LPVOID param)408 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
409 {
410 UINT rc;
411 LPCWSTR cond, action;
412 MSIPACKAGE *package = param;
413
414 action = MSI_RecordGetString(row,1);
415 if (!action)
416 {
417 ERR("Error is retrieving action name\n");
418 return ERROR_FUNCTION_FAILED;
419 }
420
421 /* check conditions */
422 cond = MSI_RecordGetString(row,2);
423
424 /* this is a hack to skip errors in the condition code */
425 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
426 {
427 TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
428 return ERROR_SUCCESS;
429 }
430
431 rc = ACTION_PerformAction(package, action);
432
433 msi_dialog_check_messages( NULL );
434
435 if (rc == ERROR_FUNCTION_NOT_CALLED)
436 rc = ERROR_SUCCESS;
437
438 if (rc != ERROR_SUCCESS)
439 ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
440
441 if (package->need_reboot_now)
442 {
443 TRACE("action %s asked for immediate reboot, suspending installation\n",
444 debugstr_w(action));
445 rc = ACTION_ForceReboot( package );
446 }
447 return rc;
448 }
449
MSI_Sequence(MSIPACKAGE * package,LPCWSTR table)450 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR table )
451 {
452 MSIQUERY *view;
453 UINT r;
454
455 TRACE("%p %s\n", package, debugstr_w(table));
456
457 r = MSI_OpenQuery( package->db, &view, L"SELECT * FROM `%s` WHERE `Sequence` > 0 ORDER BY `Sequence`", table );
458 if (r == ERROR_SUCCESS)
459 {
460 r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
461 msiobj_release(&view->hdr);
462 }
463 return r;
464 }
465
ACTION_ProcessExecSequence(MSIPACKAGE * package)466 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package)
467 {
468 MSIQUERY *view;
469 UINT rc;
470
471 if (package->ExecuteSequenceRun)
472 {
473 TRACE("Execute Sequence already Run\n");
474 return ERROR_SUCCESS;
475 }
476
477 package->ExecuteSequenceRun = TRUE;
478
479 rc = MSI_OpenQuery(package->db, &view,
480 L"SELECT * FROM `InstallExecuteSequence` WHERE `Sequence` > 0 ORDER BY `Sequence`");
481 if (rc == ERROR_SUCCESS)
482 {
483 TRACE("Running the actions\n");
484
485 msi_set_property( package->db, L"SourceDir", NULL, -1 );
486 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
487 msiobj_release(&view->hdr);
488 }
489 return rc;
490 }
491
ACTION_ProcessUISequence(MSIPACKAGE * package)492 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
493 {
494 MSIQUERY *view;
495 UINT rc;
496
497 rc = MSI_DatabaseOpenViewW(package->db,
498 L"SELECT * FROM `InstallUISequence` WHERE `Sequence` > 0 ORDER BY `Sequence`",
499 &view);
500 if (rc == ERROR_SUCCESS)
501 {
502 TRACE("Running the actions\n");
503 rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
504 msiobj_release(&view->hdr);
505 }
506 return rc;
507 }
508
509 /********************************************************
510 * ACTION helper functions and functions that perform the actions
511 *******************************************************/
ACTION_HandleCustomAction(MSIPACKAGE * package,LPCWSTR action)512 static UINT ACTION_HandleCustomAction(MSIPACKAGE *package, LPCWSTR action)
513 {
514 UINT arc;
515 INT uirc;
516
517 uirc = ui_actionstart(package, action, NULL, NULL);
518 if (uirc == IDCANCEL)
519 return ERROR_INSTALL_USEREXIT;
520 ui_actioninfo(package, action, TRUE, 0);
521 arc = ACTION_CustomAction(package, action);
522 uirc = !arc;
523
524 if (arc == ERROR_FUNCTION_NOT_CALLED && needs_ui_sequence(package))
525 {
526 uirc = ACTION_ShowDialog(package, action);
527 switch (uirc)
528 {
529 case -1:
530 return ERROR_SUCCESS; /* stop immediately */
531 case 0: arc = ERROR_FUNCTION_NOT_CALLED; break;
532 case 1: arc = ERROR_SUCCESS; break;
533 case 2: arc = ERROR_INSTALL_USEREXIT; break;
534 case 3: arc = ERROR_INSTALL_FAILURE; break;
535 case 4: arc = ERROR_INSTALL_SUSPEND; break;
536 case 5: arc = ERROR_MORE_DATA; break;
537 case 6: arc = ERROR_INVALID_HANDLE_STATE; break;
538 case 7: arc = ERROR_INVALID_DATA; break;
539 case 8: arc = ERROR_INSTALL_ALREADY_RUNNING; break;
540 case 9: arc = ERROR_INSTALL_PACKAGE_REJECTED; break;
541 default: arc = ERROR_FUNCTION_FAILED; break;
542 }
543 }
544
545 ui_actioninfo(package, action, FALSE, uirc);
546
547 return arc;
548 }
549
msi_get_loaded_component(MSIPACKAGE * package,const WCHAR * Component)550 MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component )
551 {
552 MSICOMPONENT *comp;
553
554 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
555 {
556 if (!wcscmp( Component, comp->Component )) return comp;
557 }
558 return NULL;
559 }
560
msi_get_loaded_feature(MSIPACKAGE * package,const WCHAR * Feature)561 MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature )
562 {
563 MSIFEATURE *feature;
564
565 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
566 {
567 if (!wcscmp( Feature, feature->Feature )) return feature;
568 }
569 return NULL;
570 }
571
msi_get_loaded_file(MSIPACKAGE * package,const WCHAR * key)572 MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key )
573 {
574 MSIFILE *file;
575
576 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
577 {
578 if (!wcscmp( key, file->File )) return file;
579 }
580 return NULL;
581 }
582
msi_get_loaded_folder(MSIPACKAGE * package,const WCHAR * dir)583 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
584 {
585 MSIFOLDER *folder;
586
587 LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
588 {
589 if (!wcscmp( dir, folder->Directory )) return folder;
590 }
591 return NULL;
592 }
593
msi_ui_progress(MSIPACKAGE * package,int a,int b,int c,int d)594 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
595 {
596 MSIRECORD *row;
597
598 row = MSI_CreateRecord( 4 );
599 MSI_RecordSetInteger( row, 1, a );
600 MSI_RecordSetInteger( row, 2, b );
601 MSI_RecordSetInteger( row, 3, c );
602 MSI_RecordSetInteger( row, 4, d );
603 MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row );
604 msiobj_release( &row->hdr );
605
606 msi_dialog_check_messages( NULL );
607 }
608
msi_get_component_action(MSIPACKAGE * package,MSICOMPONENT * comp)609 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp )
610 {
611 if (!comp->Enabled)
612 {
613 TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
614 return INSTALLSTATE_UNKNOWN;
615 }
616 if (package->need_rollback) return comp->Installed;
617 if (comp->num_clients > 0 && comp->ActionRequest == INSTALLSTATE_ABSENT)
618 {
619 TRACE("%s has %u clients left\n", debugstr_w(comp->Component), comp->num_clients);
620 return INSTALLSTATE_UNKNOWN;
621 }
622 return comp->ActionRequest;
623 }
624
msi_get_feature_action(MSIPACKAGE * package,MSIFEATURE * feature)625 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature )
626 {
627 if (package->need_rollback) return feature->Installed;
628 return feature->ActionRequest;
629 }
630
ITERATE_CreateFolders(MSIRECORD * row,LPVOID param)631 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
632 {
633 MSIPACKAGE *package = param;
634 LPCWSTR dir, component, full_path;
635 MSIRECORD *uirow;
636 MSIFOLDER *folder;
637 MSICOMPONENT *comp;
638
639 component = MSI_RecordGetString(row, 2);
640 if (!component)
641 return ERROR_SUCCESS;
642
643 comp = msi_get_loaded_component(package, component);
644 if (!comp)
645 return ERROR_SUCCESS;
646
647 comp->Action = msi_get_component_action( package, comp );
648 if (comp->Action != INSTALLSTATE_LOCAL)
649 {
650 TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
651 return ERROR_SUCCESS;
652 }
653
654 dir = MSI_RecordGetString(row,1);
655 if (!dir)
656 {
657 ERR("Unable to get folder id\n");
658 return ERROR_SUCCESS;
659 }
660
661 uirow = MSI_CreateRecord(1);
662 MSI_RecordSetStringW(uirow, 1, dir);
663 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
664 msiobj_release(&uirow->hdr);
665
666 full_path = msi_get_target_folder( package, dir );
667 if (!full_path)
668 {
669 ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
670 return ERROR_SUCCESS;
671 }
672 TRACE("folder is %s\n", debugstr_w(full_path));
673
674 folder = msi_get_loaded_folder( package, dir );
675 if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( package, full_path );
676 folder->State = FOLDER_STATE_CREATED;
677
678 return ERROR_SUCCESS;
679 }
680
ACTION_CreateFolders(MSIPACKAGE * package)681 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
682 {
683 MSIQUERY *view;
684 UINT rc;
685
686 if (package->script == SCRIPT_NONE)
687 return msi_schedule_action(package, SCRIPT_INSTALL, L"CreateFolders");
688
689 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `CreateFolder`", &view );
690 if (rc != ERROR_SUCCESS)
691 return ERROR_SUCCESS;
692
693 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
694 msiobj_release(&view->hdr);
695 return rc;
696 }
697
remove_persistent_folder(MSIFOLDER * folder)698 static void remove_persistent_folder( MSIFOLDER *folder )
699 {
700 FolderList *fl;
701
702 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
703 {
704 remove_persistent_folder( fl->folder );
705 }
706 if (folder->persistent && folder->State != FOLDER_STATE_REMOVED)
707 {
708 if (RemoveDirectoryW( folder->ResolvedTarget )) folder->State = FOLDER_STATE_REMOVED;
709 }
710 }
711
ITERATE_RemoveFolders(MSIRECORD * row,LPVOID param)712 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
713 {
714 MSIPACKAGE *package = param;
715 LPCWSTR dir, component, full_path;
716 MSIRECORD *uirow;
717 MSIFOLDER *folder;
718 MSICOMPONENT *comp;
719
720 component = MSI_RecordGetString(row, 2);
721 if (!component)
722 return ERROR_SUCCESS;
723
724 comp = msi_get_loaded_component(package, component);
725 if (!comp)
726 return ERROR_SUCCESS;
727
728 comp->Action = msi_get_component_action( package, comp );
729 if (comp->Action != INSTALLSTATE_ABSENT)
730 {
731 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
732 return ERROR_SUCCESS;
733 }
734
735 dir = MSI_RecordGetString( row, 1 );
736 if (!dir)
737 {
738 ERR("Unable to get folder id\n");
739 return ERROR_SUCCESS;
740 }
741
742 full_path = msi_get_target_folder( package, dir );
743 if (!full_path)
744 {
745 ERR("Unable to resolve folder %s\n", debugstr_w(dir));
746 return ERROR_SUCCESS;
747 }
748 TRACE("folder is %s\n", debugstr_w(full_path));
749
750 uirow = MSI_CreateRecord( 1 );
751 MSI_RecordSetStringW( uirow, 1, dir );
752 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
753 msiobj_release( &uirow->hdr );
754
755 folder = msi_get_loaded_folder( package, dir );
756 remove_persistent_folder( folder );
757 return ERROR_SUCCESS;
758 }
759
ACTION_RemoveFolders(MSIPACKAGE * package)760 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
761 {
762 MSIQUERY *view;
763 UINT rc;
764
765 if (package->script == SCRIPT_NONE)
766 return msi_schedule_action(package, SCRIPT_INSTALL, L"RemoveFolders");
767
768 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `CreateFolder`", &view );
769 if (rc != ERROR_SUCCESS)
770 return ERROR_SUCCESS;
771
772 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
773 msiobj_release( &view->hdr );
774 return rc;
775 }
776
load_component(MSIRECORD * row,LPVOID param)777 static UINT load_component( MSIRECORD *row, LPVOID param )
778 {
779 MSIPACKAGE *package = param;
780 MSICOMPONENT *comp;
781
782 comp = calloc( 1, sizeof(MSICOMPONENT) );
783 if (!comp)
784 return ERROR_FUNCTION_FAILED;
785
786 list_add_tail( &package->components, &comp->entry );
787
788 /* fill in the data */
789 comp->Component = msi_dup_record_field( row, 1 );
790
791 TRACE("Loading Component %s\n", debugstr_w(comp->Component));
792
793 comp->ComponentId = msi_dup_record_field( row, 2 );
794 comp->Directory = msi_dup_record_field( row, 3 );
795 comp->Attributes = MSI_RecordGetInteger(row,4);
796 comp->Condition = msi_dup_record_field( row, 5 );
797 comp->KeyPath = msi_dup_record_field( row, 6 );
798
799 comp->Installed = INSTALLSTATE_UNKNOWN;
800 comp->Action = INSTALLSTATE_UNKNOWN;
801 comp->ActionRequest = INSTALLSTATE_UNKNOWN;
802
803 comp->assembly = msi_load_assembly( package, comp );
804 return ERROR_SUCCESS;
805 }
806
msi_load_all_components(MSIPACKAGE * package)807 UINT msi_load_all_components( MSIPACKAGE *package )
808 {
809 MSIQUERY *view;
810 UINT r;
811
812 if (!list_empty(&package->components))
813 return ERROR_SUCCESS;
814
815 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Component`", &view );
816 if (r != ERROR_SUCCESS)
817 return r;
818
819 r = MSI_IterateRecords(view, NULL, load_component, package);
820 msiobj_release(&view->hdr);
821 return r;
822 }
823
add_feature_component(MSIFEATURE * feature,MSICOMPONENT * comp)824 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
825 {
826 ComponentList *cl;
827
828 cl = malloc( sizeof(*cl) );
829 if ( !cl )
830 return ERROR_NOT_ENOUGH_MEMORY;
831 cl->component = comp;
832 list_add_tail( &feature->Components, &cl->entry );
833
834 return ERROR_SUCCESS;
835 }
836
add_feature_child(MSIFEATURE * parent,MSIFEATURE * child)837 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
838 {
839 FeatureList *fl;
840
841 fl = malloc( sizeof(*fl) );
842 if ( !fl )
843 return ERROR_NOT_ENOUGH_MEMORY;
844 fl->feature = child;
845 list_add_tail( &parent->Children, &fl->entry );
846
847 return ERROR_SUCCESS;
848 }
849
850 struct package_feature
851 {
852 MSIPACKAGE *package;
853 MSIFEATURE *feature;
854 };
855
iterate_load_featurecomponents(MSIRECORD * row,LPVOID param)856 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
857 {
858 struct package_feature *package_feature = param;
859 LPCWSTR component;
860 MSICOMPONENT *comp;
861
862 component = MSI_RecordGetString(row,1);
863
864 /* check to see if the component is already loaded */
865 comp = msi_get_loaded_component( package_feature->package, component );
866 if (!comp)
867 {
868 WARN("ignoring unknown component %s\n", debugstr_w(component));
869 return ERROR_SUCCESS;
870 }
871 add_feature_component( package_feature->feature, comp );
872 comp->Enabled = TRUE;
873
874 return ERROR_SUCCESS;
875 }
876
load_feature(MSIRECORD * row,LPVOID param)877 static UINT load_feature(MSIRECORD *row, LPVOID param)
878 {
879 MSIPACKAGE *package = param;
880 MSIFEATURE *feature;
881 MSIQUERY *view;
882 struct package_feature package_feature;
883 UINT rc;
884
885 /* fill in the data */
886
887 feature = calloc( 1, sizeof(MSIFEATURE) );
888 if (!feature)
889 return ERROR_NOT_ENOUGH_MEMORY;
890
891 list_init( &feature->Children );
892 list_init( &feature->Components );
893
894 feature->Feature = msi_dup_record_field( row, 1 );
895
896 TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
897
898 feature->Feature_Parent = msi_dup_record_field( row, 2 );
899 feature->Title = msi_dup_record_field( row, 3 );
900 feature->Description = msi_dup_record_field( row, 4 );
901
902 if (!MSI_RecordIsNull(row,5))
903 feature->Display = MSI_RecordGetInteger(row,5);
904
905 feature->Level= MSI_RecordGetInteger(row,6);
906 feature->Directory = msi_dup_record_field( row, 7 );
907 feature->Attributes = MSI_RecordGetInteger(row,8);
908
909 feature->Installed = INSTALLSTATE_UNKNOWN;
910 feature->Action = INSTALLSTATE_UNKNOWN;
911 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
912
913 list_add_tail( &package->features, &feature->entry );
914
915 /* load feature components */
916
917 rc = MSI_OpenQuery( package->db, &view, L"SELECT `Component_` FROM `FeatureComponents` WHERE `Feature_` = '%s'",
918 feature->Feature );
919 if (rc != ERROR_SUCCESS)
920 return ERROR_SUCCESS;
921
922 package_feature.package = package;
923 package_feature.feature = feature;
924
925 rc = MSI_IterateRecords(view, NULL, iterate_load_featurecomponents, &package_feature);
926 msiobj_release(&view->hdr);
927 return rc;
928 }
929
find_feature_children(MSIRECORD * row,LPVOID param)930 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
931 {
932 MSIPACKAGE *package = param;
933 MSIFEATURE *parent, *child;
934
935 child = msi_get_loaded_feature( package, MSI_RecordGetString( row, 1 ) );
936 if (!child)
937 return ERROR_FUNCTION_FAILED;
938
939 if (!child->Feature_Parent)
940 return ERROR_SUCCESS;
941
942 parent = msi_get_loaded_feature( package, child->Feature_Parent );
943 if (!parent)
944 return ERROR_FUNCTION_FAILED;
945
946 add_feature_child( parent, child );
947 return ERROR_SUCCESS;
948 }
949
msi_load_all_features(MSIPACKAGE * package)950 UINT msi_load_all_features( MSIPACKAGE *package )
951 {
952 MSIQUERY *view;
953 UINT r;
954
955 if (!list_empty(&package->features))
956 return ERROR_SUCCESS;
957
958 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Feature` ORDER BY `Display`", &view );
959 if (r != ERROR_SUCCESS)
960 return r;
961
962 r = MSI_IterateRecords( view, NULL, load_feature, package );
963 if (r != ERROR_SUCCESS)
964 {
965 msiobj_release( &view->hdr );
966 return r;
967 }
968 r = MSI_IterateRecords( view, NULL, find_feature_children, package );
969 msiobj_release( &view->hdr );
970 return r;
971 }
972
folder_split_path(LPWSTR p,WCHAR ch)973 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
974 {
975 if (!p)
976 return p;
977 p = wcschr(p, ch);
978 if (!p)
979 return p;
980 *p = 0;
981 return p+1;
982 }
983
load_file_hash(MSIPACKAGE * package,MSIFILE * file)984 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
985 {
986 MSIQUERY *view = NULL;
987 MSIRECORD *row = NULL;
988 UINT r;
989
990 TRACE("%s\n", debugstr_w(file->File));
991
992 r = MSI_OpenQuery(package->db, &view, L"SELECT * FROM `MsiFileHash` WHERE `File_` = '%s'", file->File);
993 if (r != ERROR_SUCCESS)
994 goto done;
995
996 r = MSI_ViewExecute(view, NULL);
997 if (r != ERROR_SUCCESS)
998 goto done;
999
1000 r = MSI_ViewFetch(view, &row);
1001 if (r != ERROR_SUCCESS)
1002 goto done;
1003
1004 file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1005 file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1006 file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1007 file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1008 file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1009
1010 done:
1011 if (view) msiobj_release(&view->hdr);
1012 if (row) msiobj_release(&row->hdr);
1013 return r;
1014 }
1015
load_file_disk_id(MSIPACKAGE * package,MSIFILE * file)1016 static UINT load_file_disk_id( MSIPACKAGE *package, MSIFILE *file )
1017 {
1018 MSIRECORD *row = MSI_QueryGetRecord( package->db, L"SELECT `DiskId` FROM `Media` WHERE `LastSequence` >= %d",
1019 file->Sequence );
1020 if (!row)
1021 {
1022 WARN("query failed\n");
1023 return ERROR_FUNCTION_FAILED;
1024 }
1025
1026 file->disk_id = MSI_RecordGetInteger( row, 1 );
1027 msiobj_release( &row->hdr );
1028 return ERROR_SUCCESS;
1029 }
1030
load_file(MSIRECORD * row,LPVOID param)1031 static UINT load_file(MSIRECORD *row, LPVOID param)
1032 {
1033 MSIPACKAGE* package = param;
1034 LPCWSTR component;
1035 MSIFILE *file;
1036
1037 /* fill in the data */
1038
1039 file = calloc( 1, sizeof(MSIFILE) );
1040 if (!file)
1041 return ERROR_NOT_ENOUGH_MEMORY;
1042
1043 file->File = msi_dup_record_field( row, 1 );
1044
1045 component = MSI_RecordGetString( row, 2 );
1046 file->Component = msi_get_loaded_component( package, component );
1047
1048 if (!file->Component)
1049 {
1050 WARN("Component not found: %s\n", debugstr_w(component));
1051 free(file->File);
1052 free(file);
1053 return ERROR_SUCCESS;
1054 }
1055
1056 file->FileName = msi_dup_record_field( row, 3 );
1057 msi_reduce_to_long_filename( file->FileName );
1058
1059 file->ShortName = msi_dup_record_field( row, 3 );
1060 file->LongName = wcsdup( folder_split_path(file->ShortName, '|') );
1061
1062 file->FileSize = MSI_RecordGetInteger( row, 4 );
1063 file->Version = msi_dup_record_field( row, 5 );
1064 file->Language = msi_dup_record_field( row, 6 );
1065 file->Attributes = MSI_RecordGetInteger( row, 7 );
1066 file->Sequence = MSI_RecordGetInteger( row, 8 );
1067
1068 file->state = msifs_invalid;
1069
1070 /* if the compressed bits are not set in the file attributes,
1071 * then read the information from the package word count property
1072 */
1073 if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1074 {
1075 file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1076 }
1077 else if (file->Attributes & (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1078 {
1079 file->IsCompressed = TRUE;
1080 }
1081 else if (file->Attributes & msidbFileAttributesNoncompressed)
1082 {
1083 file->IsCompressed = FALSE;
1084 }
1085 else file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1086
1087 load_file_hash(package, file);
1088 load_file_disk_id(package, file);
1089
1090 TRACE("File loaded (file %s sequence %u)\n", debugstr_w(file->File), file->Sequence);
1091
1092 list_add_tail( &package->files, &file->entry );
1093 return ERROR_SUCCESS;
1094 }
1095
load_all_files(MSIPACKAGE * package)1096 static UINT load_all_files(MSIPACKAGE *package)
1097 {
1098 MSIQUERY *view;
1099 UINT rc;
1100
1101 if (!list_empty(&package->files))
1102 return ERROR_SUCCESS;
1103
1104 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `File` ORDER BY `Sequence`", &view);
1105 if (rc != ERROR_SUCCESS)
1106 return ERROR_SUCCESS;
1107
1108 rc = MSI_IterateRecords(view, NULL, load_file, package);
1109 msiobj_release(&view->hdr);
1110 return rc;
1111 }
1112
load_media(MSIRECORD * row,LPVOID param)1113 static UINT load_media( MSIRECORD *row, LPVOID param )
1114 {
1115 MSIPACKAGE *package = param;
1116 UINT disk_id = MSI_RecordGetInteger( row, 1 );
1117 const WCHAR *cabinet = MSI_RecordGetString( row, 4 );
1118
1119 /* FIXME: load external cabinets and directory sources too */
1120 if (!cabinet || cabinet[0] != '#' || disk_id >= MSI_INITIAL_MEDIA_TRANSFORM_DISKID)
1121 return ERROR_SUCCESS;
1122
1123 return msi_add_cabinet_stream( package, disk_id, package->db->storage, cabinet );
1124 }
1125
load_all_media(MSIPACKAGE * package)1126 static UINT load_all_media( MSIPACKAGE *package )
1127 {
1128 MSIQUERY *view;
1129 UINT r;
1130
1131 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Media` ORDER BY `DiskId`", &view );
1132 if (r != ERROR_SUCCESS)
1133 return ERROR_SUCCESS;
1134
1135 r = MSI_IterateRecords( view, NULL, load_media, package );
1136 msiobj_release( &view->hdr );
1137 return r;
1138 }
1139
load_patch_disk_id(MSIPACKAGE * package,MSIFILEPATCH * patch)1140 static UINT load_patch_disk_id( MSIPACKAGE *package, MSIFILEPATCH *patch )
1141 {
1142 MSIRECORD *rec = MSI_QueryGetRecord( package->db, L"SELECT `DiskId` FROM `Media` WHERE `LastSequence` >= %u",
1143 patch->Sequence );
1144 if (!rec)
1145 {
1146 WARN("query failed\n");
1147 return ERROR_FUNCTION_FAILED;
1148 }
1149
1150 patch->disk_id = MSI_RecordGetInteger( rec, 1 );
1151 msiobj_release( &rec->hdr );
1152 return ERROR_SUCCESS;
1153 }
1154
load_patch(MSIRECORD * row,LPVOID param)1155 static UINT load_patch(MSIRECORD *row, LPVOID param)
1156 {
1157 MSIPACKAGE *package = param;
1158 MSIFILEPATCH *patch;
1159 const WCHAR *file_key;
1160
1161 patch = calloc( 1, sizeof(MSIFILEPATCH) );
1162 if (!patch)
1163 return ERROR_NOT_ENOUGH_MEMORY;
1164
1165 file_key = MSI_RecordGetString( row, 1 );
1166 patch->File = msi_get_loaded_file( package, file_key );
1167 if (!patch->File)
1168 {
1169 ERR("Failed to find target for patch in File table\n");
1170 free(patch);
1171 return ERROR_FUNCTION_FAILED;
1172 }
1173
1174 patch->Sequence = MSI_RecordGetInteger( row, 2 );
1175 patch->PatchSize = MSI_RecordGetInteger( row, 3 );
1176 patch->Attributes = MSI_RecordGetInteger( row, 4 );
1177
1178 /* FIXME:
1179 * Header field - for patch validation.
1180 * _StreamRef - External key into MsiPatchHeaders (instead of the header field)
1181 */
1182
1183 load_patch_disk_id( package, patch );
1184
1185 TRACE("Patch loaded (file %s sequence %u)\n", debugstr_w(patch->File->File), patch->Sequence);
1186
1187 list_add_tail( &package->filepatches, &patch->entry );
1188
1189 return ERROR_SUCCESS;
1190 }
1191
load_all_patches(MSIPACKAGE * package)1192 static UINT load_all_patches(MSIPACKAGE *package)
1193 {
1194 MSIQUERY *view;
1195 UINT rc;
1196
1197 if (!list_empty(&package->filepatches))
1198 return ERROR_SUCCESS;
1199
1200 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `Patch` ORDER BY `Sequence`", &view);
1201 if (rc != ERROR_SUCCESS)
1202 return ERROR_SUCCESS;
1203
1204 rc = MSI_IterateRecords(view, NULL, load_patch, package);
1205 msiobj_release(&view->hdr);
1206 return rc;
1207 }
1208
iterate_patched_component(MSIRECORD * row,LPVOID param)1209 static UINT iterate_patched_component( MSIRECORD *row, LPVOID param )
1210 {
1211 MSIPACKAGE *package = param;
1212 const WCHAR *name;
1213 MSICOMPONENT *c;
1214
1215 name = MSI_RecordGetString( row, 1 );
1216 TRACE( "found patched component: %s\n", wine_dbgstr_w(name) );
1217 c = msi_get_loaded_component( package, name );
1218 if (!c)
1219 return ERROR_SUCCESS;
1220
1221 c->updated = 1;
1222 if (!wcscmp( MSI_RecordGetString( row, 2 ), L"INSERT" ))
1223 c->added = 1;
1224 return ERROR_SUCCESS;
1225 }
1226
mark_patched_components(MSIPACKAGE * package)1227 static void mark_patched_components( MSIPACKAGE *package )
1228 {
1229 static const WCHAR select[] = L"SELECT `Row`, `Column` FROM `_TransformView` WHERE `Table`='Component'";
1230 MSIQUERY *q;
1231 UINT r;
1232
1233 r = MSI_OpenQuery( package->db, &q, select );
1234 if (r != ERROR_SUCCESS)
1235 return;
1236
1237 MSI_IterateRecords( q, NULL, iterate_patched_component, package );
1238 msiobj_release( &q->hdr );
1239
1240 while (1)
1241 {
1242 r = MSI_OpenQuery( package->db, &q, L"ALTER TABLE `_TransformView` FREE" );
1243 if (r != ERROR_SUCCESS)
1244 return;
1245 r = MSI_ViewExecute( q, NULL );
1246 msiobj_release( &q->hdr );
1247 if (r != ERROR_SUCCESS)
1248 return;
1249 }
1250 }
1251
load_folder_persistence(MSIPACKAGE * package,MSIFOLDER * folder)1252 static UINT load_folder_persistence( MSIPACKAGE *package, MSIFOLDER *folder )
1253 {
1254 MSIQUERY *view;
1255
1256 folder->persistent = FALSE;
1257 if (!MSI_OpenQuery( package->db, &view, L"SELECT * FROM `CreateFolder` WHERE `Directory_` = '%s'",
1258 folder->Directory ))
1259 {
1260 if (!MSI_ViewExecute( view, NULL ))
1261 {
1262 MSIRECORD *rec;
1263 if (!MSI_ViewFetch( view, &rec ))
1264 {
1265 TRACE("directory %s is persistent\n", debugstr_w(folder->Directory));
1266 folder->persistent = TRUE;
1267 msiobj_release( &rec->hdr );
1268 }
1269 }
1270 msiobj_release( &view->hdr );
1271 }
1272 return ERROR_SUCCESS;
1273 }
1274
load_folder(MSIRECORD * row,LPVOID param)1275 static UINT load_folder( MSIRECORD *row, LPVOID param )
1276 {
1277 MSIPACKAGE *package = param;
1278 static WCHAR szEmpty[] = L"";
1279 LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1280 MSIFOLDER *folder;
1281
1282 if (!(folder = calloc( 1, sizeof(*folder) ))) return ERROR_NOT_ENOUGH_MEMORY;
1283 list_init( &folder->children );
1284 folder->Directory = msi_dup_record_field( row, 1 );
1285 folder->Parent = msi_dup_record_field( row, 2 );
1286 p = msi_dup_record_field(row, 3);
1287
1288 TRACE("%s\n", debugstr_w(folder->Directory));
1289
1290 /* split src and target dir */
1291 tgt_short = p;
1292 src_short = folder_split_path( p, ':' );
1293
1294 /* split the long and short paths */
1295 tgt_long = folder_split_path( tgt_short, '|' );
1296 src_long = folder_split_path( src_short, '|' );
1297
1298 /* check for no-op dirs */
1299 if (tgt_short && !wcscmp( L".", tgt_short ))
1300 tgt_short = szEmpty;
1301 if (src_short && !wcscmp( L".", src_short ))
1302 src_short = szEmpty;
1303
1304 if (!tgt_long)
1305 tgt_long = tgt_short;
1306
1307 if (!src_short) {
1308 src_short = tgt_short;
1309 src_long = tgt_long;
1310 }
1311
1312 if (!src_long)
1313 src_long = src_short;
1314
1315 /* FIXME: use the target short path too */
1316 folder->TargetDefault = wcsdup(tgt_long);
1317 folder->SourceShortPath = wcsdup(src_short);
1318 folder->SourceLongPath = wcsdup(src_long);
1319 free(p);
1320
1321 TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1322 TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1323 TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1324
1325 load_folder_persistence( package, folder );
1326
1327 list_add_tail( &package->folders, &folder->entry );
1328 return ERROR_SUCCESS;
1329 }
1330
add_folder_child(MSIFOLDER * parent,MSIFOLDER * child)1331 static UINT add_folder_child( MSIFOLDER *parent, MSIFOLDER *child )
1332 {
1333 FolderList *fl;
1334
1335 if (!(fl = malloc( sizeof(*fl) ))) return ERROR_NOT_ENOUGH_MEMORY;
1336 fl->folder = child;
1337 list_add_tail( &parent->children, &fl->entry );
1338 return ERROR_SUCCESS;
1339 }
1340
find_folder_children(MSIRECORD * row,LPVOID param)1341 static UINT find_folder_children( MSIRECORD *row, LPVOID param )
1342 {
1343 MSIPACKAGE *package = param;
1344 MSIFOLDER *parent, *child;
1345
1346 if (!(child = msi_get_loaded_folder( package, MSI_RecordGetString( row, 1 ) )))
1347 return ERROR_FUNCTION_FAILED;
1348
1349 if (!child->Parent) return ERROR_SUCCESS;
1350
1351 if (!(parent = msi_get_loaded_folder( package, child->Parent )))
1352 return ERROR_FUNCTION_FAILED;
1353
1354 return add_folder_child( parent, child );
1355 }
1356
load_all_folders(MSIPACKAGE * package)1357 static UINT load_all_folders( MSIPACKAGE *package )
1358 {
1359 MSIQUERY *view;
1360 UINT r;
1361
1362 if (!list_empty(&package->folders))
1363 return ERROR_SUCCESS;
1364
1365 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Directory`", &view );
1366 if (r != ERROR_SUCCESS)
1367 return r;
1368
1369 r = MSI_IterateRecords( view, NULL, load_folder, package );
1370 if (r != ERROR_SUCCESS)
1371 {
1372 msiobj_release( &view->hdr );
1373 return r;
1374 }
1375 r = MSI_IterateRecords( view, NULL, find_folder_children, package );
1376 msiobj_release( &view->hdr );
1377 return r;
1378 }
1379
ACTION_CostInitialize(MSIPACKAGE * package)1380 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1381 {
1382 msi_set_property( package->db, L"CostingComplete", L"0", -1 );
1383 msi_set_property( package->db, L"ROOTDRIVE", L"C:\\", -1 );
1384
1385 load_all_folders( package );
1386 msi_load_all_components( package );
1387 msi_load_all_features( package );
1388 load_all_files( package );
1389 load_all_patches( package );
1390 mark_patched_components( package );
1391 load_all_media( package );
1392
1393 return ERROR_SUCCESS;
1394 }
1395
execute_script(MSIPACKAGE * package,UINT script)1396 static UINT execute_script( MSIPACKAGE *package, UINT script )
1397 {
1398 UINT i, rc = ERROR_SUCCESS;
1399
1400 TRACE("executing script %u\n", script);
1401
1402 package->script = script;
1403
1404 if (script == SCRIPT_ROLLBACK)
1405 {
1406 for (i = package->script_actions_count[script]; i > 0; i--)
1407 {
1408 rc = ACTION_PerformAction(package, package->script_actions[script][i-1]);
1409 if (rc != ERROR_SUCCESS)
1410 {
1411 ERR("Execution of script %i halted; action %s returned %u\n",
1412 script, debugstr_w(package->script_actions[script][i-1]), rc);
1413 break;
1414 }
1415 }
1416 }
1417 else
1418 {
1419 for (i = 0; i < package->script_actions_count[script]; i++)
1420 {
1421 rc = ACTION_PerformAction(package, package->script_actions[script][i]);
1422 if (rc != ERROR_SUCCESS)
1423 {
1424 ERR("Execution of script %i halted; action %s returned %u\n",
1425 script, debugstr_w(package->script_actions[script][i]), rc);
1426 break;
1427 }
1428 }
1429 }
1430
1431 package->script = SCRIPT_NONE;
1432
1433 msi_free_action_script(package, script);
1434 return rc;
1435 }
1436
ACTION_FileCost(MSIPACKAGE * package)1437 static UINT ACTION_FileCost(MSIPACKAGE *package)
1438 {
1439 return ERROR_SUCCESS;
1440 }
1441
get_client_counts(MSIPACKAGE * package)1442 static void get_client_counts( MSIPACKAGE *package )
1443 {
1444 MSICOMPONENT *comp;
1445 HKEY hkey;
1446
1447 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1448 {
1449 if (!comp->ComponentId) continue;
1450
1451 if (MSIREG_OpenUserDataComponentKey( comp->ComponentId, L"S-1-5-18", &hkey, FALSE ) &&
1452 MSIREG_OpenUserDataComponentKey( comp->ComponentId, NULL, &hkey, FALSE ))
1453 {
1454 comp->num_clients = 0;
1455 continue;
1456 }
1457 RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, NULL, (DWORD *)&comp->num_clients,
1458 NULL, NULL, NULL, NULL );
1459 RegCloseKey( hkey );
1460 }
1461 }
1462
ACTION_GetComponentInstallStates(MSIPACKAGE * package)1463 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1464 {
1465 MSICOMPONENT *comp;
1466 UINT r;
1467
1468 LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1469 {
1470 if (!comp->ComponentId) continue;
1471
1472 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1473 MSIINSTALLCONTEXT_USERMANAGED, comp->ComponentId,
1474 &comp->Installed );
1475 if (r == ERROR_SUCCESS) continue;
1476
1477 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1478 MSIINSTALLCONTEXT_USERUNMANAGED, comp->ComponentId,
1479 &comp->Installed );
1480 if (r == ERROR_SUCCESS) continue;
1481
1482 r = MsiQueryComponentStateW( package->ProductCode, NULL,
1483 MSIINSTALLCONTEXT_MACHINE, comp->ComponentId,
1484 &comp->Installed );
1485 if (r == ERROR_SUCCESS) continue;
1486
1487 comp->Installed = INSTALLSTATE_ABSENT;
1488 }
1489 }
1490
ACTION_GetFeatureInstallStates(MSIPACKAGE * package)1491 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1492 {
1493 MSIFEATURE *feature;
1494
1495 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1496 {
1497 INSTALLSTATE state = MsiQueryFeatureStateW( package->ProductCode, feature->Feature );
1498
1499 if (state == INSTALLSTATE_UNKNOWN || state == INSTALLSTATE_INVALIDARG)
1500 feature->Installed = INSTALLSTATE_ABSENT;
1501 else
1502 feature->Installed = state;
1503 }
1504 }
1505
is_feature_selected(MSIFEATURE * feature,INT level)1506 static inline BOOL is_feature_selected( MSIFEATURE *feature, INT level )
1507 {
1508 return (feature->Level > 0 && feature->Level <= level);
1509 }
1510
process_state_property(MSIPACKAGE * package,int level,LPCWSTR property,INSTALLSTATE state)1511 static BOOL process_state_property(MSIPACKAGE* package, int level,
1512 LPCWSTR property, INSTALLSTATE state)
1513 {
1514 LPWSTR override;
1515 MSIFEATURE *feature;
1516 BOOL remove = !wcscmp(property, L"REMOVE");
1517 BOOL reinstall = !wcscmp(property, L"REINSTALL");
1518
1519 override = msi_dup_property( package->db, property );
1520 if (!override)
1521 return FALSE;
1522
1523 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1524 {
1525 if (feature->Level <= 0)
1526 continue;
1527
1528 if (reinstall)
1529 state = (feature->Installed == INSTALLSTATE_ABSENT ? INSTALLSTATE_UNKNOWN : feature->Installed);
1530 else if (remove)
1531 state = (feature->Installed == INSTALLSTATE_ABSENT ? INSTALLSTATE_UNKNOWN : INSTALLSTATE_ABSENT);
1532
1533 if (!wcsicmp( override, L"ALL" ))
1534 {
1535 feature->Action = state;
1536 feature->ActionRequest = state;
1537 }
1538 else
1539 {
1540 LPWSTR ptr = override;
1541 LPWSTR ptr2 = wcschr(override,',');
1542
1543 while (ptr)
1544 {
1545 int len = ptr2 - ptr;
1546
1547 if ((ptr2 && lstrlenW(feature->Feature) == len && !wcsncmp(ptr, feature->Feature, len))
1548 || (!ptr2 && !wcscmp(ptr, feature->Feature)))
1549 {
1550 feature->Action = state;
1551 feature->ActionRequest = state;
1552 break;
1553 }
1554 if (ptr2)
1555 {
1556 ptr=ptr2+1;
1557 ptr2 = wcschr(ptr,',');
1558 }
1559 else
1560 break;
1561 }
1562 }
1563 }
1564 free(override);
1565 return TRUE;
1566 }
1567
process_overrides(MSIPACKAGE * package,int level)1568 static BOOL process_overrides( MSIPACKAGE *package, int level )
1569 {
1570 BOOL ret = FALSE;
1571
1572 /* all these activation/deactivation things happen in order and things
1573 * later on the list override things earlier on the list.
1574 *
1575 * 0 INSTALLLEVEL processing
1576 * 1 ADDLOCAL
1577 * 2 REMOVE
1578 * 3 ADDSOURCE
1579 * 4 ADDDEFAULT
1580 * 5 REINSTALL
1581 * 6 ADVERTISE
1582 * 7 COMPADDLOCAL
1583 * 8 COMPADDSOURCE
1584 * 9 FILEADDLOCAL
1585 * 10 FILEADDSOURCE
1586 * 11 FILEADDDEFAULT
1587 */
1588 ret |= process_state_property( package, level, L"ADDLOCAL", INSTALLSTATE_LOCAL );
1589 ret |= process_state_property( package, level, L"REMOVE", INSTALLSTATE_ABSENT );
1590 ret |= process_state_property( package, level, L"ADDSOURCE", INSTALLSTATE_SOURCE );
1591 ret |= process_state_property( package, level, L"REINSTALL", INSTALLSTATE_UNKNOWN );
1592 ret |= process_state_property( package, level, L"ADVERTISE", INSTALLSTATE_ADVERTISED );
1593
1594 if (ret)
1595 msi_set_property( package->db, L"Preselected", L"1", -1 );
1596
1597 return ret;
1598 }
1599
disable_children(MSIFEATURE * feature,int level)1600 static void disable_children( MSIFEATURE *feature, int level )
1601 {
1602 FeatureList *fl;
1603
1604 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1605 {
1606 if (!is_feature_selected( feature, level ))
1607 {
1608 TRACE("child %s (level %d request %d) follows disabled parent %s (level %d request %d)\n",
1609 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1610 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1611
1612 fl->feature->Level = feature->Level;
1613 fl->feature->Action = INSTALLSTATE_UNKNOWN;
1614 fl->feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1615 }
1616 disable_children( fl->feature, level );
1617 }
1618 }
1619
follow_parent(MSIFEATURE * feature)1620 static void follow_parent( MSIFEATURE *feature )
1621 {
1622 FeatureList *fl;
1623
1624 LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1625 {
1626 if (fl->feature->Attributes & msidbFeatureAttributesFollowParent)
1627 {
1628 TRACE("child %s (level %d request %d) follows parent %s (level %d request %d)\n",
1629 debugstr_w(fl->feature->Feature), fl->feature->Level, fl->feature->ActionRequest,
1630 debugstr_w(feature->Feature), feature->Level, feature->ActionRequest);
1631
1632 fl->feature->Action = feature->Action;
1633 fl->feature->ActionRequest = feature->ActionRequest;
1634 }
1635 follow_parent( fl->feature );
1636 }
1637 }
1638
MSI_SetFeatureStates(MSIPACKAGE * package)1639 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1640 {
1641 int level;
1642 MSICOMPONENT* component;
1643 MSIFEATURE *feature;
1644
1645 TRACE("Checking Install Level\n");
1646
1647 level = msi_get_property_int(package->db, L"INSTALLLEVEL", 1);
1648
1649 if (msi_get_property_int( package->db, L"Preselected", 0 ))
1650 {
1651 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1652 {
1653 if (!is_feature_selected( feature, level )) continue;
1654
1655 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1656 {
1657 if (feature->Installed == INSTALLSTATE_ABSENT)
1658 {
1659 feature->Action = INSTALLSTATE_UNKNOWN;
1660 feature->ActionRequest = INSTALLSTATE_UNKNOWN;
1661 }
1662 else
1663 {
1664 feature->Action = feature->Installed;
1665 feature->ActionRequest = feature->Installed;
1666 }
1667 }
1668 }
1669 }
1670 else if (!msi_get_property_int( package->db, L"Installed", 0 ))
1671 {
1672 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1673 {
1674 if (!is_feature_selected( feature, level )) continue;
1675
1676 if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1677 {
1678 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1679 {
1680 feature->Action = INSTALLSTATE_SOURCE;
1681 feature->ActionRequest = INSTALLSTATE_SOURCE;
1682 }
1683 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1684 {
1685 feature->Action = INSTALLSTATE_ADVERTISED;
1686 feature->ActionRequest = INSTALLSTATE_ADVERTISED;
1687 }
1688 else
1689 {
1690 feature->Action = INSTALLSTATE_LOCAL;
1691 feature->ActionRequest = INSTALLSTATE_LOCAL;
1692 }
1693 }
1694 }
1695 }
1696 else
1697 {
1698 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1699 {
1700 ComponentList *cl;
1701 MSIFEATURE *cur;
1702
1703 if (!is_feature_selected( feature, level )) continue;
1704 if (feature->ActionRequest != INSTALLSTATE_UNKNOWN) continue;
1705
1706 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1707 {
1708 if (!cl->component->updated && !cl->component->added)
1709 continue;
1710
1711 cur = feature;
1712 while (cur)
1713 {
1714 if (cur->ActionRequest != INSTALLSTATE_UNKNOWN)
1715 break;
1716
1717 if (cur->Installed != INSTALLSTATE_ABSENT)
1718 {
1719 cur->Action = cur->Installed;
1720 cur->ActionRequest = cur->Installed;
1721 }
1722 else if (!cl->component->added)
1723 {
1724 break;
1725 }
1726 else if (cur->Attributes & msidbFeatureAttributesFavorSource)
1727 {
1728 cur->Action = INSTALLSTATE_SOURCE;
1729 cur->ActionRequest = INSTALLSTATE_SOURCE;
1730 }
1731 else if (cur->Attributes & msidbFeatureAttributesFavorAdvertise)
1732 {
1733 cur->Action = INSTALLSTATE_ADVERTISED;
1734 cur->ActionRequest = INSTALLSTATE_ADVERTISED;
1735 }
1736 else
1737 {
1738 cur->Action = INSTALLSTATE_LOCAL;
1739 cur->ActionRequest = INSTALLSTATE_LOCAL;
1740 }
1741
1742 if (!cur->Feature_Parent)
1743 break;
1744 cur = msi_get_loaded_feature(package, cur->Feature_Parent);
1745 }
1746 }
1747 }
1748 }
1749
1750 /* disable child features of unselected parent or follow parent */
1751 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1752 {
1753 if (feature->Feature_Parent) continue;
1754 disable_children( feature, level );
1755 follow_parent( feature );
1756 }
1757
1758 /* now we want to set component state based based on feature state */
1759 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1760 {
1761 ComponentList *cl;
1762
1763 TRACE("examining feature %s (level %d installed %d request %d action %d)\n",
1764 debugstr_w(feature->Feature), feature->Level, feature->Installed,
1765 feature->ActionRequest, feature->Action);
1766
1767 /* features with components that have compressed files are made local */
1768 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1769 {
1770 if (cl->component->ForceLocalState &&
1771 feature->ActionRequest == INSTALLSTATE_SOURCE)
1772 {
1773 feature->Action = INSTALLSTATE_LOCAL;
1774 feature->ActionRequest = INSTALLSTATE_LOCAL;
1775 break;
1776 }
1777 }
1778
1779 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1780 {
1781 component = cl->component;
1782
1783 switch (feature->ActionRequest)
1784 {
1785 case INSTALLSTATE_ABSENT:
1786 component->anyAbsent = 1;
1787 break;
1788 case INSTALLSTATE_ADVERTISED:
1789 component->hasAdvertisedFeature = 1;
1790 break;
1791 case INSTALLSTATE_SOURCE:
1792 component->hasSourceFeature = 1;
1793 break;
1794 case INSTALLSTATE_LOCAL:
1795 component->hasLocalFeature = 1;
1796 break;
1797 case INSTALLSTATE_DEFAULT:
1798 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1799 component->hasAdvertisedFeature = 1;
1800 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1801 component->hasSourceFeature = 1;
1802 else
1803 component->hasLocalFeature = 1;
1804 break;
1805 case INSTALLSTATE_UNKNOWN:
1806 if (feature->Installed == INSTALLSTATE_ADVERTISED)
1807 component->hasAdvertisedFeature = 1;
1808 if (feature->Installed == INSTALLSTATE_SOURCE)
1809 component->hasSourceFeature = 1;
1810 if (feature->Installed == INSTALLSTATE_LOCAL)
1811 component->hasLocalFeature = 1;
1812 break;
1813 default:
1814 break;
1815 }
1816 }
1817 }
1818
1819 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1820 {
1821 /* check if it's local or source */
1822 if (!(component->Attributes & msidbComponentAttributesOptional) &&
1823 (component->hasLocalFeature || component->hasSourceFeature))
1824 {
1825 if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1826 !component->ForceLocalState)
1827 {
1828 component->Action = INSTALLSTATE_SOURCE;
1829 component->ActionRequest = INSTALLSTATE_SOURCE;
1830 }
1831 else
1832 {
1833 component->Action = INSTALLSTATE_LOCAL;
1834 component->ActionRequest = INSTALLSTATE_LOCAL;
1835 }
1836 continue;
1837 }
1838
1839 /* if any feature is local, the component must be local too */
1840 if (component->hasLocalFeature)
1841 {
1842 component->Action = INSTALLSTATE_LOCAL;
1843 component->ActionRequest = INSTALLSTATE_LOCAL;
1844 continue;
1845 }
1846 if (component->hasSourceFeature)
1847 {
1848 component->Action = INSTALLSTATE_SOURCE;
1849 component->ActionRequest = INSTALLSTATE_SOURCE;
1850 continue;
1851 }
1852 if (component->hasAdvertisedFeature)
1853 {
1854 component->Action = INSTALLSTATE_ADVERTISED;
1855 component->ActionRequest = INSTALLSTATE_ADVERTISED;
1856 continue;
1857 }
1858 TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1859 if (component->anyAbsent && component->ComponentId)
1860 {
1861 component->Action = INSTALLSTATE_ABSENT;
1862 component->ActionRequest = INSTALLSTATE_ABSENT;
1863 }
1864 }
1865
1866 LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1867 {
1868 if (component->ActionRequest == INSTALLSTATE_DEFAULT)
1869 {
1870 TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1871 component->Action = INSTALLSTATE_LOCAL;
1872 component->ActionRequest = INSTALLSTATE_LOCAL;
1873 }
1874
1875 if (component->ActionRequest == INSTALLSTATE_SOURCE &&
1876 component->Installed == INSTALLSTATE_SOURCE &&
1877 component->hasSourceFeature)
1878 {
1879 component->Action = INSTALLSTATE_UNKNOWN;
1880 component->ActionRequest = INSTALLSTATE_UNKNOWN;
1881 }
1882
1883 if (component->Action == INSTALLSTATE_LOCAL || component->Action == INSTALLSTATE_SOURCE)
1884 component->num_clients++;
1885 else if (component->Action == INSTALLSTATE_ABSENT)
1886 {
1887 component->num_clients--;
1888
1889 if (component->num_clients > 0)
1890 {
1891 TRACE("multiple clients uses %s - disallowing uninstallation\n", debugstr_w(component->Component));
1892 component->Action = INSTALLSTATE_UNKNOWN;
1893 }
1894 }
1895
1896 TRACE("component %s (installed %d request %d action %d)\n",
1897 debugstr_w(component->Component), component->Installed, component->ActionRequest, component->Action);
1898 }
1899
1900 return ERROR_SUCCESS;
1901 }
1902
ITERATE_CostFinalizeConditions(MSIRECORD * row,LPVOID param)1903 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1904 {
1905 MSIPACKAGE *package = param;
1906 LPCWSTR name;
1907 MSIFEATURE *feature;
1908
1909 name = MSI_RecordGetString( row, 1 );
1910
1911 feature = msi_get_loaded_feature( package, name );
1912 if (!feature)
1913 ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1914 else
1915 {
1916 LPCWSTR Condition;
1917 Condition = MSI_RecordGetString(row,3);
1918
1919 if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1920 {
1921 int level = MSI_RecordGetInteger(row,2);
1922 TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1923 feature->Level = level;
1924 }
1925 }
1926 return ERROR_SUCCESS;
1927 }
1928
msi_compare_file_versions(VS_FIXEDFILEINFO * fi,const WCHAR * version)1929 int msi_compare_file_versions( VS_FIXEDFILEINFO *fi, const WCHAR *version )
1930 {
1931 DWORD ms, ls;
1932
1933 msi_parse_version_string( version, &ms, &ls );
1934
1935 if (fi->dwFileVersionMS > ms) return 1;
1936 else if (fi->dwFileVersionMS < ms) return -1;
1937 else if (fi->dwFileVersionLS > ls) return 1;
1938 else if (fi->dwFileVersionLS < ls) return -1;
1939 return 0;
1940 }
1941
msi_compare_font_versions(const WCHAR * ver1,const WCHAR * ver2)1942 int msi_compare_font_versions( const WCHAR *ver1, const WCHAR *ver2 )
1943 {
1944 DWORD ms1, ms2;
1945
1946 msi_parse_version_string( ver1, &ms1, NULL );
1947 msi_parse_version_string( ver2, &ms2, NULL );
1948
1949 if (ms1 > ms2) return 1;
1950 else if (ms1 < ms2) return -1;
1951 return 0;
1952 }
1953
create_temp_dir(MSIDATABASE * db)1954 static WCHAR *create_temp_dir( MSIDATABASE *db )
1955 {
1956 static UINT id;
1957 WCHAR *ret;
1958
1959 if (!db->tempfolder)
1960 {
1961 WCHAR tmp[MAX_PATH];
1962 DWORD len = ARRAY_SIZE( tmp );
1963
1964 if (msi_get_property( db, L"TempFolder", tmp, &len ) ||
1965 GetFileAttributesW( tmp ) != FILE_ATTRIBUTE_DIRECTORY)
1966 {
1967 GetTempPathW( MAX_PATH, tmp );
1968 }
1969 if (!(db->tempfolder = wcsdup( tmp ))) return NULL;
1970 }
1971
1972 if ((ret = malloc( (wcslen( db->tempfolder ) + 20) * sizeof(WCHAR) )))
1973 {
1974 for (;;)
1975 {
1976 if (!GetTempFileNameW( db->tempfolder, L"msi", ++id, ret ))
1977 {
1978 free( ret );
1979 return NULL;
1980 }
1981 if (CreateDirectoryW( ret, NULL )) break;
1982 }
1983 }
1984
1985 return ret;
1986 }
1987
1988 /*
1989 * msi_build_directory_name()
1990 *
1991 * This function is to save messing round with directory names
1992 * It handles adding backslashes between path segments,
1993 * and can add \ at the end of the directory name if told to.
1994 *
1995 * It takes a variable number of arguments.
1996 * It always allocates a new string for the result, so make sure
1997 * to free the return value when finished with it.
1998 *
1999 * The first arg is the number of path segments that follow.
2000 * The arguments following count are a list of path segments.
2001 * A path segment may be NULL.
2002 *
2003 * Path segments will be added with a \ separating them.
2004 * A \ will not be added after the last segment, however if the
2005 * last segment is NULL, then the last character will be a \
2006 */
msi_build_directory_name(DWORD count,...)2007 WCHAR * WINAPIV msi_build_directory_name( DWORD count, ... )
2008 {
2009 DWORD sz = 1, i;
2010 WCHAR *dir;
2011 va_list va;
2012
2013 va_start( va, count );
2014 for (i = 0; i < count; i++)
2015 {
2016 const WCHAR *str = va_arg( va, const WCHAR * );
2017 if (str) sz += lstrlenW( str ) + 1;
2018 }
2019 va_end( va );
2020
2021 dir = malloc( sz * sizeof(WCHAR) );
2022 dir[0] = 0;
2023
2024 va_start( va, count );
2025 for (i = 0; i < count; i++)
2026 {
2027 const WCHAR *str = va_arg( va, const WCHAR * );
2028 if (!str) continue;
2029 lstrcatW( dir, str );
2030 if ( i + 1 != count && dir[0] && dir[lstrlenW( dir ) - 1] != '\\') lstrcatW( dir, L"\\" );
2031 }
2032 va_end( va );
2033 return dir;
2034 }
2035
msi_is_global_assembly(MSICOMPONENT * comp)2036 BOOL msi_is_global_assembly( MSICOMPONENT *comp )
2037 {
2038 return comp->assembly && !comp->assembly->application;
2039 }
2040
set_target_path(MSIPACKAGE * package,MSIFILE * file)2041 static void set_target_path( MSIPACKAGE *package, MSIFILE *file )
2042 {
2043 free( file->TargetPath );
2044 if (msi_is_global_assembly( file->Component ))
2045 {
2046 MSIASSEMBLY *assembly = file->Component->assembly;
2047
2048 if (!assembly->tempdir) assembly->tempdir = create_temp_dir( package->db );
2049 file->TargetPath = msi_build_directory_name( 2, assembly->tempdir, file->FileName );
2050 }
2051 else
2052 {
2053 const WCHAR *dir = msi_get_target_folder( package, file->Component->Directory );
2054 file->TargetPath = msi_build_directory_name( 2, dir, file->FileName );
2055 }
2056
2057 TRACE("file %s resolves to %s\n", debugstr_w(file->File), debugstr_w(file->TargetPath));
2058 }
2059
calculate_file_cost(MSIPACKAGE * package)2060 static UINT calculate_file_cost( MSIPACKAGE *package )
2061 {
2062 VS_FIXEDFILEINFO *file_version;
2063 WCHAR *font_version;
2064 MSIFILE *file;
2065
2066 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2067 {
2068 MSICOMPONENT *comp = file->Component;
2069 DWORD file_size;
2070
2071 if (!comp->Enabled) continue;
2072
2073 if (file->IsCompressed)
2074 comp->ForceLocalState = TRUE;
2075
2076 set_target_path( package, file );
2077
2078 if (msi_get_file_attributes( package, file->TargetPath ) == INVALID_FILE_ATTRIBUTES)
2079 {
2080 comp->cost += cost_from_size( file->FileSize );
2081 continue;
2082 }
2083 file_size = msi_get_disk_file_size( package, file->TargetPath );
2084 TRACE("%s (size %lu)\n", debugstr_w(file->TargetPath), file_size);
2085
2086 if (file->Version)
2087 {
2088 if ((file_version = msi_get_disk_file_version( package, file->TargetPath )))
2089 {
2090 if (msi_compare_file_versions( file_version, file->Version ) < 0)
2091 {
2092 comp->cost += cost_from_size( file->FileSize - file_size );
2093 }
2094 free( file_version );
2095 continue;
2096 }
2097 else if ((font_version = msi_get_font_file_version( package, file->TargetPath )))
2098 {
2099 if (msi_compare_font_versions( font_version, file->Version ) < 0)
2100 {
2101 comp->cost += cost_from_size( file->FileSize - file_size );
2102 }
2103 free( font_version );
2104 continue;
2105 }
2106 }
2107 if (file_size != file->FileSize)
2108 {
2109 comp->cost += cost_from_size( file->FileSize - file_size );
2110 }
2111 }
2112
2113 return ERROR_SUCCESS;
2114 }
2115
msi_normalize_path(const WCHAR * in)2116 WCHAR *msi_normalize_path( const WCHAR *in )
2117 {
2118 const WCHAR *p = in;
2119 WCHAR *q, *ret;
2120 int n, len = lstrlenW( in ) + 2;
2121
2122 if (!(q = ret = malloc( len * sizeof(WCHAR) ))) return NULL;
2123
2124 len = 0;
2125 while (1)
2126 {
2127 /* copy until the end of the string or a space */
2128 while (*p != ' ' && (*q = *p))
2129 {
2130 p++, len++;
2131 /* reduce many backslashes to one */
2132 if (*p != '\\' || *q != '\\')
2133 q++;
2134 }
2135
2136 /* quit at the end of the string */
2137 if (!*p)
2138 break;
2139
2140 /* count the number of spaces */
2141 n = 0;
2142 while (p[n] == ' ')
2143 n++;
2144
2145 /* if it's leading or trailing space, skip it */
2146 if ( len == 0 || p[-1] == '\\' || p[n] == '\\' )
2147 p += n;
2148 else /* copy n spaces */
2149 while (n && (*q++ = *p++)) n--;
2150 }
2151 while (q - ret > 0 && q[-1] == ' ') q--;
2152 if (q - ret > 0 && q[-1] != '\\')
2153 {
2154 q[0] = '\\';
2155 q[1] = 0;
2156 }
2157 return ret;
2158 }
2159
get_install_location(MSIPACKAGE * package)2160 static WCHAR *get_install_location( MSIPACKAGE *package )
2161 {
2162 HKEY hkey;
2163 WCHAR *path;
2164
2165 if (!package->ProductCode) return NULL;
2166 if (MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE )) return NULL;
2167 if ((path = msi_reg_get_val_str( hkey, L"InstallLocation" )) && !path[0])
2168 {
2169 free( path );
2170 path = NULL;
2171 }
2172 RegCloseKey( hkey );
2173 return path;
2174 }
2175
msi_resolve_target_folder(MSIPACKAGE * package,const WCHAR * name,BOOL load_prop)2176 void msi_resolve_target_folder( MSIPACKAGE *package, const WCHAR *name, BOOL load_prop )
2177 {
2178 FolderList *fl;
2179 MSIFOLDER *folder, *parent, *child;
2180 WCHAR *path, *normalized_path;
2181
2182 TRACE("resolving %s\n", debugstr_w(name));
2183
2184 if (!(folder = msi_get_loaded_folder( package, name ))) return;
2185
2186 if (!wcscmp( folder->Directory, L"TARGETDIR" )) /* special resolving for target root dir */
2187 {
2188 if (!(path = get_install_location( package )) &&
2189 (!load_prop || !(path = msi_dup_property( package->db, L"TARGETDIR" ))))
2190 {
2191 path = msi_dup_property( package->db, L"ROOTDRIVE" );
2192 }
2193 }
2194 else if (!load_prop || !(path = msi_dup_property( package->db, folder->Directory )))
2195 {
2196 if (folder->Parent && wcscmp( folder->Directory, folder->Parent ))
2197 {
2198 parent = msi_get_loaded_folder( package, folder->Parent );
2199 path = msi_build_directory_name( 3, parent->ResolvedTarget, folder->TargetDefault, NULL );
2200 }
2201 else
2202 path = msi_build_directory_name( 2, folder->TargetDefault, NULL );
2203 }
2204
2205 normalized_path = msi_normalize_path( path );
2206 msi_set_property( package->db, folder->Directory, normalized_path, -1 );
2207 free( path );
2208
2209 free( folder->ResolvedTarget );
2210 folder->ResolvedTarget = normalized_path;
2211
2212 LIST_FOR_EACH_ENTRY( fl, &folder->children, FolderList, entry )
2213 {
2214 child = fl->folder;
2215 msi_resolve_target_folder( package, child->Directory, load_prop );
2216 }
2217 TRACE("%s resolves to %s\n", debugstr_w(name), debugstr_w(folder->ResolvedTarget));
2218 }
2219
get_volume_space_required(MSIPACKAGE * package)2220 static ULONGLONG get_volume_space_required( MSIPACKAGE *package )
2221 {
2222 MSICOMPONENT *comp;
2223 ULONGLONG ret = 0;
2224
2225 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2226 {
2227 if (comp->Action == INSTALLSTATE_LOCAL) ret += comp->cost;
2228 }
2229 return ret;
2230 }
2231
ACTION_CostFinalize(MSIPACKAGE * package)2232 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2233 {
2234 MSICOMPONENT *comp;
2235 MSIQUERY *view;
2236 WCHAR *level, *primary_key, *primary_folder;
2237 UINT rc;
2238
2239 TRACE("Building directory properties\n");
2240 msi_resolve_target_folder( package, L"TARGETDIR", TRUE );
2241
2242 TRACE("Evaluating component conditions\n");
2243 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2244 {
2245 if (MSI_EvaluateConditionW( package, comp->Condition ) == MSICONDITION_FALSE)
2246 {
2247 TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2248 comp->Enabled = FALSE;
2249 }
2250 else
2251 comp->Enabled = TRUE;
2252 }
2253 get_client_counts( package );
2254
2255 /* read components states from the registry */
2256 ACTION_GetComponentInstallStates(package);
2257 ACTION_GetFeatureInstallStates(package);
2258
2259 if (!process_overrides( package, msi_get_property_int( package->db, L"INSTALLLEVEL", 1 ) ))
2260 {
2261 TRACE("Evaluating feature conditions\n");
2262
2263 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Condition`", &view );
2264 if (rc == ERROR_SUCCESS)
2265 {
2266 rc = MSI_IterateRecords( view, NULL, ITERATE_CostFinalizeConditions, package );
2267 msiobj_release( &view->hdr );
2268 if (rc != ERROR_SUCCESS)
2269 return rc;
2270 }
2271 }
2272
2273 TRACE("Calculating file cost\n");
2274 calculate_file_cost( package );
2275
2276 msi_set_property( package->db, L"CostingComplete", L"1", -1 );
2277 /* set default run level if not set */
2278 level = msi_dup_property( package->db, L"INSTALLLEVEL" );
2279 if (!level) msi_set_property( package->db, L"INSTALLLEVEL", L"1", -1 );
2280 free(level);
2281
2282 if ((rc = MSI_SetFeatureStates( package ))) return rc;
2283
2284 if ((primary_key = msi_dup_property( package->db, L"PRIMARYFOLDER" )))
2285 {
2286 if ((primary_folder = msi_dup_property( package->db, primary_key )))
2287 {
2288 if (((primary_folder[0] >= 'A' && primary_folder[0] <= 'Z') ||
2289 (primary_folder[0] >= 'a' && primary_folder[0] <= 'z')) && primary_folder[1] == ':')
2290 {
2291 ULARGE_INTEGER free;
2292 ULONGLONG required;
2293 WCHAR buf[21];
2294
2295 primary_folder[2] = 0;
2296 if (GetDiskFreeSpaceExW( primary_folder, &free, NULL, NULL ))
2297 {
2298 #ifdef __REACTOS__
2299 swprintf(buf, ARRAY_SIZE(buf), L"%I64u", free.QuadPart / 512);
2300 #else
2301 swprintf( buf, ARRAY_SIZE(buf), L"%lu", free.QuadPart / 512 );
2302 #endif
2303 msi_set_property( package->db, L"PrimaryVolumeSpaceAvailable", buf, -1 );
2304 }
2305 required = get_volume_space_required( package );
2306 #ifdef __REACTOS__
2307 swprintf( buf, ARRAY_SIZE(buf), L"%I64u", required );
2308 #else
2309 swprintf( buf, ARRAY_SIZE(buf), L"%lu", required );
2310 #endif
2311 msi_set_property( package->db, L"PrimaryVolumeSpaceRequired", buf, -1 );
2312
2313 #ifdef __REACTOS__
2314 swprintf( buf, ARRAY_SIZE(buf), L"%I64u", (free.QuadPart / 512) - required );
2315 #else
2316 swprintf( buf, ARRAY_SIZE(buf), L"%lu", (free.QuadPart / 512) - required );
2317 #endif
2318 msi_set_property( package->db, L"PrimaryVolumeSpaceRemaining", buf, -1 );
2319 msi_set_property( package->db, L"PrimaryVolumePath", primary_folder, 2 );
2320 }
2321 free( primary_folder );
2322 }
2323 free( primary_key );
2324 }
2325
2326 /* FIXME: check volume disk space */
2327 msi_set_property( package->db, L"OutOfDiskSpace", L"0", -1 );
2328 msi_set_property( package->db, L"OutOfNoRbDiskSpace", L"0", -1 );
2329
2330 return ERROR_SUCCESS;
2331 }
2332
parse_value(MSIPACKAGE * package,const WCHAR * value,DWORD len,DWORD * type,DWORD * size)2333 static BYTE *parse_value( MSIPACKAGE *package, const WCHAR *value, DWORD len, DWORD *type, DWORD *size )
2334 {
2335 BYTE *data;
2336
2337 if (!value)
2338 {
2339 *size = sizeof(WCHAR);
2340 *type = REG_SZ;
2341 if ((data = malloc( *size ))) *(WCHAR *)data = 0;
2342 return data;
2343 }
2344 if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2345 {
2346 if (value[1]=='x')
2347 {
2348 LPWSTR ptr;
2349 CHAR byte[5];
2350 LPWSTR deformated = NULL;
2351 int count;
2352
2353 deformat_string(package, &value[2], &deformated);
2354
2355 /* binary value type */
2356 ptr = deformated;
2357 *type = REG_BINARY;
2358 if (lstrlenW(ptr)%2)
2359 *size = (lstrlenW(ptr)/2)+1;
2360 else
2361 *size = lstrlenW(ptr)/2;
2362
2363 data = malloc(*size);
2364
2365 byte[0] = '0';
2366 byte[1] = 'x';
2367 byte[4] = 0;
2368 count = 0;
2369 /* if uneven pad with a zero in front */
2370 if (lstrlenW(ptr)%2)
2371 {
2372 byte[2]= '0';
2373 byte[3]= *ptr;
2374 ptr++;
2375 data[count] = (BYTE)strtol(byte,NULL,0);
2376 count ++;
2377 TRACE("Uneven byte count\n");
2378 }
2379 while (*ptr)
2380 {
2381 byte[2]= *ptr;
2382 ptr++;
2383 byte[3]= *ptr;
2384 ptr++;
2385 data[count] = (BYTE)strtol(byte,NULL,0);
2386 count ++;
2387 }
2388 free(deformated);
2389
2390 TRACE( "data %lu bytes(%u)\n", *size, count );
2391 }
2392 else
2393 {
2394 LPWSTR deformated;
2395 LPWSTR p;
2396 DWORD d = 0;
2397 deformat_string(package, &value[1], &deformated);
2398
2399 *type=REG_DWORD;
2400 *size = sizeof(DWORD);
2401 data = malloc(*size);
2402 p = deformated;
2403 if (*p == '-')
2404 p++;
2405 while (*p)
2406 {
2407 if ( (*p < '0') || (*p > '9') )
2408 break;
2409 d *= 10;
2410 d += (*p - '0');
2411 p++;
2412 }
2413 if (deformated[0] == '-')
2414 d = -d;
2415 *(DWORD *)data = d;
2416 TRACE( "DWORD %lu\n", *(DWORD *)data);
2417
2418 free(deformated);
2419 }
2420 }
2421 else
2422 {
2423 const WCHAR *ptr = value;
2424
2425 *type = REG_SZ;
2426 if (value[0] == '#')
2427 {
2428 ptr++; len--;
2429 if (value[1] == '%')
2430 {
2431 ptr++; len--;
2432 *type = REG_EXPAND_SZ;
2433 }
2434 }
2435 data = (BYTE *)msi_strdupW( ptr, len );
2436 if (len > lstrlenW( (const WCHAR *)data )) *type = REG_MULTI_SZ;
2437 *size = (len + 1) * sizeof(WCHAR);
2438 }
2439 return data;
2440 }
2441
get_root_key(MSIPACKAGE * package,INT root,HKEY * root_key)2442 static const WCHAR *get_root_key( MSIPACKAGE *package, INT root, HKEY *root_key )
2443 {
2444 const WCHAR *ret;
2445
2446 switch (root)
2447 {
2448 case -1:
2449 if (msi_get_property_int( package->db, L"ALLUSERS", 0 ))
2450 {
2451 *root_key = HKEY_LOCAL_MACHINE;
2452 ret = L"HKEY_LOCAL_MACHINE\\";
2453 }
2454 else
2455 {
2456 *root_key = HKEY_CURRENT_USER;
2457 ret = L"HKEY_CURRENT_USER\\";
2458 }
2459 break;
2460 case 0:
2461 *root_key = HKEY_CLASSES_ROOT;
2462 ret = L"HKEY_CLASSES_ROOT\\";
2463 break;
2464 case 1:
2465 *root_key = HKEY_CURRENT_USER;
2466 ret = L"HKEY_CURRENT_USER\\";
2467 break;
2468 case 2:
2469 *root_key = HKEY_LOCAL_MACHINE;
2470 ret = L"HKEY_LOCAL_MACHINE\\";
2471 break;
2472 case 3:
2473 *root_key = HKEY_USERS;
2474 ret = L"HKEY_USERS\\";
2475 break;
2476 default:
2477 ERR("Unknown root %i\n", root);
2478 return NULL;
2479 }
2480
2481 return ret;
2482 }
2483
get_registry_view(const MSICOMPONENT * comp)2484 static inline REGSAM get_registry_view( const MSICOMPONENT *comp )
2485 {
2486 REGSAM view = 0;
2487 if (is_wow64 || is_64bit)
2488 view |= (comp->Attributes & msidbComponentAttributes64bit) ? KEY_WOW64_64KEY : KEY_WOW64_32KEY;
2489 return view;
2490 }
2491
open_key(const MSICOMPONENT * comp,HKEY root,const WCHAR * path,BOOL create,REGSAM access)2492 static HKEY open_key( const MSICOMPONENT *comp, HKEY root, const WCHAR *path, BOOL create, REGSAM access )
2493 {
2494 WCHAR *subkey, *p, *q;
2495 HKEY hkey, ret = NULL;
2496 LONG res;
2497
2498 access |= get_registry_view( comp );
2499
2500 if (!(subkey = wcsdup( path ))) return NULL;
2501 p = subkey;
2502 if ((q = wcschr( p, '\\' ))) *q = 0;
2503 if (create)
2504 res = RegCreateKeyExW( root, subkey, 0, NULL, 0, access, NULL, &hkey, NULL );
2505 else
2506 res = RegOpenKeyExW( root, subkey, 0, access, &hkey );
2507 if (res)
2508 {
2509 TRACE( "failed to open key %s (%ld)\n", debugstr_w(subkey), res );
2510 free( subkey );
2511 return NULL;
2512 }
2513 if (q && q[1])
2514 {
2515 ret = open_key( comp, hkey, q + 1, create, access );
2516 RegCloseKey( hkey );
2517 }
2518 else ret = hkey;
2519 free( subkey );
2520 return ret;
2521 }
2522
is_special_entry(const WCHAR * name)2523 static BOOL is_special_entry( const WCHAR *name )
2524 {
2525 return (name && (name[0] == '*' || name[0] == '+') && !name[1]);
2526 }
2527
split_multi_string_values(const WCHAR * str,DWORD len,DWORD * count)2528 static WCHAR **split_multi_string_values( const WCHAR *str, DWORD len, DWORD *count )
2529 {
2530 const WCHAR *p = str;
2531 WCHAR **ret;
2532 int i = 0;
2533
2534 *count = 0;
2535 if (!str) return NULL;
2536 while ((p - str) < len)
2537 {
2538 p += lstrlenW( p ) + 1;
2539 (*count)++;
2540 }
2541 if (!(ret = malloc( *count * sizeof(WCHAR *) ))) return NULL;
2542 p = str;
2543 while ((p - str) < len)
2544 {
2545 if (!(ret[i] = wcsdup( p )))
2546 {
2547 for (; i >= 0; i--) free( ret[i] );
2548 free( ret );
2549 return NULL;
2550 }
2551 p += lstrlenW( p ) + 1;
2552 i++;
2553 }
2554 return ret;
2555 }
2556
flatten_multi_string_values(WCHAR ** left,DWORD left_count,WCHAR ** right,DWORD right_count,DWORD * size)2557 static WCHAR *flatten_multi_string_values( WCHAR **left, DWORD left_count,
2558 WCHAR **right, DWORD right_count, DWORD *size )
2559 {
2560 WCHAR *ret, *p;
2561 unsigned int i;
2562
2563 *size = sizeof(WCHAR);
2564 for (i = 0; i < left_count; i++) *size += (lstrlenW( left[i] ) + 1) * sizeof(WCHAR);
2565 for (i = 0; i < right_count; i++) *size += (lstrlenW( right[i] ) + 1) * sizeof(WCHAR);
2566
2567 if (!(ret = p = malloc( *size ))) return NULL;
2568
2569 for (i = 0; i < left_count; i++)
2570 {
2571 lstrcpyW( p, left[i] );
2572 p += lstrlenW( p ) + 1;
2573 }
2574 for (i = 0; i < right_count; i++)
2575 {
2576 lstrcpyW( p, right[i] );
2577 p += lstrlenW( p ) + 1;
2578 }
2579 *p = 0;
2580 return ret;
2581 }
2582
remove_duplicate_values(WCHAR ** old,DWORD old_count,WCHAR ** new,DWORD new_count)2583 static DWORD remove_duplicate_values( WCHAR **old, DWORD old_count,
2584 WCHAR **new, DWORD new_count )
2585 {
2586 DWORD ret = old_count;
2587 unsigned int i, j, k;
2588
2589 for (i = 0; i < new_count; i++)
2590 {
2591 for (j = 0; j < old_count; j++)
2592 {
2593 if (old[j] && !wcscmp( new[i], old[j] ))
2594 {
2595 free( old[j] );
2596 for (k = j; k < old_count - 1; k++) { old[k] = old[k + 1]; }
2597 old[k] = NULL;
2598 ret--;
2599 }
2600 }
2601 }
2602 return ret;
2603 }
2604
2605 enum join_op
2606 {
2607 JOIN_OP_APPEND,
2608 JOIN_OP_PREPEND,
2609 JOIN_OP_REPLACE
2610 };
2611
join_multi_string_values(enum join_op op,WCHAR ** old,DWORD old_count,WCHAR ** new,DWORD new_count,DWORD * size)2612 static WCHAR *join_multi_string_values( enum join_op op, WCHAR **old, DWORD old_count,
2613 WCHAR **new, DWORD new_count, DWORD *size )
2614 {
2615 switch (op)
2616 {
2617 case JOIN_OP_APPEND:
2618 old_count = remove_duplicate_values( old, old_count, new, new_count );
2619 return flatten_multi_string_values( old, old_count, new, new_count, size );
2620
2621 case JOIN_OP_PREPEND:
2622 old_count = remove_duplicate_values( old, old_count, new, new_count );
2623 return flatten_multi_string_values( new, new_count, old, old_count, size );
2624
2625 case JOIN_OP_REPLACE:
2626 return flatten_multi_string_values( new, new_count, NULL, 0, size );
2627
2628 default:
2629 ERR("unhandled join op %u\n", op);
2630 return NULL;
2631 }
2632 }
2633
build_multi_string_value(BYTE * old_value,DWORD old_size,BYTE * new_value,DWORD new_size,DWORD * size)2634 static BYTE *build_multi_string_value( BYTE *old_value, DWORD old_size,
2635 BYTE *new_value, DWORD new_size, DWORD *size )
2636 {
2637 DWORD i, old_len = 0, new_len = 0, old_count = 0, new_count = 0;
2638 const WCHAR *new_ptr = NULL, *old_ptr = NULL;
2639 enum join_op op = JOIN_OP_REPLACE;
2640 WCHAR **old = NULL, **new = NULL;
2641 BYTE *ret;
2642
2643 if (new_size / sizeof(WCHAR) - 1 > 1)
2644 {
2645 new_ptr = (const WCHAR *)new_value;
2646 new_len = new_size / sizeof(WCHAR) - 1;
2647
2648 if (!new_ptr[0] && new_ptr[new_len - 1])
2649 {
2650 op = JOIN_OP_APPEND;
2651 new_len--;
2652 new_ptr++;
2653 }
2654 else if (new_ptr[0] && !new_ptr[new_len - 1])
2655 {
2656 op = JOIN_OP_PREPEND;
2657 new_len--;
2658 }
2659 else if (new_len > 2 && !new_ptr[0] && !new_ptr[new_len - 1])
2660 {
2661 op = JOIN_OP_REPLACE;
2662 new_len -= 2;
2663 new_ptr++;
2664 }
2665 new = split_multi_string_values( new_ptr, new_len, &new_count );
2666 }
2667 if (old_size / sizeof(WCHAR) - 1 > 1)
2668 {
2669 old_ptr = (const WCHAR *)old_value;
2670 old_len = old_size / sizeof(WCHAR) - 1;
2671 old = split_multi_string_values( old_ptr, old_len, &old_count );
2672 }
2673 ret = (BYTE *)join_multi_string_values( op, old, old_count, new, new_count, size );
2674 for (i = 0; i < old_count; i++) free( old[i] );
2675 for (i = 0; i < new_count; i++) free( new[i] );
2676 free( old );
2677 free( new );
2678 return ret;
2679 }
2680
reg_get_value(HKEY hkey,const WCHAR * name,DWORD * type,DWORD * size)2681 static BYTE *reg_get_value( HKEY hkey, const WCHAR *name, DWORD *type, DWORD *size )
2682 {
2683 BYTE *ret;
2684 if (RegQueryValueExW( hkey, name, NULL, NULL, NULL, size )) return NULL;
2685 if (!(ret = malloc( *size ))) return NULL;
2686 RegQueryValueExW( hkey, name, NULL, type, ret, size );
2687 return ret;
2688 }
2689
ITERATE_WriteRegistryValues(MSIRECORD * row,LPVOID param)2690 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2691 {
2692 MSIPACKAGE *package = param;
2693 BYTE *new_value, *old_value = NULL;
2694 HKEY root_key, hkey;
2695 DWORD type, old_type, new_size, old_size = 0;
2696 LPWSTR deformated, uikey;
2697 const WCHAR *szRoot, *component, *name, *key, *str;
2698 MSICOMPONENT *comp;
2699 MSIRECORD * uirow;
2700 INT root;
2701 BOOL check_first = FALSE;
2702 int len;
2703
2704 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2705
2706 component = MSI_RecordGetString(row, 6);
2707 comp = msi_get_loaded_component(package,component);
2708 if (!comp)
2709 return ERROR_SUCCESS;
2710
2711 comp->Action = msi_get_component_action( package, comp );
2712 if (comp->Action != INSTALLSTATE_LOCAL && comp->Action != INSTALLSTATE_SOURCE)
2713 {
2714 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2715 return ERROR_SUCCESS;
2716 }
2717
2718 name = MSI_RecordGetString(row, 4);
2719 if( MSI_RecordIsNull(row,5) && name )
2720 {
2721 /* null values can have special meanings */
2722 if (name[0]=='-' && name[1] == 0)
2723 return ERROR_SUCCESS;
2724 if ((name[0] == '+' || name[0] == '*') && !name[1])
2725 check_first = TRUE;
2726 }
2727
2728 root = MSI_RecordGetInteger(row,2);
2729 key = MSI_RecordGetString(row, 3);
2730
2731 szRoot = get_root_key( package, root, &root_key );
2732 if (!szRoot)
2733 return ERROR_SUCCESS;
2734
2735 deformat_string(package, key , &deformated);
2736 uikey = malloc( (wcslen(deformated) + wcslen(szRoot) + 1) * sizeof(WCHAR) );
2737 lstrcpyW(uikey,szRoot);
2738 lstrcatW(uikey,deformated);
2739
2740 if (!(hkey = open_key( comp, root_key, deformated, TRUE, KEY_QUERY_VALUE | KEY_SET_VALUE )))
2741 {
2742 ERR("Could not create key %s\n", debugstr_w(deformated));
2743 free(uikey);
2744 free(deformated);
2745 return ERROR_FUNCTION_FAILED;
2746 }
2747 free( deformated );
2748 str = msi_record_get_string( row, 5, NULL );
2749 len = deformat_string( package, str, &deformated );
2750 new_value = parse_value( package, deformated, len, &type, &new_size );
2751
2752 free( deformated );
2753 deformat_string(package, name, &deformated);
2754
2755 if (!is_special_entry( name ))
2756 {
2757 old_value = reg_get_value( hkey, deformated, &old_type, &old_size );
2758 if (type == REG_MULTI_SZ)
2759 {
2760 BYTE *new;
2761 if (old_value && old_type != REG_MULTI_SZ)
2762 {
2763 free( old_value );
2764 old_value = NULL;
2765 old_size = 0;
2766 }
2767 new = build_multi_string_value( old_value, old_size, new_value, new_size, &new_size );
2768 free( new_value );
2769 new_value = new;
2770 }
2771 if (!check_first)
2772 {
2773 TRACE( "setting value %s of %s type %lu\n", debugstr_w(deformated), debugstr_w(uikey), type );
2774 RegSetValueExW( hkey, deformated, 0, type, new_value, new_size );
2775 }
2776 else if (!old_value)
2777 {
2778 if (deformated || new_size)
2779 {
2780 TRACE( "setting value %s of %s type %lu\n", debugstr_w(deformated), debugstr_w(uikey), type );
2781 RegSetValueExW( hkey, deformated, 0, type, new_value, new_size );
2782 }
2783 }
2784 else TRACE("not overwriting existing value %s of %s\n", debugstr_w(deformated), debugstr_w(uikey));
2785 }
2786 RegCloseKey(hkey);
2787
2788 uirow = MSI_CreateRecord(3);
2789 MSI_RecordSetStringW(uirow,2,deformated);
2790 MSI_RecordSetStringW(uirow,1,uikey);
2791 if (type == REG_SZ || type == REG_EXPAND_SZ)
2792 MSI_RecordSetStringW(uirow, 3, (LPWSTR)new_value);
2793 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
2794 msiobj_release( &uirow->hdr );
2795
2796 free(new_value);
2797 free(old_value);
2798 free(deformated);
2799 free(uikey);
2800
2801 return ERROR_SUCCESS;
2802 }
2803
ACTION_WriteRegistryValues(MSIPACKAGE * package)2804 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2805 {
2806 MSIQUERY *view;
2807 UINT rc;
2808
2809 if (package->script == SCRIPT_NONE)
2810 return msi_schedule_action(package, SCRIPT_INSTALL, L"WriteRegistryValues");
2811
2812 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `Registry`", &view);
2813 if (rc != ERROR_SUCCESS)
2814 return ERROR_SUCCESS;
2815
2816 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2817 msiobj_release(&view->hdr);
2818 return rc;
2819 }
2820
is_key_empty(const MSICOMPONENT * comp,HKEY root,const WCHAR * path)2821 static int is_key_empty(const MSICOMPONENT *comp, HKEY root, const WCHAR *path)
2822 {
2823 DWORD subkeys, values;
2824 HKEY key;
2825 LONG res;
2826
2827 key = open_key(comp, root, path, FALSE, KEY_READ);
2828 if (!key) return 0;
2829
2830 res = RegQueryInfoKeyW(key, 0, 0, 0, &subkeys, 0, 0, &values, 0, 0, 0, 0);
2831 RegCloseKey(key);
2832
2833 return !res && !subkeys && !values;
2834 }
2835
delete_key(const MSICOMPONENT * comp,HKEY root,const WCHAR * path)2836 static void delete_key( const MSICOMPONENT *comp, HKEY root, const WCHAR *path )
2837 {
2838 LONG res = ERROR_SUCCESS;
2839 REGSAM access = get_registry_view( comp );
2840 WCHAR *subkey, *p;
2841 HKEY hkey;
2842
2843 if (!(subkey = wcsdup( path ))) return;
2844 do
2845 {
2846 if ((p = wcsrchr( subkey, '\\' )))
2847 {
2848 *p = 0;
2849 if (!p[1]) continue; /* trailing backslash */
2850 hkey = open_key( comp, root, subkey, FALSE, READ_CONTROL );
2851 if (!hkey) break;
2852 if (!is_key_empty(comp, hkey, p + 1))
2853 {
2854 RegCloseKey(hkey);
2855 break;
2856 }
2857 res = RegDeleteKeyExW( hkey, p + 1, access, 0 );
2858 RegCloseKey( hkey );
2859 }
2860 else if (is_key_empty(comp, root, subkey))
2861 res = RegDeleteKeyExW( root, subkey, access, 0 );
2862 if (res)
2863 {
2864 TRACE( "failed to delete key %s (%ld)\n", debugstr_w(subkey), res );
2865 break;
2866 }
2867 } while (p);
2868 free( subkey );
2869 }
2870
delete_value(const MSICOMPONENT * comp,HKEY root,const WCHAR * path,const WCHAR * value)2871 static void delete_value( const MSICOMPONENT *comp, HKEY root, const WCHAR *path, const WCHAR *value )
2872 {
2873 LONG res;
2874 HKEY hkey;
2875
2876 if ((hkey = open_key( comp, root, path, FALSE, KEY_SET_VALUE | KEY_QUERY_VALUE )))
2877 {
2878 if ((res = RegDeleteValueW( hkey, value )))
2879 TRACE( "failed to delete value %s (%ld)\n", debugstr_w(value), res );
2880
2881 RegCloseKey( hkey );
2882 if (is_key_empty(comp, root, path))
2883 {
2884 TRACE("removing empty key %s\n", debugstr_w(path));
2885 delete_key( comp, root, path );
2886 }
2887 }
2888 }
2889
delete_tree(const MSICOMPONENT * comp,HKEY root,const WCHAR * path)2890 static void delete_tree( const MSICOMPONENT *comp, HKEY root, const WCHAR *path )
2891 {
2892 LONG res;
2893 HKEY hkey;
2894
2895 if (!(hkey = open_key( comp, root, path, FALSE, KEY_ALL_ACCESS ))) return;
2896 res = RegDeleteTreeW( hkey, NULL );
2897 if (res) TRACE( "failed to delete subtree of %s (%ld)\n", debugstr_w(path), res );
2898 delete_key( comp, root, path );
2899 RegCloseKey( hkey );
2900 }
2901
ITERATE_RemoveRegistryValuesOnUninstall(MSIRECORD * row,LPVOID param)2902 static UINT ITERATE_RemoveRegistryValuesOnUninstall( MSIRECORD *row, LPVOID param )
2903 {
2904 MSIPACKAGE *package = param;
2905 LPCWSTR component, name, key_str, root_key_str;
2906 LPWSTR deformated_key, deformated_name, ui_key_str;
2907 MSICOMPONENT *comp;
2908 MSIRECORD *uirow;
2909 BOOL delete_key = FALSE;
2910 HKEY hkey_root;
2911 UINT size;
2912 INT root;
2913
2914 msi_ui_progress( package, 2, REG_PROGRESS_VALUE, 0, 0 );
2915
2916 component = MSI_RecordGetString( row, 6 );
2917 comp = msi_get_loaded_component( package, component );
2918 if (!comp)
2919 return ERROR_SUCCESS;
2920
2921 comp->Action = msi_get_component_action( package, comp );
2922 if (comp->Action != INSTALLSTATE_ABSENT)
2923 {
2924 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
2925 return ERROR_SUCCESS;
2926 }
2927
2928 name = MSI_RecordGetString( row, 4 );
2929 if (MSI_RecordIsNull( row, 5 ) && name )
2930 {
2931 if (name[0] == '+' && !name[1])
2932 return ERROR_SUCCESS;
2933 if ((name[0] == '-' || name[0] == '*') && !name[1])
2934 {
2935 delete_key = TRUE;
2936 name = NULL;
2937 }
2938 }
2939
2940 root = MSI_RecordGetInteger( row, 2 );
2941 key_str = MSI_RecordGetString( row, 3 );
2942
2943 root_key_str = get_root_key( package, root, &hkey_root );
2944 if (!root_key_str)
2945 return ERROR_SUCCESS;
2946
2947 deformat_string( package, key_str, &deformated_key );
2948 size = lstrlenW( deformated_key ) + lstrlenW( root_key_str ) + 1;
2949 ui_key_str = malloc( size * sizeof(WCHAR) );
2950 lstrcpyW( ui_key_str, root_key_str );
2951 lstrcatW( ui_key_str, deformated_key );
2952
2953 deformat_string( package, name, &deformated_name );
2954
2955 if (delete_key) delete_tree( comp, hkey_root, deformated_key );
2956 else delete_value( comp, hkey_root, deformated_key, deformated_name );
2957 free( deformated_key );
2958
2959 uirow = MSI_CreateRecord( 2 );
2960 MSI_RecordSetStringW( uirow, 1, ui_key_str );
2961 MSI_RecordSetStringW( uirow, 2, deformated_name );
2962 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
2963 msiobj_release( &uirow->hdr );
2964
2965 free( ui_key_str );
2966 free( deformated_name );
2967 return ERROR_SUCCESS;
2968 }
2969
ITERATE_RemoveRegistryValuesOnInstall(MSIRECORD * row,LPVOID param)2970 static UINT ITERATE_RemoveRegistryValuesOnInstall( MSIRECORD *row, LPVOID param )
2971 {
2972 MSIPACKAGE *package = param;
2973 LPCWSTR component, name, key_str, root_key_str;
2974 LPWSTR deformated_key, deformated_name, ui_key_str;
2975 MSICOMPONENT *comp;
2976 MSIRECORD *uirow;
2977 BOOL delete_key = FALSE;
2978 HKEY hkey_root;
2979 UINT size;
2980 INT root;
2981
2982 component = MSI_RecordGetString( row, 5 );
2983 comp = msi_get_loaded_component( package, component );
2984 if (!comp)
2985 return ERROR_SUCCESS;
2986
2987 comp->Action = msi_get_component_action( package, comp );
2988 if (comp->Action != INSTALLSTATE_LOCAL)
2989 {
2990 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
2991 return ERROR_SUCCESS;
2992 }
2993
2994 if ((name = MSI_RecordGetString( row, 4 )))
2995 {
2996 if (name[0] == '-' && !name[1])
2997 {
2998 delete_key = TRUE;
2999 name = NULL;
3000 }
3001 }
3002
3003 root = MSI_RecordGetInteger( row, 2 );
3004 key_str = MSI_RecordGetString( row, 3 );
3005
3006 root_key_str = get_root_key( package, root, &hkey_root );
3007 if (!root_key_str)
3008 return ERROR_SUCCESS;
3009
3010 deformat_string( package, key_str, &deformated_key );
3011 size = lstrlenW( deformated_key ) + lstrlenW( root_key_str ) + 1;
3012 ui_key_str = malloc( size * sizeof(WCHAR) );
3013 lstrcpyW( ui_key_str, root_key_str );
3014 lstrcatW( ui_key_str, deformated_key );
3015
3016 deformat_string( package, name, &deformated_name );
3017
3018 if (delete_key) delete_tree( comp, hkey_root, deformated_key );
3019 else delete_value( comp, hkey_root, deformated_key, deformated_name );
3020 free( deformated_key );
3021
3022 uirow = MSI_CreateRecord( 2 );
3023 MSI_RecordSetStringW( uirow, 1, ui_key_str );
3024 MSI_RecordSetStringW( uirow, 2, deformated_name );
3025 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
3026 msiobj_release( &uirow->hdr );
3027
3028 free( ui_key_str );
3029 free( deformated_name );
3030 return ERROR_SUCCESS;
3031 }
3032
ACTION_RemoveRegistryValues(MSIPACKAGE * package)3033 static UINT ACTION_RemoveRegistryValues( MSIPACKAGE *package )
3034 {
3035 MSIQUERY *view;
3036 UINT rc;
3037
3038 if (package->script == SCRIPT_NONE)
3039 return msi_schedule_action(package, SCRIPT_INSTALL, L"RemoveRegistryValues");
3040
3041 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Registry`", &view );
3042 if (rc == ERROR_SUCCESS)
3043 {
3044 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnUninstall, package );
3045 msiobj_release( &view->hdr );
3046 if (rc != ERROR_SUCCESS)
3047 return rc;
3048 }
3049 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `RemoveRegistry`", &view );
3050 if (rc == ERROR_SUCCESS)
3051 {
3052 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveRegistryValuesOnInstall, package );
3053 msiobj_release( &view->hdr );
3054 if (rc != ERROR_SUCCESS)
3055 return rc;
3056 }
3057 return ERROR_SUCCESS;
3058 }
3059
ACTION_InstallInitialize(MSIPACKAGE * package)3060 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3061 {
3062 return ERROR_SUCCESS;
3063 }
3064
3065
ACTION_InstallValidate(MSIPACKAGE * package)3066 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3067 {
3068 MSICOMPONENT *comp;
3069 DWORD total = 0, count = 0;
3070 MSIQUERY *view;
3071 MSIFEATURE *feature;
3072 MSIFILE *file;
3073 UINT rc;
3074
3075 TRACE("InstallValidate\n");
3076
3077 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Registry`", &view );
3078 if (rc == ERROR_SUCCESS)
3079 {
3080 rc = MSI_IterateRecords( view, &count, NULL, package );
3081 msiobj_release( &view->hdr );
3082 if (rc != ERROR_SUCCESS)
3083 return rc;
3084 total += count * REG_PROGRESS_VALUE;
3085 }
3086 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3087 total += COMPONENT_PROGRESS_VALUE;
3088
3089 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3090 total += file->FileSize;
3091
3092 msi_ui_progress( package, 0, total, 0, 0 );
3093
3094 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3095 {
3096 TRACE("Feature: %s Installed %d Request %d Action %d\n",
3097 debugstr_w(feature->Feature), feature->Installed,
3098 feature->ActionRequest, feature->Action);
3099 }
3100 return ERROR_SUCCESS;
3101 }
3102
ITERATE_LaunchConditions(MSIRECORD * row,LPVOID param)3103 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
3104 {
3105 MSIPACKAGE* package = param;
3106 const WCHAR *cond, *message;
3107 UINT r;
3108
3109 cond = MSI_RecordGetString(row, 1);
3110 r = MSI_EvaluateConditionW(package, cond);
3111 if (r == MSICONDITION_FALSE)
3112 {
3113 if ((package->ui_level & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
3114 {
3115 WCHAR *deformated;
3116 message = MSI_RecordGetString(row, 2);
3117 deformat_string(package, message, &deformated);
3118 MessageBoxW(NULL, deformated, L"Install Failed", MB_OK);
3119 free(deformated);
3120 }
3121
3122 return ERROR_INSTALL_FAILURE;
3123 }
3124
3125 return ERROR_SUCCESS;
3126 }
3127
ACTION_LaunchConditions(MSIPACKAGE * package)3128 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3129 {
3130 MSIQUERY *view;
3131 UINT rc;
3132
3133 TRACE("Checking launch conditions\n");
3134
3135 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `LaunchCondition`", &view);
3136 if (rc != ERROR_SUCCESS)
3137 return ERROR_SUCCESS;
3138
3139 rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
3140 msiobj_release(&view->hdr);
3141 return rc;
3142 }
3143
resolve_keypath(MSIPACKAGE * package,MSICOMPONENT * cmp)3144 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
3145 {
3146
3147 if (!cmp->KeyPath)
3148 return wcsdup( msi_get_target_folder( package, cmp->Directory ) );
3149
3150 if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3151 {
3152 MSIRECORD *row;
3153 UINT root, len;
3154 LPWSTR deformated, buffer, deformated_name;
3155 LPCWSTR key, name;
3156
3157 row = MSI_QueryGetRecord(package->db, L"SELECT * FROM `Registry` WHERE `Registry` = '%s'", cmp->KeyPath);
3158 if (!row)
3159 return NULL;
3160
3161 root = MSI_RecordGetInteger(row,2);
3162 key = MSI_RecordGetString(row, 3);
3163 name = MSI_RecordGetString(row, 4);
3164 deformat_string(package, key , &deformated);
3165 deformat_string(package, name, &deformated_name);
3166
3167 len = lstrlenW(deformated) + 6;
3168 if (deformated_name)
3169 len+=lstrlenW(deformated_name);
3170
3171 buffer = malloc(len * sizeof(WCHAR));
3172
3173 if (deformated_name)
3174 swprintf(buffer, len, L"%02d:\\%s\\%s", root, deformated, deformated_name);
3175 else
3176 swprintf(buffer, len, L"%02d:\\%s\\", root, deformated);
3177
3178 free(deformated);
3179 free(deformated_name);
3180 msiobj_release(&row->hdr);
3181
3182 return buffer;
3183 }
3184 else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3185 {
3186 FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3187 return NULL;
3188 }
3189 else
3190 {
3191 MSIFILE *file = msi_get_loaded_file( package, cmp->KeyPath );
3192
3193 if (file)
3194 return wcsdup( file->TargetPath );
3195 }
3196 return NULL;
3197 }
3198
open_shared_dlls_key(MSICOMPONENT * comp,BOOL create,REGSAM access)3199 static HKEY open_shared_dlls_key( MSICOMPONENT *comp, BOOL create, REGSAM access )
3200 {
3201 return open_key( comp, HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\SharedDLLs",
3202 create, access );
3203 }
3204
get_shared_dlls_count(MSICOMPONENT * comp)3205 static UINT get_shared_dlls_count( MSICOMPONENT *comp )
3206 {
3207 DWORD count, type, sz = sizeof(count);
3208 HKEY hkey = open_shared_dlls_key( comp, FALSE, KEY_READ );
3209 if (RegQueryValueExW( hkey, comp->FullKeypath, NULL, &type, (BYTE *)&count, &sz )) count = 0;
3210 RegCloseKey( hkey );
3211 return count;
3212 }
3213
write_shared_dlls_count(MSICOMPONENT * comp,const WCHAR * path,INT count)3214 static void write_shared_dlls_count( MSICOMPONENT *comp, const WCHAR *path, INT count )
3215 {
3216 HKEY hkey = open_shared_dlls_key( comp, TRUE, KEY_SET_VALUE );
3217 if (count > 0)
3218 msi_reg_set_val_dword( hkey, path, count );
3219 else
3220 RegDeleteValueW( hkey, path );
3221 RegCloseKey(hkey);
3222 }
3223
refcount_component(MSIPACKAGE * package,MSICOMPONENT * comp)3224 static void refcount_component( MSIPACKAGE *package, MSICOMPONENT *comp )
3225 {
3226 MSIFEATURE *feature;
3227 INT count = 0;
3228 BOOL write = FALSE;
3229
3230 /* only refcount DLLs */
3231 if (!comp->KeyPath || comp->assembly || comp->Attributes & msidbComponentAttributesRegistryKeyPath ||
3232 comp->Attributes & msidbComponentAttributesODBCDataSource)
3233 write = FALSE;
3234 else
3235 {
3236 count = get_shared_dlls_count( comp );
3237 write = (count > 0);
3238 if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
3239 write = TRUE;
3240 }
3241
3242 /* increment counts */
3243 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3244 {
3245 ComponentList *cl;
3246
3247 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_LOCAL)
3248 continue;
3249
3250 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3251 {
3252 if ( cl->component == comp )
3253 count++;
3254 }
3255 }
3256
3257 /* decrement counts */
3258 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3259 {
3260 ComponentList *cl;
3261
3262 if (msi_get_feature_action( package, feature ) != INSTALLSTATE_ABSENT)
3263 continue;
3264
3265 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3266 {
3267 if ( cl->component == comp )
3268 count--;
3269 }
3270 }
3271
3272 /* ref count all the files in the component */
3273 if (write)
3274 {
3275 MSIFILE *file;
3276
3277 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
3278 {
3279 if (file->Component == comp)
3280 write_shared_dlls_count( comp, file->TargetPath, count );
3281 }
3282 }
3283
3284 /* add a count for permanent */
3285 if (comp->Attributes & msidbComponentAttributesPermanent)
3286 count ++;
3287
3288 comp->RefCount = count;
3289
3290 if (write)
3291 write_shared_dlls_count( comp, comp->FullKeypath, comp->RefCount );
3292 }
3293
build_full_keypath(MSIPACKAGE * package,MSICOMPONENT * comp)3294 static WCHAR *build_full_keypath( MSIPACKAGE *package, MSICOMPONENT *comp )
3295 {
3296 if (comp->assembly)
3297 {
3298 DWORD len = lstrlenW( L"<\\" ) + lstrlenW( comp->assembly->display_name );
3299 WCHAR *keypath = malloc( (len + 1) * sizeof(WCHAR) );
3300
3301 if (keypath)
3302 {
3303 lstrcpyW( keypath, L"<\\" );
3304 lstrcatW( keypath, comp->assembly->display_name );
3305 }
3306 return keypath;
3307 }
3308 return resolve_keypath( package, comp );
3309 }
3310
ACTION_ProcessComponents(MSIPACKAGE * package)3311 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
3312 {
3313 WCHAR squashed_pc[SQUASHED_GUID_SIZE], squashed_cc[SQUASHED_GUID_SIZE];
3314 UINT rc;
3315 MSICOMPONENT *comp;
3316 HKEY hkey;
3317
3318 TRACE("\n");
3319
3320 msi_set_sourcedir_props(package, FALSE);
3321
3322 if (package->script == SCRIPT_NONE)
3323 return msi_schedule_action(package, SCRIPT_INSTALL, L"ProcessComponents");
3324
3325 squash_guid( package->ProductCode, squashed_pc );
3326
3327 LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
3328 {
3329 MSIRECORD *uirow;
3330 INSTALLSTATE action;
3331
3332 msi_ui_progress( package, 2, COMPONENT_PROGRESS_VALUE, 0, 0 );
3333 if (!comp->ComponentId)
3334 continue;
3335
3336 squash_guid( comp->ComponentId, squashed_cc );
3337 free( comp->FullKeypath );
3338 comp->FullKeypath = build_full_keypath( package, comp );
3339
3340 refcount_component( package, comp );
3341
3342 if (package->need_rollback) action = comp->Installed;
3343 else action = comp->ActionRequest;
3344
3345 TRACE("Component %s (%s) Keypath=%s RefCount=%u Clients=%u Action=%u\n",
3346 debugstr_w(comp->Component), debugstr_w(squashed_cc),
3347 debugstr_w(comp->FullKeypath), comp->RefCount, comp->num_clients, action);
3348
3349 if (action == INSTALLSTATE_LOCAL || action == INSTALLSTATE_SOURCE)
3350 {
3351 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3352 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, L"S-1-5-18", &hkey, TRUE);
3353 else
3354 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL, &hkey, TRUE);
3355
3356 if (rc != ERROR_SUCCESS)
3357 continue;
3358
3359 if (comp->Attributes & msidbComponentAttributesPermanent)
3360 {
3361 msi_reg_set_val_str(hkey, L"00000000000000000000000000000000", comp->FullKeypath);
3362 }
3363 if (action == INSTALLSTATE_LOCAL)
3364 msi_reg_set_val_str( hkey, squashed_pc, comp->FullKeypath );
3365 else
3366 {
3367 MSIFILE *file;
3368 MSIRECORD *row;
3369 LPWSTR ptr, ptr2;
3370 WCHAR source[MAX_PATH];
3371 WCHAR base[MAX_PATH];
3372 LPWSTR sourcepath;
3373
3374 if (!comp->KeyPath || !(file = msi_get_loaded_file(package, comp->KeyPath)))
3375 continue;
3376
3377 if (!(row = MSI_QueryGetRecord(package->db, L"SELECT * FROM `Media` WHERE `LastSequence` >= %d "
3378 L"ORDER BY `DiskId`", file->Sequence)))
3379 return ERROR_FUNCTION_FAILED;
3380
3381 swprintf(source, ARRAY_SIZE(source), L"%02d\\", MSI_RecordGetInteger(row, 1));
3382 ptr2 = wcsrchr(source, '\\') + 1;
3383 msiobj_release(&row->hdr);
3384
3385 lstrcpyW(base, package->PackagePath);
3386 ptr = wcsrchr(base, '\\');
3387 *(ptr + 1) = '\0';
3388
3389 sourcepath = msi_resolve_file_source(package, file);
3390 ptr = sourcepath + lstrlenW(base);
3391 lstrcpyW(ptr2, ptr);
3392 free(sourcepath);
3393
3394 msi_reg_set_val_str( hkey, squashed_pc, source );
3395 }
3396 RegCloseKey(hkey);
3397 }
3398 else if (action == INSTALLSTATE_ABSENT)
3399 {
3400 if (comp->num_clients <= 0)
3401 {
3402 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3403 rc = MSIREG_DeleteUserDataComponentKey( comp->ComponentId, L"S-1-5-18" );
3404 else
3405 rc = MSIREG_DeleteUserDataComponentKey( comp->ComponentId, NULL );
3406
3407 if (rc != ERROR_SUCCESS) WARN( "failed to delete component key %u\n", rc );
3408 }
3409 else
3410 {
3411 LONG res;
3412
3413 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3414 rc = MSIREG_OpenUserDataComponentKey( comp->ComponentId, L"S-1-5-18", &hkey, FALSE );
3415 else
3416 rc = MSIREG_OpenUserDataComponentKey( comp->ComponentId, NULL, &hkey, FALSE );
3417
3418 if (rc != ERROR_SUCCESS)
3419 {
3420 WARN( "failed to open component key %u\n", rc );
3421 continue;
3422 }
3423 res = RegDeleteValueW( hkey, squashed_pc );
3424 RegCloseKey(hkey);
3425 if (res) WARN( "failed to delete component value %ld\n", res );
3426 }
3427 }
3428
3429 /* UI stuff */
3430 uirow = MSI_CreateRecord(3);
3431 MSI_RecordSetStringW(uirow,1,package->ProductCode);
3432 MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3433 MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3434 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
3435 msiobj_release( &uirow->hdr );
3436 }
3437 return ERROR_SUCCESS;
3438 }
3439
3440 struct typelib
3441 {
3442 CLSID clsid;
3443 LPWSTR source;
3444 LPWSTR path;
3445 ITypeLib *ptLib;
3446 };
3447
Typelib_EnumResNameProc(HMODULE hModule,LPCWSTR lpszType,LPWSTR lpszName,LONG_PTR lParam)3448 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType,
3449 LPWSTR lpszName, LONG_PTR lParam)
3450 {
3451 TLIBATTR *attr;
3452 struct typelib *tl_struct = (struct typelib *)lParam;
3453 int sz;
3454 HRESULT res;
3455
3456 if (!IS_INTRESOURCE(lpszName))
3457 {
3458 ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3459 return TRUE;
3460 }
3461
3462 sz = lstrlenW(tl_struct->source)+4;
3463
3464 if ((INT_PTR)lpszName == 1)
3465 tl_struct->path = wcsdup(tl_struct->source);
3466 else
3467 {
3468 tl_struct->path = malloc(sz * sizeof(WCHAR));
3469 #ifdef __REACTOS__
3470 swprintf(tl_struct->path, sz, L"%s\\%d", tl_struct->source, (WORD)(INT_PTR)lpszName);
3471 #else
3472 swprintf(tl_struct->path, sz, L"%s\\%d", tl_struct->source, lpszName);
3473 #endif
3474 }
3475
3476 TRACE("trying %s\n", debugstr_w(tl_struct->path));
3477 res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3478 if (FAILED(res))
3479 {
3480 free(tl_struct->path);
3481 tl_struct->path = NULL;
3482
3483 return TRUE;
3484 }
3485
3486 ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3487 if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3488 {
3489 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3490 return FALSE;
3491 }
3492
3493 free(tl_struct->path);
3494 tl_struct->path = NULL;
3495
3496 ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3497 ITypeLib_Release(tl_struct->ptLib);
3498
3499 return TRUE;
3500 }
3501
load_library(MSIPACKAGE * package,const WCHAR * filename,DWORD flags)3502 static HMODULE load_library( MSIPACKAGE *package, const WCHAR *filename, DWORD flags )
3503 {
3504 HMODULE module;
3505 msi_disable_fs_redirection( package );
3506 module = LoadLibraryExW( filename, NULL, flags );
3507 msi_revert_fs_redirection( package );
3508 return module;
3509 }
3510
load_typelib(MSIPACKAGE * package,const WCHAR * filename,REGKIND kind,ITypeLib ** lib)3511 static HRESULT load_typelib( MSIPACKAGE *package, const WCHAR *filename, REGKIND kind, ITypeLib **lib )
3512 {
3513 HRESULT hr;
3514 msi_disable_fs_redirection( package );
3515 hr = LoadTypeLibEx( filename, kind, lib );
3516 msi_revert_fs_redirection( package );
3517 return hr;
3518 }
3519
ITERATE_RegisterTypeLibraries(MSIRECORD * row,LPVOID param)3520 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3521 {
3522 MSIPACKAGE* package = param;
3523 LPCWSTR component;
3524 MSICOMPONENT *comp;
3525 MSIFILE *file;
3526 struct typelib tl_struct;
3527 ITypeLib *tlib;
3528 HMODULE module;
3529 HRESULT hr;
3530
3531 component = MSI_RecordGetString(row,3);
3532 comp = msi_get_loaded_component(package,component);
3533 if (!comp)
3534 return ERROR_SUCCESS;
3535
3536 comp->Action = msi_get_component_action( package, comp );
3537 if (comp->Action != INSTALLSTATE_LOCAL)
3538 {
3539 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3540 return ERROR_SUCCESS;
3541 }
3542
3543 if (!comp->KeyPath || !(file = msi_get_loaded_file( package, comp->KeyPath )))
3544 {
3545 TRACE("component has no key path\n");
3546 return ERROR_SUCCESS;
3547 }
3548 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
3549
3550 module = load_library( package, file->TargetPath, LOAD_LIBRARY_AS_DATAFILE );
3551 if (module)
3552 {
3553 LPCWSTR guid;
3554 guid = MSI_RecordGetString(row,1);
3555 CLSIDFromString( guid, &tl_struct.clsid);
3556 tl_struct.source = wcsdup( file->TargetPath );
3557 tl_struct.path = NULL;
3558
3559 EnumResourceNamesW(module, L"TYPELIB", Typelib_EnumResNameProc,
3560 (LONG_PTR)&tl_struct);
3561
3562 if (tl_struct.path)
3563 {
3564 LPCWSTR helpid, help_path = NULL;
3565 HRESULT res;
3566
3567 helpid = MSI_RecordGetString(row,6);
3568
3569 if (helpid) help_path = msi_get_target_folder( package, helpid );
3570 res = RegisterTypeLib( tl_struct.ptLib, tl_struct.path, (OLECHAR *)help_path );
3571
3572 if (FAILED(res))
3573 ERR("Failed to register type library %s\n", debugstr_w(tl_struct.path));
3574 else
3575 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3576
3577 ITypeLib_Release(tl_struct.ptLib);
3578 free(tl_struct.path);
3579 }
3580 else ERR("Failed to load type library %s\n", debugstr_w(tl_struct.source));
3581
3582 FreeLibrary(module);
3583 free(tl_struct.source);
3584 }
3585 else
3586 {
3587 hr = load_typelib( package, file->TargetPath, REGKIND_REGISTER, &tlib );
3588 if (FAILED(hr))
3589 {
3590 ERR( "failed to load type library: %#lx\n", hr );
3591 return ERROR_INSTALL_FAILURE;
3592 }
3593
3594 ITypeLib_Release(tlib);
3595 }
3596
3597 return ERROR_SUCCESS;
3598 }
3599
ACTION_RegisterTypeLibraries(MSIPACKAGE * package)3600 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3601 {
3602 MSIQUERY *view;
3603 UINT rc;
3604
3605 if (package->script == SCRIPT_NONE)
3606 return msi_schedule_action(package, SCRIPT_INSTALL, L"RegisterTypeLibraries");
3607
3608 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `TypeLib`", &view);
3609 if (rc != ERROR_SUCCESS)
3610 return ERROR_SUCCESS;
3611
3612 rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3613 msiobj_release(&view->hdr);
3614 return rc;
3615 }
3616
ITERATE_UnregisterTypeLibraries(MSIRECORD * row,LPVOID param)3617 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3618 {
3619 MSIPACKAGE *package = param;
3620 LPCWSTR component, guid;
3621 MSICOMPONENT *comp;
3622 GUID libid;
3623 UINT version;
3624 LCID language;
3625 SYSKIND syskind;
3626 HRESULT hr;
3627
3628 component = MSI_RecordGetString( row, 3 );
3629 comp = msi_get_loaded_component( package, component );
3630 if (!comp)
3631 return ERROR_SUCCESS;
3632
3633 comp->Action = msi_get_component_action( package, comp );
3634 if (comp->Action != INSTALLSTATE_ABSENT)
3635 {
3636 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3637 return ERROR_SUCCESS;
3638 }
3639 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
3640
3641 guid = MSI_RecordGetString( row, 1 );
3642 CLSIDFromString( guid, &libid );
3643 version = MSI_RecordGetInteger( row, 4 );
3644 language = MSI_RecordGetInteger( row, 2 );
3645
3646 #ifdef _WIN64
3647 syskind = SYS_WIN64;
3648 #else
3649 syskind = SYS_WIN32;
3650 #endif
3651
3652 hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3653 if (FAILED(hr))
3654 {
3655 WARN( "failed to unregister typelib: %#lx\n", hr );
3656 }
3657
3658 return ERROR_SUCCESS;
3659 }
3660
ACTION_UnregisterTypeLibraries(MSIPACKAGE * package)3661 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3662 {
3663 MSIQUERY *view;
3664 UINT rc;
3665
3666 if (package->script == SCRIPT_NONE)
3667 return msi_schedule_action(package, SCRIPT_INSTALL, L"UnregisterTypeLibraries");
3668
3669 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `TypeLib`", &view );
3670 if (rc != ERROR_SUCCESS)
3671 return ERROR_SUCCESS;
3672
3673 rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3674 msiobj_release( &view->hdr );
3675 return rc;
3676 }
3677
get_link_file(MSIPACKAGE * package,MSIRECORD * row)3678 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3679 {
3680 LPCWSTR directory, extension, link_folder;
3681 WCHAR *link_file = NULL, *filename, *new_filename;
3682
3683 directory = MSI_RecordGetString( row, 2 );
3684 link_folder = msi_get_target_folder( package, directory );
3685 if (!link_folder)
3686 {
3687 ERR("unable to resolve folder %s\n", debugstr_w(directory));
3688 return NULL;
3689 }
3690 /* may be needed because of a bug somewhere else */
3691 msi_create_full_path( package, link_folder );
3692
3693 filename = msi_dup_record_field( row, 3 );
3694 if (!filename) return NULL;
3695 msi_reduce_to_long_filename( filename );
3696
3697 extension = wcsrchr( filename, '.' );
3698 if (!extension || wcsicmp( extension, L".lnk" ))
3699 {
3700 int len = lstrlenW( filename );
3701 new_filename = realloc( filename, len * sizeof(WCHAR) + sizeof(L".lnk") );
3702 if (!new_filename) goto done;
3703 filename = new_filename;
3704 memcpy( filename + len, L".lnk", sizeof(L".lnk") );
3705 }
3706 link_file = msi_build_directory_name( 2, link_folder, filename );
3707
3708 done:
3709 free( filename );
3710 return link_file;
3711 }
3712
msi_build_icon_path(MSIPACKAGE * package,const WCHAR * icon_name)3713 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3714 {
3715 WCHAR *folder, *dest, *path;
3716
3717 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3718 folder = msi_dup_property( package->db, L"WindowsFolder" );
3719 else
3720 {
3721 WCHAR *appdata = msi_dup_property( package->db, L"AppDataFolder" );
3722 folder = msi_build_directory_name( 2, appdata, L"Microsoft\\" );
3723 free( appdata );
3724 }
3725 dest = msi_build_directory_name( 3, folder, L"Installer\\", package->ProductCode );
3726 msi_create_full_path( package, dest );
3727 path = msi_build_directory_name( 2, dest, icon_name );
3728 free( folder );
3729 free( dest );
3730 return path;
3731 }
3732
ITERATE_CreateShortcuts(MSIRECORD * row,LPVOID param)3733 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3734 {
3735 MSIPACKAGE *package = param;
3736 LPWSTR link_file, deformated, path;
3737 LPCWSTR component, target;
3738 MSICOMPONENT *comp;
3739 IShellLinkW *sl = NULL;
3740 IPersistFile *pf = NULL;
3741 HRESULT res;
3742
3743 component = MSI_RecordGetString(row, 4);
3744 comp = msi_get_loaded_component(package, component);
3745 if (!comp)
3746 return ERROR_SUCCESS;
3747
3748 comp->Action = msi_get_component_action( package, comp );
3749 if (comp->Action != INSTALLSTATE_LOCAL)
3750 {
3751 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3752 return ERROR_SUCCESS;
3753 }
3754 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
3755
3756 res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3757 &IID_IShellLinkW, (LPVOID *) &sl );
3758
3759 if (FAILED( res ))
3760 {
3761 ERR("CLSID_ShellLink not available\n");
3762 goto err;
3763 }
3764
3765 res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3766 if (FAILED( res ))
3767 {
3768 ERR("QueryInterface(IID_IPersistFile) failed\n");
3769 goto err;
3770 }
3771
3772 target = MSI_RecordGetString(row, 5);
3773 if (wcschr(target, '['))
3774 {
3775 deformat_string( package, target, &path );
3776 TRACE("target path is %s\n", debugstr_w(path));
3777 IShellLinkW_SetPath( sl, path );
3778 free( path );
3779 }
3780 else
3781 {
3782 FIXME("poorly handled shortcut format, advertised shortcut\n");
3783 path = resolve_keypath( package, comp );
3784 IShellLinkW_SetPath( sl, path );
3785 free( path );
3786 }
3787
3788 if (!MSI_RecordIsNull(row,6))
3789 {
3790 LPCWSTR arguments = MSI_RecordGetString(row, 6);
3791 deformat_string(package, arguments, &deformated);
3792 IShellLinkW_SetArguments(sl,deformated);
3793 free(deformated);
3794 }
3795
3796 if (!MSI_RecordIsNull(row,7))
3797 {
3798 LPCWSTR description = MSI_RecordGetString(row, 7);
3799 IShellLinkW_SetDescription(sl, description);
3800 }
3801
3802 if (!MSI_RecordIsNull(row,8))
3803 IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3804
3805 if (!MSI_RecordIsNull(row,9))
3806 {
3807 INT index;
3808 LPCWSTR icon = MSI_RecordGetString(row, 9);
3809
3810 path = msi_build_icon_path(package, icon);
3811 index = MSI_RecordGetInteger(row,10);
3812
3813 /* no value means 0 */
3814 if (index == MSI_NULL_INTEGER)
3815 index = 0;
3816
3817 IShellLinkW_SetIconLocation(sl, path, index);
3818 free(path);
3819 }
3820
3821 if (!MSI_RecordIsNull(row,11))
3822 IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3823
3824 if (!MSI_RecordIsNull(row,12))
3825 {
3826 LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3827 full_path = msi_get_target_folder( package, wkdir );
3828 if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3829 }
3830
3831 link_file = get_link_file(package, row);
3832 TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3833
3834 msi_disable_fs_redirection( package );
3835 IPersistFile_Save(pf, link_file, FALSE);
3836 msi_revert_fs_redirection( package );
3837
3838 free(link_file);
3839
3840 err:
3841 if (pf)
3842 IPersistFile_Release( pf );
3843 if (sl)
3844 IShellLinkW_Release( sl );
3845
3846 return ERROR_SUCCESS;
3847 }
3848
ACTION_CreateShortcuts(MSIPACKAGE * package)3849 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3850 {
3851 MSIQUERY *view;
3852 HRESULT res;
3853 UINT rc;
3854
3855 if (package->script == SCRIPT_NONE)
3856 return msi_schedule_action(package, SCRIPT_INSTALL, L"CreateShortcuts");
3857
3858 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `Shortcut`", &view);
3859 if (rc != ERROR_SUCCESS)
3860 return ERROR_SUCCESS;
3861
3862 res = CoInitialize( NULL );
3863
3864 rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3865 msiobj_release(&view->hdr);
3866
3867 if (SUCCEEDED(res)) CoUninitialize();
3868 return rc;
3869 }
3870
ITERATE_RemoveShortcuts(MSIRECORD * row,LPVOID param)3871 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3872 {
3873 MSIPACKAGE *package = param;
3874 LPWSTR link_file;
3875 LPCWSTR component;
3876 MSICOMPONENT *comp;
3877
3878 component = MSI_RecordGetString( row, 4 );
3879 comp = msi_get_loaded_component( package, component );
3880 if (!comp)
3881 return ERROR_SUCCESS;
3882
3883 comp->Action = msi_get_component_action( package, comp );
3884 if (comp->Action != INSTALLSTATE_ABSENT)
3885 {
3886 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3887 return ERROR_SUCCESS;
3888 }
3889 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
3890
3891 link_file = get_link_file( package, row );
3892 TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3893 if (!msi_delete_file( package, link_file )) WARN( "failed to remove shortcut file %lu\n", GetLastError() );
3894 free( link_file );
3895
3896 return ERROR_SUCCESS;
3897 }
3898
ACTION_RemoveShortcuts(MSIPACKAGE * package)3899 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3900 {
3901 MSIQUERY *view;
3902 UINT rc;
3903
3904 if (package->script == SCRIPT_NONE)
3905 return msi_schedule_action(package, SCRIPT_INSTALL, L"RemoveShortcuts");
3906
3907 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Shortcut`", &view );
3908 if (rc != ERROR_SUCCESS)
3909 return ERROR_SUCCESS;
3910
3911 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3912 msiobj_release( &view->hdr );
3913 return rc;
3914 }
3915
ITERATE_PublishIcon(MSIRECORD * row,LPVOID param)3916 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3917 {
3918 MSIPACKAGE *package = param;
3919 HANDLE handle;
3920 WCHAR *icon_path;
3921 const WCHAR *filename;
3922 char buffer[1024];
3923 DWORD sz;
3924 UINT rc;
3925
3926 filename = MSI_RecordGetString( row, 1 );
3927 if (!filename)
3928 {
3929 ERR("Unable to get filename\n");
3930 return ERROR_SUCCESS;
3931 }
3932
3933 icon_path = msi_build_icon_path( package, filename );
3934
3935 TRACE("Creating icon file at %s\n", debugstr_w(icon_path));
3936
3937 handle = msi_create_file( package, icon_path, GENERIC_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL );
3938 if (handle == INVALID_HANDLE_VALUE)
3939 {
3940 ERR("Unable to create file %s\n", debugstr_w(icon_path));
3941 free( icon_path );
3942 return ERROR_SUCCESS;
3943 }
3944
3945 do
3946 {
3947 DWORD count;
3948 sz = 1024;
3949 rc = MSI_RecordReadStream( row, 2, buffer, &sz );
3950 if (rc != ERROR_SUCCESS)
3951 {
3952 ERR("Failed to get stream\n");
3953 msi_delete_file( package, icon_path );
3954 break;
3955 }
3956 WriteFile( handle, buffer, sz, &count, NULL );
3957 } while (sz == 1024);
3958
3959 free( icon_path );
3960 CloseHandle( handle );
3961
3962 return ERROR_SUCCESS;
3963 }
3964
publish_icons(MSIPACKAGE * package)3965 static UINT publish_icons(MSIPACKAGE *package)
3966 {
3967 MSIQUERY *view;
3968 UINT r;
3969
3970 r = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `Icon`", &view);
3971 if (r == ERROR_SUCCESS)
3972 {
3973 r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3974 msiobj_release(&view->hdr);
3975 if (r != ERROR_SUCCESS)
3976 return r;
3977 }
3978 return ERROR_SUCCESS;
3979 }
3980
publish_sourcelist(MSIPACKAGE * package,HKEY hkey)3981 static UINT publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3982 {
3983 UINT r;
3984 HKEY source;
3985 LPWSTR buffer;
3986 MSIMEDIADISK *disk;
3987 MSISOURCELISTINFO *info;
3988
3989 r = RegCreateKeyW(hkey, L"SourceList", &source);
3990 if (r != ERROR_SUCCESS)
3991 return r;
3992
3993 RegCloseKey(source);
3994
3995 buffer = wcsrchr(package->PackagePath, '\\') + 1;
3996 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3997 package->Context, MSICODE_PRODUCT,
3998 INSTALLPROPERTY_PACKAGENAMEW, buffer);
3999 if (r != ERROR_SUCCESS)
4000 return r;
4001
4002 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4003 package->Context, MSICODE_PRODUCT,
4004 INSTALLPROPERTY_MEDIAPACKAGEPATHW, L"");
4005 if (r != ERROR_SUCCESS)
4006 return r;
4007
4008 r = MsiSourceListSetInfoW(package->ProductCode, NULL,
4009 package->Context, MSICODE_PRODUCT,
4010 INSTALLPROPERTY_DISKPROMPTW, L"");
4011 if (r != ERROR_SUCCESS)
4012 return r;
4013
4014 LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
4015 {
4016 if (!wcscmp( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
4017 msi_set_last_used_source(package->ProductCode, NULL, info->context,
4018 info->options, info->value);
4019 else
4020 MsiSourceListSetInfoW(package->ProductCode, NULL,
4021 info->context, info->options,
4022 info->property, info->value);
4023 }
4024
4025 LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
4026 {
4027 MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
4028 disk->context, disk->options,
4029 disk->disk_id, disk->volume_label, disk->disk_prompt);
4030 }
4031
4032 return ERROR_SUCCESS;
4033 }
4034
publish_product_properties(MSIPACKAGE * package,HKEY hkey)4035 static UINT publish_product_properties(MSIPACKAGE *package, HKEY hkey)
4036 {
4037 WCHAR *buffer, *ptr, *guids, packcode[SQUASHED_GUID_SIZE];
4038 DWORD langid;
4039
4040 buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
4041 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
4042 free(buffer);
4043
4044 langid = msi_get_property_int(package->db, L"ProductLanguage", 0);
4045 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4046
4047 /* FIXME */
4048 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
4049
4050 buffer = msi_dup_property(package->db, L"ARPPRODUCTICON");
4051 if (buffer)
4052 {
4053 LPWSTR path = msi_build_icon_path(package, buffer);
4054 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
4055 free(path);
4056 free(buffer);
4057 }
4058
4059 buffer = msi_dup_property(package->db, L"ProductVersion");
4060 if (buffer)
4061 {
4062 DWORD verdword = msi_version_str_to_dword(buffer);
4063 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4064 free(buffer);
4065 }
4066
4067 msi_reg_set_val_dword(hkey, L"Assignment", 0);
4068 msi_reg_set_val_dword(hkey, L"AdvertiseFlags", 0x184);
4069 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
4070 msi_reg_set_val_multi_str(hkey, L"Clients", L":\0");
4071
4072 if (!(guids = msi_get_package_code(package->db))) return ERROR_OUTOFMEMORY;
4073 if ((ptr = wcschr(guids, ';'))) *ptr = 0;
4074 squash_guid(guids, packcode);
4075 free(guids);
4076 msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
4077
4078 return ERROR_SUCCESS;
4079 }
4080
publish_upgrade_code(MSIPACKAGE * package)4081 static UINT publish_upgrade_code(MSIPACKAGE *package)
4082 {
4083 UINT r;
4084 HKEY hkey;
4085 WCHAR *upgrade, squashed_pc[SQUASHED_GUID_SIZE];
4086
4087 upgrade = msi_dup_property(package->db, L"UpgradeCode");
4088 if (!upgrade)
4089 return ERROR_SUCCESS;
4090
4091 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4092 r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
4093 else
4094 r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
4095
4096 if (r != ERROR_SUCCESS)
4097 {
4098 WARN("failed to open upgrade code key\n");
4099 free(upgrade);
4100 return ERROR_SUCCESS;
4101 }
4102 squash_guid(package->ProductCode, squashed_pc);
4103 msi_reg_set_val_str(hkey, squashed_pc, NULL);
4104 RegCloseKey(hkey);
4105 free(upgrade);
4106 return ERROR_SUCCESS;
4107 }
4108
check_publish(MSIPACKAGE * package)4109 static BOOL check_publish(MSIPACKAGE *package)
4110 {
4111 MSIFEATURE *feature;
4112
4113 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4114 {
4115 feature->Action = msi_get_feature_action( package, feature );
4116 if (feature->Action == INSTALLSTATE_LOCAL || feature->Action == INSTALLSTATE_SOURCE)
4117 return TRUE;
4118 }
4119
4120 return FALSE;
4121 }
4122
check_unpublish(MSIPACKAGE * package)4123 static BOOL check_unpublish(MSIPACKAGE *package)
4124 {
4125 MSIFEATURE *feature;
4126
4127 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4128 {
4129 feature->Action = msi_get_feature_action( package, feature );
4130 if (feature->Action != INSTALLSTATE_ABSENT)
4131 return FALSE;
4132 }
4133
4134 return TRUE;
4135 }
4136
publish_patches(MSIPACKAGE * package)4137 static UINT publish_patches( MSIPACKAGE *package )
4138 {
4139 WCHAR patch_squashed[GUID_SIZE];
4140 HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4141 LONG res;
4142 MSIPATCHINFO *patch;
4143 UINT r;
4144 WCHAR *p, *all_patches = NULL;
4145 DWORD len = 0;
4146
4147 r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4148 if (r != ERROR_SUCCESS)
4149 return ERROR_FUNCTION_FAILED;
4150
4151 res = RegCreateKeyExW( product_key, L"Patches", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4152 if (res != ERROR_SUCCESS)
4153 {
4154 r = ERROR_FUNCTION_FAILED;
4155 goto done;
4156 }
4157
4158 r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4159 if (r != ERROR_SUCCESS)
4160 goto done;
4161
4162 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4163 {
4164 squash_guid( patch->patchcode, patch_squashed );
4165 len += lstrlenW( patch_squashed ) + 1;
4166 }
4167
4168 p = all_patches = malloc( (len + 1) * sizeof(WCHAR) );
4169 if (!all_patches)
4170 goto done;
4171
4172 LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4173 {
4174 HKEY patch_key;
4175
4176 squash_guid( patch->patchcode, p );
4177 p += lstrlenW( p ) + 1;
4178
4179 res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4180 (const BYTE *)patch->transforms,
4181 (lstrlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4182 if (res != ERROR_SUCCESS)
4183 goto done;
4184
4185 r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4186 if (r != ERROR_SUCCESS)
4187 goto done;
4188
4189 res = RegSetValueExW( patch_key, L"LocalPackage", 0, REG_SZ, (const BYTE *)patch->localfile,
4190 (lstrlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4191 RegCloseKey( patch_key );
4192 if (res != ERROR_SUCCESS)
4193 goto done;
4194
4195 if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4196 {
4197 res = GetLastError();
4198 ERR( "unable to copy patch package %lu\n", res );
4199 goto done;
4200 }
4201 res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4202 if (res != ERROR_SUCCESS)
4203 goto done;
4204
4205 res = RegSetValueExW( patch_key, L"State", 0, REG_DWORD, (const BYTE *)&patch->state,
4206 sizeof(patch->state) );
4207 if (res != ERROR_SUCCESS)
4208 {
4209 RegCloseKey( patch_key );
4210 goto done;
4211 }
4212
4213 res = RegSetValueExW( patch_key, L"Uninstallable", 0, REG_DWORD, (const BYTE *)&patch->uninstallable,
4214 sizeof(patch->uninstallable) );
4215 RegCloseKey( patch_key );
4216 if (res != ERROR_SUCCESS)
4217 goto done;
4218 }
4219
4220 all_patches[len] = 0;
4221 res = RegSetValueExW( patches_key, L"Patches", 0, REG_MULTI_SZ,
4222 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4223 if (res != ERROR_SUCCESS)
4224 goto done;
4225
4226 res = RegSetValueExW( product_patches_key, L"AllPatches", 0, REG_MULTI_SZ,
4227 (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4228 if (res != ERROR_SUCCESS)
4229 r = ERROR_FUNCTION_FAILED;
4230
4231 done:
4232 RegCloseKey( product_patches_key );
4233 RegCloseKey( patches_key );
4234 RegCloseKey( product_key );
4235 free( all_patches );
4236 return r;
4237 }
4238
ACTION_PublishProduct(MSIPACKAGE * package)4239 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4240 {
4241 UINT rc;
4242 HKEY hukey = NULL, hudkey = NULL;
4243 MSIRECORD *uirow;
4244 BOOL republish = FALSE;
4245
4246 if (package->script == SCRIPT_NONE)
4247 return msi_schedule_action(package, SCRIPT_INSTALL, L"PublishProduct");
4248
4249 if (!list_empty(&package->patches))
4250 {
4251 rc = publish_patches(package);
4252 if (rc != ERROR_SUCCESS)
4253 goto end;
4254 }
4255
4256 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4257 &hukey, FALSE);
4258 if (rc == ERROR_SUCCESS)
4259 {
4260 WCHAR *package_code;
4261
4262 package_code = msi_reg_get_val_str(hukey, INSTALLPROPERTY_PACKAGECODEW);
4263 if (package_code)
4264 {
4265 WCHAR *guid;
4266
4267 guid = msi_get_package_code(package->db);
4268 if (guid)
4269 {
4270 WCHAR packed[SQUASHED_GUID_SIZE];
4271
4272 squash_guid(guid, packed);
4273 free(guid);
4274 if (!wcscmp(packed, package_code))
4275 {
4276 TRACE("re-publishing product - new package\n");
4277 republish = TRUE;
4278 }
4279 }
4280 free(package_code);
4281 }
4282 }
4283
4284 /* FIXME: also need to publish if the product is in advertise mode */
4285 if (!republish && !check_publish(package))
4286 {
4287 if (hukey)
4288 RegCloseKey(hukey);
4289 return ERROR_SUCCESS;
4290 }
4291
4292 if (!hukey)
4293 {
4294 rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4295 &hukey, TRUE);
4296 if (rc != ERROR_SUCCESS)
4297 goto end;
4298 }
4299
4300 rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4301 NULL, &hudkey, TRUE);
4302 if (rc != ERROR_SUCCESS)
4303 goto end;
4304
4305 rc = publish_upgrade_code(package);
4306 if (rc != ERROR_SUCCESS)
4307 goto end;
4308
4309 rc = publish_product_properties(package, hukey);
4310 if (rc != ERROR_SUCCESS)
4311 goto end;
4312
4313 rc = publish_sourcelist(package, hukey);
4314 if (rc != ERROR_SUCCESS)
4315 goto end;
4316
4317 rc = publish_icons(package);
4318
4319 end:
4320 uirow = MSI_CreateRecord( 1 );
4321 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4322 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
4323 msiobj_release( &uirow->hdr );
4324
4325 RegCloseKey(hukey);
4326 RegCloseKey(hudkey);
4327 return rc;
4328 }
4329
get_ini_file_name(MSIPACKAGE * package,MSIRECORD * row)4330 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4331 {
4332 WCHAR *filename, *ptr, *folder, *ret;
4333 const WCHAR *dirprop;
4334
4335 filename = msi_dup_record_field( row, 2 );
4336 if (filename && (ptr = wcschr( filename, '|' )))
4337 ptr++;
4338 else
4339 ptr = filename;
4340
4341 dirprop = MSI_RecordGetString( row, 3 );
4342 if (dirprop)
4343 {
4344 folder = wcsdup( msi_get_target_folder( package, dirprop ) );
4345 if (!folder) folder = msi_dup_property( package->db, dirprop );
4346 }
4347 else
4348 folder = msi_dup_property( package->db, L"WindowsFolder" );
4349
4350 if (!folder)
4351 {
4352 ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4353 free( filename );
4354 return NULL;
4355 }
4356
4357 ret = msi_build_directory_name( 2, folder, ptr );
4358
4359 free( filename );
4360 free( folder );
4361 return ret;
4362 }
4363
ITERATE_WriteIniValues(MSIRECORD * row,LPVOID param)4364 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4365 {
4366 MSIPACKAGE *package = param;
4367 LPCWSTR component, section, key, value, identifier;
4368 LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4369 MSIRECORD * uirow;
4370 INT action;
4371 MSICOMPONENT *comp;
4372
4373 component = MSI_RecordGetString(row, 8);
4374 comp = msi_get_loaded_component(package,component);
4375 if (!comp)
4376 return ERROR_SUCCESS;
4377
4378 comp->Action = msi_get_component_action( package, comp );
4379 if (comp->Action != INSTALLSTATE_LOCAL)
4380 {
4381 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4382 return ERROR_SUCCESS;
4383 }
4384
4385 identifier = MSI_RecordGetString(row,1);
4386 section = MSI_RecordGetString(row,4);
4387 key = MSI_RecordGetString(row,5);
4388 value = MSI_RecordGetString(row,6);
4389 action = MSI_RecordGetInteger(row,7);
4390
4391 deformat_string(package,section,&deformated_section);
4392 deformat_string(package,key,&deformated_key);
4393 deformat_string(package,value,&deformated_value);
4394
4395 fullname = get_ini_file_name(package, row);
4396
4397 if (action == 0)
4398 {
4399 TRACE("Adding value %s to section %s in %s\n",
4400 debugstr_w(deformated_key), debugstr_w(deformated_section),
4401 debugstr_w(fullname));
4402 WritePrivateProfileStringW(deformated_section, deformated_key,
4403 deformated_value, fullname);
4404 }
4405 else if (action == 1)
4406 {
4407 WCHAR returned[10];
4408 GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4409 returned, 10, fullname);
4410 if (returned[0] == 0)
4411 {
4412 TRACE("Adding value %s to section %s in %s\n",
4413 debugstr_w(deformated_key), debugstr_w(deformated_section),
4414 debugstr_w(fullname));
4415
4416 WritePrivateProfileStringW(deformated_section, deformated_key,
4417 deformated_value, fullname);
4418 }
4419 }
4420 else if (action == 3)
4421 FIXME("Append to existing section not yet implemented\n");
4422
4423 uirow = MSI_CreateRecord(4);
4424 MSI_RecordSetStringW(uirow,1,identifier);
4425 MSI_RecordSetStringW(uirow,2,deformated_section);
4426 MSI_RecordSetStringW(uirow,3,deformated_key);
4427 MSI_RecordSetStringW(uirow,4,deformated_value);
4428 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
4429 msiobj_release( &uirow->hdr );
4430
4431 free(fullname);
4432 free(deformated_key);
4433 free(deformated_value);
4434 free(deformated_section);
4435 return ERROR_SUCCESS;
4436 }
4437
ACTION_WriteIniValues(MSIPACKAGE * package)4438 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4439 {
4440 MSIQUERY *view;
4441 UINT rc;
4442
4443 if (package->script == SCRIPT_NONE)
4444 return msi_schedule_action(package, SCRIPT_INSTALL, L"WriteIniValues");
4445
4446 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `IniFile`", &view);
4447 if (rc != ERROR_SUCCESS)
4448 return ERROR_SUCCESS;
4449
4450 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4451 msiobj_release(&view->hdr);
4452 return rc;
4453 }
4454
ITERATE_RemoveIniValuesOnUninstall(MSIRECORD * row,LPVOID param)4455 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4456 {
4457 MSIPACKAGE *package = param;
4458 LPCWSTR component, section, key, value, identifier;
4459 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4460 MSICOMPONENT *comp;
4461 MSIRECORD *uirow;
4462 INT action;
4463
4464 component = MSI_RecordGetString( row, 8 );
4465 comp = msi_get_loaded_component( package, component );
4466 if (!comp)
4467 return ERROR_SUCCESS;
4468
4469 comp->Action = msi_get_component_action( package, comp );
4470 if (comp->Action != INSTALLSTATE_ABSENT)
4471 {
4472 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4473 return ERROR_SUCCESS;
4474 }
4475
4476 identifier = MSI_RecordGetString( row, 1 );
4477 section = MSI_RecordGetString( row, 4 );
4478 key = MSI_RecordGetString( row, 5 );
4479 value = MSI_RecordGetString( row, 6 );
4480 action = MSI_RecordGetInteger( row, 7 );
4481
4482 deformat_string( package, section, &deformated_section );
4483 deformat_string( package, key, &deformated_key );
4484 deformat_string( package, value, &deformated_value );
4485
4486 if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4487 {
4488 filename = get_ini_file_name( package, row );
4489
4490 TRACE("Removing key %s from section %s in %s\n",
4491 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4492
4493 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4494 {
4495 WARN( "unable to remove key %lu\n", GetLastError() );
4496 }
4497 free( filename );
4498 }
4499 else
4500 FIXME("Unsupported action %d\n", action);
4501
4502
4503 uirow = MSI_CreateRecord( 4 );
4504 MSI_RecordSetStringW( uirow, 1, identifier );
4505 MSI_RecordSetStringW( uirow, 2, deformated_section );
4506 MSI_RecordSetStringW( uirow, 3, deformated_key );
4507 MSI_RecordSetStringW( uirow, 4, deformated_value );
4508 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
4509 msiobj_release( &uirow->hdr );
4510
4511 free( deformated_key );
4512 free( deformated_value );
4513 free( deformated_section );
4514 return ERROR_SUCCESS;
4515 }
4516
ITERATE_RemoveIniValuesOnInstall(MSIRECORD * row,LPVOID param)4517 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4518 {
4519 MSIPACKAGE *package = param;
4520 LPCWSTR component, section, key, value, identifier;
4521 LPWSTR deformated_section, deformated_key, deformated_value, filename;
4522 MSICOMPONENT *comp;
4523 MSIRECORD *uirow;
4524 INT action;
4525
4526 component = MSI_RecordGetString( row, 8 );
4527 comp = msi_get_loaded_component( package, component );
4528 if (!comp)
4529 return ERROR_SUCCESS;
4530
4531 comp->Action = msi_get_component_action( package, comp );
4532 if (comp->Action != INSTALLSTATE_LOCAL)
4533 {
4534 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4535 return ERROR_SUCCESS;
4536 }
4537
4538 identifier = MSI_RecordGetString( row, 1 );
4539 section = MSI_RecordGetString( row, 4 );
4540 key = MSI_RecordGetString( row, 5 );
4541 value = MSI_RecordGetString( row, 6 );
4542 action = MSI_RecordGetInteger( row, 7 );
4543
4544 deformat_string( package, section, &deformated_section );
4545 deformat_string( package, key, &deformated_key );
4546 deformat_string( package, value, &deformated_value );
4547
4548 if (action == msidbIniFileActionRemoveLine)
4549 {
4550 filename = get_ini_file_name( package, row );
4551
4552 TRACE("Removing key %s from section %s in %s\n",
4553 debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4554
4555 if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4556 {
4557 WARN( "unable to remove key %lu\n", GetLastError() );
4558 }
4559 free( filename );
4560 }
4561 else
4562 FIXME("Unsupported action %d\n", action);
4563
4564 uirow = MSI_CreateRecord( 4 );
4565 MSI_RecordSetStringW( uirow, 1, identifier );
4566 MSI_RecordSetStringW( uirow, 2, deformated_section );
4567 MSI_RecordSetStringW( uirow, 3, deformated_key );
4568 MSI_RecordSetStringW( uirow, 4, deformated_value );
4569 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
4570 msiobj_release( &uirow->hdr );
4571
4572 free( deformated_key );
4573 free( deformated_value );
4574 free( deformated_section );
4575 return ERROR_SUCCESS;
4576 }
4577
ACTION_RemoveIniValues(MSIPACKAGE * package)4578 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4579 {
4580 MSIQUERY *view;
4581 UINT rc;
4582
4583 if (package->script == SCRIPT_NONE)
4584 return msi_schedule_action(package, SCRIPT_INSTALL, L"RemoveIniValues");
4585
4586 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `IniFile`", &view );
4587 if (rc == ERROR_SUCCESS)
4588 {
4589 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4590 msiobj_release( &view->hdr );
4591 if (rc != ERROR_SUCCESS)
4592 return rc;
4593 }
4594 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `RemoveIniFile`", &view );
4595 if (rc == ERROR_SUCCESS)
4596 {
4597 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4598 msiobj_release( &view->hdr );
4599 if (rc != ERROR_SUCCESS)
4600 return rc;
4601 }
4602 return ERROR_SUCCESS;
4603 }
4604
register_dll(const WCHAR * dll,BOOL unregister)4605 static void register_dll( const WCHAR *dll, BOOL unregister )
4606 {
4607 static const WCHAR regW[] = L"regsvr32.exe /s \"%s\"";
4608 static const WCHAR unregW[] = L"regsvr32.exe /s /u \"%s\"";
4609 PROCESS_INFORMATION pi;
4610 STARTUPINFOW si;
4611 WCHAR *cmd;
4612
4613 if (!(cmd = malloc( wcslen(dll) * sizeof(WCHAR) + sizeof(unregW) ))) return;
4614
4615 if (unregister) swprintf( cmd, lstrlenW(dll) + ARRAY_SIZE(unregW), unregW, dll );
4616 else swprintf( cmd, lstrlenW(dll) + ARRAY_SIZE(unregW), regW, dll );
4617
4618 memset( &si, 0, sizeof(STARTUPINFOW) );
4619 if (CreateProcessW( NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi ))
4620 {
4621 CloseHandle( pi.hThread );
4622 msi_dialog_check_messages( pi.hProcess );
4623 CloseHandle( pi.hProcess );
4624 }
4625 free( cmd );
4626 }
4627
ITERATE_SelfRegModules(MSIRECORD * row,LPVOID param)4628 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4629 {
4630 MSIPACKAGE *package = param;
4631 LPCWSTR filename;
4632 MSIFILE *file;
4633 MSIRECORD *uirow;
4634
4635 filename = MSI_RecordGetString( row, 1 );
4636 file = msi_get_loaded_file( package, filename );
4637 if (!file)
4638 {
4639 WARN("unable to find file %s\n", debugstr_w(filename));
4640 return ERROR_SUCCESS;
4641 }
4642 file->Component->Action = msi_get_component_action( package, file->Component );
4643 if (file->Component->Action != INSTALLSTATE_LOCAL)
4644 {
4645 TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4646 return ERROR_SUCCESS;
4647 }
4648
4649 TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4650 register_dll( file->TargetPath, FALSE );
4651
4652 uirow = MSI_CreateRecord( 2 );
4653 MSI_RecordSetStringW( uirow, 1, file->File );
4654 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4655 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
4656 msiobj_release( &uirow->hdr );
4657
4658 return ERROR_SUCCESS;
4659 }
4660
ACTION_SelfRegModules(MSIPACKAGE * package)4661 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4662 {
4663 MSIQUERY *view;
4664 UINT rc;
4665
4666 if (package->script == SCRIPT_NONE)
4667 return msi_schedule_action(package, SCRIPT_INSTALL, L"SelfRegModules");
4668
4669 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `SelfReg`", &view);
4670 if (rc != ERROR_SUCCESS)
4671 return ERROR_SUCCESS;
4672
4673 rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4674 msiobj_release(&view->hdr);
4675 return rc;
4676 }
4677
ITERATE_SelfUnregModules(MSIRECORD * row,LPVOID param)4678 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4679 {
4680 MSIPACKAGE *package = param;
4681 LPCWSTR filename;
4682 MSIFILE *file;
4683 MSIRECORD *uirow;
4684
4685 filename = MSI_RecordGetString( row, 1 );
4686 file = msi_get_loaded_file( package, filename );
4687 if (!file)
4688 {
4689 WARN("unable to find file %s\n", debugstr_w(filename));
4690 return ERROR_SUCCESS;
4691 }
4692 file->Component->Action = msi_get_component_action( package, file->Component );
4693 if (file->Component->Action != INSTALLSTATE_ABSENT)
4694 {
4695 TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4696 return ERROR_SUCCESS;
4697 }
4698
4699 TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4700 register_dll( file->TargetPath, TRUE );
4701
4702 uirow = MSI_CreateRecord( 2 );
4703 MSI_RecordSetStringW( uirow, 1, file->File );
4704 MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4705 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
4706 msiobj_release( &uirow->hdr );
4707
4708 return ERROR_SUCCESS;
4709 }
4710
ACTION_SelfUnregModules(MSIPACKAGE * package)4711 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4712 {
4713 MSIQUERY *view;
4714 UINT rc;
4715
4716 if (package->script == SCRIPT_NONE)
4717 return msi_schedule_action(package, SCRIPT_INSTALL, L"SelfUnregModules");
4718
4719 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `SelfReg`", &view );
4720 if (rc != ERROR_SUCCESS)
4721 return ERROR_SUCCESS;
4722
4723 rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4724 msiobj_release( &view->hdr );
4725 return rc;
4726 }
4727
ACTION_PublishFeatures(MSIPACKAGE * package)4728 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4729 {
4730 MSIFEATURE *feature;
4731 UINT rc;
4732 HKEY hkey = NULL, userdata = NULL;
4733
4734 if (package->script == SCRIPT_NONE)
4735 return msi_schedule_action(package, SCRIPT_INSTALL, L"PublishFeatures");
4736
4737 if (!check_publish(package))
4738 return ERROR_SUCCESS;
4739
4740 rc = MSIREG_OpenFeaturesKey(package->ProductCode, NULL, package->Context,
4741 &hkey, TRUE);
4742 if (rc != ERROR_SUCCESS)
4743 goto end;
4744
4745 rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, NULL, package->Context,
4746 &userdata, TRUE);
4747 if (rc != ERROR_SUCCESS)
4748 goto end;
4749
4750 /* here the guids are base 85 encoded */
4751 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4752 {
4753 ComponentList *cl;
4754 LPWSTR data = NULL;
4755 GUID clsid;
4756 INT size;
4757 BOOL absent = FALSE;
4758 MSIRECORD *uirow;
4759
4760 if (feature->Level <= 0) continue;
4761 if (feature->Action == INSTALLSTATE_UNKNOWN &&
4762 feature->Installed != INSTALLSTATE_ABSENT) continue;
4763
4764 if (feature->Action != INSTALLSTATE_LOCAL &&
4765 feature->Action != INSTALLSTATE_SOURCE &&
4766 feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4767
4768 size = 1;
4769 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4770 {
4771 size += 21;
4772 }
4773 if (feature->Feature_Parent)
4774 size += lstrlenW( feature->Feature_Parent )+2;
4775
4776 data = malloc(size * sizeof(WCHAR));
4777
4778 data[0] = 0;
4779 LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4780 {
4781 MSICOMPONENT* component = cl->component;
4782 WCHAR buf[21];
4783
4784 buf[0] = 0;
4785 if (component->ComponentId)
4786 {
4787 TRACE("From %s\n",debugstr_w(component->ComponentId));
4788 CLSIDFromString(component->ComponentId, &clsid);
4789 encode_base85_guid(&clsid,buf);
4790 TRACE("to %s\n",debugstr_w(buf));
4791 lstrcatW(data,buf);
4792 }
4793 }
4794
4795 if (feature->Feature_Parent)
4796 {
4797 lstrcatW(data, L"\2");
4798 lstrcatW(data, feature->Feature_Parent);
4799 }
4800
4801 msi_reg_set_val_str( userdata, feature->Feature, data );
4802 free(data);
4803
4804 size = 0;
4805 if (feature->Feature_Parent)
4806 size = lstrlenW(feature->Feature_Parent)*sizeof(WCHAR);
4807 if (!absent)
4808 {
4809 size += sizeof(WCHAR);
4810 RegSetValueExW(hkey, feature->Feature, 0 ,REG_SZ,
4811 (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : L""), size);
4812 }
4813 else
4814 {
4815 size += 2*sizeof(WCHAR);
4816 data = malloc(size);
4817 data[0] = 0x6;
4818 data[1] = 0;
4819 if (feature->Feature_Parent)
4820 lstrcpyW( &data[1], feature->Feature_Parent );
4821 RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4822 (LPBYTE)data,size);
4823 free(data);
4824 }
4825
4826 /* the UI chunk */
4827 uirow = MSI_CreateRecord( 1 );
4828 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4829 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
4830 msiobj_release( &uirow->hdr );
4831 /* FIXME: call msi_ui_progress? */
4832 }
4833
4834 end:
4835 RegCloseKey(hkey);
4836 RegCloseKey(userdata);
4837 return rc;
4838 }
4839
unpublish_feature(MSIPACKAGE * package,MSIFEATURE * feature)4840 static UINT unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4841 {
4842 UINT r;
4843 HKEY hkey;
4844 MSIRECORD *uirow;
4845
4846 TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4847
4848 r = MSIREG_OpenFeaturesKey(package->ProductCode, NULL, package->Context,
4849 &hkey, FALSE);
4850 if (r == ERROR_SUCCESS)
4851 {
4852 RegDeleteValueW(hkey, feature->Feature);
4853 RegCloseKey(hkey);
4854 }
4855
4856 r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, NULL, package->Context,
4857 &hkey, FALSE);
4858 if (r == ERROR_SUCCESS)
4859 {
4860 RegDeleteValueW(hkey, feature->Feature);
4861 RegCloseKey(hkey);
4862 }
4863
4864 uirow = MSI_CreateRecord( 1 );
4865 MSI_RecordSetStringW( uirow, 1, feature->Feature );
4866 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
4867 msiobj_release( &uirow->hdr );
4868
4869 return ERROR_SUCCESS;
4870 }
4871
ACTION_UnpublishFeatures(MSIPACKAGE * package)4872 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4873 {
4874 MSIFEATURE *feature;
4875
4876 if (package->script == SCRIPT_NONE)
4877 return msi_schedule_action(package, SCRIPT_INSTALL, L"UnpublishFeatures");
4878
4879 if (!check_unpublish(package))
4880 return ERROR_SUCCESS;
4881
4882 LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4883 {
4884 unpublish_feature(package, feature);
4885 }
4886
4887 return ERROR_SUCCESS;
4888 }
4889
publish_install_properties(MSIPACKAGE * package,HKEY hkey)4890 static UINT publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4891 {
4892 static const WCHAR *propval[] =
4893 {
4894 L"ARPAUTHORIZEDCDFPREFIX", L"AuthorizedCDFPrefix",
4895 L"ARPCONTACT", L"Contact",
4896 L"ARPCOMMENTS", L"Comments",
4897 L"ProductName", L"DisplayName",
4898 L"ARPHELPLINK", L"HelpLink",
4899 L"ARPHELPTELEPHONE", L"HelpTelephone",
4900 L"ARPINSTALLLOCATION", L"InstallLocation",
4901 L"SourceDir", L"InstallSource",
4902 L"Manufacturer", L"Publisher",
4903 L"ARPREADME", L"ReadMe",
4904 L"ARPSIZE", L"Size",
4905 L"ARPURLINFOABOUT", L"URLInfoAbout",
4906 L"ARPURLUPDATEINFO", L"URLUpdateInfo",
4907 NULL
4908 };
4909 const WCHAR **p = propval;
4910 SYSTEMTIME systime;
4911 DWORD size, langid;
4912 WCHAR date[9], *val, *buffer;
4913 const WCHAR *prop, *key;
4914
4915 while (*p)
4916 {
4917 prop = *p++;
4918 key = *p++;
4919 val = msi_dup_property(package->db, prop);
4920 msi_reg_set_val_str(hkey, key, val);
4921 free(val);
4922 }
4923
4924 msi_reg_set_val_dword(hkey, L"WindowsInstaller", 1);
4925 if (msi_get_property_int( package->db, L"ARPSYSTEMCOMPONENT", 0 ))
4926 {
4927 msi_reg_set_val_dword( hkey, L"SystemComponent", 1 );
4928 }
4929
4930 if (msi_get_property_int( package->db, L"ARPNOREMOVE", 0 ))
4931 msi_reg_set_val_dword( hkey, L"NoRemove", 1 );
4932 else
4933 {
4934 static const WCHAR fmt_install[] = L"MsiExec.exe /I[ProductCode]";
4935 static const WCHAR fmt_uninstall[] = L"MsiExec.exe /X[ProductCode]";
4936 const WCHAR *fmt = fmt_install;
4937
4938 if (msi_get_property_int( package->db, L"ARPNOREPAIR", 0 ))
4939 msi_reg_set_val_dword( hkey, L"NoRepair", 1 );
4940
4941 if (msi_get_property_int( package->db, L"ARPNOMODIFY", 0 ))
4942 {
4943 msi_reg_set_val_dword( hkey, L"NoModify", 1 );
4944 fmt = fmt_uninstall;
4945 }
4946
4947 size = deformat_string(package, fmt, &buffer) * sizeof(WCHAR);
4948 RegSetValueExW(hkey, L"ModifyPath", 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4949 RegSetValueExW(hkey, L"UninstallString", 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4950 free(buffer);
4951 }
4952
4953 /* FIXME: Write real Estimated Size when we have it */
4954 msi_reg_set_val_dword(hkey, L"EstimatedSize", 0);
4955
4956 GetLocalTime(&systime);
4957 swprintf(date, ARRAY_SIZE(date), L"%d%02d%02d", systime.wYear, systime.wMonth, systime.wDay);
4958 msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4959
4960 langid = msi_get_property_int(package->db, L"ProductLanguage", 0);
4961 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4962
4963 buffer = msi_dup_property(package->db, L"ProductVersion");
4964 msi_reg_set_val_str(hkey, L"DisplayVersion", buffer);
4965 if (buffer)
4966 {
4967 DWORD verdword = msi_version_str_to_dword(buffer);
4968
4969 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4970 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4971 msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4972 free(buffer);
4973 }
4974
4975 return ERROR_SUCCESS;
4976 }
4977
ACTION_RegisterProduct(MSIPACKAGE * package)4978 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4979 {
4980 WCHAR *upgrade_code, squashed_pc[SQUASHED_GUID_SIZE];
4981 MSIRECORD *uirow;
4982 HKEY hkey, props, upgrade_key;
4983 UINT rc;
4984
4985 if (package->script == SCRIPT_NONE)
4986 return msi_schedule_action(package, SCRIPT_INSTALL, L"RegisterProduct");
4987
4988 /* FIXME: also need to publish if the product is in advertise mode */
4989 if (!msi_get_property_int( package->db, L"ProductToBeRegistered", 0 ) && !check_publish(package))
4990 return ERROR_SUCCESS;
4991
4992 rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4993 if (rc != ERROR_SUCCESS)
4994 return rc;
4995
4996 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4997 if (rc != ERROR_SUCCESS)
4998 goto done;
4999
5000 rc = publish_install_properties(package, hkey);
5001 if (rc != ERROR_SUCCESS)
5002 goto done;
5003
5004 rc = publish_install_properties(package, props);
5005 if (rc != ERROR_SUCCESS)
5006 goto done;
5007
5008 upgrade_code = msi_dup_property(package->db, L"UpgradeCode");
5009 if (upgrade_code)
5010 {
5011 rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
5012 if (rc == ERROR_SUCCESS)
5013 {
5014 squash_guid( package->ProductCode, squashed_pc );
5015 msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
5016 RegCloseKey( upgrade_key );
5017 }
5018 free( upgrade_code );
5019 }
5020 msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
5021 package->delete_on_close = FALSE;
5022
5023 done:
5024 uirow = MSI_CreateRecord( 1 );
5025 MSI_RecordSetStringW( uirow, 1, package->ProductCode );
5026 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
5027 msiobj_release( &uirow->hdr );
5028
5029 RegCloseKey(hkey);
5030 return ERROR_SUCCESS;
5031 }
5032
ACTION_InstallExecute(MSIPACKAGE * package)5033 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
5034 {
5035 return execute_script(package, SCRIPT_INSTALL);
5036 }
5037
ITERATE_UnpublishIcon(MSIRECORD * row,LPVOID param)5038 static UINT ITERATE_UnpublishIcon( MSIRECORD *row, LPVOID param )
5039 {
5040 MSIPACKAGE *package = param;
5041 const WCHAR *icon = MSI_RecordGetString( row, 1 );
5042 WCHAR *p, *icon_path;
5043
5044 if (!icon) return ERROR_SUCCESS;
5045 if ((icon_path = msi_build_icon_path( package, icon )))
5046 {
5047 TRACE("removing icon file %s\n", debugstr_w(icon_path));
5048 msi_delete_file( package, icon_path );
5049 if ((p = wcsrchr( icon_path, '\\' )))
5050 {
5051 *p = 0;
5052 msi_remove_directory( package, icon_path );
5053 }
5054 free( icon_path );
5055 }
5056 return ERROR_SUCCESS;
5057 }
5058
unpublish_icons(MSIPACKAGE * package)5059 static UINT unpublish_icons( MSIPACKAGE *package )
5060 {
5061 MSIQUERY *view;
5062 UINT r;
5063
5064 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Icon`", &view );
5065 if (r == ERROR_SUCCESS)
5066 {
5067 r = MSI_IterateRecords( view, NULL, ITERATE_UnpublishIcon, package );
5068 msiobj_release( &view->hdr );
5069 if (r != ERROR_SUCCESS)
5070 return r;
5071 }
5072 return ERROR_SUCCESS;
5073 }
5074
remove_product_upgrade_code(MSIPACKAGE * package)5075 static void remove_product_upgrade_code( MSIPACKAGE *package )
5076 {
5077 WCHAR *code, product[SQUASHED_GUID_SIZE];
5078 HKEY hkey;
5079 LONG res;
5080 DWORD count;
5081
5082 squash_guid( package->ProductCode, product );
5083 if (!(code = msi_dup_property( package->db, L"UpgradeCode" )))
5084 {
5085 WARN( "upgrade code not found\n" );
5086 return;
5087 }
5088 if (!MSIREG_OpenUpgradeCodesKey( code, &hkey, FALSE ))
5089 {
5090 RegDeleteValueW( hkey, product );
5091 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL, NULL );
5092 RegCloseKey( hkey );
5093 if (!res && !count) MSIREG_DeleteUpgradeCodesKey( code );
5094 }
5095 if (!MSIREG_OpenUserUpgradeCodesKey( code, &hkey, FALSE ))
5096 {
5097 RegDeleteValueW( hkey, product );
5098 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL, NULL );
5099 RegCloseKey( hkey );
5100 if (!res && !count) MSIREG_DeleteUserUpgradeCodesKey( code );
5101 }
5102 if (!MSIREG_OpenClassesUpgradeCodesKey( code, &hkey, FALSE ))
5103 {
5104 RegDeleteValueW( hkey, product );
5105 res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL, NULL );
5106 RegCloseKey( hkey );
5107 if (!res && !count) MSIREG_DeleteClassesUpgradeCodesKey( code );
5108 }
5109
5110 free( code );
5111 }
5112
ACTION_UnpublishProduct(MSIPACKAGE * package)5113 static UINT ACTION_UnpublishProduct(MSIPACKAGE *package)
5114 {
5115 MSIPATCHINFO *patch;
5116
5117 MSIREG_DeleteProductKey(package->ProductCode);
5118 MSIREG_DeleteUserDataProductKey(package->ProductCode, package->Context);
5119 MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
5120
5121 MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
5122 MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5123 MSIREG_DeleteUserProductKey(package->ProductCode);
5124 MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5125
5126 remove_product_upgrade_code( package );
5127
5128 LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5129 {
5130 MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5131 if (!wcscmp( package->ProductCode, patch->products ))
5132 {
5133 TRACE("removing local patch package %s\n", debugstr_w(patch->localfile));
5134 patch->delete_on_close = TRUE;
5135 }
5136 /* FIXME: remove local patch package if this is the last product */
5137 }
5138 TRACE("removing local package %s\n", debugstr_w(package->localfile));
5139 package->delete_on_close = TRUE;
5140
5141 unpublish_icons( package );
5142 return ERROR_SUCCESS;
5143 }
5144
is_full_uninstall(MSIPACKAGE * package)5145 static BOOL is_full_uninstall( MSIPACKAGE *package )
5146 {
5147 MSIFEATURE *feature;
5148
5149 LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
5150 {
5151 if (feature->Action != INSTALLSTATE_ABSENT &&
5152 (feature->Installed != INSTALLSTATE_ABSENT || feature->Action != INSTALLSTATE_UNKNOWN))
5153 return FALSE;
5154 }
5155
5156 return TRUE;
5157 }
5158
ACTION_InstallFinalize(MSIPACKAGE * package)5159 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5160 {
5161 UINT rc;
5162 MSIFILE *file;
5163 MSIFILEPATCH *patch;
5164
5165 /* first do the same as an InstallExecute */
5166 rc = execute_script(package, SCRIPT_INSTALL);
5167 if (rc != ERROR_SUCCESS)
5168 return rc;
5169
5170 /* install global assemblies */
5171 LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
5172 {
5173 MSICOMPONENT *comp = file->Component;
5174
5175 if (!msi_is_global_assembly( comp ) || (file->state != msifs_missing && file->state != msifs_overwrite))
5176 continue;
5177
5178 rc = msi_install_assembly( package, comp );
5179 if (rc != ERROR_SUCCESS)
5180 {
5181 ERR("Failed to install assembly\n");
5182 return ERROR_INSTALL_FAILURE;
5183 }
5184 file->state = msifs_installed;
5185 }
5186
5187 /* patch global assemblies */
5188 LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
5189 {
5190 MSICOMPONENT *comp = patch->File->Component;
5191
5192 if (!msi_is_global_assembly( comp ) || !patch->path) continue;
5193
5194 rc = msi_patch_assembly( package, comp->assembly, patch );
5195 if (rc && !(patch->Attributes & msidbPatchAttributesNonVital))
5196 {
5197 ERR("Failed to apply patch to file: %s\n", debugstr_w(patch->File->File));
5198 return rc;
5199 }
5200
5201 if ((rc = msi_install_assembly( package, comp )))
5202 {
5203 ERR("Failed to install patched assembly\n");
5204 return rc;
5205 }
5206 }
5207
5208 /* then handle commit actions */
5209 rc = execute_script(package, SCRIPT_COMMIT);
5210 if (rc != ERROR_SUCCESS)
5211 return rc;
5212
5213 if (is_full_uninstall(package))
5214 rc = ACTION_UnpublishProduct(package);
5215
5216 return rc;
5217 }
5218
ACTION_ForceReboot(MSIPACKAGE * package)5219 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5220 {
5221 WCHAR buffer[256], sysdir[MAX_PATH], squashed_pc[SQUASHED_GUID_SIZE];
5222 HKEY hkey;
5223
5224 squash_guid( package->ProductCode, squashed_pc );
5225
5226 GetSystemDirectoryW(sysdir, ARRAY_SIZE(sysdir));
5227 RegCreateKeyW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce", &hkey);
5228 swprintf(buffer, ARRAY_SIZE(buffer), L"%s\\MsiExec.exe /@ \"%s\"", sysdir, squashed_pc);
5229
5230 msi_reg_set_val_str( hkey, squashed_pc, buffer );
5231 RegCloseKey(hkey);
5232
5233 TRACE("Reboot command %s\n",debugstr_w(buffer));
5234
5235 RegCreateKeyW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Installer\\RunOnceEntries",
5236 &hkey);
5237 swprintf( buffer, ARRAY_SIZE(buffer), L"/I \"%s\" AFTERREBOOT=1 RUNONCEENTRY=\"%s\"", package->ProductCode,
5238 squashed_pc );
5239
5240 msi_reg_set_val_str( hkey, squashed_pc, buffer );
5241 RegCloseKey(hkey);
5242
5243 return ERROR_INSTALL_SUSPEND;
5244 }
5245
ACTION_ResolveSource(MSIPACKAGE * package)5246 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5247 {
5248 DWORD attrib;
5249 UINT rc;
5250
5251 /*
5252 * We are currently doing what should be done here in the top level Install
5253 * however for Administrative and uninstalls this step will be needed
5254 */
5255 if (!package->PackagePath)
5256 return ERROR_SUCCESS;
5257
5258 msi_set_sourcedir_props(package, TRUE);
5259
5260 attrib = GetFileAttributesW(package->db->path);
5261 if (attrib == INVALID_FILE_ATTRIBUTES)
5262 {
5263 MSIRECORD *record;
5264 LPWSTR prompt;
5265 DWORD size = 0;
5266
5267 rc = MsiSourceListGetInfoW(package->ProductCode, NULL,
5268 package->Context, MSICODE_PRODUCT,
5269 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5270 if (rc == ERROR_MORE_DATA)
5271 {
5272 prompt = malloc(size * sizeof(WCHAR));
5273 MsiSourceListGetInfoW(package->ProductCode, NULL,
5274 package->Context, MSICODE_PRODUCT,
5275 INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5276 }
5277 else
5278 prompt = wcsdup(package->db->path);
5279
5280 record = MSI_CreateRecord(2);
5281 MSI_RecordSetInteger(record, 1, MSIERR_INSERTDISK);
5282 MSI_RecordSetStringW(record, 2, prompt);
5283 free(prompt);
5284 while(attrib == INVALID_FILE_ATTRIBUTES)
5285 {
5286 MSI_RecordSetStringW(record, 0, NULL);
5287 rc = MSI_ProcessMessage(package, INSTALLMESSAGE_ERROR, record);
5288 if (rc == IDCANCEL)
5289 {
5290 msiobj_release(&record->hdr);
5291 return ERROR_INSTALL_USEREXIT;
5292 }
5293 attrib = GetFileAttributesW(package->db->path);
5294 }
5295 msiobj_release(&record->hdr);
5296 rc = ERROR_SUCCESS;
5297 }
5298 else
5299 return ERROR_SUCCESS;
5300
5301 return rc;
5302 }
5303
ACTION_RegisterUser(MSIPACKAGE * package)5304 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5305 {
5306 static const WCHAR szPropKeys[][80] =
5307 {
5308 L"ProductID",
5309 L"USERNAME",
5310 L"COMPANYNAME",
5311 L"",
5312 };
5313 static const WCHAR szRegKeys[][80] =
5314 {
5315 L"ProductID",
5316 L"RegOwner",
5317 L"RegCompany",
5318 L"",
5319 };
5320 HKEY hkey = 0;
5321 LPWSTR buffer, productid = NULL;
5322 UINT i, rc = ERROR_SUCCESS;
5323 MSIRECORD *uirow;
5324
5325 if (package->script == SCRIPT_NONE)
5326 return msi_schedule_action(package, SCRIPT_INSTALL, L"RegisterUser");
5327
5328 if (check_unpublish(package))
5329 {
5330 MSIREG_DeleteUserDataProductKey(package->ProductCode, package->Context);
5331 goto end;
5332 }
5333
5334 productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5335 if (!productid)
5336 goto end;
5337
5338 rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5339 NULL, &hkey, TRUE);
5340 if (rc != ERROR_SUCCESS)
5341 goto end;
5342
5343 for( i = 0; szPropKeys[i][0]; i++ )
5344 {
5345 buffer = msi_dup_property( package->db, szPropKeys[i] );
5346 msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5347 free( buffer );
5348 }
5349
5350 end:
5351 uirow = MSI_CreateRecord( 1 );
5352 MSI_RecordSetStringW( uirow, 1, productid );
5353 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
5354 msiobj_release( &uirow->hdr );
5355
5356 free(productid);
5357 RegCloseKey(hkey);
5358 return rc;
5359 }
5360
iterate_properties(MSIRECORD * record,void * param)5361 static UINT iterate_properties(MSIRECORD *record, void *param)
5362 {
5363 MSIRECORD *uirow;
5364
5365 uirow = MSI_CloneRecord(record);
5366 if (!uirow) return ERROR_OUTOFMEMORY;
5367 MSI_RecordSetStringW(uirow, 0, L"Property(S): [1] = [2]");
5368 MSI_ProcessMessage(param, INSTALLMESSAGE_INFO|MB_ICONHAND, uirow);
5369 msiobj_release(&uirow->hdr);
5370
5371 return ERROR_SUCCESS;
5372 }
5373
5374
ACTION_ExecuteAction(MSIPACKAGE * package)5375 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5376 {
5377 WCHAR *productname;
5378 WCHAR *action;
5379 WCHAR *info_template;
5380 MSIQUERY *view;
5381 MSIRECORD *uirow, *uirow_info;
5382 UINT rc;
5383
5384 /* Send COMMONDATA and INFO messages. */
5385 /* FIXME: when should these messages be sent? [see also MsiOpenPackage()] */
5386 uirow = MSI_CreateRecord(3);
5387 if (!uirow) return ERROR_OUTOFMEMORY;
5388 MSI_RecordSetStringW(uirow, 0, NULL);
5389 MSI_RecordSetInteger(uirow, 1, 0);
5390 MSI_RecordSetInteger(uirow, 2, package->num_langids ? package->langids[0] : 0);
5391 MSI_RecordSetInteger(uirow, 3, msi_get_string_table_codepage(package->db->strings));
5392 MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_COMMONDATA, uirow);
5393 /* FIXME: send INSTALLMESSAGE_PROGRESS */
5394 MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_COMMONDATA, uirow);
5395
5396 if (!(needs_ui_sequence(package) && ui_sequence_exists(package)))
5397 {
5398 uirow_info = MSI_CreateRecord(0);
5399 if (!uirow_info)
5400 {
5401 msiobj_release(&uirow->hdr);
5402 return ERROR_OUTOFMEMORY;
5403 }
5404 info_template = msi_get_error_message(package->db, MSIERR_INFO_LOGGINGSTART);
5405 MSI_RecordSetStringW(uirow_info, 0, info_template);
5406 free(info_template);
5407 MSI_ProcessMessage(package, INSTALLMESSAGE_INFO|MB_ICONHAND, uirow_info);
5408 msiobj_release(&uirow_info->hdr);
5409 }
5410
5411 MSI_ProcessMessage(package, INSTALLMESSAGE_COMMONDATA, uirow);
5412
5413 productname = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
5414 MSI_RecordSetInteger(uirow, 1, 1);
5415 MSI_RecordSetStringW(uirow, 2, productname);
5416 MSI_RecordSetStringW(uirow, 3, NULL);
5417 MSI_ProcessMessage(package, INSTALLMESSAGE_COMMONDATA, uirow);
5418 msiobj_release(&uirow->hdr);
5419
5420 package->LastActionResult = MSI_NULL_INTEGER;
5421
5422 action = msi_dup_property(package->db, L"EXECUTEACTION");
5423 if (!action) action = msi_strdupW(L"INSTALL", ARRAY_SIZE(L"INSTALL") - 1);
5424
5425 /* Perform the action. Top-level actions trigger a sequence. */
5426 if (!wcscmp(action, L"INSTALL"))
5427 {
5428 /* Send ACTIONSTART/INFO and INSTALLSTART. */
5429 ui_actionstart(package, L"INSTALL", NULL, NULL);
5430 ui_actioninfo(package, L"INSTALL", TRUE, 0);
5431 uirow = MSI_CreateRecord(2);
5432 if (!uirow)
5433 {
5434 rc = ERROR_OUTOFMEMORY;
5435 goto end;
5436 }
5437 MSI_RecordSetStringW(uirow, 0, NULL);
5438 MSI_RecordSetStringW(uirow, 1, productname);
5439 MSI_RecordSetStringW(uirow, 2, package->ProductCode);
5440 MSI_ProcessMessage(package, INSTALLMESSAGE_INSTALLSTART, uirow);
5441 msiobj_release(&uirow->hdr);
5442
5443 /* Perform the installation. Always use the ExecuteSequence. */
5444 package->InWhatSequence |= SEQUENCE_EXEC;
5445 rc = ACTION_ProcessExecSequence(package);
5446
5447 /* Send return value and INSTALLEND. */
5448 ui_actioninfo(package, L"INSTALL", FALSE, !rc);
5449 uirow = MSI_CreateRecord(3);
5450 if (!uirow)
5451 {
5452 rc = ERROR_OUTOFMEMORY;
5453 goto end;
5454 }
5455 MSI_RecordSetStringW(uirow, 0, NULL);
5456 MSI_RecordSetStringW(uirow, 1, productname);
5457 MSI_RecordSetStringW(uirow, 2, package->ProductCode);
5458 MSI_RecordSetInteger(uirow, 3, !rc);
5459 MSI_ProcessMessage(package, INSTALLMESSAGE_INSTALLEND, uirow);
5460 msiobj_release(&uirow->hdr);
5461 }
5462 else
5463 rc = ACTION_PerformAction(package, action);
5464
5465 /* Send all set properties. */
5466 if (!MSI_OpenQuery(package->db, &view, L"SELECT * FROM `_Property`"))
5467 {
5468 MSI_IterateRecords(view, NULL, iterate_properties, package);
5469 msiobj_release(&view->hdr);
5470 }
5471
5472 /* And finally, toggle the cancel off and on. */
5473 uirow = MSI_CreateRecord(2);
5474 if (!uirow)
5475 {
5476 rc = ERROR_OUTOFMEMORY;
5477 goto end;
5478 }
5479 MSI_RecordSetStringW(uirow, 0, NULL);
5480 MSI_RecordSetInteger(uirow, 1, 2);
5481 MSI_RecordSetInteger(uirow, 2, 0);
5482 MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_COMMONDATA, uirow);
5483 MSI_RecordSetInteger(uirow, 2, 1);
5484 MSI_ProcessMessageVerbatim(package, INSTALLMESSAGE_COMMONDATA, uirow);
5485 msiobj_release(&uirow->hdr);
5486
5487 end:
5488 free(productname);
5489 free(action);
5490 return rc;
5491 }
5492
ACTION_INSTALL(MSIPACKAGE * package)5493 static UINT ACTION_INSTALL(MSIPACKAGE *package)
5494 {
5495 msi_set_property(package->db, L"EXECUTEACTION", L"INSTALL", -1);
5496 if (needs_ui_sequence(package) && ui_sequence_exists(package))
5497 {
5498 package->InWhatSequence |= SEQUENCE_UI;
5499 return ACTION_ProcessUISequence(package);
5500 }
5501 else
5502 return ACTION_ExecuteAction(package);
5503 }
5504
msi_create_component_advertise_string(MSIPACKAGE * package,MSICOMPONENT * component,const WCHAR * feature)5505 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5506 {
5507 WCHAR productid_85[21], component_85[21], *ret;
5508 GUID clsid;
5509 DWORD sz;
5510
5511 /* > is used if there is a component GUID and < if not. */
5512
5513 productid_85[0] = 0;
5514 component_85[0] = 0;
5515 CLSIDFromString( package->ProductCode, &clsid );
5516
5517 encode_base85_guid( &clsid, productid_85 );
5518 if (component)
5519 {
5520 CLSIDFromString( component->ComponentId, &clsid );
5521 encode_base85_guid( &clsid, component_85 );
5522 }
5523
5524 TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5525 debugstr_w(component_85));
5526
5527 sz = 20 + lstrlenW( feature ) + 20 + 3;
5528 ret = calloc( 1, sz * sizeof(WCHAR) );
5529 if (ret) swprintf( ret, sz, L"%s%s%c%s", productid_85, feature, component ? '>' : '<', component_85 );
5530 return ret;
5531 }
5532
ITERATE_PublishComponent(MSIRECORD * rec,LPVOID param)5533 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5534 {
5535 MSIPACKAGE *package = param;
5536 LPCWSTR compgroupid, component, feature, qualifier, text;
5537 LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5538 HKEY hkey = NULL;
5539 UINT rc;
5540 MSICOMPONENT *comp;
5541 MSIFEATURE *feat;
5542 DWORD sz;
5543 MSIRECORD *uirow;
5544 int len;
5545
5546 feature = MSI_RecordGetString(rec, 5);
5547 feat = msi_get_loaded_feature(package, feature);
5548 if (!feat)
5549 return ERROR_SUCCESS;
5550
5551 feat->Action = msi_get_feature_action( package, feat );
5552 if (feat->Action != INSTALLSTATE_LOCAL &&
5553 feat->Action != INSTALLSTATE_SOURCE &&
5554 feat->Action != INSTALLSTATE_ADVERTISED)
5555 {
5556 TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5557 return ERROR_SUCCESS;
5558 }
5559
5560 component = MSI_RecordGetString(rec, 3);
5561 comp = msi_get_loaded_component(package, component);
5562 if (!comp)
5563 return ERROR_SUCCESS;
5564
5565 compgroupid = MSI_RecordGetString(rec,1);
5566 qualifier = MSI_RecordGetString(rec,2);
5567
5568 rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5569 if (rc != ERROR_SUCCESS)
5570 goto end;
5571
5572 advertise = msi_create_component_advertise_string( package, comp, feature );
5573 text = MSI_RecordGetString( rec, 4 );
5574 if (text)
5575 {
5576 p = malloc( (wcslen( advertise ) + wcslen( text ) + 1) * sizeof(WCHAR) );
5577 lstrcpyW( p, advertise );
5578 lstrcatW( p, text );
5579 free( advertise );
5580 advertise = p;
5581 }
5582 existing = msi_reg_get_val_str( hkey, qualifier );
5583
5584 sz = lstrlenW( advertise ) + 1;
5585 if (existing)
5586 {
5587 for (p = existing; *p; p += len)
5588 {
5589 len = lstrlenW( p ) + 1;
5590 if (wcscmp( advertise, p )) sz += len;
5591 }
5592 }
5593 if (!(output = malloc( (sz + 1) * sizeof(WCHAR) )))
5594 {
5595 rc = ERROR_OUTOFMEMORY;
5596 goto end;
5597 }
5598 q = output;
5599 if (existing)
5600 {
5601 for (p = existing; *p; p += len)
5602 {
5603 len = lstrlenW( p ) + 1;
5604 if (wcscmp( advertise, p ))
5605 {
5606 memcpy( q, p, len * sizeof(WCHAR) );
5607 q += len;
5608 }
5609 }
5610 }
5611 lstrcpyW( q, advertise );
5612 q[lstrlenW( q ) + 1] = 0;
5613
5614 msi_reg_set_val_multi_str( hkey, qualifier, output );
5615
5616 end:
5617 RegCloseKey(hkey);
5618 free( output );
5619 free( advertise );
5620 free( existing );
5621
5622 /* the UI chunk */
5623 uirow = MSI_CreateRecord( 2 );
5624 MSI_RecordSetStringW( uirow, 1, compgroupid );
5625 MSI_RecordSetStringW( uirow, 2, qualifier);
5626 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
5627 msiobj_release( &uirow->hdr );
5628 /* FIXME: call ui_progress? */
5629
5630 return rc;
5631 }
5632
5633 /*
5634 * At present I am ignoring the advertised components part of this and only
5635 * focusing on the qualified component sets
5636 */
ACTION_PublishComponents(MSIPACKAGE * package)5637 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5638 {
5639 MSIQUERY *view;
5640 UINT rc;
5641
5642 if (package->script == SCRIPT_NONE)
5643 return msi_schedule_action(package, SCRIPT_INSTALL, L"PublishComponents");
5644
5645 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `PublishComponent`", &view);
5646 if (rc != ERROR_SUCCESS)
5647 return ERROR_SUCCESS;
5648
5649 rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5650 msiobj_release(&view->hdr);
5651 return rc;
5652 }
5653
ITERATE_UnpublishComponent(MSIRECORD * rec,LPVOID param)5654 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5655 {
5656 MSIPACKAGE *package = param;
5657 LPCWSTR compgroupid, component, feature, qualifier;
5658 MSICOMPONENT *comp;
5659 MSIFEATURE *feat;
5660 MSIRECORD *uirow;
5661 WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5662 LONG res;
5663
5664 feature = MSI_RecordGetString( rec, 5 );
5665 feat = msi_get_loaded_feature( package, feature );
5666 if (!feat)
5667 return ERROR_SUCCESS;
5668
5669 feat->Action = msi_get_feature_action( package, feat );
5670 if (feat->Action != INSTALLSTATE_ABSENT)
5671 {
5672 TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5673 return ERROR_SUCCESS;
5674 }
5675
5676 component = MSI_RecordGetString( rec, 3 );
5677 comp = msi_get_loaded_component( package, component );
5678 if (!comp)
5679 return ERROR_SUCCESS;
5680
5681 compgroupid = MSI_RecordGetString( rec, 1 );
5682 qualifier = MSI_RecordGetString( rec, 2 );
5683
5684 squash_guid( compgroupid, squashed );
5685 lstrcpyW( keypath, L"Software\\Microsoft\\Installer\\Components\\" );
5686 lstrcatW( keypath, squashed );
5687
5688 res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5689 if (res != ERROR_SUCCESS)
5690 {
5691 WARN( "unable to delete component key %ld\n", res );
5692 }
5693
5694 uirow = MSI_CreateRecord( 2 );
5695 MSI_RecordSetStringW( uirow, 1, compgroupid );
5696 MSI_RecordSetStringW( uirow, 2, qualifier );
5697 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
5698 msiobj_release( &uirow->hdr );
5699
5700 return ERROR_SUCCESS;
5701 }
5702
ACTION_UnpublishComponents(MSIPACKAGE * package)5703 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5704 {
5705 MSIQUERY *view;
5706 UINT rc;
5707
5708 if (package->script == SCRIPT_NONE)
5709 return msi_schedule_action(package, SCRIPT_INSTALL, L"UnpublishComponents");
5710
5711 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `PublishComponent`", &view );
5712 if (rc != ERROR_SUCCESS)
5713 return ERROR_SUCCESS;
5714
5715 rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5716 msiobj_release( &view->hdr );
5717 return rc;
5718 }
5719
ITERATE_InstallService(MSIRECORD * rec,LPVOID param)5720 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5721 {
5722 MSIPACKAGE *package = param;
5723 MSICOMPONENT *component;
5724 MSIRECORD *row;
5725 MSIFILE *file;
5726 SC_HANDLE hscm = NULL, service = NULL;
5727 LPCWSTR comp, key;
5728 LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5729 LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5730 DWORD serv_type, start_type, err_control;
5731 BOOL is_vital;
5732 SERVICE_DESCRIPTIONW sd = {NULL};
5733 UINT ret = ERROR_SUCCESS;
5734
5735 comp = MSI_RecordGetString( rec, 12 );
5736 component = msi_get_loaded_component( package, comp );
5737 if (!component)
5738 {
5739 WARN("service component not found\n");
5740 goto done;
5741 }
5742 component->Action = msi_get_component_action( package, component );
5743 if (component->Action != INSTALLSTATE_LOCAL)
5744 {
5745 TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5746 goto done;
5747 }
5748 hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5749 if (!hscm)
5750 {
5751 ERR("Failed to open the SC Manager!\n");
5752 goto done;
5753 }
5754
5755 start_type = MSI_RecordGetInteger(rec, 5);
5756 if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5757 goto done;
5758
5759 deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5760 deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5761 serv_type = MSI_RecordGetInteger(rec, 4);
5762 err_control = MSI_RecordGetInteger(rec, 6);
5763 deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5764 deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5765 deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5766 deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5767 deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5768 deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5769
5770 /* Should the complete install fail if CreateService fails? */
5771 is_vital = (err_control & msidbServiceInstallErrorControlVital);
5772
5773 /* Remove the msidbServiceInstallErrorControlVital-flag from err_control.
5774 CreateService (under Windows) would fail if not. */
5775 err_control &= ~msidbServiceInstallErrorControlVital;
5776
5777 /* fetch the service path */
5778 row = MSI_QueryGetRecord(package->db, L"SELECT * FROM `Component` WHERE `Component` = '%s'", comp);
5779 if (!row)
5780 {
5781 ERR("Query failed\n");
5782 goto done;
5783 }
5784 if (!(key = MSI_RecordGetString(row, 6)))
5785 {
5786 msiobj_release(&row->hdr);
5787 goto done;
5788 }
5789 file = msi_get_loaded_file(package, key);
5790 msiobj_release(&row->hdr);
5791 if (!file)
5792 {
5793 ERR("Failed to load the service file\n");
5794 goto done;
5795 }
5796
5797 if (!args || !args[0]) image_path = file->TargetPath;
5798 else
5799 {
5800 int len = lstrlenW(file->TargetPath) + lstrlenW(args) + 2;
5801 if (!(image_path = malloc(len * sizeof(WCHAR))))
5802 {
5803 ret = ERROR_OUTOFMEMORY;
5804 goto done;
5805 }
5806
5807 lstrcpyW(image_path, file->TargetPath);
5808 lstrcatW(image_path, L" ");
5809 lstrcatW(image_path, args);
5810 }
5811 service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5812 start_type, err_control, image_path, load_order,
5813 NULL, depends, serv_name, pass);
5814
5815 if (!service)
5816 {
5817 if (GetLastError() != ERROR_SERVICE_EXISTS)
5818 {
5819 WARN( "failed to create service %s (%lu)\n", debugstr_w(name), GetLastError() );
5820 if (is_vital)
5821 ret = ERROR_INSTALL_FAILURE;
5822
5823 }
5824 }
5825 else if (sd.lpDescription)
5826 {
5827 if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5828 WARN( "failed to set service description %lu\n", GetLastError() );
5829 }
5830
5831 if (image_path != file->TargetPath) free(image_path);
5832 done:
5833 if (service) CloseServiceHandle(service);
5834 if (hscm) CloseServiceHandle(hscm);
5835 free(name);
5836 free(disp);
5837 free(sd.lpDescription);
5838 free(load_order);
5839 free(serv_name);
5840 free(pass);
5841 free(depends);
5842 free(args);
5843
5844 return ret;
5845 }
5846
ACTION_InstallServices(MSIPACKAGE * package)5847 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5848 {
5849 MSIQUERY *view;
5850 UINT rc;
5851
5852 if (package->script == SCRIPT_NONE)
5853 return msi_schedule_action(package, SCRIPT_INSTALL, L"InstallServices");
5854
5855 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `ServiceInstall`", &view);
5856 if (rc != ERROR_SUCCESS)
5857 return ERROR_SUCCESS;
5858
5859 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5860 msiobj_release(&view->hdr);
5861 return rc;
5862 }
5863
5864 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
service_args_to_vector(WCHAR * args,DWORD * numargs)5865 static const WCHAR **service_args_to_vector(WCHAR *args, DWORD *numargs)
5866 {
5867 LPCWSTR *vector, *temp_vector;
5868 LPWSTR p, q;
5869 DWORD sep_len;
5870
5871 *numargs = 0;
5872 sep_len = ARRAY_SIZE(L"[~]") - 1;
5873
5874 if (!args)
5875 return NULL;
5876
5877 vector = malloc(sizeof(WCHAR *));
5878 if (!vector)
5879 return NULL;
5880
5881 p = args;
5882 do
5883 {
5884 (*numargs)++;
5885 vector[*numargs - 1] = p;
5886
5887 if ((q = wcsstr(p, L"[~]")))
5888 {
5889 *q = '\0';
5890
5891 temp_vector = realloc(vector, (*numargs + 1) * sizeof(WCHAR *));
5892 if (!temp_vector)
5893 {
5894 free(vector);
5895 return NULL;
5896 }
5897 vector = temp_vector;
5898
5899 p = q + sep_len;
5900 }
5901 } while (q);
5902
5903 return vector;
5904 }
5905
ITERATE_StartService(MSIRECORD * rec,LPVOID param)5906 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5907 {
5908 MSIPACKAGE *package = param;
5909 MSICOMPONENT *comp;
5910 MSIRECORD *uirow;
5911 SC_HANDLE scm = NULL, service = NULL;
5912 LPCWSTR component, *vector = NULL;
5913 LPWSTR name, args, display_name = NULL;
5914 DWORD event, numargs, len, wait, dummy;
5915 UINT r = ERROR_FUNCTION_FAILED;
5916 SERVICE_STATUS_PROCESS status;
5917 ULONGLONG start_time;
5918
5919 component = MSI_RecordGetString(rec, 6);
5920 comp = msi_get_loaded_component(package, component);
5921 if (!comp)
5922 return ERROR_SUCCESS;
5923
5924 event = MSI_RecordGetInteger( rec, 3 );
5925 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5926
5927 comp->Action = msi_get_component_action( package, comp );
5928 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventStart)) &&
5929 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallStart)))
5930 {
5931 TRACE("not starting %s\n", debugstr_w(name));
5932 free(name);
5933 return ERROR_SUCCESS;
5934 }
5935
5936 deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5937 wait = MSI_RecordGetInteger(rec, 5);
5938
5939 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5940 if (!scm)
5941 {
5942 ERR("Failed to open the service control manager\n");
5943 goto done;
5944 }
5945
5946 len = 0;
5947 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5948 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5949 {
5950 if ((display_name = malloc(++len * sizeof(WCHAR))))
5951 GetServiceDisplayNameW( scm, name, display_name, &len );
5952 }
5953
5954 service = OpenServiceW(scm, name, SERVICE_START|SERVICE_QUERY_STATUS);
5955 if (!service)
5956 {
5957 ERR( "failed to open service %s (%lu)\n", debugstr_w(name), GetLastError() );
5958 goto done;
5959 }
5960
5961 vector = service_args_to_vector(args, &numargs);
5962
5963 if (!StartServiceW(service, numargs, vector) &&
5964 GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5965 {
5966 ERR( "failed to start service %s (%lu)\n", debugstr_w(name), GetLastError() );
5967 goto done;
5968 }
5969
5970 r = ERROR_SUCCESS;
5971 if (wait)
5972 {
5973 /* wait for at most 30 seconds for the service to be up and running */
5974 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5975 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5976 {
5977 TRACE( "failed to query service status (%lu)\n", GetLastError() );
5978 goto done;
5979 }
5980 start_time = GetTickCount64();
5981 while (status.dwCurrentState == SERVICE_START_PENDING)
5982 {
5983 if (GetTickCount64() - start_time > 30000) break;
5984 Sleep(1000);
5985 if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO,
5986 (BYTE *)&status, sizeof(SERVICE_STATUS_PROCESS), &dummy))
5987 {
5988 TRACE( "failed to query service status (%lu)\n", GetLastError() );
5989 goto done;
5990 }
5991 }
5992 if (status.dwCurrentState != SERVICE_RUNNING)
5993 {
5994 WARN( "service failed to start %lu\n", status.dwCurrentState );
5995 r = ERROR_FUNCTION_FAILED;
5996 }
5997 }
5998
5999 done:
6000 uirow = MSI_CreateRecord( 2 );
6001 MSI_RecordSetStringW( uirow, 1, display_name );
6002 MSI_RecordSetStringW( uirow, 2, name );
6003 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
6004 msiobj_release( &uirow->hdr );
6005
6006 if (service) CloseServiceHandle(service);
6007 if (scm) CloseServiceHandle(scm);
6008
6009 free(name);
6010 free(args);
6011 free(vector);
6012 free(display_name);
6013 return r;
6014 }
6015
ACTION_StartServices(MSIPACKAGE * package)6016 static UINT ACTION_StartServices( MSIPACKAGE *package )
6017 {
6018 MSIQUERY *view;
6019 UINT rc;
6020
6021 if (package->script == SCRIPT_NONE)
6022 return msi_schedule_action(package, SCRIPT_INSTALL, L"StartServices");
6023
6024 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `ServiceControl`", &view);
6025 if (rc != ERROR_SUCCESS)
6026 return ERROR_SUCCESS;
6027
6028 rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
6029 msiobj_release(&view->hdr);
6030 return rc;
6031 }
6032
stop_service_dependents(SC_HANDLE scm,SC_HANDLE service)6033 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
6034 {
6035 DWORD i, needed, count;
6036 ENUM_SERVICE_STATUSW *dependencies;
6037 SERVICE_STATUS ss;
6038 SC_HANDLE depserv;
6039 BOOL stopped, ret = FALSE;
6040
6041 if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
6042 0, &needed, &count))
6043 return TRUE;
6044
6045 if (GetLastError() != ERROR_MORE_DATA)
6046 return FALSE;
6047
6048 dependencies = malloc(needed);
6049 if (!dependencies)
6050 return FALSE;
6051
6052 if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
6053 needed, &needed, &count))
6054 goto done;
6055
6056 for (i = 0; i < count; i++)
6057 {
6058 depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
6059 SERVICE_STOP | SERVICE_QUERY_STATUS);
6060 if (!depserv)
6061 goto done;
6062
6063 stopped = ControlService(depserv, SERVICE_CONTROL_STOP, &ss);
6064 CloseServiceHandle(depserv);
6065 if (!stopped)
6066 goto done;
6067 }
6068
6069 ret = TRUE;
6070
6071 done:
6072 free(dependencies);
6073 return ret;
6074 }
6075
stop_service(LPCWSTR name)6076 static UINT stop_service( LPCWSTR name )
6077 {
6078 SC_HANDLE scm = NULL, service = NULL;
6079 SERVICE_STATUS status;
6080 SERVICE_STATUS_PROCESS ssp;
6081 DWORD needed;
6082
6083 scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
6084 if (!scm)
6085 {
6086 WARN( "failed to open the SCM (%lu)\n", GetLastError() );
6087 goto done;
6088 }
6089
6090 service = OpenServiceW(scm, name, SERVICE_STOP | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS);
6091 if (!service)
6092 {
6093 WARN( "failed to open service %s (%lu)\n", debugstr_w(name), GetLastError() );
6094 goto done;
6095 }
6096
6097 if (!QueryServiceStatusEx( service, SC_STATUS_PROCESS_INFO, (BYTE *)&ssp, sizeof(ssp), &needed) )
6098 {
6099 WARN( "failed to query service status %s (%lu)\n", debugstr_w(name), GetLastError() );
6100 goto done;
6101 }
6102
6103 if (ssp.dwCurrentState == SERVICE_STOPPED)
6104 goto done;
6105
6106 stop_service_dependents(scm, service);
6107
6108 if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
6109 WARN( "failed to stop service %s (%lu)\n", debugstr_w(name), GetLastError() );
6110
6111 done:
6112 if (service) CloseServiceHandle(service);
6113 if (scm) CloseServiceHandle(scm);
6114
6115 return ERROR_SUCCESS;
6116 }
6117
ITERATE_StopService(MSIRECORD * rec,LPVOID param)6118 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
6119 {
6120 MSIPACKAGE *package = param;
6121 MSICOMPONENT *comp;
6122 MSIRECORD *uirow;
6123 LPCWSTR component;
6124 WCHAR *name, *display_name = NULL;
6125 DWORD event, len;
6126 SC_HANDLE scm;
6127
6128 component = MSI_RecordGetString( rec, 6 );
6129 comp = msi_get_loaded_component( package, component );
6130 if (!comp)
6131 return ERROR_SUCCESS;
6132
6133 event = MSI_RecordGetInteger( rec, 3 );
6134 deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
6135
6136 comp->Action = msi_get_component_action( package, comp );
6137 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventStop)) &&
6138 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallStop)))
6139 {
6140 TRACE("not stopping %s\n", debugstr_w(name));
6141 free( name );
6142 return ERROR_SUCCESS;
6143 }
6144
6145 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
6146 if (!scm)
6147 {
6148 ERR("Failed to open the service control manager\n");
6149 goto done;
6150 }
6151
6152 len = 0;
6153 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6154 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6155 {
6156 if ((display_name = malloc( ++len * sizeof(WCHAR ))))
6157 GetServiceDisplayNameW( scm, name, display_name, &len );
6158 }
6159 CloseServiceHandle( scm );
6160
6161 stop_service( name );
6162
6163 done:
6164 uirow = MSI_CreateRecord( 2 );
6165 MSI_RecordSetStringW( uirow, 1, display_name );
6166 MSI_RecordSetStringW( uirow, 2, name );
6167 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
6168 msiobj_release( &uirow->hdr );
6169
6170 free( name );
6171 free( display_name );
6172 return ERROR_SUCCESS;
6173 }
6174
ACTION_StopServices(MSIPACKAGE * package)6175 static UINT ACTION_StopServices( MSIPACKAGE *package )
6176 {
6177 MSIQUERY *view;
6178 UINT rc;
6179
6180 if (package->script == SCRIPT_NONE)
6181 return msi_schedule_action(package, SCRIPT_INSTALL, L"StopServices");
6182
6183 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `ServiceControl`", &view);
6184 if (rc != ERROR_SUCCESS)
6185 return ERROR_SUCCESS;
6186
6187 rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
6188 msiobj_release(&view->hdr);
6189 return rc;
6190 }
6191
ITERATE_DeleteService(MSIRECORD * rec,LPVOID param)6192 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
6193 {
6194 MSIPACKAGE *package = param;
6195 MSICOMPONENT *comp;
6196 MSIRECORD *uirow;
6197 LPWSTR name = NULL, display_name = NULL;
6198 DWORD event, len;
6199 SC_HANDLE scm = NULL, service = NULL;
6200
6201 comp = msi_get_loaded_component( package, MSI_RecordGetString(rec, 6) );
6202 if (!comp)
6203 return ERROR_SUCCESS;
6204
6205 event = MSI_RecordGetInteger( rec, 3 );
6206 deformat_string( package, MSI_RecordGetString(rec, 2), &name );
6207
6208 comp->Action = msi_get_component_action( package, comp );
6209 if (!(comp->Action == INSTALLSTATE_LOCAL && (event & msidbServiceControlEventDelete)) &&
6210 !(comp->Action == INSTALLSTATE_ABSENT && (event & msidbServiceControlEventUninstallDelete)))
6211 {
6212 TRACE("service %s not scheduled for removal\n", debugstr_w(name));
6213 free( name );
6214 return ERROR_SUCCESS;
6215 }
6216 stop_service( name );
6217
6218 scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
6219 if (!scm)
6220 {
6221 WARN( "failed to open the SCM (%lu)\n", GetLastError() );
6222 goto done;
6223 }
6224
6225 len = 0;
6226 if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
6227 GetLastError() == ERROR_INSUFFICIENT_BUFFER)
6228 {
6229 if ((display_name = malloc( ++len * sizeof(WCHAR ))))
6230 GetServiceDisplayNameW( scm, name, display_name, &len );
6231 }
6232
6233 service = OpenServiceW( scm, name, DELETE );
6234 if (!service)
6235 {
6236 WARN( "failed to open service %s (%lu)\n", debugstr_w(name), GetLastError() );
6237 goto done;
6238 }
6239
6240 if (!DeleteService( service ))
6241 WARN( "failed to delete service %s (%lu)\n", debugstr_w(name), GetLastError() );
6242
6243 done:
6244 uirow = MSI_CreateRecord( 2 );
6245 MSI_RecordSetStringW( uirow, 1, display_name );
6246 MSI_RecordSetStringW( uirow, 2, name );
6247 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
6248 msiobj_release( &uirow->hdr );
6249
6250 if (service) CloseServiceHandle( service );
6251 if (scm) CloseServiceHandle( scm );
6252 free( name );
6253 free( display_name );
6254
6255 return ERROR_SUCCESS;
6256 }
6257
ACTION_DeleteServices(MSIPACKAGE * package)6258 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
6259 {
6260 MSIQUERY *view;
6261 UINT rc;
6262
6263 if (package->script == SCRIPT_NONE)
6264 return msi_schedule_action(package, SCRIPT_INSTALL, L"DeleteServices");
6265
6266 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `ServiceControl`", &view );
6267 if (rc != ERROR_SUCCESS)
6268 return ERROR_SUCCESS;
6269
6270 rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
6271 msiobj_release( &view->hdr );
6272 return rc;
6273 }
6274
ITERATE_InstallODBCDriver(MSIRECORD * rec,LPVOID param)6275 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
6276 {
6277 MSIPACKAGE *package = param;
6278 LPWSTR driver, driver_path, ptr;
6279 WCHAR outpath[MAX_PATH];
6280 MSIFILE *driver_file = NULL, *setup_file = NULL;
6281 MSICOMPONENT *comp;
6282 MSIRECORD *uirow;
6283 LPCWSTR desc, file_key, component;
6284 DWORD len, usage;
6285 UINT r = ERROR_SUCCESS;
6286
6287 component = MSI_RecordGetString( rec, 2 );
6288 comp = msi_get_loaded_component( package, component );
6289 if (!comp)
6290 return ERROR_SUCCESS;
6291
6292 comp->Action = msi_get_component_action( package, comp );
6293 if (comp->Action != INSTALLSTATE_LOCAL)
6294 {
6295 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6296 return ERROR_SUCCESS;
6297 }
6298 desc = MSI_RecordGetString(rec, 3);
6299
6300 file_key = MSI_RecordGetString( rec, 4 );
6301 if (file_key) driver_file = msi_get_loaded_file( package, file_key );
6302
6303 file_key = MSI_RecordGetString( rec, 5 );
6304 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6305
6306 if (!driver_file)
6307 {
6308 ERR("ODBC Driver entry not found!\n");
6309 return ERROR_FUNCTION_FAILED;
6310 }
6311
6312 len = lstrlenW(desc) + lstrlenW(L"Driver=%s") + lstrlenW(driver_file->FileName);
6313 if (setup_file)
6314 len += lstrlenW(L"Setup=%s") + lstrlenW(setup_file->FileName);
6315 len += lstrlenW(L"FileUsage=1") + 2; /* \0\0 */
6316
6317 driver = malloc(len * sizeof(WCHAR));
6318 if (!driver)
6319 return ERROR_OUTOFMEMORY;
6320
6321 ptr = driver;
6322 lstrcpyW(ptr, desc);
6323 ptr += lstrlenW(ptr) + 1;
6324
6325 len = swprintf(ptr, len - (ptr - driver), L"Driver=%s", driver_file->FileName);
6326 ptr += len + 1;
6327
6328 if (setup_file)
6329 {
6330 len = swprintf(ptr, len - (ptr - driver), L"Setup=%s", setup_file->FileName);
6331 ptr += len + 1;
6332 }
6333
6334 lstrcpyW(ptr, L"FileUsage=1");
6335 ptr += lstrlenW(ptr) + 1;
6336 *ptr = '\0';
6337
6338 if (!driver_file->TargetPath)
6339 {
6340 const WCHAR *dir = msi_get_target_folder( package, driver_file->Component->Directory );
6341 driver_file->TargetPath = msi_build_directory_name( 2, dir, driver_file->FileName );
6342 }
6343 driver_path = wcsdup(driver_file->TargetPath);
6344 ptr = wcsrchr(driver_path, '\\');
6345 if (ptr) *ptr = '\0';
6346
6347 if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6348 NULL, ODBC_INSTALL_COMPLETE, &usage))
6349 {
6350 ERR("Failed to install SQL driver!\n");
6351 r = ERROR_FUNCTION_FAILED;
6352 }
6353
6354 uirow = MSI_CreateRecord( 5 );
6355 MSI_RecordSetStringW( uirow, 1, desc );
6356 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6357 MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6358 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
6359 msiobj_release( &uirow->hdr );
6360
6361 free(driver);
6362 free(driver_path);
6363
6364 return r;
6365 }
6366
ITERATE_InstallODBCTranslator(MSIRECORD * rec,LPVOID param)6367 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6368 {
6369 MSIPACKAGE *package = param;
6370 LPWSTR translator, translator_path, ptr;
6371 WCHAR outpath[MAX_PATH];
6372 MSIFILE *translator_file = NULL, *setup_file = NULL;
6373 MSICOMPONENT *comp;
6374 MSIRECORD *uirow;
6375 LPCWSTR desc, file_key, component;
6376 DWORD len, usage;
6377 UINT r = ERROR_SUCCESS;
6378
6379 component = MSI_RecordGetString( rec, 2 );
6380 comp = msi_get_loaded_component( package, component );
6381 if (!comp)
6382 return ERROR_SUCCESS;
6383
6384 comp->Action = msi_get_component_action( package, comp );
6385 if (comp->Action != INSTALLSTATE_LOCAL)
6386 {
6387 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6388 return ERROR_SUCCESS;
6389 }
6390 desc = MSI_RecordGetString(rec, 3);
6391
6392 file_key = MSI_RecordGetString( rec, 4 );
6393 if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6394
6395 file_key = MSI_RecordGetString( rec, 5 );
6396 if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6397
6398 if (!translator_file)
6399 {
6400 ERR("ODBC Translator entry not found!\n");
6401 return ERROR_FUNCTION_FAILED;
6402 }
6403
6404 len = lstrlenW(desc) + lstrlenW(L"Translator=%s") + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6405 if (setup_file)
6406 len += lstrlenW(L"Setup=%s") + lstrlenW(setup_file->FileName);
6407
6408 translator = malloc(len * sizeof(WCHAR));
6409 if (!translator)
6410 return ERROR_OUTOFMEMORY;
6411
6412 ptr = translator;
6413 lstrcpyW(ptr, desc);
6414 ptr += lstrlenW(ptr) + 1;
6415
6416 len = swprintf(ptr, len - (ptr - translator), L"Translator=%s", translator_file->FileName);
6417 ptr += len + 1;
6418
6419 if (setup_file)
6420 {
6421 len = swprintf(ptr, len - (ptr - translator), L"Setup=%s", setup_file->FileName);
6422 ptr += len + 1;
6423 }
6424 *ptr = '\0';
6425
6426 translator_path = wcsdup(translator_file->TargetPath);
6427 ptr = wcsrchr(translator_path, '\\');
6428 if (ptr) *ptr = '\0';
6429
6430 if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6431 NULL, ODBC_INSTALL_COMPLETE, &usage))
6432 {
6433 ERR("Failed to install SQL translator!\n");
6434 r = ERROR_FUNCTION_FAILED;
6435 }
6436
6437 uirow = MSI_CreateRecord( 5 );
6438 MSI_RecordSetStringW( uirow, 1, desc );
6439 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6440 MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6441 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
6442 msiobj_release( &uirow->hdr );
6443
6444 free(translator);
6445 free(translator_path);
6446
6447 return r;
6448 }
6449
ITERATE_InstallODBCDataSource(MSIRECORD * rec,LPVOID param)6450 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6451 {
6452 MSIPACKAGE *package = param;
6453 MSICOMPONENT *comp;
6454 LPWSTR attrs;
6455 LPCWSTR desc, driver, component;
6456 WORD request = ODBC_ADD_SYS_DSN;
6457 INT registration;
6458 DWORD len;
6459 UINT r = ERROR_SUCCESS;
6460 MSIRECORD *uirow;
6461
6462 component = MSI_RecordGetString( rec, 2 );
6463 comp = msi_get_loaded_component( package, component );
6464 if (!comp)
6465 return ERROR_SUCCESS;
6466
6467 comp->Action = msi_get_component_action( package, comp );
6468 if (comp->Action != INSTALLSTATE_LOCAL)
6469 {
6470 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6471 return ERROR_SUCCESS;
6472 }
6473
6474 desc = MSI_RecordGetString(rec, 3);
6475 driver = MSI_RecordGetString(rec, 4);
6476 registration = MSI_RecordGetInteger(rec, 5);
6477
6478 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6479 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6480
6481 len = lstrlenW(L"DSN=%s") + lstrlenW(desc) + 2; /* \0\0 */
6482 attrs = malloc(len * sizeof(WCHAR));
6483 if (!attrs)
6484 return ERROR_OUTOFMEMORY;
6485
6486 len = swprintf(attrs, len, L"DSN=%s", desc);
6487 attrs[len + 1] = 0;
6488
6489 if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6490 WARN("Failed to install SQL data source!\n");
6491
6492 uirow = MSI_CreateRecord( 5 );
6493 MSI_RecordSetStringW( uirow, 1, desc );
6494 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6495 MSI_RecordSetInteger( uirow, 3, request );
6496 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
6497 msiobj_release( &uirow->hdr );
6498
6499 free(attrs);
6500
6501 return r;
6502 }
6503
ACTION_InstallODBC(MSIPACKAGE * package)6504 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6505 {
6506 MSIQUERY *view;
6507 UINT rc;
6508
6509 if (package->script == SCRIPT_NONE)
6510 return msi_schedule_action(package, SCRIPT_INSTALL, L"InstallODBC");
6511
6512 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `ODBCDriver`", &view);
6513 if (rc == ERROR_SUCCESS)
6514 {
6515 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6516 msiobj_release(&view->hdr);
6517 if (rc != ERROR_SUCCESS)
6518 return rc;
6519 }
6520 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `ODBCTranslator`", &view);
6521 if (rc == ERROR_SUCCESS)
6522 {
6523 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6524 msiobj_release(&view->hdr);
6525 if (rc != ERROR_SUCCESS)
6526 return rc;
6527 }
6528 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `ODBCDataSource`", &view);
6529 if (rc == ERROR_SUCCESS)
6530 {
6531 rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6532 msiobj_release(&view->hdr);
6533 if (rc != ERROR_SUCCESS)
6534 return rc;
6535 }
6536 return ERROR_SUCCESS;
6537 }
6538
ITERATE_RemoveODBCDriver(MSIRECORD * rec,LPVOID param)6539 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6540 {
6541 MSIPACKAGE *package = param;
6542 MSICOMPONENT *comp;
6543 MSIRECORD *uirow;
6544 DWORD usage;
6545 LPCWSTR desc, component;
6546
6547 component = MSI_RecordGetString( rec, 2 );
6548 comp = msi_get_loaded_component( package, component );
6549 if (!comp)
6550 return ERROR_SUCCESS;
6551
6552 comp->Action = msi_get_component_action( package, comp );
6553 if (comp->Action != INSTALLSTATE_ABSENT)
6554 {
6555 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6556 return ERROR_SUCCESS;
6557 }
6558
6559 desc = MSI_RecordGetString( rec, 3 );
6560 if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6561 {
6562 WARN("Failed to remove ODBC driver\n");
6563 }
6564 else if (!usage)
6565 {
6566 FIXME("Usage count reached 0\n");
6567 }
6568
6569 uirow = MSI_CreateRecord( 2 );
6570 MSI_RecordSetStringW( uirow, 1, desc );
6571 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6572 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
6573 msiobj_release( &uirow->hdr );
6574
6575 return ERROR_SUCCESS;
6576 }
6577
ITERATE_RemoveODBCTranslator(MSIRECORD * rec,LPVOID param)6578 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6579 {
6580 MSIPACKAGE *package = param;
6581 MSICOMPONENT *comp;
6582 MSIRECORD *uirow;
6583 DWORD usage;
6584 LPCWSTR desc, component;
6585
6586 component = MSI_RecordGetString( rec, 2 );
6587 comp = msi_get_loaded_component( package, component );
6588 if (!comp)
6589 return ERROR_SUCCESS;
6590
6591 comp->Action = msi_get_component_action( package, comp );
6592 if (comp->Action != INSTALLSTATE_ABSENT)
6593 {
6594 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6595 return ERROR_SUCCESS;
6596 }
6597
6598 desc = MSI_RecordGetString( rec, 3 );
6599 if (!SQLRemoveTranslatorW( desc, &usage ))
6600 {
6601 WARN("Failed to remove ODBC translator\n");
6602 }
6603 else if (!usage)
6604 {
6605 FIXME("Usage count reached 0\n");
6606 }
6607
6608 uirow = MSI_CreateRecord( 2 );
6609 MSI_RecordSetStringW( uirow, 1, desc );
6610 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6611 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
6612 msiobj_release( &uirow->hdr );
6613
6614 return ERROR_SUCCESS;
6615 }
6616
ITERATE_RemoveODBCDataSource(MSIRECORD * rec,LPVOID param)6617 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6618 {
6619 MSIPACKAGE *package = param;
6620 MSICOMPONENT *comp;
6621 MSIRECORD *uirow;
6622 LPWSTR attrs;
6623 LPCWSTR desc, driver, component;
6624 WORD request = ODBC_REMOVE_SYS_DSN;
6625 INT registration;
6626 DWORD len;
6627
6628 component = MSI_RecordGetString( rec, 2 );
6629 comp = msi_get_loaded_component( package, component );
6630 if (!comp)
6631 return ERROR_SUCCESS;
6632
6633 comp->Action = msi_get_component_action( package, comp );
6634 if (comp->Action != INSTALLSTATE_ABSENT)
6635 {
6636 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6637 return ERROR_SUCCESS;
6638 }
6639
6640 desc = MSI_RecordGetString( rec, 3 );
6641 driver = MSI_RecordGetString( rec, 4 );
6642 registration = MSI_RecordGetInteger( rec, 5 );
6643
6644 if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6645 else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6646
6647 len = lstrlenW( L"DSN=%s" ) + lstrlenW( desc ) + 2; /* \0\0 */
6648 attrs = malloc( len * sizeof(WCHAR) );
6649 if (!attrs)
6650 return ERROR_OUTOFMEMORY;
6651
6652 FIXME("Use ODBCSourceAttribute table\n");
6653
6654 len = swprintf( attrs, len, L"DSN=%s", desc );
6655 attrs[len + 1] = 0;
6656
6657 if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6658 {
6659 WARN("Failed to remove ODBC data source\n");
6660 }
6661 free( attrs );
6662
6663 uirow = MSI_CreateRecord( 3 );
6664 MSI_RecordSetStringW( uirow, 1, desc );
6665 MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6666 MSI_RecordSetInteger( uirow, 3, request );
6667 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
6668 msiobj_release( &uirow->hdr );
6669
6670 return ERROR_SUCCESS;
6671 }
6672
ACTION_RemoveODBC(MSIPACKAGE * package)6673 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6674 {
6675 MSIQUERY *view;
6676 UINT rc;
6677
6678 if (package->script == SCRIPT_NONE)
6679 return msi_schedule_action(package, SCRIPT_INSTALL, L"RemoveODBC");
6680
6681 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `ODBCDriver`", &view );
6682 if (rc == ERROR_SUCCESS)
6683 {
6684 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6685 msiobj_release( &view->hdr );
6686 if (rc != ERROR_SUCCESS)
6687 return rc;
6688 }
6689 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `ODBCTranslator`", &view );
6690 if (rc == ERROR_SUCCESS)
6691 {
6692 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6693 msiobj_release( &view->hdr );
6694 if (rc != ERROR_SUCCESS)
6695 return rc;
6696 }
6697 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `ODBCDataSource`", &view );
6698 if (rc == ERROR_SUCCESS)
6699 {
6700 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6701 msiobj_release( &view->hdr );
6702 if (rc != ERROR_SUCCESS)
6703 return rc;
6704 }
6705 return ERROR_SUCCESS;
6706 }
6707
6708 #define ENV_ACT_SETALWAYS 0x1
6709 #define ENV_ACT_SETABSENT 0x2
6710 #define ENV_ACT_REMOVE 0x4
6711 #define ENV_ACT_REMOVEMATCH 0x8
6712
6713 #define ENV_MOD_MACHINE 0x20000000
6714 #define ENV_MOD_APPEND 0x40000000
6715 #define ENV_MOD_PREFIX 0x80000000
6716 #define ENV_MOD_MASK 0xC0000000
6717
6718 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6719
env_parse_flags(LPCWSTR * name,LPCWSTR * value,DWORD * flags)6720 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6721 {
6722 const WCHAR *cptr = *name;
6723
6724 *flags = 0;
6725 while (*cptr)
6726 {
6727 if (*cptr == '=')
6728 *flags |= ENV_ACT_SETALWAYS;
6729 else if (*cptr == '+')
6730 *flags |= ENV_ACT_SETABSENT;
6731 else if (*cptr == '-')
6732 *flags |= ENV_ACT_REMOVE;
6733 else if (*cptr == '!')
6734 *flags |= ENV_ACT_REMOVEMATCH;
6735 else if (*cptr == '*')
6736 *flags |= ENV_MOD_MACHINE | ENV_ACT_REMOVE;
6737 else
6738 break;
6739
6740 cptr++;
6741 (*name)++;
6742 }
6743
6744 if (!*cptr)
6745 {
6746 ERR("Missing environment variable\n");
6747 return ERROR_FUNCTION_FAILED;
6748 }
6749
6750 if (*value)
6751 {
6752 LPCWSTR ptr = *value;
6753 if (!wcsncmp(ptr, L"[~]", 3))
6754 {
6755 if (ptr[3] == ';')
6756 {
6757 *flags |= ENV_MOD_APPEND;
6758 *value += 3;
6759 }
6760 else
6761 {
6762 *value = NULL;
6763 }
6764 }
6765 else if (lstrlenW(*value) >= 3)
6766 {
6767 ptr += lstrlenW(ptr) - 3;
6768 if (!wcscmp( ptr, L"[~]" ))
6769 {
6770 if ((ptr-1) > *value && *(ptr-1) == ';')
6771 {
6772 *flags |= ENV_MOD_PREFIX;
6773 /* the "[~]" will be removed by deformat_string */;
6774 }
6775 else
6776 {
6777 *value = NULL;
6778 }
6779 }
6780 }
6781 }
6782
6783 if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6784 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6785 check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6786 check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6787 {
6788 ERR( "invalid flags: %#lx\n", *flags );
6789 return ERROR_FUNCTION_FAILED;
6790 }
6791
6792 if (!*flags)
6793 *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6794
6795 return ERROR_SUCCESS;
6796 }
6797
open_env_key(DWORD flags,HKEY * key)6798 static UINT open_env_key( DWORD flags, HKEY *key )
6799 {
6800 const WCHAR *env;
6801 HKEY root;
6802 LONG res;
6803
6804 if (flags & ENV_MOD_MACHINE)
6805 {
6806 env = L"System\\CurrentControlSet\\Control\\Session Manager\\Environment";
6807 root = HKEY_LOCAL_MACHINE;
6808 }
6809 else
6810 {
6811 env = L"Environment";
6812 root = HKEY_CURRENT_USER;
6813 }
6814
6815 res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6816 if (res != ERROR_SUCCESS)
6817 {
6818 WARN( "failed to open key %s (%ld)\n", debugstr_w(env), res );
6819 return ERROR_FUNCTION_FAILED;
6820 }
6821
6822 return ERROR_SUCCESS;
6823 }
6824
ITERATE_WriteEnvironmentString(MSIRECORD * rec,LPVOID param)6825 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6826 {
6827 MSIPACKAGE *package = param;
6828 LPCWSTR name, value, component;
6829 WCHAR *data = NULL, *newval = NULL, *deformatted = NULL, *p, *q;
6830 DWORD flags, type, size, len, len_value = 0;
6831 UINT res;
6832 HKEY env = NULL;
6833 MSICOMPONENT *comp;
6834 MSIRECORD *uirow;
6835 int action = 0, found = 0;
6836
6837 component = MSI_RecordGetString(rec, 4);
6838 comp = msi_get_loaded_component(package, component);
6839 if (!comp)
6840 return ERROR_SUCCESS;
6841
6842 comp->Action = msi_get_component_action( package, comp );
6843 if (comp->Action != INSTALLSTATE_LOCAL)
6844 {
6845 TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6846 return ERROR_SUCCESS;
6847 }
6848 name = MSI_RecordGetString(rec, 2);
6849 value = MSI_RecordGetString(rec, 3);
6850
6851 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6852
6853 res = env_parse_flags(&name, &value, &flags);
6854 if (res != ERROR_SUCCESS || !value)
6855 goto done;
6856
6857 if (value)
6858 {
6859 DWORD len = deformat_string( package, value, &deformatted );
6860 if (!deformatted)
6861 {
6862 res = ERROR_OUTOFMEMORY;
6863 goto done;
6864 }
6865
6866 if (len)
6867 {
6868 value = deformatted;
6869 if (flags & ENV_MOD_PREFIX)
6870 {
6871 p = wcsrchr( value, ';' );
6872 len_value = p - value;
6873 }
6874 else if (flags & ENV_MOD_APPEND)
6875 {
6876 value = wcschr( value, ';' ) + 1;
6877 len_value = lstrlenW( value );
6878 }
6879 else len_value = lstrlenW( value );
6880 }
6881 else
6882 {
6883 value = NULL;
6884 }
6885 }
6886
6887 res = open_env_key( flags, &env );
6888 if (res != ERROR_SUCCESS)
6889 goto done;
6890
6891 if (flags & ENV_MOD_MACHINE)
6892 action |= 0x20000000;
6893
6894 size = 0;
6895 type = REG_SZ;
6896 res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6897 if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6898 (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6899 goto done;
6900
6901 if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6902 {
6903 action = 0x2;
6904
6905 /* Nothing to do. */
6906 if (!value)
6907 {
6908 res = ERROR_SUCCESS;
6909 goto done;
6910 }
6911 size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6912 newval = wcsdup(value);
6913 if (!newval)
6914 {
6915 res = ERROR_OUTOFMEMORY;
6916 goto done;
6917 }
6918 }
6919 else
6920 {
6921 action = 0x1;
6922
6923 /* Contrary to MSDN, +-variable to [~];path works */
6924 if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6925 {
6926 res = ERROR_SUCCESS;
6927 goto done;
6928 }
6929
6930 if (!(p = q = data = malloc( size )))
6931 {
6932 free(deformatted);
6933 RegCloseKey(env);
6934 return ERROR_OUTOFMEMORY;
6935 }
6936
6937 res = RegQueryValueExW( env, name, NULL, &type, (BYTE *)data, &size );
6938 if (res != ERROR_SUCCESS)
6939 goto done;
6940
6941 if (flags & ENV_ACT_REMOVEMATCH && (!value || !wcscmp( data, value )))
6942 {
6943 action = 0x4;
6944 res = RegDeleteValueW(env, name);
6945 if (res != ERROR_SUCCESS)
6946 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6947 goto done;
6948 }
6949
6950 for (;;)
6951 {
6952 while (*q && *q != ';') q++;
6953 len = q - p;
6954 if (value && len == len_value && !memcmp( value, p, len * sizeof(WCHAR) ) &&
6955 (!p[len] || p[len] == ';'))
6956 {
6957 found = 1;
6958 break;
6959 }
6960 if (!*q) break;
6961 p = ++q;
6962 }
6963
6964 if (found)
6965 {
6966 TRACE("string already set\n");
6967 goto done;
6968 }
6969
6970 size = (len_value + 1 + lstrlenW( data ) + 1) * sizeof(WCHAR);
6971 if (!(p = newval = malloc( size )))
6972 {
6973 res = ERROR_OUTOFMEMORY;
6974 goto done;
6975 }
6976
6977 if (flags & ENV_MOD_PREFIX)
6978 {
6979 memcpy( newval, value, len_value * sizeof(WCHAR) );
6980 newval[len_value] = ';';
6981 p = newval + len_value + 1;
6982 action |= 0x80000000;
6983 }
6984
6985 lstrcpyW( p, data );
6986
6987 if (flags & ENV_MOD_APPEND)
6988 {
6989 p += lstrlenW( data );
6990 *p++ = ';';
6991 memcpy( p, value, (len_value + 1) * sizeof(WCHAR) );
6992 action |= 0x40000000;
6993 }
6994 }
6995 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6996 res = RegSetValueExW( env, name, 0, type, (BYTE *)newval, size );
6997 if (res)
6998 {
6999 WARN("Failed to set %s to %s (%d)\n", debugstr_w(name), debugstr_w(newval), res);
7000 }
7001
7002 done:
7003 uirow = MSI_CreateRecord( 3 );
7004 MSI_RecordSetStringW( uirow, 1, name );
7005 MSI_RecordSetStringW( uirow, 2, newval );
7006 MSI_RecordSetInteger( uirow, 3, action );
7007 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
7008 msiobj_release( &uirow->hdr );
7009
7010 if (env) RegCloseKey(env);
7011 free(deformatted);
7012 free(data);
7013 free(newval);
7014 return res;
7015 }
7016
ACTION_WriteEnvironmentStrings(MSIPACKAGE * package)7017 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
7018 {
7019 MSIQUERY *view;
7020 UINT rc;
7021
7022 if (package->script == SCRIPT_NONE)
7023 return msi_schedule_action(package, SCRIPT_INSTALL, L"WriteEnvironmentStrings");
7024
7025 rc = MSI_DatabaseOpenViewW(package->db, L"SELECT * FROM `Environment`", &view);
7026 if (rc != ERROR_SUCCESS)
7027 return ERROR_SUCCESS;
7028
7029 rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
7030 msiobj_release(&view->hdr);
7031 return rc;
7032 }
7033
ITERATE_RemoveEnvironmentString(MSIRECORD * rec,LPVOID param)7034 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
7035 {
7036 MSIPACKAGE *package = param;
7037 LPCWSTR name, value, component;
7038 WCHAR *p, *q, *deformatted = NULL, *new_value = NULL;
7039 DWORD flags, type, size, len, len_value = 0, len_new_value;
7040 HKEY env = NULL;
7041 MSICOMPONENT *comp;
7042 MSIRECORD *uirow;
7043 int action = 0;
7044 LONG res;
7045 UINT r;
7046
7047 component = MSI_RecordGetString( rec, 4 );
7048 comp = msi_get_loaded_component( package, component );
7049 if (!comp)
7050 return ERROR_SUCCESS;
7051
7052 comp->Action = msi_get_component_action( package, comp );
7053 if (comp->Action != INSTALLSTATE_ABSENT)
7054 {
7055 TRACE("component not scheduled for removal %s\n", debugstr_w(component));
7056 return ERROR_SUCCESS;
7057 }
7058 name = MSI_RecordGetString( rec, 2 );
7059 value = MSI_RecordGetString( rec, 3 );
7060
7061 TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
7062
7063 r = env_parse_flags( &name, &value, &flags );
7064 if (r != ERROR_SUCCESS)
7065 return r;
7066
7067 if (!(flags & ENV_ACT_REMOVE))
7068 {
7069 TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
7070 return ERROR_SUCCESS;
7071 }
7072
7073 if (value)
7074 {
7075 DWORD len = deformat_string( package, value, &deformatted );
7076 if (!deformatted)
7077 {
7078 res = ERROR_OUTOFMEMORY;
7079 goto done;
7080 }
7081
7082 if (len)
7083 {
7084 value = deformatted;
7085 if (flags & ENV_MOD_PREFIX)
7086 {
7087 p = wcsrchr( value, ';' );
7088 len_value = p - value;
7089 }
7090 else if (flags & ENV_MOD_APPEND)
7091 {
7092 value = wcschr( value, ';' ) + 1;
7093 len_value = lstrlenW( value );
7094 }
7095 else len_value = lstrlenW( value );
7096 }
7097 else
7098 {
7099 value = NULL;
7100 }
7101 }
7102
7103 r = open_env_key( flags, &env );
7104 if (r != ERROR_SUCCESS)
7105 {
7106 r = ERROR_SUCCESS;
7107 goto done;
7108 }
7109
7110 if (flags & ENV_MOD_MACHINE)
7111 action |= 0x20000000;
7112
7113 size = 0;
7114 type = REG_SZ;
7115 res = RegQueryValueExW( env, name, NULL, &type, NULL, &size );
7116 if (res != ERROR_SUCCESS || (type != REG_SZ && type != REG_EXPAND_SZ))
7117 goto done;
7118
7119 if (!(new_value = malloc( size ))) goto done;
7120
7121 res = RegQueryValueExW( env, name, NULL, &type, (BYTE *)new_value, &size );
7122 if (res != ERROR_SUCCESS)
7123 goto done;
7124
7125 len_new_value = size / sizeof(WCHAR) - 1;
7126 p = q = new_value;
7127 for (;;)
7128 {
7129 while (*q && *q != ';') q++;
7130 len = q - p;
7131 if (value && len == len_value && !memcmp( value, p, len * sizeof(WCHAR) ))
7132 {
7133 if (*q == ';') q++;
7134 memmove( p, q, (len_new_value - (q - new_value) + 1) * sizeof(WCHAR) );
7135 break;
7136 }
7137 if (!*q) break;
7138 p = ++q;
7139 }
7140
7141 if (!new_value[0] || !value)
7142 {
7143 TRACE("removing %s\n", debugstr_w(name));
7144 res = RegDeleteValueW( env, name );
7145 if (res != ERROR_SUCCESS)
7146 WARN( "failed to delete value %s (%ld)\n", debugstr_w(name), res );
7147 }
7148 else
7149 {
7150 TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(new_value));
7151 size = (lstrlenW( new_value ) + 1) * sizeof(WCHAR);
7152 res = RegSetValueExW( env, name, 0, type, (BYTE *)new_value, size );
7153 if (res != ERROR_SUCCESS)
7154 WARN( "failed to set %s to %s (%ld)\n", debugstr_w(name), debugstr_w(new_value), res );
7155 }
7156
7157 done:
7158 uirow = MSI_CreateRecord( 3 );
7159 MSI_RecordSetStringW( uirow, 1, name );
7160 MSI_RecordSetStringW( uirow, 2, value );
7161 MSI_RecordSetInteger( uirow, 3, action );
7162 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
7163 msiobj_release( &uirow->hdr );
7164
7165 if (env) RegCloseKey( env );
7166 free( deformatted );
7167 free( new_value );
7168 return r;
7169 }
7170
ACTION_RemoveEnvironmentStrings(MSIPACKAGE * package)7171 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
7172 {
7173 MSIQUERY *view;
7174 UINT rc;
7175
7176 if (package->script == SCRIPT_NONE)
7177 return msi_schedule_action(package, SCRIPT_INSTALL, L"RemoveEnvironmentStrings");
7178
7179 rc = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Environment`", &view );
7180 if (rc != ERROR_SUCCESS)
7181 return ERROR_SUCCESS;
7182
7183 rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
7184 msiobj_release( &view->hdr );
7185 return rc;
7186 }
7187
msi_validate_product_id(MSIPACKAGE * package)7188 UINT msi_validate_product_id( MSIPACKAGE *package )
7189 {
7190 LPWSTR key, template, id;
7191 UINT r = ERROR_SUCCESS;
7192
7193 id = msi_dup_property( package->db, L"ProductID" );
7194 if (id)
7195 {
7196 free( id );
7197 return ERROR_SUCCESS;
7198 }
7199 template = msi_dup_property( package->db, L"PIDTemplate" );
7200 key = msi_dup_property( package->db, L"PIDKEY" );
7201 if (key && template)
7202 {
7203 FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
7204 #ifdef __REACTOS__
7205 WARN("Product key validation HACK, see CORE-14710\n");
7206 #else
7207 r = msi_set_property( package->db, L"ProductID", key, -1 );
7208 #endif
7209 }
7210 free( template );
7211 free( key );
7212 return r;
7213 }
7214
ACTION_ValidateProductID(MSIPACKAGE * package)7215 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
7216 {
7217 return msi_validate_product_id( package );
7218 }
7219
ACTION_ScheduleReboot(MSIPACKAGE * package)7220 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
7221 {
7222 TRACE("\n");
7223 package->need_reboot_at_end = 1;
7224 return ERROR_SUCCESS;
7225 }
7226
ACTION_AllocateRegistrySpace(MSIPACKAGE * package)7227 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
7228 {
7229 MSIRECORD *uirow;
7230 int space = msi_get_property_int( package->db, L"AVAILABLEFREEREG", 0 );
7231
7232 TRACE("%p %d kilobytes\n", package, space);
7233
7234 uirow = MSI_CreateRecord( 1 );
7235 MSI_RecordSetInteger( uirow, 1, space );
7236 MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, uirow);
7237 msiobj_release( &uirow->hdr );
7238
7239 return ERROR_SUCCESS;
7240 }
7241
ACTION_DisableRollback(MSIPACKAGE * package)7242 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
7243 {
7244 TRACE("%p\n", package);
7245
7246 msi_set_property( package->db, L"RollbackDisabled", L"1", -1 );
7247 return ERROR_SUCCESS;
7248 }
7249
ACTION_InstallAdminPackage(MSIPACKAGE * package)7250 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
7251 {
7252 FIXME("%p\n", package);
7253 return ERROR_SUCCESS;
7254 }
7255
ACTION_SetODBCFolders(MSIPACKAGE * package)7256 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
7257 {
7258 MSIQUERY *view;
7259 UINT r;
7260 DWORD count;
7261
7262 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `ODBCDriver`", &view );
7263 if (r == ERROR_SUCCESS)
7264 {
7265 count = 0;
7266 r = MSI_IterateRecords( view, &count, NULL, package );
7267 msiobj_release( &view->hdr );
7268 if (r != ERROR_SUCCESS)
7269 return r;
7270 if (count) FIXME( "ignored %lu rows in ODBCDriver table\n", count );
7271 }
7272 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `ODBCTranslator`", &view );
7273 if (r == ERROR_SUCCESS)
7274 {
7275 count = 0;
7276 r = MSI_IterateRecords( view, &count, NULL, package );
7277 msiobj_release( &view->hdr );
7278 if (r != ERROR_SUCCESS)
7279 return r;
7280 if (count) FIXME( "ignored %lu rows in ODBCTranslator table\n", count );
7281 }
7282 return ERROR_SUCCESS;
7283 }
7284
ITERATE_RemoveExistingProducts(MSIRECORD * rec,LPVOID param)7285 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
7286 {
7287 MSIPACKAGE *package = param;
7288 const WCHAR *property = MSI_RecordGetString( rec, 7 );
7289 int attrs = MSI_RecordGetInteger( rec, 5 );
7290 UINT len = ARRAY_SIZE( L"msiexec /qn /i %s REMOVE=%s" );
7291 WCHAR *product, *features, *cmd;
7292 STARTUPINFOW si;
7293 PROCESS_INFORMATION info;
7294 BOOL ret;
7295
7296 if (attrs & msidbUpgradeAttributesOnlyDetect) return ERROR_SUCCESS;
7297 if (!(product = msi_dup_property( package->db, property ))) return ERROR_SUCCESS;
7298
7299 deformat_string( package, MSI_RecordGetString( rec, 6 ), &features );
7300
7301 len += lstrlenW( product );
7302 if (features)
7303 len += lstrlenW( features );
7304 else
7305 len += ARRAY_SIZE( L"ALL" );
7306
7307 if (!(cmd = malloc( len * sizeof(WCHAR) )))
7308 {
7309 free( product );
7310 free( features );
7311 return ERROR_OUTOFMEMORY;
7312 }
7313 swprintf( cmd, len, L"msiexec /qn /i %s REMOVE=%s", product, features ? features : L"ALL" );
7314 free( product );
7315 free( features );
7316
7317 memset( &si, 0, sizeof(STARTUPINFOW) );
7318 ret = CreateProcessW( NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &info );
7319 free( cmd );
7320 if (!ret) return GetLastError();
7321 CloseHandle( info.hThread );
7322
7323 WaitForSingleObject( info.hProcess, INFINITE );
7324 CloseHandle( info.hProcess );
7325 return ERROR_SUCCESS;
7326 }
7327
ACTION_RemoveExistingProducts(MSIPACKAGE * package)7328 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
7329 {
7330 MSIQUERY *view;
7331 UINT r;
7332
7333 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Upgrade`", &view );
7334 if (r == ERROR_SUCCESS)
7335 {
7336 r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
7337 msiobj_release( &view->hdr );
7338 if (r != ERROR_SUCCESS)
7339 return r;
7340 }
7341 return ERROR_SUCCESS;
7342 }
7343
ITERATE_MigrateFeatureStates(MSIRECORD * rec,LPVOID param)7344 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
7345 {
7346 MSIPACKAGE *package = param;
7347 int attributes = MSI_RecordGetInteger( rec, 5 );
7348
7349 if (attributes & msidbUpgradeAttributesMigrateFeatures)
7350 {
7351 const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
7352 const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
7353 const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
7354 const WCHAR *language = MSI_RecordGetString( rec, 4 );
7355 HKEY hkey;
7356 UINT r;
7357
7358 if (package->Context == MSIINSTALLCONTEXT_MACHINE)
7359 {
7360 r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7361 if (r != ERROR_SUCCESS)
7362 return ERROR_SUCCESS;
7363 }
7364 else
7365 {
7366 r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
7367 if (r != ERROR_SUCCESS)
7368 return ERROR_SUCCESS;
7369 }
7370 RegCloseKey( hkey );
7371
7372 FIXME("migrate feature states from %s version min %s version max %s language %s\n",
7373 debugstr_w(upgrade_code), debugstr_w(version_min),
7374 debugstr_w(version_max), debugstr_w(language));
7375 }
7376 return ERROR_SUCCESS;
7377 }
7378
ACTION_MigrateFeatureStates(MSIPACKAGE * package)7379 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
7380 {
7381 MSIQUERY *view;
7382 UINT r;
7383
7384 if (msi_get_property_int( package->db, L"Installed", 0 ))
7385 {
7386 TRACE("product is installed, skipping action\n");
7387 return ERROR_SUCCESS;
7388 }
7389 if (msi_get_property_int( package->db, L"Preselected", 0 ))
7390 {
7391 TRACE("Preselected property is set, not migrating feature states\n");
7392 return ERROR_SUCCESS;
7393 }
7394 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `Upgrade`", &view );
7395 if (r == ERROR_SUCCESS)
7396 {
7397 r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
7398 msiobj_release( &view->hdr );
7399 if (r != ERROR_SUCCESS)
7400 return r;
7401 }
7402 return ERROR_SUCCESS;
7403 }
7404
bind_image(MSIPACKAGE * package,const char * filename,const char * path)7405 static void bind_image( MSIPACKAGE *package, const char *filename, const char *path )
7406 {
7407 msi_disable_fs_redirection( package );
7408 if (!BindImage( filename, path, NULL )) WARN( "failed to bind image %lu\n", GetLastError() );
7409 msi_revert_fs_redirection( package );
7410 }
7411
ITERATE_BindImage(MSIRECORD * rec,LPVOID param)7412 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
7413 {
7414 UINT i;
7415 MSIFILE *file;
7416 MSIPACKAGE *package = param;
7417 const WCHAR *key = MSI_RecordGetString( rec, 1 );
7418 const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7419 char *filenameA, *pathA;
7420 WCHAR *pathW, **path_list;
7421
7422 if (!(file = msi_get_loaded_file( package, key )))
7423 {
7424 WARN("file %s not found\n", debugstr_w(key));
7425 return ERROR_SUCCESS;
7426 }
7427 if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7428
7429 path_list = msi_split_string( paths, ';' );
7430 if (!path_list) bind_image( package, filenameA, NULL );
7431 else
7432 {
7433 for (i = 0; path_list[i] && path_list[i][0]; i++)
7434 {
7435 deformat_string( package, path_list[i], &pathW );
7436 if ((pathA = strdupWtoA( pathW )))
7437 {
7438 bind_image( package, filenameA, pathA );
7439 free( pathA );
7440 }
7441 free( pathW );
7442 }
7443 }
7444 free( path_list );
7445 free( filenameA );
7446
7447 return ERROR_SUCCESS;
7448 }
7449
ACTION_BindImage(MSIPACKAGE * package)7450 static UINT ACTION_BindImage( MSIPACKAGE *package )
7451 {
7452 MSIQUERY *view;
7453 UINT r;
7454
7455 r = MSI_DatabaseOpenViewW( package->db, L"SELECT * FROM `BindImage`", &view );
7456 if (r == ERROR_SUCCESS)
7457 {
7458 MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7459 msiobj_release( &view->hdr );
7460 }
7461 return ERROR_SUCCESS;
7462 }
7463
unimplemented_action_stub(MSIPACKAGE * package,LPCSTR action,LPCWSTR table)7464 static UINT unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7465 {
7466 MSIQUERY *view;
7467 DWORD count = 0;
7468 UINT r;
7469
7470 r = MSI_OpenQuery( package->db, &view, L"SELECT * FROM `%s`", table );
7471 if (r == ERROR_SUCCESS)
7472 {
7473 r = MSI_IterateRecords(view, &count, NULL, package);
7474 msiobj_release(&view->hdr);
7475 if (r != ERROR_SUCCESS)
7476 return r;
7477 }
7478 if (count) FIXME( "%s: ignored %lu rows from %s\n", action, count, debugstr_w(table) );
7479 return ERROR_SUCCESS;
7480 }
7481
ACTION_IsolateComponents(MSIPACKAGE * package)7482 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7483 {
7484 return unimplemented_action_stub( package, "IsolateComponents", L"IsolateComponent" );
7485 }
7486
ACTION_RMCCPSearch(MSIPACKAGE * package)7487 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7488 {
7489 return unimplemented_action_stub( package, "RMCCPSearch", L"CCPSearch" );
7490 }
7491
ACTION_RegisterComPlus(MSIPACKAGE * package)7492 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7493 {
7494 return unimplemented_action_stub( package, "RegisterComPlus", L"Complus" );
7495 }
7496
ACTION_UnregisterComPlus(MSIPACKAGE * package)7497 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7498 {
7499 return unimplemented_action_stub( package, "UnregisterComPlus", L"Complus" );
7500 }
7501
ACTION_InstallSFPCatalogFile(MSIPACKAGE * package)7502 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7503 {
7504 return unimplemented_action_stub( package, "InstallSFPCatalogFile", L"SFPCatalog" );
7505 }
7506
7507 static const struct
7508 {
7509 const WCHAR *action;
7510 const UINT description;
7511 const UINT template;
7512 UINT (*handler)(MSIPACKAGE *);
7513 const WCHAR *action_rollback;
7514 }
7515 StandardActions[] =
7516 {
7517 { L"AllocateRegistrySpace", IDS_DESC_ALLOCATEREGISTRYSPACE, IDS_TEMP_ALLOCATEREGISTRYSPACE, ACTION_AllocateRegistrySpace, NULL },
7518 { L"AppSearch", IDS_DESC_APPSEARCH, IDS_TEMP_APPSEARCH, ACTION_AppSearch, NULL },
7519 { L"BindImage", IDS_DESC_BINDIMAGE, IDS_TEMP_BINDIMAGE, ACTION_BindImage, NULL },
7520 { L"CCPSearch", IDS_DESC_CCPSEARCH, 0, ACTION_CCPSearch, NULL },
7521 { L"CostFinalize", IDS_DESC_COSTFINALIZE, 0, ACTION_CostFinalize, NULL },
7522 { L"CostInitialize", IDS_DESC_COSTINITIALIZE, 0, ACTION_CostInitialize, NULL },
7523 { L"CreateFolders", IDS_DESC_CREATEFOLDERS, IDS_TEMP_CREATEFOLDERS, ACTION_CreateFolders, L"RemoveFolders" },
7524 { L"CreateShortcuts", IDS_DESC_CREATESHORTCUTS, IDS_TEMP_CREATESHORTCUTS, ACTION_CreateShortcuts, L"RemoveShortcuts" },
7525 { L"DeleteServices", IDS_DESC_DELETESERVICES, IDS_TEMP_DELETESERVICES, ACTION_DeleteServices, L"InstallServices" },
7526 { L"DisableRollback", 0, 0, ACTION_DisableRollback, NULL },
7527 { L"DuplicateFiles", IDS_DESC_DUPLICATEFILES, IDS_TEMP_DUPLICATEFILES, ACTION_DuplicateFiles, L"RemoveDuplicateFiles" },
7528 { L"ExecuteAction", 0, 0, ACTION_ExecuteAction, NULL },
7529 { L"FileCost", IDS_DESC_FILECOST, 0, ACTION_FileCost, NULL },
7530 { L"FindRelatedProducts", IDS_DESC_FINDRELATEDPRODUCTS, IDS_TEMP_FINDRELATEDPRODUCTS, ACTION_FindRelatedProducts, NULL },
7531 { L"ForceReboot", 0, 0, ACTION_ForceReboot, NULL },
7532 { L"InstallAdminPackage", IDS_DESC_INSTALLADMINPACKAGE, IDS_TEMP_INSTALLADMINPACKAGE, ACTION_InstallAdminPackage, NULL },
7533 { L"InstallExecute", 0, 0, ACTION_InstallExecute, NULL },
7534 { L"InstallExecuteAgain", 0, 0, ACTION_InstallExecute, NULL },
7535 { L"InstallFiles", IDS_DESC_INSTALLFILES, IDS_TEMP_INSTALLFILES, ACTION_InstallFiles, L"RemoveFiles" },
7536 { L"InstallFinalize", 0, 0, ACTION_InstallFinalize, NULL },
7537 { L"InstallInitialize", 0, 0, ACTION_InstallInitialize, NULL },
7538 { L"InstallODBC", IDS_DESC_INSTALLODBC, 0, ACTION_InstallODBC, L"RemoveODBC" },
7539 { L"InstallServices", IDS_DESC_INSTALLSERVICES, IDS_TEMP_INSTALLSERVICES, ACTION_InstallServices, L"DeleteServices" },
7540 { L"InstallSFPCatalogFile", IDS_DESC_INSTALLSFPCATALOGFILE, IDS_TEMP_INSTALLSFPCATALOGFILE, ACTION_InstallSFPCatalogFile, NULL },
7541 { L"InstallValidate", IDS_DESC_INSTALLVALIDATE, 0, ACTION_InstallValidate, NULL },
7542 { L"IsolateComponents", 0, 0, ACTION_IsolateComponents, NULL },
7543 { L"LaunchConditions", IDS_DESC_LAUNCHCONDITIONS, 0, ACTION_LaunchConditions, NULL },
7544 { L"MigrateFeutureStates", IDS_DESC_MIGRATEFEATURESTATES, IDS_TEMP_MIGRATEFEATURESTATES, ACTION_MigrateFeatureStates, NULL },
7545 { L"MoveFiles", IDS_DESC_MOVEFILES, IDS_TEMP_MOVEFILES, ACTION_MoveFiles, NULL },
7546 { L"MsiPublishAssemblies", IDS_DESC_MSIPUBLISHASSEMBLIES, IDS_TEMP_MSIPUBLISHASSEMBLIES, ACTION_MsiPublishAssemblies, L"MsiUnpublishAssemblies" },
7547 { L"MsiUnpublishAssemblies", IDS_DESC_MSIUNPUBLISHASSEMBLIES, IDS_TEMP_MSIUNPUBLISHASSEMBLIES, ACTION_MsiUnpublishAssemblies, L"MsiPublishAssemblies" },
7548 { L"PatchFiles", IDS_DESC_PATCHFILES, IDS_TEMP_PATCHFILES, ACTION_PatchFiles, NULL },
7549 { L"ProcessComponents", IDS_DESC_PROCESSCOMPONENTS, 0, ACTION_ProcessComponents, L"ProcessComponents" },
7550 { L"PublishComponents", IDS_DESC_PUBLISHCOMPONENTS, IDS_TEMP_PUBLISHCOMPONENTS, ACTION_PublishComponents, L"UnpublishComponents" },
7551 { L"PublishFeatures", IDS_DESC_PUBLISHFEATURES, IDS_TEMP_PUBLISHFEATURES, ACTION_PublishFeatures, L"UnpublishFeatures" },
7552 { L"PublishProduct", IDS_DESC_PUBLISHPRODUCT, 0, ACTION_PublishProduct, L"UnpublishProduct" },
7553 { L"RegisterClassInfo", IDS_DESC_REGISTERCLASSINFO, IDS_TEMP_REGISTERCLASSINFO, ACTION_RegisterClassInfo, L"UnregisterClassInfo" },
7554 { L"RegisterComPlus", IDS_DESC_REGISTERCOMPLUS, IDS_TEMP_REGISTERCOMPLUS, ACTION_RegisterComPlus, L"UnregisterComPlus" },
7555 { L"RegisterExtensionInfo", IDS_DESC_REGISTEREXTENSIONINFO, 0, ACTION_RegisterExtensionInfo, L"UnregisterExtensionInfo" },
7556 { L"RegisterFonts", IDS_DESC_REGISTERFONTS, IDS_TEMP_REGISTERFONTS, ACTION_RegisterFonts, L"UnregisterFonts" },
7557 { L"RegisterMIMEInfo", IDS_DESC_REGISTERMIMEINFO, IDS_TEMP_REGISTERMIMEINFO, ACTION_RegisterMIMEInfo, L"UnregisterMIMEInfo" },
7558 { L"RegisterProduct", IDS_DESC_REGISTERPRODUCT, 0, ACTION_RegisterProduct, NULL },
7559 { L"RegisterProgIdInfo", IDS_DESC_REGISTERPROGIDINFO, IDS_TEMP_REGISTERPROGIDINFO, ACTION_RegisterProgIdInfo, L"UnregisterProgIdInfo" },
7560 { L"RegisterTypeLibraries", IDS_DESC_REGISTERTYPELIBRARIES, IDS_TEMP_REGISTERTYPELIBRARIES, ACTION_RegisterTypeLibraries, L"UnregisterTypeLibraries" },
7561 { L"RegisterUser", IDS_DESC_REGISTERUSER, 0, ACTION_RegisterUser, NULL },
7562 { L"RemoveDuplicateFiles", IDS_DESC_REMOVEDUPLICATEFILES, IDS_TEMP_REMOVEDUPLICATEFILES, ACTION_RemoveDuplicateFiles, L"DuplicateFiles" },
7563 { L"RemoveEnvironmentStrings", IDS_DESC_REMOVEENVIRONMENTSTRINGS, IDS_TEMP_REMOVEENVIRONMENTSTRINGS, ACTION_RemoveEnvironmentStrings, L"WriteEnvironmentStrings" },
7564 { L"RemoveExistingProducts", IDS_DESC_REMOVEEXISTINGPRODUCTS, IDS_TEMP_REMOVEEXISTINGPRODUCTS, ACTION_RemoveExistingProducts, NULL },
7565 { L"RemoveFiles", IDS_DESC_REMOVEFILES, IDS_TEMP_REMOVEFILES, ACTION_RemoveFiles, L"InstallFiles" },
7566 { L"RemoveFolders", IDS_DESC_REMOVEFOLDERS, IDS_TEMP_REMOVEFOLDERS, ACTION_RemoveFolders, L"CreateFolders" },
7567 { L"RemoveIniValues", IDS_DESC_REMOVEINIVALUES, IDS_TEMP_REMOVEINIVALUES, ACTION_RemoveIniValues, L"WriteIniValues" },
7568 { L"RemoveODBC", IDS_DESC_REMOVEODBC, 0, ACTION_RemoveODBC, L"InstallODBC" },
7569 { L"RemoveRegistryValues", IDS_DESC_REMOVEREGISTRYVALUES, IDS_TEMP_REMOVEREGISTRYVALUES, ACTION_RemoveRegistryValues, L"WriteRegistryValues" },
7570 { L"RemoveShortcuts", IDS_DESC_REMOVESHORTCUTS, IDS_TEMP_REMOVESHORTCUTS, ACTION_RemoveShortcuts, L"CreateShortcuts" },
7571 { L"ResolveSource", 0, 0, ACTION_ResolveSource, NULL },
7572 { L"RMCCPSearch", IDS_DESC_RMCCPSEARCH, 0, ACTION_RMCCPSearch, NULL },
7573 { L"ScheduleReboot", 0, 0, ACTION_ScheduleReboot, NULL },
7574 { L"SelfRegModules", IDS_DESC_SELFREGMODULES, IDS_TEMP_SELFREGMODULES, ACTION_SelfRegModules, L"SelfUnregModules" },
7575 { L"SelfUnregModules", IDS_DESC_SELFUNREGMODULES, IDS_TEMP_SELFUNREGMODULES, ACTION_SelfUnregModules, L"SelfRegModules" },
7576 { L"SetODBCFolders", IDS_DESC_SETODBCFOLDERS, 0, ACTION_SetODBCFolders, NULL },
7577 { L"StartServices", IDS_DESC_STARTSERVICES, IDS_TEMP_STARTSERVICES, ACTION_StartServices, L"StopServices" },
7578 { L"StopServices", IDS_DESC_STOPSERVICES, IDS_TEMP_STOPSERVICES, ACTION_StopServices, L"StartServices" },
7579 { L"UnpublishComponents", IDS_DESC_UNPUBLISHCOMPONENTS, IDS_TEMP_UNPUBLISHCOMPONENTS, ACTION_UnpublishComponents, L"PublishComponents" },
7580 { L"UnpublishFeatures", IDS_DESC_UNPUBLISHFEATURES, IDS_TEMP_UNPUBLISHFEATURES, ACTION_UnpublishFeatures, L"PublishFeatures" },
7581 { L"UnpublishProduct", IDS_DESC_UNPUBLISHPRODUCT, 0, ACTION_UnpublishProduct, NULL }, /* for rollback only */
7582 { L"UnregisterClassInfo", IDS_DESC_UNREGISTERCLASSINFO, IDS_TEMP_UNREGISTERCLASSINFO, ACTION_UnregisterClassInfo, L"RegisterClassInfo" },
7583 { L"UnregisterComPlus", IDS_DESC_UNREGISTERCOMPLUS, IDS_TEMP_UNREGISTERCOMPLUS, ACTION_UnregisterComPlus, L"RegisterComPlus" },
7584 { L"UnregisterExtensionInfo", IDS_DESC_UNREGISTEREXTENSIONINFO, IDS_TEMP_UNREGISTEREXTENSIONINFO, ACTION_UnregisterExtensionInfo, L"RegisterExtensionInfo" },
7585 { L"UnregisterFonts", IDS_DESC_UNREGISTERFONTS, IDS_TEMP_UNREGISTERFONTS, ACTION_UnregisterFonts, L"RegisterFonts" },
7586 { L"UnregisterMIMEInfo", IDS_DESC_UNREGISTERMIMEINFO, IDS_TEMP_UNREGISTERMIMEINFO, ACTION_UnregisterMIMEInfo, L"RegisterMIMEInfo" },
7587 { L"UnregisterProgIdInfo", IDS_DESC_UNREGISTERPROGIDINFO, IDS_TEMP_UNREGISTERPROGIDINFO, ACTION_UnregisterProgIdInfo, L"RegisterProgIdInfo" },
7588 { L"UnregisterTypeLibraries", IDS_DESC_UNREGISTERTYPELIBRARIES, IDS_TEMP_UNREGISTERTYPELIBRARIES, ACTION_UnregisterTypeLibraries, L"RegisterTypeLibraries" },
7589 { L"ValidateProductID", 0, 0, ACTION_ValidateProductID, NULL },
7590 { L"WriteEnvironmentStrings", IDS_DESC_WRITEENVIRONMENTSTRINGS, IDS_TEMP_WRITEENVIRONMENTSTRINGS, ACTION_WriteEnvironmentStrings, L"RemoveEnvironmentStrings" },
7591 { L"WriteIniValues", IDS_DESC_WRITEINIVALUES, IDS_TEMP_WRITEINIVALUES, ACTION_WriteIniValues, L"RemoveIniValues" },
7592 { L"WriteRegistryValues", IDS_DESC_WRITEREGISTRYVALUES, IDS_TEMP_WRITEREGISTRYVALUES, ACTION_WriteRegistryValues, L"RemoveRegistryValues" },
7593 { L"INSTALL", 0, 0, ACTION_INSTALL, NULL },
7594 { 0 }
7595 };
7596
ACTION_HandleStandardAction(MSIPACKAGE * package,LPCWSTR action)7597 static UINT ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action)
7598 {
7599 UINT rc = ERROR_FUNCTION_NOT_CALLED;
7600 UINT i;
7601
7602 i = 0;
7603 while (StandardActions[i].action != NULL)
7604 {
7605 if (!wcscmp( StandardActions[i].action, action ))
7606 {
7607 WCHAR description[100] = {0}, template[100] = {0};
7608
7609 if (StandardActions[i].description != 0)
7610 LoadStringW(msi_hInstance, StandardActions[i].description, (LPWSTR)&description, 100);
7611 if (StandardActions[i].template != 0)
7612 LoadStringW(msi_hInstance, StandardActions[i].template, (LPWSTR)&template, 100);
7613
7614 ui_actionstart(package, action, description, template);
7615 if (StandardActions[i].handler)
7616 {
7617 ui_actioninfo( package, action, TRUE, 0 );
7618 rc = StandardActions[i].handler( package );
7619 ui_actioninfo( package, action, FALSE, !rc );
7620
7621 if (StandardActions[i].action_rollback && !package->need_rollback)
7622 {
7623 TRACE("scheduling rollback action\n");
7624 msi_schedule_action( package, SCRIPT_ROLLBACK, StandardActions[i].action_rollback );
7625 }
7626 }
7627 else
7628 {
7629 FIXME("unhandled standard action %s\n", debugstr_w(action));
7630 rc = ERROR_SUCCESS;
7631 }
7632 break;
7633 }
7634 i++;
7635 }
7636
7637 return rc;
7638 }
7639
ACTION_PerformAction(MSIPACKAGE * package,const WCHAR * action)7640 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action)
7641 {
7642 UINT rc;
7643
7644 TRACE("Performing action (%s)\n", debugstr_w(action));
7645
7646 package->action_progress_increment = 0;
7647 rc = ACTION_HandleStandardAction(package, action);
7648
7649 if (rc == ERROR_FUNCTION_NOT_CALLED)
7650 rc = ACTION_HandleCustomAction(package, action);
7651
7652 if (rc == ERROR_FUNCTION_NOT_CALLED)
7653 WARN("unhandled msi action %s\n", debugstr_w(action));
7654
7655 return rc;
7656 }
7657
ACTION_PerformActionSequence(MSIPACKAGE * package,UINT seq)7658 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7659 {
7660 UINT rc = ERROR_SUCCESS;
7661 MSIRECORD *row;
7662
7663 if (needs_ui_sequence(package))
7664 row = MSI_QueryGetRecord(package->db, L"SELECT * FROM `InstallUISequence` WHERE `Sequence` = %d", seq);
7665 else
7666 row = MSI_QueryGetRecord(package->db, L"SELECT * FROM `InstallExecuteSequence` WHERE `Sequence` = %d", seq);
7667
7668 if (row)
7669 {
7670 LPCWSTR action, cond;
7671
7672 TRACE("Running the actions\n");
7673
7674 /* check conditions */
7675 cond = MSI_RecordGetString(row, 2);
7676
7677 /* this is a hack to skip errors in the condition code */
7678 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7679 {
7680 msiobj_release(&row->hdr);
7681 return ERROR_SUCCESS;
7682 }
7683
7684 action = MSI_RecordGetString(row, 1);
7685 if (!action)
7686 {
7687 ERR("failed to fetch action\n");
7688 msiobj_release(&row->hdr);
7689 return ERROR_FUNCTION_FAILED;
7690 }
7691
7692 rc = ACTION_PerformAction(package, action);
7693
7694 msiobj_release(&row->hdr);
7695 }
7696
7697 return rc;
7698 }
7699
dummy_thread_proc(void * arg)7700 DWORD WINAPI dummy_thread_proc(void *arg)
7701 {
7702 struct dummy_thread *info = arg;
7703 HRESULT hr;
7704
7705 hr = CoInitializeEx(0, COINIT_MULTITHREADED);
7706 if (FAILED(hr)) ERR("CoInitializeEx failed %08x\n", hr);
7707
7708 SetEvent(info->started);
7709 WaitForSingleObject(info->stopped, INFINITE);
7710
7711 CoUninitialize();
7712 return 0;
7713 }
7714
start_dummy_thread(struct dummy_thread * info)7715 static void start_dummy_thread(struct dummy_thread *info)
7716 {
7717 if (!(info->started = CreateEventA(NULL, TRUE, FALSE, NULL))) return;
7718 if (!(info->stopped = CreateEventA(NULL, TRUE, FALSE, NULL))) return;
7719 if (!(info->thread = CreateThread(NULL, 0, dummy_thread_proc, info, 0, NULL))) return;
7720
7721 WaitForSingleObject(info->started, INFINITE);
7722 }
7723
stop_dummy_thread(struct dummy_thread * info)7724 static void stop_dummy_thread(struct dummy_thread *info)
7725 {
7726 if (info->thread)
7727 {
7728 SetEvent(info->stopped);
7729 WaitForSingleObject(info->thread, INFINITE);
7730 CloseHandle(info->thread);
7731 }
7732 if (info->started) CloseHandle(info->started);
7733 if (info->stopped) CloseHandle(info->stopped);
7734 }
7735
7736 /****************************************************
7737 * TOP level entry points
7738 *****************************************************/
7739
MSI_InstallPackage(MSIPACKAGE * package,LPCWSTR szPackagePath,LPCWSTR szCommandLine)7740 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7741 LPCWSTR szCommandLine )
7742 {
7743 WCHAR *reinstall = NULL, *productcode, *action;
7744 struct dummy_thread thread_info = {NULL, NULL, NULL};
7745 UINT rc;
7746 DWORD len = 0;
7747
7748 if (szPackagePath)
7749 {
7750 LPWSTR p, dir;
7751 LPCWSTR file;
7752
7753 dir = wcsdup(szPackagePath);
7754 p = wcsrchr(dir, '\\');
7755 if (p)
7756 {
7757 *(++p) = 0;
7758 file = szPackagePath + (p - dir);
7759 }
7760 else
7761 {
7762 free(dir);
7763 dir = malloc(MAX_PATH * sizeof(WCHAR));
7764 GetCurrentDirectoryW(MAX_PATH, dir);
7765 lstrcatW(dir, L"\\");
7766 file = szPackagePath;
7767 }
7768
7769 free(package->PackagePath);
7770 package->PackagePath = malloc((wcslen(dir) + wcslen(file) + 1) * sizeof(WCHAR));
7771 if (!package->PackagePath)
7772 {
7773 free(dir);
7774 return ERROR_OUTOFMEMORY;
7775 }
7776
7777 lstrcpyW(package->PackagePath, dir);
7778 lstrcatW(package->PackagePath, file);
7779 free(dir);
7780
7781 msi_set_sourcedir_props(package, FALSE);
7782 }
7783
7784 rc = msi_parse_command_line( package, szCommandLine, FALSE );
7785 if (rc != ERROR_SUCCESS)
7786 return rc;
7787
7788 msi_apply_transforms( package );
7789 msi_apply_patches( package );
7790
7791 if (msi_get_property( package->db, L"ACTION", NULL, &len ))
7792 msi_set_property( package->db, L"ACTION", L"INSTALL", -1 );
7793 action = msi_dup_property( package->db, L"ACTION" );
7794 CharUpperW(action);
7795
7796 msi_set_original_database_property( package->db, szPackagePath );
7797 msi_parse_command_line( package, szCommandLine, FALSE );
7798 msi_adjust_privilege_properties( package );
7799 msi_set_context( package );
7800
7801 start_dummy_thread(&thread_info);
7802
7803 productcode = msi_dup_property( package->db, L"ProductCode" );
7804 if (wcsicmp( productcode, package->ProductCode ))
7805 {
7806 TRACE( "product code changed %s -> %s\n", debugstr_w(package->ProductCode), debugstr_w(productcode) );
7807 free( package->ProductCode );
7808 package->ProductCode = productcode;
7809 }
7810 else free( productcode );
7811
7812 if (msi_get_property_int( package->db, L"DISABLEROLLBACK", 0 ))
7813 {
7814 TRACE("disabling rollback\n");
7815 msi_set_property( package->db, L"RollbackDisabled", L"1", -1 );
7816 }
7817
7818 rc = ACTION_PerformAction(package, action);
7819
7820 /* process the ending type action */
7821 if (rc == ERROR_SUCCESS)
7822 ACTION_PerformActionSequence(package, -1);
7823 else if (rc == ERROR_INSTALL_USEREXIT)
7824 ACTION_PerformActionSequence(package, -2);
7825 else if (rc == ERROR_INSTALL_SUSPEND)
7826 ACTION_PerformActionSequence(package, -4);
7827 else /* failed */
7828 {
7829 ACTION_PerformActionSequence(package, -3);
7830 if (!msi_get_property_int( package->db, L"RollbackDisabled", 0 ))
7831 {
7832 package->need_rollback = TRUE;
7833 }
7834 }
7835
7836 /* finish up running custom actions */
7837 ACTION_FinishCustomActions(package);
7838
7839 stop_dummy_thread(&thread_info);
7840
7841 if (package->need_rollback && !(reinstall = msi_dup_property( package->db, L"REINSTALL" )))
7842 {
7843 WARN("installation failed, running rollback script\n");
7844 execute_script( package, SCRIPT_ROLLBACK );
7845 }
7846 free( reinstall );
7847 free( action );
7848
7849 if (rc == ERROR_SUCCESS && package->need_reboot_at_end)
7850 return ERROR_SUCCESS_REBOOT_REQUIRED;
7851
7852 return rc;
7853 }
7854