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