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