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