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