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