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