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