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