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