dmloader: Simplify the module refcount handling.
[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     int num;
492
493     package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
494
495     num = msi_get_property_int(package->db, szAllUsers, 0);
496     if (num == 1 || num == 2)
497         package->Context = MSIINSTALLCONTEXT_MACHINE;
498
499     return ERROR_SUCCESS;
500 }
501
502 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
503 {
504     UINT rc;
505     LPCWSTR cond, action;
506     MSIPACKAGE *package = param;
507
508     action = MSI_RecordGetString(row,1);
509     if (!action)
510     {
511         ERR("Error is retrieving action name\n");
512         return ERROR_FUNCTION_FAILED;
513     }
514
515     /* check conditions */
516     cond = MSI_RecordGetString(row,2);
517
518     /* this is a hack to skip errors in the condition code */
519     if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
520     {
521         TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
522         return ERROR_SUCCESS;
523     }
524
525     if (needs_ui_sequence(package))
526         rc = ACTION_PerformUIAction(package, action, -1);
527     else
528         rc = ACTION_PerformAction(package, action, -1);
529
530     msi_dialog_check_messages( NULL );
531
532     if (package->CurrentInstallState != ERROR_SUCCESS)
533         rc = package->CurrentInstallState;
534
535     if (rc == ERROR_FUNCTION_NOT_CALLED)
536         rc = ERROR_SUCCESS;
537
538     if (rc != ERROR_SUCCESS)
539         ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
540
541     return rc;
542 }
543
544 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR table )
545 {
546     static const WCHAR query[] = {
547         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',
548          ' ','W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ',
549          '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
550          '`','S','e','q','u','e','n','c','e','`',0};
551     MSIQUERY *view;
552     UINT r;
553
554     TRACE("%p %s\n", package, debugstr_w(table));
555
556     r = MSI_OpenQuery( package->db, &view, query, table );
557     if (r == ERROR_SUCCESS)
558     {
559         r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
560         msiobj_release(&view->hdr);
561     }
562     return r;
563 }
564
565 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
566 {
567     static const WCHAR query[] = {
568         'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
569         '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
570         'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
571         '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
572         'O','R','D','E','R',' ', 'B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
573     static const WCHAR query_validate[] = {
574         'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
575         ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
576         'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
577         'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
578         ' ','\'', 'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','\'',0};
579     MSIQUERY *view;
580     INT seq = 0;
581     UINT rc;
582
583     if (package->script->ExecuteSequenceRun)
584     {
585         TRACE("Execute Sequence already Run\n");
586         return ERROR_SUCCESS;
587     }
588
589     package->script->ExecuteSequenceRun = TRUE;
590
591     /* get the sequence number */
592     if (UIran)
593     {
594         MSIRECORD *row = MSI_QueryGetRecord(package->db, query_validate);
595         if (!row) return ERROR_FUNCTION_FAILED;
596         seq = MSI_RecordGetInteger(row,1);
597         msiobj_release(&row->hdr);
598     }
599     rc = MSI_OpenQuery(package->db, &view, query, seq);
600     if (rc == ERROR_SUCCESS)
601     {
602         TRACE("Running the actions\n");
603
604         msi_set_property(package->db, szSourceDir, NULL);
605         rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
606         msiobj_release(&view->hdr);
607     }
608     return rc;
609 }
610
611 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
612 {
613     static const WCHAR query[] = {
614         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
615         '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e','`',' ',
616         'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',' ','>',' ','0',' ',
617         'O','R','D','E','R',' ','B','Y',' ','`','S','e','q','u','e','n','c','e','`',0};
618     MSIQUERY *view;
619     UINT rc;
620
621     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
622     if (rc == ERROR_SUCCESS)
623     {
624         TRACE("Running the actions\n"); 
625         rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
626         msiobj_release(&view->hdr);
627     }
628     return rc;
629 }
630
631 /********************************************************
632  * ACTION helper functions and functions that perform the actions
633  *******************************************************/
634 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
635                                        UINT* rc, UINT script, BOOL force )
636 {
637     BOOL ret=FALSE;
638     UINT arc;
639
640     arc = ACTION_CustomAction(package, action, script, force);
641
642     if (arc != ERROR_CALL_NOT_IMPLEMENTED)
643     {
644         *rc = arc;
645         ret = TRUE;
646     }
647     return ret;
648 }
649
650 MSICOMPONENT *msi_get_loaded_component( MSIPACKAGE *package, const WCHAR *Component )
651 {
652     MSICOMPONENT *comp;
653
654     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
655     {
656         if (!strcmpW( Component, comp->Component )) return comp;
657     }
658     return NULL;
659 }
660
661 MSIFEATURE *msi_get_loaded_feature(MSIPACKAGE* package, const WCHAR *Feature )
662 {
663     MSIFEATURE *feature;
664
665     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
666     {
667         if (!strcmpW( Feature, feature->Feature )) return feature;
668     }
669     return NULL;
670 }
671
672 MSIFILE *msi_get_loaded_file( MSIPACKAGE *package, const WCHAR *key )
673 {
674     MSIFILE *file;
675
676     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
677     {
678         if (!strcmpW( key, file->File )) return file;
679     }
680     return NULL;
681 }
682
683 MSIFILEPATCH *msi_get_loaded_filepatch( MSIPACKAGE *package, const WCHAR *key )
684 {
685     MSIFILEPATCH *patch;
686
687     /* FIXME: There might be more than one patch */
688     LIST_FOR_EACH_ENTRY( patch, &package->filepatches, MSIFILEPATCH, entry )
689     {
690         if (!strcmpW( key, patch->File->File )) return patch;
691     }
692     return NULL;
693 }
694
695 MSIFOLDER *msi_get_loaded_folder( MSIPACKAGE *package, const WCHAR *dir )
696 {
697     MSIFOLDER *folder;
698
699     LIST_FOR_EACH_ENTRY( folder, &package->folders, MSIFOLDER, entry )
700     {
701         if (!strcmpW( dir, folder->Directory )) return folder;
702     }
703     return NULL;
704 }
705
706 /*
707  * Recursively create all directories in the path.
708  * shamelessly stolen from setupapi/queue.c
709  */
710 BOOL msi_create_full_path( const WCHAR *path )
711 {
712     BOOL ret = TRUE;
713     WCHAR *new_path;
714     int len;
715
716     new_path = msi_alloc( (strlenW( path ) + 1) * sizeof(WCHAR) );
717     strcpyW( new_path, path );
718
719     while ((len = strlenW( new_path )) && new_path[len - 1] == '\\')
720     new_path[len - 1] = 0;
721
722     while (!CreateDirectoryW( new_path, NULL ))
723     {
724         WCHAR *slash;
725         DWORD last_error = GetLastError();
726         if (last_error == ERROR_ALREADY_EXISTS) break;
727         if (last_error != ERROR_PATH_NOT_FOUND)
728         {
729             ret = FALSE;
730             break;
731         }
732         if (!(slash = strrchrW( new_path, '\\' )))
733         {
734             ret = FALSE;
735             break;
736         }
737         len = slash - new_path;
738         new_path[len] = 0;
739         if (!msi_create_full_path( new_path ))
740         {
741             ret = FALSE;
742             break;
743         }
744         new_path[len] = '\\';
745     }
746     msi_free( new_path );
747     return ret;
748 }
749
750 void msi_ui_progress( MSIPACKAGE *package, int a, int b, int c, int d )
751 {
752     MSIRECORD *row;
753
754     row = MSI_CreateRecord( 4 );
755     MSI_RecordSetInteger( row, 1, a );
756     MSI_RecordSetInteger( row, 2, b );
757     MSI_RecordSetInteger( row, 3, c );
758     MSI_RecordSetInteger( row, 4, d );
759     MSI_ProcessMessage( package, INSTALLMESSAGE_PROGRESS, row );
760     msiobj_release( &row->hdr );
761
762     msi_dialog_check_messages( NULL );
763 }
764
765 void msi_ui_actiondata( MSIPACKAGE *package, const WCHAR *action, MSIRECORD *record )
766 {
767     static const WCHAR query[] =
768         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
769          '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
770          'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=',' ','\'','%','s','\'',0};
771     WCHAR message[1024];
772     MSIRECORD *row = 0;
773     DWORD size;
774
775     if (!package->LastAction || strcmpW( package->LastAction, action ))
776     {
777         if (!(row = MSI_QueryGetRecord( package->db, query, action ))) return;
778
779         if (MSI_RecordIsNull( row, 3 ))
780         {
781             msiobj_release( &row->hdr );
782             return;
783         }
784         /* update the cached action format */
785         msi_free( package->ActionFormat );
786         package->ActionFormat = msi_dup_record_field( row, 3 );
787         msi_free( package->LastAction );
788         package->LastAction = strdupW( action );
789         msiobj_release( &row->hdr );
790     }
791     size = 1024;
792     MSI_RecordSetStringW( record, 0, package->ActionFormat );
793     MSI_FormatRecordW( package, record, message, &size );
794     row = MSI_CreateRecord( 1 );
795     MSI_RecordSetStringW( row, 1, message );
796     MSI_ProcessMessage( package, INSTALLMESSAGE_ACTIONDATA, row );
797     msiobj_release( &row->hdr );
798 }
799
800 INSTALLSTATE msi_get_component_action( MSIPACKAGE *package, MSICOMPONENT *comp )
801 {
802     if (!comp->Enabled)
803     {
804         TRACE("component is disabled: %s\n", debugstr_w(comp->Component));
805         return INSTALLSTATE_UNKNOWN;
806     }
807     if (package->need_rollback) return comp->Installed;
808     return comp->ActionRequest;
809 }
810
811 INSTALLSTATE msi_get_feature_action( MSIPACKAGE *package, MSIFEATURE *feature )
812 {
813     if (package->need_rollback) return feature->Installed;
814     return feature->ActionRequest;
815 }
816
817 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
818 {
819     MSIPACKAGE *package = param;
820     LPCWSTR dir, component, full_path;
821     MSIRECORD *uirow;
822     MSIFOLDER *folder;
823     MSICOMPONENT *comp;
824
825     component = MSI_RecordGetString(row, 2);
826     if (!component)
827         return ERROR_SUCCESS;
828
829     comp = msi_get_loaded_component(package, component);
830     if (!comp)
831         return ERROR_SUCCESS;
832
833     comp->Action = msi_get_component_action( package, comp );
834     if (comp->Action != INSTALLSTATE_LOCAL)
835     {
836         TRACE("component not scheduled for installation: %s\n", debugstr_w(component));
837         return ERROR_SUCCESS;
838     }
839
840     dir = MSI_RecordGetString(row,1);
841     if (!dir)
842     {
843         ERR("Unable to get folder id\n");
844         return ERROR_SUCCESS;
845     }
846
847     uirow = MSI_CreateRecord(1);
848     MSI_RecordSetStringW(uirow, 1, dir);
849     msi_ui_actiondata(package, szCreateFolders, uirow);
850     msiobj_release(&uirow->hdr);
851
852     full_path = msi_get_target_folder( package, dir );
853     if (!full_path)
854     {
855         ERR("Unable to retrieve folder %s\n", debugstr_w(dir));
856         return ERROR_SUCCESS;
857     }
858     TRACE("folder is %s\n", debugstr_w(full_path));
859
860     folder = msi_get_loaded_folder( package, dir );
861     if (folder->State == FOLDER_STATE_UNINITIALIZED) msi_create_full_path( full_path );
862     folder->State = FOLDER_STATE_CREATED;
863     return ERROR_SUCCESS;
864 }
865
866 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
867 {
868     static const WCHAR query[] = {
869         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
870         '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
871     MSIQUERY *view;
872     UINT rc;
873
874     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
875     if (rc != ERROR_SUCCESS)
876         return ERROR_SUCCESS;
877
878     rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
879     msiobj_release(&view->hdr);
880     return rc;
881 }
882
883 static UINT ITERATE_RemoveFolders( MSIRECORD *row, LPVOID param )
884 {
885     MSIPACKAGE *package = param;
886     LPCWSTR dir, component, full_path;
887     MSIRECORD *uirow;
888     MSIFOLDER *folder;
889     MSICOMPONENT *comp;
890
891     component = MSI_RecordGetString(row, 2);
892     if (!component)
893         return ERROR_SUCCESS;
894
895     comp = msi_get_loaded_component(package, component);
896     if (!comp)
897         return ERROR_SUCCESS;
898
899     comp->Action = msi_get_component_action( package, comp );
900     if (comp->Action != INSTALLSTATE_ABSENT)
901     {
902         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
903         return ERROR_SUCCESS;
904     }
905
906     dir = MSI_RecordGetString( row, 1 );
907     if (!dir)
908     {
909         ERR("Unable to get folder id\n");
910         return ERROR_SUCCESS;
911     }
912
913     full_path = msi_get_target_folder( package, dir );
914     if (!full_path)
915     {
916         ERR("Unable to resolve folder %s\n", debugstr_w(dir));
917         return ERROR_SUCCESS;
918     }
919     TRACE("folder is %s\n", debugstr_w(full_path));
920
921     uirow = MSI_CreateRecord( 1 );
922     MSI_RecordSetStringW( uirow, 1, dir );
923     msi_ui_actiondata( package, szRemoveFolders, uirow );
924     msiobj_release( &uirow->hdr );
925
926     RemoveDirectoryW( full_path );
927     folder = msi_get_loaded_folder( package, dir );
928     folder->State = FOLDER_STATE_REMOVED;
929     return ERROR_SUCCESS;
930 }
931
932 static UINT ACTION_RemoveFolders( MSIPACKAGE *package )
933 {
934     static const WCHAR query[] = {
935         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
936         '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0};
937     MSIQUERY *view;
938     UINT rc;
939
940     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
941     if (rc != ERROR_SUCCESS)
942         return ERROR_SUCCESS;
943
944     rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveFolders, package );
945     msiobj_release( &view->hdr );
946     return rc;
947 }
948
949 static UINT load_component( MSIRECORD *row, LPVOID param )
950 {
951     MSIPACKAGE *package = param;
952     MSICOMPONENT *comp;
953
954     comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
955     if (!comp)
956         return ERROR_FUNCTION_FAILED;
957
958     list_add_tail( &package->components, &comp->entry );
959
960     /* fill in the data */
961     comp->Component = msi_dup_record_field( row, 1 );
962
963     TRACE("Loading Component %s\n", debugstr_w(comp->Component));
964
965     comp->ComponentId = msi_dup_record_field( row, 2 );
966     comp->Directory = msi_dup_record_field( row, 3 );
967     comp->Attributes = MSI_RecordGetInteger(row,4);
968     comp->Condition = msi_dup_record_field( row, 5 );
969     comp->KeyPath = msi_dup_record_field( row, 6 );
970
971     comp->Installed = INSTALLSTATE_UNKNOWN;
972     comp->Action = INSTALLSTATE_UNKNOWN;
973     comp->ActionRequest = INSTALLSTATE_UNKNOWN;
974
975     comp->assembly = msi_load_assembly( package, comp );
976     return ERROR_SUCCESS;
977 }
978
979 UINT msi_load_all_components( MSIPACKAGE *package )
980 {
981     static const WCHAR query[] = {
982         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
983         '`','C','o','m','p','o','n','e','n','t','`',0};
984     MSIQUERY *view;
985     UINT r;
986
987     if (!list_empty(&package->components))
988         return ERROR_SUCCESS;
989
990     r = MSI_DatabaseOpenViewW( package->db, query, &view );
991     if (r != ERROR_SUCCESS)
992         return r;
993
994     if (!msi_init_assembly_caches( package ))
995     {
996         ERR("can't initialize assembly caches\n");
997         msiobj_release( &view->hdr );
998         return ERROR_FUNCTION_FAILED;
999     }
1000
1001     r = MSI_IterateRecords(view, NULL, load_component, package);
1002     msiobj_release(&view->hdr);
1003     msi_destroy_assembly_caches( package );
1004     return r;
1005 }
1006
1007 typedef struct {
1008     MSIPACKAGE *package;
1009     MSIFEATURE *feature;
1010 } _ilfs;
1011
1012 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1013 {
1014     ComponentList *cl;
1015
1016     cl = msi_alloc( sizeof (*cl) );
1017     if ( !cl )
1018         return ERROR_NOT_ENOUGH_MEMORY;
1019     cl->component = comp;
1020     list_add_tail( &feature->Components, &cl->entry );
1021
1022     return ERROR_SUCCESS;
1023 }
1024
1025 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1026 {
1027     FeatureList *fl;
1028
1029     fl = msi_alloc( sizeof(*fl) );
1030     if ( !fl )
1031         return ERROR_NOT_ENOUGH_MEMORY;
1032     fl->feature = child;
1033     list_add_tail( &parent->Children, &fl->entry );
1034
1035     return ERROR_SUCCESS;
1036 }
1037
1038 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1039 {
1040     _ilfs* ilfs = param;
1041     LPCWSTR component;
1042     MSICOMPONENT *comp;
1043
1044     component = MSI_RecordGetString(row,1);
1045
1046     /* check to see if the component is already loaded */
1047     comp = msi_get_loaded_component( ilfs->package, component );
1048     if (!comp)
1049     {
1050         ERR("unknown component %s\n", debugstr_w(component));
1051         return ERROR_FUNCTION_FAILED;
1052     }
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
3521     /* may be needed because of a bug somewhere else */
3522     msi_create_full_path( link_folder );
3523
3524     filename = msi_dup_record_field( row, 3 );
3525     msi_reduce_to_long_filename( filename );
3526
3527     extension = strchrW( filename, '.' );
3528     if (!extension || strcmpiW( extension, szlnk ))
3529     {
3530         int len = strlenW( filename );
3531         filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3532         memcpy( filename + len, szlnk, sizeof(szlnk) );
3533     }
3534     link_file = msi_build_directory_name( 2, link_folder, filename );
3535     msi_free( filename );
3536
3537     return link_file;
3538 }
3539
3540 WCHAR *msi_build_icon_path( MSIPACKAGE *package, const WCHAR *icon_name )
3541 {
3542     static const WCHAR szMicrosoft[] = {'M','i','c','r','o','s','o','f','t','\\',0};
3543     static const WCHAR szInstaller[] = {'I','n','s','t','a','l','l','e','r','\\',0};
3544     WCHAR *folder, *dest, *path;
3545
3546     if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3547         folder = msi_dup_property( package->db, szWindowsFolder );
3548     else
3549     {
3550         WCHAR *appdata = msi_dup_property( package->db, szAppDataFolder );
3551         folder = msi_build_directory_name( 2, appdata, szMicrosoft );
3552         msi_free( appdata );
3553     }
3554     dest = msi_build_directory_name( 3, folder, szInstaller, package->ProductCode );
3555     msi_create_full_path( dest );
3556     path = msi_build_directory_name( 2, dest, icon_name );
3557     msi_free( folder );
3558     msi_free( dest );
3559     return path;
3560 }
3561
3562 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3563 {
3564     MSIPACKAGE *package = param;
3565     LPWSTR link_file, deformated, path;
3566     LPCWSTR component, target;
3567     MSICOMPONENT *comp;
3568     IShellLinkW *sl = NULL;
3569     IPersistFile *pf = NULL;
3570     HRESULT res;
3571
3572     component = MSI_RecordGetString(row, 4);
3573     comp = msi_get_loaded_component(package, component);
3574     if (!comp)
3575         return ERROR_SUCCESS;
3576
3577     comp->Action = msi_get_component_action( package, comp );
3578     if (comp->Action != INSTALLSTATE_LOCAL)
3579     {
3580         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
3581         return ERROR_SUCCESS;
3582     }
3583     msi_ui_actiondata( package, szCreateShortcuts, row );
3584
3585     res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3586                     &IID_IShellLinkW, (LPVOID *) &sl );
3587
3588     if (FAILED( res ))
3589     {
3590         ERR("CLSID_ShellLink not available\n");
3591         goto err;
3592     }
3593
3594     res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3595     if (FAILED( res ))
3596     {
3597         ERR("QueryInterface(IID_IPersistFile) failed\n");
3598         goto err;
3599     }
3600
3601     target = MSI_RecordGetString(row, 5);
3602     if (strchrW(target, '['))
3603     {
3604         deformat_string(package, target, &deformated);
3605         IShellLinkW_SetPath(sl,deformated);
3606         msi_free(deformated);
3607     }
3608     else
3609     {
3610         FIXME("poorly handled shortcut format, advertised shortcut\n");
3611         IShellLinkW_SetPath(sl,comp->FullKeypath);
3612     }
3613
3614     if (!MSI_RecordIsNull(row,6))
3615     {
3616         LPCWSTR arguments = MSI_RecordGetString(row, 6);
3617         deformat_string(package, arguments, &deformated);
3618         IShellLinkW_SetArguments(sl,deformated);
3619         msi_free(deformated);
3620     }
3621
3622     if (!MSI_RecordIsNull(row,7))
3623     {
3624         LPCWSTR description = MSI_RecordGetString(row, 7);
3625         IShellLinkW_SetDescription(sl, description);
3626     }
3627
3628     if (!MSI_RecordIsNull(row,8))
3629         IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3630
3631     if (!MSI_RecordIsNull(row,9))
3632     {
3633         INT index; 
3634         LPCWSTR icon = MSI_RecordGetString(row, 9);
3635
3636         path = msi_build_icon_path(package, icon);
3637         index = MSI_RecordGetInteger(row,10);
3638
3639         /* no value means 0 */
3640         if (index == MSI_NULL_INTEGER)
3641             index = 0;
3642
3643         IShellLinkW_SetIconLocation(sl, path, index);
3644         msi_free(path);
3645     }
3646
3647     if (!MSI_RecordIsNull(row,11))
3648         IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3649
3650     if (!MSI_RecordIsNull(row,12))
3651     {
3652         LPCWSTR full_path, wkdir = MSI_RecordGetString( row, 12 );
3653         full_path = msi_get_target_folder( package, wkdir );
3654         if (full_path) IShellLinkW_SetWorkingDirectory( sl, full_path );
3655     }
3656     link_file = get_link_file(package, row);
3657
3658     TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3659     IPersistFile_Save(pf, link_file, FALSE);
3660     msi_free(link_file);
3661
3662 err:
3663     if (pf)
3664         IPersistFile_Release( pf );
3665     if (sl)
3666         IShellLinkW_Release( sl );
3667
3668     return ERROR_SUCCESS;
3669 }
3670
3671 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3672 {
3673     static const WCHAR query[] = {
3674         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3675         '`','S','h','o','r','t','c','u','t','`',0};
3676     MSIQUERY *view;
3677     HRESULT res;
3678     UINT rc;
3679
3680     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
3681     if (rc != ERROR_SUCCESS)
3682         return ERROR_SUCCESS;
3683
3684     res = CoInitialize( NULL );
3685
3686     rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3687     msiobj_release(&view->hdr);
3688
3689     if (SUCCEEDED(res)) CoUninitialize();
3690     return rc;
3691 }
3692
3693 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3694 {
3695     MSIPACKAGE *package = param;
3696     LPWSTR link_file;
3697     LPCWSTR component;
3698     MSICOMPONENT *comp;
3699
3700     component = MSI_RecordGetString( row, 4 );
3701     comp = msi_get_loaded_component( package, component );
3702     if (!comp)
3703         return ERROR_SUCCESS;
3704
3705     comp->Action = msi_get_component_action( package, comp );
3706     if (comp->Action != INSTALLSTATE_ABSENT)
3707     {
3708         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
3709         return ERROR_SUCCESS;
3710     }
3711     msi_ui_actiondata( package, szRemoveShortcuts, row );
3712
3713     link_file = get_link_file( package, row );
3714
3715     TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3716     if (!DeleteFileW( link_file ))
3717     {
3718         WARN("Failed to remove shortcut file %u\n", GetLastError());
3719     }
3720     msi_free( link_file );
3721
3722     return ERROR_SUCCESS;
3723 }
3724
3725 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3726 {
3727     static const WCHAR query[] = {
3728         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3729         '`','S','h','o','r','t','c','u','t','`',0};
3730     MSIQUERY *view;
3731     UINT rc;
3732
3733     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3734     if (rc != ERROR_SUCCESS)
3735         return ERROR_SUCCESS;
3736
3737     rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3738     msiobj_release( &view->hdr );
3739     return rc;
3740 }
3741
3742 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3743 {
3744     MSIPACKAGE* package = param;
3745     HANDLE the_file;
3746     LPWSTR FilePath;
3747     LPCWSTR FileName;
3748     CHAR buffer[1024];
3749     DWORD sz;
3750     UINT rc;
3751
3752     FileName = MSI_RecordGetString(row,1);
3753     if (!FileName)
3754     {
3755         ERR("Unable to get FileName\n");
3756         return ERROR_SUCCESS;
3757     }
3758
3759     FilePath = msi_build_icon_path(package, FileName);
3760
3761     TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3762
3763     the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3764                         FILE_ATTRIBUTE_NORMAL, NULL);
3765
3766     if (the_file == INVALID_HANDLE_VALUE)
3767     {
3768         ERR("Unable to create file %s\n",debugstr_w(FilePath));
3769         msi_free(FilePath);
3770         return ERROR_SUCCESS;
3771     }
3772
3773     do 
3774     {
3775         DWORD write;
3776         sz = 1024;
3777         rc = MSI_RecordReadStream(row,2,buffer,&sz);
3778         if (rc != ERROR_SUCCESS)
3779         {
3780             ERR("Failed to get stream\n");
3781             CloseHandle(the_file);  
3782             DeleteFileW(FilePath);
3783             break;
3784         }
3785         WriteFile(the_file,buffer,sz,&write,NULL);
3786     } while (sz == 1024);
3787
3788     msi_free(FilePath);
3789     CloseHandle(the_file);
3790
3791     return ERROR_SUCCESS;
3792 }
3793
3794 static UINT msi_publish_icons(MSIPACKAGE *package)
3795 {
3796     static const WCHAR query[]= {
3797         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3798         '`','I','c','o','n','`',0};
3799     MSIQUERY *view;
3800     UINT r;
3801
3802     r = MSI_DatabaseOpenViewW(package->db, query, &view);
3803     if (r == ERROR_SUCCESS)
3804     {
3805         r = MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3806         msiobj_release(&view->hdr);
3807         if (r != ERROR_SUCCESS)
3808             return r;
3809     }
3810     return ERROR_SUCCESS;
3811 }
3812
3813 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3814 {
3815     UINT r;
3816     HKEY source;
3817     LPWSTR buffer;
3818     MSIMEDIADISK *disk;
3819     MSISOURCELISTINFO *info;
3820
3821     r = RegCreateKeyW(hkey, szSourceList, &source);
3822     if (r != ERROR_SUCCESS)
3823         return r;
3824
3825     RegCloseKey(source);
3826
3827     buffer = strrchrW(package->PackagePath, '\\') + 1;
3828     r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3829                               package->Context, MSICODE_PRODUCT,
3830                               INSTALLPROPERTY_PACKAGENAMEW, buffer);
3831     if (r != ERROR_SUCCESS)
3832         return r;
3833
3834     r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3835                               package->Context, MSICODE_PRODUCT,
3836                               INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3837     if (r != ERROR_SUCCESS)
3838         return r;
3839
3840     r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3841                               package->Context, MSICODE_PRODUCT,
3842                               INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3843     if (r != ERROR_SUCCESS)
3844         return r;
3845
3846     LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3847     {
3848         if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3849             msi_set_last_used_source(package->ProductCode, NULL, info->context,
3850                                      info->options, info->value);
3851         else
3852             MsiSourceListSetInfoW(package->ProductCode, NULL,
3853                                   info->context, info->options,
3854                                   info->property, info->value);
3855     }
3856
3857     LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3858     {
3859         MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3860                                    disk->context, disk->options,
3861                                    disk->disk_id, disk->volume_label, disk->disk_prompt);
3862     }
3863
3864     return ERROR_SUCCESS;
3865 }
3866
3867 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3868 {
3869     MSIHANDLE hdb, suminfo;
3870     WCHAR guids[MAX_PATH];
3871     WCHAR packcode[SQUISH_GUID_SIZE];
3872     LPWSTR buffer;
3873     LPWSTR ptr;
3874     DWORD langid;
3875     DWORD size;
3876     UINT r;
3877
3878     static const WCHAR szARPProductIcon[] =
3879         {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3880     static const WCHAR szAssignment[] =
3881         {'A','s','s','i','g','n','m','e','n','t',0};
3882     static const WCHAR szAdvertiseFlags[] =
3883         {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3884     static const WCHAR szClients[] =
3885         {'C','l','i','e','n','t','s',0};
3886     static const WCHAR szColon[] = {':',0};
3887
3888     buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3889     msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3890     msi_free(buffer);
3891
3892     langid = msi_get_property_int(package->db, szProductLanguage, 0);
3893     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3894
3895     /* FIXME */
3896     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3897
3898     buffer = msi_dup_property(package->db, szARPProductIcon);
3899     if (buffer)
3900     {
3901         LPWSTR path = msi_build_icon_path(package, buffer);
3902         msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3903         msi_free(path);
3904         msi_free(buffer);
3905     }
3906
3907     buffer = msi_dup_property(package->db, szProductVersion);
3908     if (buffer)
3909     {
3910         DWORD verdword = msi_version_str_to_dword(buffer);
3911         msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3912         msi_free(buffer);
3913     }
3914
3915     msi_reg_set_val_dword(hkey, szAssignment, 0);
3916     msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3917     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3918     msi_reg_set_val_str(hkey, szClients, szColon);
3919
3920     hdb = alloc_msihandle(&package->db->hdr);
3921     if (!hdb)
3922         return ERROR_NOT_ENOUGH_MEMORY;
3923
3924     r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3925     MsiCloseHandle(hdb);
3926     if (r != ERROR_SUCCESS)
3927         goto done;
3928
3929     size = MAX_PATH;
3930     r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3931                                    NULL, guids, &size);
3932     if (r != ERROR_SUCCESS)
3933         goto done;
3934
3935     ptr = strchrW(guids, ';');
3936     if (ptr) *ptr = 0;
3937     squash_guid(guids, packcode);
3938     msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3939
3940 done:
3941     MsiCloseHandle(suminfo);
3942     return ERROR_SUCCESS;
3943 }
3944
3945 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3946 {
3947     UINT r;
3948     HKEY hkey;
3949     LPWSTR upgrade;
3950     WCHAR squashed_pc[SQUISH_GUID_SIZE];
3951
3952     upgrade = msi_dup_property(package->db, szUpgradeCode);
3953     if (!upgrade)
3954         return ERROR_SUCCESS;
3955
3956     if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3957         r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3958     else
3959         r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3960
3961     if (r != ERROR_SUCCESS)
3962     {
3963         WARN("failed to open upgrade code key\n");
3964         msi_free(upgrade);
3965         return ERROR_SUCCESS;
3966     }
3967     squash_guid(package->ProductCode, squashed_pc);
3968     msi_reg_set_val_str(hkey, squashed_pc, NULL);
3969     RegCloseKey(hkey);
3970     msi_free(upgrade);
3971     return ERROR_SUCCESS;
3972 }
3973
3974 static BOOL msi_check_publish(MSIPACKAGE *package)
3975 {
3976     MSIFEATURE *feature;
3977
3978     LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3979     {
3980         feature->Action = msi_get_feature_action( package, feature );
3981         if (feature->Action == INSTALLSTATE_LOCAL)
3982             return TRUE;
3983     }
3984
3985     return FALSE;
3986 }
3987
3988 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3989 {
3990     MSIFEATURE *feature;
3991
3992     LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3993     {
3994         feature->Action = msi_get_feature_action( package, feature );
3995         if (feature->Action != INSTALLSTATE_ABSENT)
3996             return FALSE;
3997     }
3998
3999     return TRUE;
4000 }
4001
4002 static UINT msi_publish_patches( MSIPACKAGE *package )
4003 {
4004     static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4005     WCHAR patch_squashed[GUID_SIZE];
4006     HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4007     LONG res;
4008     MSIPATCHINFO *patch;
4009     UINT r;
4010     WCHAR *p, *all_patches = NULL;
4011     DWORD len = 0;
4012
4013     r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4014     if (r != ERROR_SUCCESS)
4015         return ERROR_FUNCTION_FAILED;
4016
4017     res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4018     if (res != ERROR_SUCCESS)
4019     {
4020         r = ERROR_FUNCTION_FAILED;
4021         goto done;
4022     }
4023
4024     r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4025     if (r != ERROR_SUCCESS)
4026         goto done;
4027
4028     LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4029     {
4030         squash_guid( patch->patchcode, patch_squashed );
4031         len += strlenW( patch_squashed ) + 1;
4032     }
4033
4034     p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4035     if (!all_patches)
4036         goto done;
4037
4038     LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4039     {
4040         HKEY patch_key;
4041
4042         squash_guid( patch->patchcode, p );
4043         p += strlenW( p ) + 1;
4044
4045         res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4046                               (const BYTE *)patch->transforms,
4047                               (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4048         if (res != ERROR_SUCCESS)
4049             goto done;
4050
4051         r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4052         if (r != ERROR_SUCCESS)
4053             goto done;
4054
4055         res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ, (const BYTE *)patch->localfile,
4056                               (strlenW( patch->localfile ) + 1) * sizeof(WCHAR) );
4057         RegCloseKey( patch_key );
4058         if (res != ERROR_SUCCESS)
4059             goto done;
4060
4061         if (patch->filename && !CopyFileW( patch->filename, patch->localfile, FALSE ))
4062         {
4063             res = GetLastError();
4064             ERR("Unable to copy patch package %d\n", res);
4065             goto done;
4066         }
4067         res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4068         if (res != ERROR_SUCCESS)
4069             goto done;
4070
4071         res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4072         RegCloseKey( patch_key );
4073         if (res != ERROR_SUCCESS)
4074             goto done;
4075     }
4076
4077     all_patches[len] = 0;
4078     res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4079                           (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4080     if (res != ERROR_SUCCESS)
4081         goto done;
4082
4083     res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4084                           (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4085     if (res != ERROR_SUCCESS)
4086         r = ERROR_FUNCTION_FAILED;
4087
4088 done:
4089     RegCloseKey( product_patches_key );
4090     RegCloseKey( patches_key );
4091     RegCloseKey( product_key );
4092     msi_free( all_patches );
4093     return r;
4094 }
4095
4096 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4097 {
4098     UINT rc;
4099     HKEY hukey = NULL, hudkey = NULL;
4100     MSIRECORD *uirow;
4101
4102     if (!list_empty(&package->patches))
4103     {
4104         rc = msi_publish_patches(package);
4105         if (rc != ERROR_SUCCESS)
4106             goto end;
4107     }
4108
4109     /* FIXME: also need to publish if the product is in advertise mode */
4110     if (!msi_check_publish(package))
4111         return ERROR_SUCCESS;
4112
4113     rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4114                                &hukey, TRUE);
4115     if (rc != ERROR_SUCCESS)
4116         goto end;
4117
4118     rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4119                                        NULL, &hudkey, TRUE);
4120     if (rc != ERROR_SUCCESS)
4121         goto end;
4122
4123     rc = msi_publish_upgrade_code(package);
4124     if (rc != ERROR_SUCCESS)
4125         goto end;
4126
4127     rc = msi_publish_product_properties(package, hukey);
4128     if (rc != ERROR_SUCCESS)
4129         goto end;
4130
4131     rc = msi_publish_sourcelist(package, hukey);
4132     if (rc != ERROR_SUCCESS)
4133         goto end;
4134
4135     rc = msi_publish_icons(package);
4136
4137 end:
4138     uirow = MSI_CreateRecord( 1 );
4139     MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4140     msi_ui_actiondata( package, szPublishProduct, uirow );
4141     msiobj_release( &uirow->hdr );
4142
4143     RegCloseKey(hukey);
4144     RegCloseKey(hudkey);
4145     return rc;
4146 }
4147
4148 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4149 {
4150     WCHAR *filename, *ptr, *folder, *ret;
4151     const WCHAR *dirprop;
4152
4153     filename = msi_dup_record_field( row, 2 );
4154     if (filename && (ptr = strchrW( filename, '|' )))
4155         ptr++;
4156     else
4157         ptr = filename;
4158
4159     dirprop = MSI_RecordGetString( row, 3 );
4160     if (dirprop)
4161     {
4162         folder = strdupW( msi_get_target_folder( package, dirprop ) );
4163         if (!folder) folder = msi_dup_property( package->db, dirprop );
4164     }
4165     else
4166         folder = msi_dup_property( package->db, szWindowsFolder );
4167
4168     if (!folder)
4169     {
4170         ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4171         msi_free( filename );
4172         return NULL;
4173     }
4174
4175     ret = msi_build_directory_name( 2, folder, ptr );
4176
4177     msi_free( filename );
4178     msi_free( folder );
4179     return ret;
4180 }
4181
4182 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4183 {
4184     MSIPACKAGE *package = param;
4185     LPCWSTR component, section, key, value, identifier;
4186     LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4187     MSIRECORD * uirow;
4188     INT action;
4189     MSICOMPONENT *comp;
4190
4191     component = MSI_RecordGetString(row, 8);
4192     comp = msi_get_loaded_component(package,component);
4193     if (!comp)
4194         return ERROR_SUCCESS;
4195
4196     comp->Action = msi_get_component_action( package, comp );
4197     if (comp->Action != INSTALLSTATE_LOCAL)
4198     {
4199         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4200         return ERROR_SUCCESS;
4201     }
4202
4203     identifier = MSI_RecordGetString(row,1); 
4204     section = MSI_RecordGetString(row,4);
4205     key = MSI_RecordGetString(row,5);
4206     value = MSI_RecordGetString(row,6);
4207     action = MSI_RecordGetInteger(row,7);
4208
4209     deformat_string(package,section,&deformated_section);
4210     deformat_string(package,key,&deformated_key);
4211     deformat_string(package,value,&deformated_value);
4212
4213     fullname = get_ini_file_name(package, row);
4214
4215     if (action == 0)
4216     {
4217         TRACE("Adding value %s to section %s in %s\n",
4218                 debugstr_w(deformated_key), debugstr_w(deformated_section),
4219                 debugstr_w(fullname));
4220         WritePrivateProfileStringW(deformated_section, deformated_key,
4221                                    deformated_value, fullname);
4222     }
4223     else if (action == 1)
4224     {
4225         WCHAR returned[10];
4226         GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4227                                  returned, 10, fullname);
4228         if (returned[0] == 0)
4229         {
4230             TRACE("Adding value %s to section %s in %s\n",
4231                     debugstr_w(deformated_key), debugstr_w(deformated_section),
4232                     debugstr_w(fullname));
4233
4234             WritePrivateProfileStringW(deformated_section, deformated_key,
4235                                        deformated_value, fullname);
4236         }
4237     }
4238     else if (action == 3)
4239         FIXME("Append to existing section not yet implemented\n");
4240
4241     uirow = MSI_CreateRecord(4);
4242     MSI_RecordSetStringW(uirow,1,identifier);
4243     MSI_RecordSetStringW(uirow,2,deformated_section);
4244     MSI_RecordSetStringW(uirow,3,deformated_key);
4245     MSI_RecordSetStringW(uirow,4,deformated_value);
4246     msi_ui_actiondata( package, szWriteIniValues, uirow );
4247     msiobj_release( &uirow->hdr );
4248
4249     msi_free(fullname);
4250     msi_free(deformated_key);
4251     msi_free(deformated_value);
4252     msi_free(deformated_section);
4253     return ERROR_SUCCESS;
4254 }
4255
4256 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4257 {
4258     static const WCHAR query[] = {
4259         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4260         '`','I','n','i','F','i','l','e','`',0};
4261     MSIQUERY *view;
4262     UINT rc;
4263
4264     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4265     if (rc != ERROR_SUCCESS)
4266         return ERROR_SUCCESS;
4267
4268     rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4269     msiobj_release(&view->hdr);
4270     return rc;
4271 }
4272
4273 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4274 {
4275     MSIPACKAGE *package = param;
4276     LPCWSTR component, section, key, value, identifier;
4277     LPWSTR deformated_section, deformated_key, deformated_value, filename;
4278     MSICOMPONENT *comp;
4279     MSIRECORD *uirow;
4280     INT action;
4281
4282     component = MSI_RecordGetString( row, 8 );
4283     comp = msi_get_loaded_component( package, component );
4284     if (!comp)
4285         return ERROR_SUCCESS;
4286
4287     comp->Action = msi_get_component_action( package, comp );
4288     if (comp->Action != INSTALLSTATE_ABSENT)
4289     {
4290         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
4291         return ERROR_SUCCESS;
4292     }
4293
4294     identifier = MSI_RecordGetString( row, 1 );
4295     section = MSI_RecordGetString( row, 4 );
4296     key = MSI_RecordGetString( row, 5 );
4297     value = MSI_RecordGetString( row, 6 );
4298     action = MSI_RecordGetInteger( row, 7 );
4299
4300     deformat_string( package, section, &deformated_section );
4301     deformat_string( package, key, &deformated_key );
4302     deformat_string( package, value, &deformated_value );
4303
4304     if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4305     {
4306         filename = get_ini_file_name( package, row );
4307
4308         TRACE("Removing key %s from section %s in %s\n",
4309                debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4310
4311         if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4312         {
4313             WARN("Unable to remove key %u\n", GetLastError());
4314         }
4315         msi_free( filename );
4316     }
4317     else
4318         FIXME("Unsupported action %d\n", action);
4319
4320
4321     uirow = MSI_CreateRecord( 4 );
4322     MSI_RecordSetStringW( uirow, 1, identifier );
4323     MSI_RecordSetStringW( uirow, 2, deformated_section );
4324     MSI_RecordSetStringW( uirow, 3, deformated_key );
4325     MSI_RecordSetStringW( uirow, 4, deformated_value );
4326     msi_ui_actiondata( package, szRemoveIniValues, uirow );
4327     msiobj_release( &uirow->hdr );
4328
4329     msi_free( deformated_key );
4330     msi_free( deformated_value );
4331     msi_free( deformated_section );
4332     return ERROR_SUCCESS;
4333 }
4334
4335 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4336 {
4337     MSIPACKAGE *package = param;
4338     LPCWSTR component, section, key, value, identifier;
4339     LPWSTR deformated_section, deformated_key, deformated_value, filename;
4340     MSICOMPONENT *comp;
4341     MSIRECORD *uirow;
4342     INT action;
4343
4344     component = MSI_RecordGetString( row, 8 );
4345     comp = msi_get_loaded_component( package, component );
4346     if (!comp)
4347         return ERROR_SUCCESS;
4348
4349     comp->Action = msi_get_component_action( package, comp );
4350     if (comp->Action != INSTALLSTATE_LOCAL)
4351     {
4352         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
4353         return ERROR_SUCCESS;
4354     }
4355
4356     identifier = MSI_RecordGetString( row, 1 );
4357     section = MSI_RecordGetString( row, 4 );
4358     key = MSI_RecordGetString( row, 5 );
4359     value = MSI_RecordGetString( row, 6 );
4360     action = MSI_RecordGetInteger( row, 7 );
4361
4362     deformat_string( package, section, &deformated_section );
4363     deformat_string( package, key, &deformated_key );
4364     deformat_string( package, value, &deformated_value );
4365
4366     if (action == msidbIniFileActionRemoveLine)
4367     {
4368         filename = get_ini_file_name( package, row );
4369
4370         TRACE("Removing key %s from section %s in %s\n",
4371                debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4372
4373         if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4374         {
4375             WARN("Unable to remove key %u\n", GetLastError());
4376         }
4377         msi_free( filename );
4378     }
4379     else
4380         FIXME("Unsupported action %d\n", action);
4381
4382     uirow = MSI_CreateRecord( 4 );
4383     MSI_RecordSetStringW( uirow, 1, identifier );
4384     MSI_RecordSetStringW( uirow, 2, deformated_section );
4385     MSI_RecordSetStringW( uirow, 3, deformated_key );
4386     MSI_RecordSetStringW( uirow, 4, deformated_value );
4387     msi_ui_actiondata( package, szRemoveIniValues, uirow );
4388     msiobj_release( &uirow->hdr );
4389
4390     msi_free( deformated_key );
4391     msi_free( deformated_value );
4392     msi_free( deformated_section );
4393     return ERROR_SUCCESS;
4394 }
4395
4396 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4397 {
4398     static const WCHAR query[] = {
4399         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4400         '`','I','n','i','F','i','l','e','`',0};
4401     static const WCHAR remove_query[] = {
4402         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4403         '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4404     MSIQUERY *view;
4405     UINT rc;
4406
4407     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4408     if (rc == ERROR_SUCCESS)
4409     {
4410         rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4411         msiobj_release( &view->hdr );
4412         if (rc != ERROR_SUCCESS)
4413             return rc;
4414     }
4415     rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4416     if (rc == ERROR_SUCCESS)
4417     {
4418         rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4419         msiobj_release( &view->hdr );
4420         if (rc != ERROR_SUCCESS)
4421             return rc;
4422     }
4423     return ERROR_SUCCESS;
4424 }
4425
4426 static void register_dll( const WCHAR *dll, BOOL unregister )
4427 {
4428     HMODULE hmod;
4429
4430     hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4431     if (hmod)
4432     {
4433         HRESULT (WINAPI *func_ptr)( void );
4434         const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4435
4436         func_ptr = (void *)GetProcAddress( hmod, func );
4437         if (func_ptr)
4438         {
4439             HRESULT hr = func_ptr();
4440             if (FAILED( hr ))
4441                 WARN("failed to register dll 0x%08x\n", hr);
4442         }
4443         else
4444             WARN("entry point %s not found\n", func);
4445         FreeLibrary( hmod );
4446         return;
4447     }
4448     WARN("failed to load library %u\n", GetLastError());
4449 }
4450
4451 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4452 {
4453     MSIPACKAGE *package = param;
4454     LPCWSTR filename;
4455     MSIFILE *file;
4456     MSIRECORD *uirow;
4457
4458     filename = MSI_RecordGetString(row,1);
4459     file = msi_get_loaded_file( package, filename );
4460     if (!file)
4461     {
4462         WARN("unable to find file %s\n", debugstr_w(filename));
4463         return ERROR_SUCCESS;
4464     }
4465     file->Component->Action = msi_get_component_action( package, file->Component );
4466     if (file->Component->Action != INSTALLSTATE_LOCAL)
4467     {
4468         TRACE("component not scheduled for installation %s\n", debugstr_w(file->Component->Component));
4469         return ERROR_SUCCESS;
4470     }
4471
4472     TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4473     register_dll( file->TargetPath, FALSE );
4474
4475     uirow = MSI_CreateRecord( 2 );
4476     MSI_RecordSetStringW( uirow, 1, filename );
4477     MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4478     msi_ui_actiondata( package, szSelfRegModules, uirow );
4479     msiobj_release( &uirow->hdr );
4480
4481     return ERROR_SUCCESS;
4482 }
4483
4484 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4485 {
4486     static const WCHAR query[] = {
4487         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4488         '`','S','e','l','f','R','e','g','`',0};
4489     MSIQUERY *view;
4490     UINT rc;
4491
4492     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
4493     if (rc != ERROR_SUCCESS)
4494         return ERROR_SUCCESS;
4495
4496     rc = MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4497     msiobj_release(&view->hdr);
4498     return rc;
4499 }
4500
4501 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4502 {
4503     MSIPACKAGE *package = param;
4504     LPCWSTR filename;
4505     MSIFILE *file;
4506     MSIRECORD *uirow;
4507
4508     filename = MSI_RecordGetString( row, 1 );
4509     file = msi_get_loaded_file( package, filename );
4510     if (!file)
4511     {
4512         WARN("unable to find file %s\n", debugstr_w(filename));
4513         return ERROR_SUCCESS;
4514     }
4515     file->Component->Action = msi_get_component_action( package, file->Component );
4516     if (file->Component->Action != INSTALLSTATE_ABSENT)
4517     {
4518         TRACE("component not scheduled for removal %s\n", debugstr_w(file->Component->Component));
4519         return ERROR_SUCCESS;
4520     }
4521
4522     TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4523     register_dll( file->TargetPath, TRUE );
4524
4525     uirow = MSI_CreateRecord( 2 );
4526     MSI_RecordSetStringW( uirow, 1, filename );
4527     MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4528     msi_ui_actiondata( package, szSelfUnregModules, uirow );
4529     msiobj_release( &uirow->hdr );
4530
4531     return ERROR_SUCCESS;
4532 }
4533
4534 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4535 {
4536     static const WCHAR query[] = {
4537         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4538         '`','S','e','l','f','R','e','g','`',0};
4539     MSIQUERY *view;
4540     UINT rc;
4541
4542     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4543     if (rc != ERROR_SUCCESS)
4544         return ERROR_SUCCESS;
4545
4546     rc = MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4547     msiobj_release( &view->hdr );
4548     return rc;
4549 }
4550
4551 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4552 {
4553     MSIFEATURE *feature;
4554     UINT rc;
4555     HKEY hkey = NULL, userdata = NULL;
4556
4557     if (!msi_check_publish(package))
4558         return ERROR_SUCCESS;
4559
4560     rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4561                                 &hkey, TRUE);
4562     if (rc != ERROR_SUCCESS)
4563         goto end;
4564
4565     rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4566                                         &userdata, TRUE);
4567     if (rc != ERROR_SUCCESS)
4568         goto end;
4569
4570     /* here the guids are base 85 encoded */
4571     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4572     {
4573         ComponentList *cl;
4574         LPWSTR data = NULL;
4575         GUID clsid;
4576         INT size;
4577         BOOL absent = FALSE;
4578         MSIRECORD *uirow;
4579
4580         if (feature->Action != INSTALLSTATE_LOCAL &&
4581             feature->Action != INSTALLSTATE_SOURCE &&
4582             feature->Action != INSTALLSTATE_ADVERTISED) absent = TRUE;
4583
4584         size = 1;
4585         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4586         {
4587             size += 21;
4588         }
4589         if (feature->Feature_Parent)
4590             size += strlenW( feature->Feature_Parent )+2;
4591
4592         data = msi_alloc(size * sizeof(WCHAR));
4593
4594         data[0] = 0;
4595         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4596         {
4597             MSICOMPONENT* component = cl->component;
4598             WCHAR buf[21];
4599
4600             buf[0] = 0;
4601             if (component->ComponentId)
4602             {
4603                 TRACE("From %s\n",debugstr_w(component->ComponentId));
4604                 CLSIDFromString(component->ComponentId, &clsid);
4605                 encode_base85_guid(&clsid,buf);
4606                 TRACE("to %s\n",debugstr_w(buf));
4607                 strcatW(data,buf);
4608             }
4609         }
4610
4611         if (feature->Feature_Parent)
4612         {
4613             static const WCHAR sep[] = {'\2',0};
4614             strcatW(data,sep);
4615             strcatW(data,feature->Feature_Parent);
4616         }
4617
4618         msi_reg_set_val_str( userdata, feature->Feature, data );
4619         msi_free(data);
4620
4621         size = 0;
4622         if (feature->Feature_Parent)
4623             size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4624         if (!absent)
4625         {
4626             size += sizeof(WCHAR);
4627             RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4628                            (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4629         }
4630         else
4631         {
4632             size += 2*sizeof(WCHAR);
4633             data = msi_alloc(size);
4634             data[0] = 0x6;
4635             data[1] = 0;
4636             if (feature->Feature_Parent)
4637                 strcpyW( &data[1], feature->Feature_Parent );
4638             RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4639                        (LPBYTE)data,size);
4640             msi_free(data);
4641         }
4642
4643         /* the UI chunk */
4644         uirow = MSI_CreateRecord( 1 );
4645         MSI_RecordSetStringW( uirow, 1, feature->Feature );
4646         msi_ui_actiondata( package, szPublishFeatures, uirow );
4647         msiobj_release( &uirow->hdr );
4648         /* FIXME: call msi_ui_progress? */
4649     }
4650
4651 end:
4652     RegCloseKey(hkey);
4653     RegCloseKey(userdata);
4654     return rc;
4655 }
4656
4657 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4658 {
4659     UINT r;
4660     HKEY hkey;
4661     MSIRECORD *uirow;
4662
4663     TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4664
4665     r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4666                                &hkey, FALSE);
4667     if (r == ERROR_SUCCESS)
4668     {
4669         RegDeleteValueW(hkey, feature->Feature);
4670         RegCloseKey(hkey);
4671     }
4672
4673     r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4674                                        &hkey, FALSE);
4675     if (r == ERROR_SUCCESS)
4676     {
4677         RegDeleteValueW(hkey, feature->Feature);
4678         RegCloseKey(hkey);
4679     }
4680
4681     uirow = MSI_CreateRecord( 1 );
4682     MSI_RecordSetStringW( uirow, 1, feature->Feature );
4683     msi_ui_actiondata( package, szUnpublishFeatures, uirow );
4684     msiobj_release( &uirow->hdr );
4685
4686     return ERROR_SUCCESS;
4687 }
4688
4689 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4690 {
4691     MSIFEATURE *feature;
4692
4693     if (!msi_check_unpublish(package))
4694         return ERROR_SUCCESS;
4695
4696     LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4697     {
4698         msi_unpublish_feature(package, feature);
4699     }
4700
4701     return ERROR_SUCCESS;
4702 }
4703
4704 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4705 {
4706     SYSTEMTIME systime;
4707     DWORD size, langid;
4708     WCHAR date[9], *val, *buffer;
4709     const WCHAR *prop, *key;
4710
4711     static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4712     static const WCHAR modpath_fmt[] =
4713         {'M','s','i','E','x','e','c','.','e','x','e',' ',
4714          '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4715     static const WCHAR szModifyPath[] =
4716         {'M','o','d','i','f','y','P','a','t','h',0};
4717     static const WCHAR szUninstallString[] =
4718         {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4719     static const WCHAR szEstimatedSize[] =
4720         {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4721     static const WCHAR szDisplayVersion[] =
4722         {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4723     static const WCHAR szInstallSource[] =
4724         {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4725     static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4726         {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4727     static const WCHAR szAuthorizedCDFPrefix[] =
4728         {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4729     static const WCHAR szARPCONTACT[] =
4730         {'A','R','P','C','O','N','T','A','C','T',0};
4731     static const WCHAR szContact[] =
4732         {'C','o','n','t','a','c','t',0};
4733     static const WCHAR szARPCOMMENTS[] =
4734         {'A','R','P','C','O','M','M','E','N','T','S',0};
4735     static const WCHAR szComments[] =
4736         {'C','o','m','m','e','n','t','s',0};
4737     static const WCHAR szProductName[] =
4738         {'P','r','o','d','u','c','t','N','a','m','e',0};
4739     static const WCHAR szDisplayName[] =
4740         {'D','i','s','p','l','a','y','N','a','m','e',0};
4741     static const WCHAR szARPHELPLINK[] =
4742         {'A','R','P','H','E','L','P','L','I','N','K',0};
4743     static const WCHAR szHelpLink[] =
4744         {'H','e','l','p','L','i','n','k',0};
4745     static const WCHAR szARPHELPTELEPHONE[] =
4746         {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4747     static const WCHAR szHelpTelephone[] =
4748         {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4749     static const WCHAR szARPINSTALLLOCATION[] =
4750         {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4751     static const WCHAR szInstallLocation[] =
4752         {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4753     static const WCHAR szManufacturer[] =
4754         {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4755     static const WCHAR szPublisher[] =
4756         {'P','u','b','l','i','s','h','e','r',0};
4757     static const WCHAR szARPREADME[] =
4758         {'A','R','P','R','E','A','D','M','E',0};
4759     static const WCHAR szReadme[] =
4760         {'R','e','a','d','M','e',0};
4761     static const WCHAR szARPSIZE[] =
4762         {'A','R','P','S','I','Z','E',0};
4763     static const WCHAR szSize[] =
4764         {'S','i','z','e',0};
4765     static const WCHAR szARPURLINFOABOUT[] =
4766         {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4767     static const WCHAR szURLInfoAbout[] =
4768         {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4769     static const WCHAR szARPURLUPDATEINFO[] =
4770         {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4771     static const WCHAR szURLUpdateInfo[] =
4772         {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4773     static const WCHAR szARPSYSTEMCOMPONENT[] =
4774         {'A','R','P','S','Y','S','T','E','M','C','O','M','P','O','N','E','N','T',0};
4775     static const WCHAR szSystemComponent[] =
4776         {'S','y','s','t','e','m','C','o','m','p','o','n','e','n','t',0};
4777
4778     static const WCHAR *propval[] = {
4779         szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4780         szARPCONTACT,             szContact,
4781         szARPCOMMENTS,            szComments,
4782         szProductName,            szDisplayName,
4783         szARPHELPLINK,            szHelpLink,
4784         szARPHELPTELEPHONE,       szHelpTelephone,
4785         szARPINSTALLLOCATION,     szInstallLocation,
4786         szSourceDir,              szInstallSource,
4787         szManufacturer,           szPublisher,
4788         szARPREADME,              szReadme,
4789         szARPSIZE,                szSize,
4790         szARPURLINFOABOUT,        szURLInfoAbout,
4791         szARPURLUPDATEINFO,       szURLUpdateInfo,
4792         NULL
4793     };
4794     const WCHAR **p = propval;
4795
4796     while (*p)
4797     {
4798         prop = *p++;
4799         key = *p++;
4800         val = msi_dup_property(package->db, prop);
4801         msi_reg_set_val_str(hkey, key, val);
4802         msi_free(val);
4803     }
4804
4805     msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4806     if (msi_get_property_int( package->db, szARPSYSTEMCOMPONENT, 0 ))
4807     {
4808         msi_reg_set_val_dword( hkey, szSystemComponent, 1 );
4809     }
4810     size = deformat_string(package, modpath_fmt, &buffer);
4811     RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4812     RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4813     msi_free(buffer);
4814
4815     /* FIXME: Write real Estimated Size when we have it */
4816     msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4817
4818     GetLocalTime(&systime);
4819     sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4820     msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4821
4822     langid = msi_get_property_int(package->db, szProductLanguage, 0);
4823     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4824
4825     buffer = msi_dup_property(package->db, szProductVersion);
4826     msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4827     if (buffer)
4828     {
4829         DWORD verdword = msi_version_str_to_dword(buffer);
4830
4831         msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4832         msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4833         msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4834         msi_free(buffer);
4835     }
4836
4837     return ERROR_SUCCESS;
4838 }
4839
4840 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4841 {
4842     WCHAR squashed_pc[SQUISH_GUID_SIZE];
4843     MSIRECORD *uirow;
4844     LPWSTR upgrade_code;
4845     HKEY hkey, props, upgrade_key;
4846     UINT rc;
4847
4848     /* FIXME: also need to publish if the product is in advertise mode */
4849     if (!msi_check_publish(package))
4850         return ERROR_SUCCESS;
4851
4852     rc = MSIREG_OpenUninstallKey(package->ProductCode, package->platform, &hkey, TRUE);
4853     if (rc != ERROR_SUCCESS)
4854         return rc;
4855
4856     rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context, NULL, &props, TRUE);
4857     if (rc != ERROR_SUCCESS)
4858         goto done;
4859
4860     if (!msi_get_property_int( package->db, szInstalled, 0 ))
4861     {
4862         msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->localfile );
4863         if (!CopyFileW( package->PackagePath, package->localfile, FALSE ))
4864         {
4865             rc = GetLastError();
4866             ERR("Unable to copy package %u\n", rc);
4867             goto done;
4868         }
4869     }
4870     msi_free( package->localfile );
4871     package->localfile = NULL;
4872
4873     rc = msi_publish_install_properties(package, hkey);
4874     if (rc != ERROR_SUCCESS)
4875         goto done;
4876
4877     rc = msi_publish_install_properties(package, props);
4878     if (rc != ERROR_SUCCESS)
4879         goto done;
4880
4881     upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4882     if (upgrade_code)
4883     {
4884         rc = MSIREG_OpenUpgradeCodesKey( upgrade_code, &upgrade_key, TRUE );
4885         if (rc == ERROR_SUCCESS)
4886         {
4887             squash_guid( package->ProductCode, squashed_pc );
4888             msi_reg_set_val_str( upgrade_key, squashed_pc, NULL );
4889             RegCloseKey( upgrade_key );
4890         }
4891         msi_free( upgrade_code );
4892     }
4893
4894 done:
4895     uirow = MSI_CreateRecord( 1 );
4896     MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4897     msi_ui_actiondata( package, szRegisterProduct, uirow );
4898     msiobj_release( &uirow->hdr );
4899
4900     RegCloseKey(hkey);
4901     return ERROR_SUCCESS;
4902 }
4903
4904 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4905 {
4906     return execute_script(package,INSTALL_SCRIPT);
4907 }
4908
4909 static UINT msi_unpublish_product( MSIPACKAGE *package, const WCHAR *remove )
4910 {
4911     static const WCHAR szUpgradeCode[] = {'U','p','g','r','a','d','e','C','o','d','e',0};
4912     WCHAR *upgrade, **features;
4913     BOOL full_uninstall = TRUE;
4914     MSIFEATURE *feature;
4915     MSIPATCHINFO *patch;
4916     UINT i;
4917
4918     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4919     {
4920         if (feature->Action == INSTALLSTATE_LOCAL) full_uninstall = FALSE;
4921     }
4922     features = msi_split_string( remove, ',' );
4923     for (i = 0; features && features[i]; i++)
4924     {
4925         if (!strcmpW( features[i], szAll )) full_uninstall = TRUE;
4926     }
4927     msi_free(features);
4928
4929     if (!full_uninstall)
4930         return ERROR_SUCCESS;
4931
4932     MSIREG_DeleteProductKey(package->ProductCode);
4933     MSIREG_DeleteUserDataProductKey(package->ProductCode);
4934     MSIREG_DeleteUninstallKey(package->ProductCode, package->platform);
4935
4936     MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4937     MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4938     MSIREG_DeleteUserProductKey(package->ProductCode);
4939     MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4940
4941     upgrade = msi_dup_property(package->db, szUpgradeCode);
4942     if (upgrade)
4943     {
4944         MSIREG_DeleteUserUpgradeCodesKey(upgrade);
4945         MSIREG_DeleteClassesUpgradeCodesKey(upgrade);
4946         msi_free(upgrade);
4947     }
4948
4949     LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
4950     {
4951         MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
4952         /* FIXME: remove local patch package if this is the last product */
4953     }
4954
4955     TRACE("removing local package %s\n", debugstr_w(package->localfile));
4956     DeleteFileW( package->localfile );
4957     msi_free( package->localfile );
4958     package->localfile = NULL;
4959
4960     return ERROR_SUCCESS;
4961 }
4962
4963 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
4964 {
4965     UINT rc;
4966     WCHAR *remove;
4967
4968     /* turn off scheduling */
4969     package->script->CurrentlyScripting= FALSE;
4970
4971     /* first do the same as an InstallExecute */
4972     rc = ACTION_InstallExecute(package);
4973     if (rc != ERROR_SUCCESS)
4974         return rc;
4975
4976     /* then handle Commit Actions */
4977     rc = execute_script(package,COMMIT_SCRIPT);
4978     if (rc != ERROR_SUCCESS)
4979         return rc;
4980
4981     remove = msi_dup_property(package->db, szRemove);
4982     rc = msi_unpublish_product(package, remove);
4983     msi_free(remove);
4984     return rc;
4985 }
4986
4987 UINT ACTION_ForceReboot(MSIPACKAGE *package)
4988 {
4989     static const WCHAR RunOnce[] = {
4990     'S','o','f','t','w','a','r','e','\\',
4991     'M','i','c','r','o','s','o','f','t','\\',
4992     'W','i','n','d','o','w','s','\\',
4993     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
4994     'R','u','n','O','n','c','e',0};
4995     static const WCHAR InstallRunOnce[] = {
4996     'S','o','f','t','w','a','r','e','\\',
4997     'M','i','c','r','o','s','o','f','t','\\',
4998     'W','i','n','d','o','w','s','\\',
4999     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5000     'I','n','s','t','a','l','l','e','r','\\',
5001     'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5002
5003     static const WCHAR msiexec_fmt[] = {
5004     '%','s',
5005     '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5006     '\"','%','s','\"',0};
5007     static const WCHAR install_fmt[] = {
5008     '/','I',' ','\"','%','s','\"',' ',
5009     'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5010     'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5011     WCHAR buffer[256], sysdir[MAX_PATH];
5012     HKEY hkey;
5013     WCHAR squished_pc[100];
5014
5015     squash_guid(package->ProductCode,squished_pc);
5016
5017     GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5018     RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5019     snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5020      squished_pc);
5021
5022     msi_reg_set_val_str( hkey, squished_pc, buffer );
5023     RegCloseKey(hkey);
5024
5025     TRACE("Reboot command %s\n",debugstr_w(buffer));
5026
5027     RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5028     sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5029
5030     msi_reg_set_val_str( hkey, squished_pc, buffer );
5031     RegCloseKey(hkey);
5032
5033     return ERROR_INSTALL_SUSPEND;
5034 }
5035
5036 WCHAR *msi_build_error_string( MSIPACKAGE *package, UINT error, DWORD count, ... )
5037 {
5038     static const WCHAR query[] =
5039         {'S','E','L','E','C','T',' ','`','M','e','s','s','a','g','e','`',' ',
5040          'F','R','O','M',' ','`','E','r','r','o','r','`',' ','W','H','E','R','E',' ',
5041          '`','E','r','r','o','r','`',' ','=',' ','%','i',0};
5042     MSIRECORD *rec, *row;
5043     DWORD i, size = 0;
5044     va_list va;
5045     const WCHAR *str;
5046     WCHAR *data;
5047
5048     if (!(row = MSI_QueryGetRecord( package->db, query, error ))) return 0;
5049
5050     rec = MSI_CreateRecord( count + 2 );
5051     str = MSI_RecordGetString( row, 1 );
5052     MSI_RecordSetStringW( rec, 0, str );
5053     msiobj_release( &row->hdr );
5054     MSI_RecordSetInteger( rec, 1, error );
5055
5056     va_start( va, count );
5057     for (i = 0; i < count; i++)
5058     {
5059         str = va_arg( va, const WCHAR *);
5060         MSI_RecordSetStringW( rec, i + 2, str );
5061     }
5062     va_end( va );
5063
5064     MSI_FormatRecordW( package, rec, NULL, &size );
5065     size++;
5066     data = msi_alloc( size * sizeof(WCHAR) );
5067     if (size > 1) MSI_FormatRecordW( package, rec, data, &size );
5068     else data[0] = 0;
5069     msiobj_release( &rec->hdr );
5070     return data;
5071 }
5072
5073 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5074 {
5075     DWORD attrib;
5076     UINT rc;
5077
5078     /*
5079      * We are currently doing what should be done here in the top level Install
5080      * however for Administrative and uninstalls this step will be needed
5081      */
5082     if (!package->PackagePath)
5083         return ERROR_SUCCESS;
5084
5085     msi_set_sourcedir_props(package, TRUE);
5086
5087     attrib = GetFileAttributesW(package->db->path);
5088     if (attrib == INVALID_FILE_ATTRIBUTES)
5089     {
5090         LPWSTR prompt;
5091         LPWSTR msg;
5092         DWORD size = 0;
5093
5094         rc = MsiSourceListGetInfoW(package->ProductCode, NULL, 
5095                 package->Context, MSICODE_PRODUCT,
5096                 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5097         if (rc == ERROR_MORE_DATA)
5098         {
5099             prompt = msi_alloc(size * sizeof(WCHAR));
5100             MsiSourceListGetInfoW(package->ProductCode, NULL, 
5101                     package->Context, MSICODE_PRODUCT,
5102                     INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5103         }
5104         else
5105             prompt = strdupW(package->db->path);
5106
5107         msg = msi_build_error_string(package, 1302, 1, prompt);
5108         while(attrib == INVALID_FILE_ATTRIBUTES)
5109         {
5110             rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5111             if (rc == IDCANCEL)
5112             {
5113                 rc = ERROR_INSTALL_USEREXIT;
5114                 break;
5115             }
5116             attrib = GetFileAttributesW(package->db->path);
5117         }
5118         msi_free(prompt);
5119         rc = ERROR_SUCCESS;
5120     }
5121     else
5122         return ERROR_SUCCESS;
5123
5124     return rc;
5125 }
5126
5127 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5128 {
5129     HKEY hkey = 0;
5130     LPWSTR buffer, productid = NULL;
5131     UINT i, rc = ERROR_SUCCESS;
5132     MSIRECORD *uirow;
5133
5134     static const WCHAR szPropKeys[][80] = 
5135     {
5136         {'P','r','o','d','u','c','t','I','D',0},
5137         {'U','S','E','R','N','A','M','E',0},
5138         {'C','O','M','P','A','N','Y','N','A','M','E',0},
5139         {0},
5140     };
5141
5142     static const WCHAR szRegKeys[][80] = 
5143     {
5144         {'P','r','o','d','u','c','t','I','D',0},
5145         {'R','e','g','O','w','n','e','r',0},
5146         {'R','e','g','C','o','m','p','a','n','y',0},
5147         {0},
5148     };
5149
5150     if (msi_check_unpublish(package))
5151     {
5152         MSIREG_DeleteUserDataProductKey(package->ProductCode);
5153         goto end;
5154     }
5155
5156     productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5157     if (!productid)
5158         goto end;
5159
5160     rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5161                                  NULL, &hkey, TRUE);
5162     if (rc != ERROR_SUCCESS)
5163         goto end;
5164
5165     for( i = 0; szPropKeys[i][0]; i++ )
5166     {
5167         buffer = msi_dup_property( package->db, szPropKeys[i] );
5168         msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5169         msi_free( buffer );
5170     }
5171
5172 end:
5173     uirow = MSI_CreateRecord( 1 );
5174     MSI_RecordSetStringW( uirow, 1, productid );
5175     msi_ui_actiondata( package, szRegisterUser, uirow );
5176     msiobj_release( &uirow->hdr );
5177
5178     msi_free(productid);
5179     RegCloseKey(hkey);
5180     return rc;
5181 }
5182
5183
5184 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5185 {
5186     UINT rc;
5187
5188     package->script->InWhatSequence |= SEQUENCE_EXEC;
5189     rc = ACTION_ProcessExecSequence(package,FALSE);
5190     return rc;
5191 }
5192
5193 WCHAR *msi_create_component_advertise_string( MSIPACKAGE *package, MSICOMPONENT *component, const WCHAR *feature )
5194 {
5195     static const WCHAR fmt[] = {'%','s','%','s','%','c','%','s',0};
5196     WCHAR productid_85[21], component_85[21], *ret;
5197     GUID clsid;
5198     DWORD sz;
5199
5200     /* > is used if there is a component GUID and < if not.  */
5201
5202     productid_85[0] = 0;
5203     component_85[0] = 0;
5204     CLSIDFromString( package->ProductCode, &clsid );
5205
5206     encode_base85_guid( &clsid, productid_85 );
5207     if (component)
5208     {
5209         CLSIDFromString( component->ComponentId, &clsid );
5210         encode_base85_guid( &clsid, component_85 );
5211     }
5212
5213     TRACE("product=%s feature=%s component=%s\n", debugstr_w(productid_85), debugstr_w(feature),
5214           debugstr_w(component_85));
5215
5216     sz = 20 + strlenW( feature ) + 20 + 3;
5217     ret = msi_alloc_zero( sz * sizeof(WCHAR) );
5218     if (ret) sprintfW( ret, fmt, productid_85, feature, component ? '>' : '<', component_85 );
5219     return ret;
5220 }
5221
5222 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5223 {
5224     MSIPACKAGE *package = param;
5225     LPCWSTR compgroupid, component, feature, qualifier, text;
5226     LPWSTR advertise = NULL, output = NULL, existing = NULL, p, q;
5227     HKEY hkey = NULL;
5228     UINT rc;
5229     MSICOMPONENT *comp;
5230     MSIFEATURE *feat;
5231     DWORD sz;
5232     MSIRECORD *uirow;
5233     int len;
5234
5235     feature = MSI_RecordGetString(rec, 5);
5236     feat = msi_get_loaded_feature(package, feature);
5237     if (!feat)
5238         return ERROR_SUCCESS;
5239
5240     feat->Action = msi_get_feature_action( package, feat );
5241     if (feat->Action != INSTALLSTATE_LOCAL &&
5242         feat->Action != INSTALLSTATE_SOURCE &&
5243         feat->Action != INSTALLSTATE_ADVERTISED)
5244     {
5245         TRACE("feature not scheduled for installation %s\n", debugstr_w(feature));
5246         return ERROR_SUCCESS;
5247     }
5248
5249     component = MSI_RecordGetString(rec, 3);
5250     comp = msi_get_loaded_component(package, component);
5251     if (!comp)
5252         return ERROR_SUCCESS;
5253
5254     compgroupid = MSI_RecordGetString(rec,1);
5255     qualifier = MSI_RecordGetString(rec,2);
5256
5257     rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5258     if (rc != ERROR_SUCCESS)
5259         goto end;
5260
5261     advertise = msi_create_component_advertise_string( package, comp, feature );
5262     text = MSI_RecordGetString( rec, 4 );
5263     if (text)
5264     {
5265         p = msi_alloc( (strlenW( advertise ) + strlenW( text ) + 1) * sizeof(WCHAR) );
5266         strcpyW( p, advertise );
5267         strcatW( p, text );
5268         msi_free( advertise );
5269         advertise = p;
5270     }
5271     existing = msi_reg_get_val_str( hkey, qualifier );
5272
5273     sz = strlenW( advertise ) + 1;
5274     if (existing)
5275     {
5276         for (p = existing; *p; p += len)
5277         {
5278             len = strlenW( p ) + 1;
5279             if (strcmpW( advertise, p )) sz += len;
5280         }
5281     }
5282     if (!(output = msi_alloc( (sz + 1) * sizeof(WCHAR) )))
5283     {
5284         rc = ERROR_OUTOFMEMORY;
5285         goto end;
5286     }
5287     q = output;
5288     if (existing)
5289     {
5290         for (p = existing; *p; p += len)
5291         {
5292             len = strlenW( p ) + 1;
5293             if (strcmpW( advertise, p ))
5294             {
5295                 memcpy( q, p, len * sizeof(WCHAR) );
5296                 q += len;
5297             }
5298         }
5299     }
5300     strcpyW( q, advertise );
5301     q[strlenW( q ) + 1] = 0;
5302
5303     msi_reg_set_val_multi_str( hkey, qualifier, output );
5304     
5305 end:
5306     RegCloseKey(hkey);
5307     msi_free( output );
5308     msi_free( advertise );
5309     msi_free( existing );
5310
5311     /* the UI chunk */
5312     uirow = MSI_CreateRecord( 2 );
5313     MSI_RecordSetStringW( uirow, 1, compgroupid );
5314     MSI_RecordSetStringW( uirow, 2, qualifier);
5315     msi_ui_actiondata( package, szPublishComponents, uirow );
5316     msiobj_release( &uirow->hdr );
5317     /* FIXME: call ui_progress? */
5318
5319     return rc;
5320 }
5321
5322 /*
5323  * At present I am ignorning the advertised components part of this and only
5324  * focusing on the qualified component sets
5325  */
5326 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5327 {
5328     static const WCHAR query[] = {
5329         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5330         '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5331     MSIQUERY *view;
5332     UINT rc;
5333     
5334     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5335     if (rc != ERROR_SUCCESS)
5336         return ERROR_SUCCESS;
5337
5338     rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5339     msiobj_release(&view->hdr);
5340     return rc;
5341 }
5342
5343 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5344 {
5345     static const WCHAR szInstallerComponents[] = {
5346         'S','o','f','t','w','a','r','e','\\',
5347         'M','i','c','r','o','s','o','f','t','\\',
5348         'I','n','s','t','a','l','l','e','r','\\',
5349         'C','o','m','p','o','n','e','n','t','s','\\',0};
5350
5351     MSIPACKAGE *package = param;
5352     LPCWSTR compgroupid, component, feature, qualifier;
5353     MSICOMPONENT *comp;
5354     MSIFEATURE *feat;
5355     MSIRECORD *uirow;
5356     WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5357     LONG res;
5358
5359     feature = MSI_RecordGetString( rec, 5 );
5360     feat = msi_get_loaded_feature( package, feature );
5361     if (!feat)
5362         return ERROR_SUCCESS;
5363
5364     feat->Action = msi_get_feature_action( package, feat );
5365     if (feat->Action != INSTALLSTATE_ABSENT)
5366     {
5367         TRACE("feature not scheduled for removal %s\n", debugstr_w(feature));
5368         return ERROR_SUCCESS;
5369     }
5370
5371     component = MSI_RecordGetString( rec, 3 );
5372     comp = msi_get_loaded_component( package, component );
5373     if (!comp)
5374         return ERROR_SUCCESS;
5375
5376     compgroupid = MSI_RecordGetString( rec, 1 );
5377     qualifier = MSI_RecordGetString( rec, 2 );
5378
5379     squash_guid( compgroupid, squashed );
5380     strcpyW( keypath, szInstallerComponents );
5381     strcatW( keypath, squashed );
5382
5383     res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5384     if (res != ERROR_SUCCESS)
5385     {
5386         WARN("Unable to delete component key %d\n", res);
5387     }
5388
5389     uirow = MSI_CreateRecord( 2 );
5390     MSI_RecordSetStringW( uirow, 1, compgroupid );
5391     MSI_RecordSetStringW( uirow, 2, qualifier );
5392     msi_ui_actiondata( package, szUnpublishComponents, uirow );
5393     msiobj_release( &uirow->hdr );
5394
5395     return ERROR_SUCCESS;
5396 }
5397
5398 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5399 {
5400     static const WCHAR query[] = {
5401         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5402         '`','P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','`',0};
5403     MSIQUERY *view;
5404     UINT rc;
5405
5406     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5407     if (rc != ERROR_SUCCESS)
5408         return ERROR_SUCCESS;
5409
5410     rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5411     msiobj_release( &view->hdr );
5412     return rc;
5413 }
5414
5415 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5416 {
5417     static const WCHAR query[] =
5418         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5419          '`','C','o','m','p','o','n','e','n','t','`',' ','W','H','E','R','E',' ',
5420          '`','C','o','m','p','o','n','e','n','t','`',' ','=','\'','%','s','\'',0};
5421     MSIPACKAGE *package = param;
5422     MSICOMPONENT *component;
5423     MSIRECORD *row;
5424     MSIFILE *file;
5425     SC_HANDLE hscm = NULL, service = NULL;
5426     LPCWSTR comp, key;
5427     LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5428     LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5429     DWORD serv_type, start_type, err_control;
5430     SERVICE_DESCRIPTIONW sd = {NULL};
5431
5432     comp = MSI_RecordGetString( rec, 12 );
5433     component = msi_get_loaded_component( package, comp );
5434     if (!component)
5435     {
5436         WARN("service component not found\n");
5437         goto done;
5438     }
5439     component->Action = msi_get_component_action( package, component );
5440     if (component->Action != INSTALLSTATE_LOCAL)
5441     {
5442         TRACE("component not scheduled for installation %s\n", debugstr_w(comp));
5443         goto done;
5444     }
5445     hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5446     if (!hscm)
5447     {
5448         ERR("Failed to open the SC Manager!\n");
5449         goto done;
5450     }
5451
5452     start_type = MSI_RecordGetInteger(rec, 5);
5453     if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5454         goto done;
5455
5456     deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5457     deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5458     serv_type = MSI_RecordGetInteger(rec, 4);
5459     err_control = MSI_RecordGetInteger(rec, 6);
5460     deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5461     deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5462     deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5463     deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5464     deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5465     deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5466
5467     /* fetch the service path */
5468     row = MSI_QueryGetRecord(package->db, query, comp);
5469     if (!row)
5470     {
5471         ERR("Query failed\n");
5472         goto done;
5473     }
5474     key = MSI_RecordGetString(row, 6);
5475     file = msi_get_loaded_file(package, key);
5476     msiobj_release(&row->hdr);
5477     if (!file)
5478     {
5479         ERR("Failed to load the service file\n");
5480         goto done;
5481     }
5482
5483     if (!args || !args[0]) image_path = file->TargetPath;
5484     else
5485     {
5486         int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5487         if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5488             return ERROR_OUTOFMEMORY;
5489
5490         strcpyW(image_path, file->TargetPath);
5491         strcatW(image_path, szSpace);
5492         strcatW(image_path, args);
5493     }
5494     service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5495                              start_type, err_control, image_path, load_order,
5496                              NULL, depends, serv_name, pass);
5497
5498     if (!service)
5499     {
5500         if (GetLastError() != ERROR_SERVICE_EXISTS)
5501             ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5502     }
5503     else if (sd.lpDescription)
5504     {
5505         if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5506             WARN("failed to set service description %u\n", GetLastError());
5507     }
5508
5509     if (image_path != file->TargetPath) msi_free(image_path);
5510 done:
5511     CloseServiceHandle(service);
5512     CloseServiceHandle(hscm);
5513     msi_free(name);
5514     msi_free(disp);
5515     msi_free(sd.lpDescription);
5516     msi_free(load_order);
5517     msi_free(serv_name);
5518     msi_free(pass);
5519     msi_free(depends);
5520     msi_free(args);
5521
5522     return ERROR_SUCCESS;
5523 }
5524
5525 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5526 {
5527     static const WCHAR query[] = {
5528         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5529         'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5530     MSIQUERY *view;
5531     UINT rc;
5532     
5533     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5534     if (rc != ERROR_SUCCESS)
5535         return ERROR_SUCCESS;
5536
5537     rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5538     msiobj_release(&view->hdr);
5539     return rc;
5540 }
5541
5542 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5543 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5544 {
5545     LPCWSTR *vector, *temp_vector;
5546     LPWSTR p, q;
5547     DWORD sep_len;
5548
5549     static const WCHAR separator[] = {'[','~',']',0};
5550
5551     *numargs = 0;
5552     sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5553
5554     if (!args)
5555         return NULL;
5556
5557     vector = msi_alloc(sizeof(LPWSTR));
5558     if (!vector)
5559         return NULL;
5560
5561     p = args;
5562     do
5563     {
5564         (*numargs)++;
5565         vector[*numargs - 1] = p;
5566
5567         if ((q = strstrW(p, separator)))
5568         {
5569             *q = '\0';
5570
5571             temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5572             if (!temp_vector)
5573             {
5574                 msi_free(vector);
5575                 return NULL;
5576             }
5577             vector = temp_vector;
5578
5579             p = q + sep_len;
5580         }
5581     } while (q);
5582
5583     return vector;
5584 }
5585
5586 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5587 {
5588     MSIPACKAGE *package = param;
5589     MSICOMPONENT *comp;
5590     MSIRECORD *uirow;
5591     SC_HANDLE scm = NULL, service = NULL;
5592     LPCWSTR component, *vector = NULL;
5593     LPWSTR name, args, display_name = NULL;
5594     DWORD event, numargs, len;
5595     UINT r = ERROR_FUNCTION_FAILED;
5596
5597     component = MSI_RecordGetString(rec, 6);
5598     comp = msi_get_loaded_component(package, component);
5599     if (!comp)
5600         return ERROR_SUCCESS;
5601
5602     comp->Action = msi_get_component_action( package, comp );
5603     if (comp->Action != INSTALLSTATE_LOCAL)
5604     {
5605         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5606         return ERROR_SUCCESS;
5607     }
5608
5609     deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5610     deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5611     event = MSI_RecordGetInteger(rec, 3);
5612
5613     if (!(event & msidbServiceControlEventStart))
5614     {
5615         r = ERROR_SUCCESS;
5616         goto done;
5617     }
5618
5619     scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5620     if (!scm)
5621     {
5622         ERR("Failed to open the service control manager\n");
5623         goto done;
5624     }
5625
5626     len = 0;
5627     if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5628         GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5629     {
5630         if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5631             GetServiceDisplayNameW( scm, name, display_name, &len );
5632     }
5633
5634     service = OpenServiceW(scm, name, SERVICE_START);
5635     if (!service)
5636     {
5637         ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5638         goto done;
5639     }
5640
5641     vector = msi_service_args_to_vector(args, &numargs);
5642
5643     if (!StartServiceW(service, numargs, vector) &&
5644         GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5645     {
5646         ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5647         goto done;
5648     }
5649
5650     r = ERROR_SUCCESS;
5651
5652 done:
5653     uirow = MSI_CreateRecord( 2 );
5654     MSI_RecordSetStringW( uirow, 1, display_name );
5655     MSI_RecordSetStringW( uirow, 2, name );
5656     msi_ui_actiondata( package, szStartServices, uirow );
5657     msiobj_release( &uirow->hdr );
5658
5659     CloseServiceHandle(service);
5660     CloseServiceHandle(scm);
5661
5662     msi_free(name);
5663     msi_free(args);
5664     msi_free(vector);
5665     msi_free(display_name);
5666     return r;
5667 }
5668
5669 static UINT ACTION_StartServices( MSIPACKAGE *package )
5670 {
5671     static const WCHAR query[] = {
5672         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5673         'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5674     MSIQUERY *view;
5675     UINT rc;
5676
5677     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5678     if (rc != ERROR_SUCCESS)
5679         return ERROR_SUCCESS;
5680
5681     rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5682     msiobj_release(&view->hdr);
5683     return rc;
5684 }
5685
5686 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5687 {
5688     DWORD i, needed, count;
5689     ENUM_SERVICE_STATUSW *dependencies;
5690     SERVICE_STATUS ss;
5691     SC_HANDLE depserv;
5692
5693     if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5694                                0, &needed, &count))
5695         return TRUE;
5696
5697     if (GetLastError() != ERROR_MORE_DATA)
5698         return FALSE;
5699
5700     dependencies = msi_alloc(needed);
5701     if (!dependencies)
5702         return FALSE;
5703
5704     if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5705                                 needed, &needed, &count))
5706         goto error;
5707
5708     for (i = 0; i < count; i++)
5709     {
5710         depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5711                                SERVICE_STOP | SERVICE_QUERY_STATUS);
5712         if (!depserv)
5713             goto error;
5714
5715         if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5716             goto error;
5717     }
5718
5719     return TRUE;
5720
5721 error:
5722     msi_free(dependencies);
5723     return FALSE;
5724 }
5725
5726 static UINT stop_service( LPCWSTR name )
5727 {
5728     SC_HANDLE scm = NULL, service = NULL;
5729     SERVICE_STATUS status;
5730     SERVICE_STATUS_PROCESS ssp;
5731     DWORD needed;
5732
5733     scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5734     if (!scm)
5735     {
5736         WARN("Failed to open the SCM: %d\n", GetLastError());
5737         goto done;
5738     }
5739
5740     service = OpenServiceW(scm, name,
5741                            SERVICE_STOP |
5742                            SERVICE_QUERY_STATUS |
5743                            SERVICE_ENUMERATE_DEPENDENTS);
5744     if (!service)
5745     {
5746         WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5747         goto done;
5748     }
5749
5750     if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5751                               sizeof(SERVICE_STATUS_PROCESS), &needed))
5752     {
5753         WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5754         goto done;
5755     }
5756
5757     if (ssp.dwCurrentState == SERVICE_STOPPED)
5758         goto done;
5759
5760     stop_service_dependents(scm, service);
5761
5762     if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5763         WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5764
5765 done:
5766     CloseServiceHandle(service);
5767     CloseServiceHandle(scm);
5768
5769     return ERROR_SUCCESS;
5770 }
5771
5772 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5773 {
5774     MSIPACKAGE *package = param;
5775     MSICOMPONENT *comp;
5776     MSIRECORD *uirow;
5777     LPCWSTR component;
5778     LPWSTR name = NULL, display_name = NULL;
5779     DWORD event, len;
5780     SC_HANDLE scm;
5781
5782     event = MSI_RecordGetInteger( rec, 3 );
5783     if (!(event & msidbServiceControlEventStop))
5784         return ERROR_SUCCESS;
5785
5786     component = MSI_RecordGetString( rec, 6 );
5787     comp = msi_get_loaded_component( package, component );
5788     if (!comp)
5789         return ERROR_SUCCESS;
5790
5791     comp->Action = msi_get_component_action( package, comp );
5792     if (comp->Action != INSTALLSTATE_ABSENT)
5793     {
5794         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5795         return ERROR_SUCCESS;
5796     }
5797
5798     scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5799     if (!scm)
5800     {
5801         ERR("Failed to open the service control manager\n");
5802         goto done;
5803     }
5804
5805     len = 0;
5806     if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5807         GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5808     {
5809         if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5810             GetServiceDisplayNameW( scm, name, display_name, &len );
5811     }
5812     CloseServiceHandle( scm );
5813
5814     deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5815     stop_service( name );
5816
5817 done:
5818     uirow = MSI_CreateRecord( 2 );
5819     MSI_RecordSetStringW( uirow, 1, display_name );
5820     MSI_RecordSetStringW( uirow, 2, name );
5821     msi_ui_actiondata( package, szStopServices, uirow );
5822     msiobj_release( &uirow->hdr );
5823
5824     msi_free( name );
5825     msi_free( display_name );
5826     return ERROR_SUCCESS;
5827 }
5828
5829 static UINT ACTION_StopServices( MSIPACKAGE *package )
5830 {
5831     static const WCHAR query[] = {
5832         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5833         'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5834     MSIQUERY *view;
5835     UINT rc;
5836
5837     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5838     if (rc != ERROR_SUCCESS)
5839         return ERROR_SUCCESS;
5840
5841     rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5842     msiobj_release(&view->hdr);
5843     return rc;
5844 }
5845
5846 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5847 {
5848     MSIPACKAGE *package = param;
5849     MSICOMPONENT *comp;
5850     MSIRECORD *uirow;
5851     LPCWSTR component;
5852     LPWSTR name = NULL, display_name = NULL;
5853     DWORD event, len;
5854     SC_HANDLE scm = NULL, service = NULL;
5855
5856     event = MSI_RecordGetInteger( rec, 3 );
5857     if (!(event & msidbServiceControlEventDelete))
5858         return ERROR_SUCCESS;
5859
5860     component = MSI_RecordGetString(rec, 6);
5861     comp = msi_get_loaded_component(package, component);
5862     if (!comp)
5863         return ERROR_SUCCESS;
5864
5865     comp->Action = msi_get_component_action( package, comp );
5866     if (comp->Action != INSTALLSTATE_ABSENT)
5867     {
5868         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
5869         return ERROR_SUCCESS;
5870     }
5871
5872     deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5873     stop_service( name );
5874
5875     scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5876     if (!scm)
5877     {
5878         WARN("Failed to open the SCM: %d\n", GetLastError());
5879         goto done;
5880     }
5881
5882     len = 0;
5883     if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5884         GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5885     {
5886         if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5887             GetServiceDisplayNameW( scm, name, display_name, &len );
5888     }
5889
5890     service = OpenServiceW( scm, name, DELETE );
5891     if (!service)
5892     {
5893         WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5894         goto done;
5895     }
5896
5897     if (!DeleteService( service ))
5898         WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5899
5900 done:
5901     uirow = MSI_CreateRecord( 2 );
5902     MSI_RecordSetStringW( uirow, 1, display_name );
5903     MSI_RecordSetStringW( uirow, 2, name );
5904     msi_ui_actiondata( package, szDeleteServices, uirow );
5905     msiobj_release( &uirow->hdr );
5906
5907     CloseServiceHandle( service );
5908     CloseServiceHandle( scm );
5909     msi_free( name );
5910     msi_free( display_name );
5911
5912     return ERROR_SUCCESS;
5913 }
5914
5915 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5916 {
5917     static const WCHAR query[] = {
5918         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5919         'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0};
5920     MSIQUERY *view;
5921     UINT rc;
5922
5923     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5924     if (rc != ERROR_SUCCESS)
5925         return ERROR_SUCCESS;
5926
5927     rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5928     msiobj_release( &view->hdr );
5929     return rc;
5930 }
5931
5932 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5933 {
5934     MSIPACKAGE *package = param;
5935     LPWSTR driver, driver_path, ptr;
5936     WCHAR outpath[MAX_PATH];
5937     MSIFILE *driver_file = NULL, *setup_file = NULL;
5938     MSICOMPONENT *comp;
5939     MSIRECORD *uirow;
5940     LPCWSTR desc, file_key, component;
5941     DWORD len, usage;
5942     UINT r = ERROR_SUCCESS;
5943
5944     static const WCHAR driver_fmt[] = {
5945         'D','r','i','v','e','r','=','%','s',0};
5946     static const WCHAR setup_fmt[] = {
5947         'S','e','t','u','p','=','%','s',0};
5948     static const WCHAR usage_fmt[] = {
5949         'F','i','l','e','U','s','a','g','e','=','1',0};
5950
5951     component = MSI_RecordGetString( rec, 2 );
5952     comp = msi_get_loaded_component( package, component );
5953     if (!comp)
5954         return ERROR_SUCCESS;
5955
5956     comp->Action = msi_get_component_action( package, comp );
5957     if (comp->Action != INSTALLSTATE_LOCAL)
5958     {
5959         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
5960         return ERROR_SUCCESS;
5961     }
5962     desc = MSI_RecordGetString(rec, 3);
5963
5964     file_key = MSI_RecordGetString( rec, 4 );
5965     if (file_key) driver_file = msi_get_loaded_file( package, file_key );
5966
5967     file_key = MSI_RecordGetString( rec, 5 );
5968     if (file_key) setup_file = msi_get_loaded_file( package, file_key );
5969
5970     if (!driver_file)
5971     {
5972         ERR("ODBC Driver entry not found!\n");
5973         return ERROR_FUNCTION_FAILED;
5974     }
5975
5976     len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5977     if (setup_file)
5978         len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5979     len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5980
5981     driver = msi_alloc(len * sizeof(WCHAR));
5982     if (!driver)
5983         return ERROR_OUTOFMEMORY;
5984
5985     ptr = driver;
5986     lstrcpyW(ptr, desc);
5987     ptr += lstrlenW(ptr) + 1;
5988
5989     len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5990     ptr += len + 1;
5991
5992     if (setup_file)
5993     {
5994         len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5995         ptr += len + 1;
5996     }
5997
5998     lstrcpyW(ptr, usage_fmt);
5999     ptr += lstrlenW(ptr) + 1;
6000     *ptr = '\0';
6001
6002     driver_path = strdupW(driver_file->TargetPath);
6003     ptr = strrchrW(driver_path, '\\');
6004     if (ptr) *ptr = '\0';
6005
6006     if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
6007                              NULL, ODBC_INSTALL_COMPLETE, &usage))
6008     {
6009         ERR("Failed to install SQL driver!\n");
6010         r = ERROR_FUNCTION_FAILED;
6011     }
6012
6013     uirow = MSI_CreateRecord( 5 );
6014     MSI_RecordSetStringW( uirow, 1, desc );
6015     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6016     MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
6017     msi_ui_actiondata( package, szInstallODBC, uirow );
6018     msiobj_release( &uirow->hdr );
6019
6020     msi_free(driver);
6021     msi_free(driver_path);
6022
6023     return r;
6024 }
6025
6026 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6027 {
6028     MSIPACKAGE *package = param;
6029     LPWSTR translator, translator_path, ptr;
6030     WCHAR outpath[MAX_PATH];
6031     MSIFILE *translator_file = NULL, *setup_file = NULL;
6032     MSICOMPONENT *comp;
6033     MSIRECORD *uirow;
6034     LPCWSTR desc, file_key, component;
6035     DWORD len, usage;
6036     UINT r = ERROR_SUCCESS;
6037
6038     static const WCHAR translator_fmt[] = {
6039         'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6040     static const WCHAR setup_fmt[] = {
6041         'S','e','t','u','p','=','%','s',0};
6042
6043     component = MSI_RecordGetString( rec, 2 );
6044     comp = msi_get_loaded_component( package, component );
6045     if (!comp)
6046         return ERROR_SUCCESS;
6047
6048     comp->Action = msi_get_component_action( package, comp );
6049     if (comp->Action != INSTALLSTATE_LOCAL)
6050     {
6051         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6052         return ERROR_SUCCESS;
6053     }
6054     desc = MSI_RecordGetString(rec, 3);
6055
6056     file_key = MSI_RecordGetString( rec, 4 );
6057     if (file_key) translator_file = msi_get_loaded_file( package, file_key );
6058
6059     file_key = MSI_RecordGetString( rec, 5 );
6060     if (file_key) setup_file = msi_get_loaded_file( package, file_key );
6061
6062     if (!translator_file)
6063     {
6064         ERR("ODBC Translator entry not found!\n");
6065         return ERROR_FUNCTION_FAILED;
6066     }
6067
6068     len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6069     if (setup_file)
6070         len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6071
6072     translator = msi_alloc(len * sizeof(WCHAR));
6073     if (!translator)
6074         return ERROR_OUTOFMEMORY;
6075
6076     ptr = translator;
6077     lstrcpyW(ptr, desc);
6078     ptr += lstrlenW(ptr) + 1;
6079
6080     len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6081     ptr += len + 1;
6082
6083     if (setup_file)
6084     {
6085         len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6086         ptr += len + 1;
6087     }
6088     *ptr = '\0';
6089
6090     translator_path = strdupW(translator_file->TargetPath);
6091     ptr = strrchrW(translator_path, '\\');
6092     if (ptr) *ptr = '\0';
6093
6094     if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6095                                  NULL, ODBC_INSTALL_COMPLETE, &usage))
6096     {
6097         ERR("Failed to install SQL translator!\n");
6098         r = ERROR_FUNCTION_FAILED;
6099     }
6100
6101     uirow = MSI_CreateRecord( 5 );
6102     MSI_RecordSetStringW( uirow, 1, desc );
6103     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6104     MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6105     msi_ui_actiondata( package, szInstallODBC, uirow );
6106     msiobj_release( &uirow->hdr );
6107
6108     msi_free(translator);
6109     msi_free(translator_path);
6110
6111     return r;
6112 }
6113
6114 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6115 {
6116     MSIPACKAGE *package = param;
6117     MSICOMPONENT *comp;
6118     LPWSTR attrs;
6119     LPCWSTR desc, driver, component;
6120     WORD request = ODBC_ADD_SYS_DSN;
6121     INT registration;
6122     DWORD len;
6123     UINT r = ERROR_SUCCESS;
6124     MSIRECORD *uirow;
6125
6126     static const WCHAR attrs_fmt[] = {
6127         'D','S','N','=','%','s',0 };
6128
6129     component = MSI_RecordGetString( rec, 2 );
6130     comp = msi_get_loaded_component( package, component );
6131     if (!comp)
6132         return ERROR_SUCCESS;
6133
6134     comp->Action = msi_get_component_action( package, comp );
6135     if (comp->Action != INSTALLSTATE_LOCAL)
6136     {
6137         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6138         return ERROR_SUCCESS;
6139     }
6140
6141     desc = MSI_RecordGetString(rec, 3);
6142     driver = MSI_RecordGetString(rec, 4);
6143     registration = MSI_RecordGetInteger(rec, 5);
6144
6145     if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6146     else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6147
6148     len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6149     attrs = msi_alloc(len * sizeof(WCHAR));
6150     if (!attrs)
6151         return ERROR_OUTOFMEMORY;
6152
6153     len = sprintfW(attrs, attrs_fmt, desc);
6154     attrs[len + 1] = 0;
6155
6156     if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6157     {
6158         ERR("Failed to install SQL data source!\n");
6159         r = ERROR_FUNCTION_FAILED;
6160     }
6161
6162     uirow = MSI_CreateRecord( 5 );
6163     MSI_RecordSetStringW( uirow, 1, desc );
6164     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6165     MSI_RecordSetInteger( uirow, 3, request );
6166     msi_ui_actiondata( package, szInstallODBC, uirow );
6167     msiobj_release( &uirow->hdr );
6168
6169     msi_free(attrs);
6170
6171     return r;
6172 }
6173
6174 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6175 {
6176     static const WCHAR driver_query[] = {
6177         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6178         'O','D','B','C','D','r','i','v','e','r',0};
6179     static const WCHAR translator_query[] = {
6180         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6181         'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6182     static const WCHAR source_query[] = {
6183         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6184         'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6185     MSIQUERY *view;
6186     UINT rc;
6187
6188     rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6189     if (rc == ERROR_SUCCESS)
6190     {
6191         rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6192         msiobj_release(&view->hdr);
6193         if (rc != ERROR_SUCCESS)
6194             return rc;
6195     }
6196     rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6197     if (rc == ERROR_SUCCESS)
6198     {
6199         rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6200         msiobj_release(&view->hdr);
6201         if (rc != ERROR_SUCCESS)
6202             return rc;
6203     }
6204     rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6205     if (rc == ERROR_SUCCESS)
6206     {
6207         rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6208         msiobj_release(&view->hdr);
6209         if (rc != ERROR_SUCCESS)
6210             return rc;
6211     }
6212     return ERROR_SUCCESS;
6213 }
6214
6215 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6216 {
6217     MSIPACKAGE *package = param;
6218     MSICOMPONENT *comp;
6219     MSIRECORD *uirow;
6220     DWORD usage;
6221     LPCWSTR desc, component;
6222
6223     component = MSI_RecordGetString( rec, 2 );
6224     comp = msi_get_loaded_component( package, component );
6225     if (!comp)
6226         return ERROR_SUCCESS;
6227
6228     comp->Action = msi_get_component_action( package, comp );
6229     if (comp->Action != INSTALLSTATE_ABSENT)
6230     {
6231         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6232         return ERROR_SUCCESS;
6233     }
6234
6235     desc = MSI_RecordGetString( rec, 3 );
6236     if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6237     {
6238         WARN("Failed to remove ODBC driver\n");
6239     }
6240     else if (!usage)
6241     {
6242         FIXME("Usage count reached 0\n");
6243     }
6244
6245     uirow = MSI_CreateRecord( 2 );
6246     MSI_RecordSetStringW( uirow, 1, desc );
6247     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6248     msi_ui_actiondata( package, szRemoveODBC, uirow );
6249     msiobj_release( &uirow->hdr );
6250
6251     return ERROR_SUCCESS;
6252 }
6253
6254 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6255 {
6256     MSIPACKAGE *package = param;
6257     MSICOMPONENT *comp;
6258     MSIRECORD *uirow;
6259     DWORD usage;
6260     LPCWSTR desc, component;
6261
6262     component = MSI_RecordGetString( rec, 2 );
6263     comp = msi_get_loaded_component( package, component );
6264     if (!comp)
6265         return ERROR_SUCCESS;
6266
6267     comp->Action = msi_get_component_action( package, comp );
6268     if (comp->Action != INSTALLSTATE_ABSENT)
6269     {
6270         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6271         return ERROR_SUCCESS;
6272     }
6273
6274     desc = MSI_RecordGetString( rec, 3 );
6275     if (!SQLRemoveTranslatorW( desc, &usage ))
6276     {
6277         WARN("Failed to remove ODBC translator\n");
6278     }
6279     else if (!usage)
6280     {
6281         FIXME("Usage count reached 0\n");
6282     }
6283
6284     uirow = MSI_CreateRecord( 2 );
6285     MSI_RecordSetStringW( uirow, 1, desc );
6286     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6287     msi_ui_actiondata( package, szRemoveODBC, uirow );
6288     msiobj_release( &uirow->hdr );
6289
6290     return ERROR_SUCCESS;
6291 }
6292
6293 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6294 {
6295     MSIPACKAGE *package = param;
6296     MSICOMPONENT *comp;
6297     MSIRECORD *uirow;
6298     LPWSTR attrs;
6299     LPCWSTR desc, driver, component;
6300     WORD request = ODBC_REMOVE_SYS_DSN;
6301     INT registration;
6302     DWORD len;
6303
6304     static const WCHAR attrs_fmt[] = {
6305         'D','S','N','=','%','s',0 };
6306
6307     component = MSI_RecordGetString( rec, 2 );
6308     comp = msi_get_loaded_component( package, component );
6309     if (!comp)
6310         return ERROR_SUCCESS;
6311
6312     comp->Action = msi_get_component_action( package, comp );
6313     if (comp->Action != INSTALLSTATE_ABSENT)
6314     {
6315         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6316         return ERROR_SUCCESS;
6317     }
6318
6319     desc = MSI_RecordGetString( rec, 3 );
6320     driver = MSI_RecordGetString( rec, 4 );
6321     registration = MSI_RecordGetInteger( rec, 5 );
6322
6323     if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6324     else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6325
6326     len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6327     attrs = msi_alloc( len * sizeof(WCHAR) );
6328     if (!attrs)
6329         return ERROR_OUTOFMEMORY;
6330
6331     FIXME("Use ODBCSourceAttribute table\n");
6332
6333     len = sprintfW( attrs, attrs_fmt, desc );
6334     attrs[len + 1] = 0;
6335
6336     if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6337     {
6338         WARN("Failed to remove ODBC data source\n");
6339     }
6340     msi_free( attrs );
6341
6342     uirow = MSI_CreateRecord( 3 );
6343     MSI_RecordSetStringW( uirow, 1, desc );
6344     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6345     MSI_RecordSetInteger( uirow, 3, request );
6346     msi_ui_actiondata( package, szRemoveODBC, uirow );
6347     msiobj_release( &uirow->hdr );
6348
6349     return ERROR_SUCCESS;
6350 }
6351
6352 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6353 {
6354     static const WCHAR driver_query[] = {
6355         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6356         'O','D','B','C','D','r','i','v','e','r',0};
6357     static const WCHAR translator_query[] = {
6358         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6359         'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6360     static const WCHAR source_query[] = {
6361         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6362         'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0};
6363     MSIQUERY *view;
6364     UINT rc;
6365
6366     rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6367     if (rc == ERROR_SUCCESS)
6368     {
6369         rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6370         msiobj_release( &view->hdr );
6371         if (rc != ERROR_SUCCESS)
6372             return rc;
6373     }
6374     rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6375     if (rc == ERROR_SUCCESS)
6376     {
6377         rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6378         msiobj_release( &view->hdr );
6379         if (rc != ERROR_SUCCESS)
6380             return rc;
6381     }
6382     rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6383     if (rc == ERROR_SUCCESS)
6384     {
6385         rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6386         msiobj_release( &view->hdr );
6387         if (rc != ERROR_SUCCESS)
6388             return rc;
6389     }
6390     return ERROR_SUCCESS;
6391 }
6392
6393 #define ENV_ACT_SETALWAYS   0x1
6394 #define ENV_ACT_SETABSENT   0x2
6395 #define ENV_ACT_REMOVE      0x4
6396 #define ENV_ACT_REMOVEMATCH 0x8
6397
6398 #define ENV_MOD_MACHINE     0x20000000
6399 #define ENV_MOD_APPEND      0x40000000
6400 #define ENV_MOD_PREFIX      0x80000000
6401 #define ENV_MOD_MASK        0xC0000000
6402
6403 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6404
6405 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6406 {
6407     LPCWSTR cptr = *name;
6408
6409     static const WCHAR prefix[] = {'[','~',']',0};
6410     static const int prefix_len = 3;
6411
6412     *flags = 0;
6413     while (*cptr)
6414     {
6415         if (*cptr == '=')
6416             *flags |= ENV_ACT_SETALWAYS;
6417         else if (*cptr == '+')
6418             *flags |= ENV_ACT_SETABSENT;
6419         else if (*cptr == '-')
6420             *flags |= ENV_ACT_REMOVE;
6421         else if (*cptr == '!')
6422             *flags |= ENV_ACT_REMOVEMATCH;
6423         else if (*cptr == '*')
6424             *flags |= ENV_MOD_MACHINE;
6425         else
6426             break;
6427
6428         cptr++;
6429         (*name)++;
6430     }
6431
6432     if (!*cptr)
6433     {
6434         ERR("Missing environment variable\n");
6435         return ERROR_FUNCTION_FAILED;
6436     }
6437
6438     if (*value)
6439     {
6440         LPCWSTR ptr = *value;
6441         if (!strncmpW(ptr, prefix, prefix_len))
6442         {
6443             if (ptr[prefix_len] == szSemiColon[0])
6444             {
6445                 *flags |= ENV_MOD_APPEND;
6446                 *value += lstrlenW(prefix);
6447             }
6448             else
6449             {
6450                 *value = NULL;
6451             }
6452         }
6453         else if (lstrlenW(*value) >= prefix_len)
6454         {
6455             ptr += lstrlenW(ptr) - prefix_len;
6456             if (!strcmpW( ptr, prefix ))
6457             {
6458                 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6459                 {
6460                     *flags |= ENV_MOD_PREFIX;
6461                     /* the "[~]" will be removed by deformat_string */;
6462                 }
6463                 else
6464                 {
6465                     *value = NULL;
6466                 }
6467             }
6468         }
6469     }
6470
6471     if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6472         check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6473         check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6474         check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6475     {
6476         ERR("Invalid flags: %08x\n", *flags);
6477         return ERROR_FUNCTION_FAILED;
6478     }
6479
6480     if (!*flags)
6481         *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6482
6483     return ERROR_SUCCESS;
6484 }
6485
6486 static UINT open_env_key( DWORD flags, HKEY *key )
6487 {
6488     static const WCHAR user_env[] =
6489         {'E','n','v','i','r','o','n','m','e','n','t',0};
6490     static const WCHAR machine_env[] =
6491         {'S','y','s','t','e','m','\\',
6492          'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6493          'C','o','n','t','r','o','l','\\',
6494          'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6495          'E','n','v','i','r','o','n','m','e','n','t',0};
6496     const WCHAR *env;
6497     HKEY root;
6498     LONG res;
6499
6500     if (flags & ENV_MOD_MACHINE)
6501     {
6502         env = machine_env;
6503         root = HKEY_LOCAL_MACHINE;
6504     }
6505     else
6506     {
6507         env = user_env;
6508         root = HKEY_CURRENT_USER;
6509     }
6510
6511     res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6512     if (res != ERROR_SUCCESS)
6513     {
6514         WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6515         return ERROR_FUNCTION_FAILED;
6516     }
6517
6518     return ERROR_SUCCESS;
6519 }
6520
6521 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6522 {
6523     MSIPACKAGE *package = param;
6524     LPCWSTR name, value, component;
6525     LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6526     DWORD flags, type, size;
6527     UINT res;
6528     HKEY env = NULL;
6529     MSICOMPONENT *comp;
6530     MSIRECORD *uirow;
6531     int action = 0;
6532
6533     component = MSI_RecordGetString(rec, 4);
6534     comp = msi_get_loaded_component(package, component);
6535     if (!comp)
6536         return ERROR_SUCCESS;
6537
6538     comp->Action = msi_get_component_action( package, comp );
6539     if (comp->Action != INSTALLSTATE_LOCAL)
6540     {
6541         TRACE("component not scheduled for installation %s\n", debugstr_w(component));
6542         return ERROR_SUCCESS;
6543     }
6544     name = MSI_RecordGetString(rec, 2);
6545     value = MSI_RecordGetString(rec, 3);
6546
6547     TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6548
6549     res = env_parse_flags(&name, &value, &flags);
6550     if (res != ERROR_SUCCESS || !value)
6551        goto done;
6552
6553     if (value && !deformat_string(package, value, &deformatted))
6554     {
6555         res = ERROR_OUTOFMEMORY;
6556         goto done;
6557     }
6558
6559     value = deformatted;
6560
6561     res = open_env_key( flags, &env );
6562     if (res != ERROR_SUCCESS)
6563         goto done;
6564
6565     if (flags & ENV_MOD_MACHINE)
6566         action |= 0x20000000;
6567
6568     size = 0;
6569     type = REG_SZ;
6570     res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6571     if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6572         (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6573         goto done;
6574
6575     if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6576     {
6577         action = 0x2;
6578
6579         /* Nothing to do. */
6580         if (!value)
6581         {
6582             res = ERROR_SUCCESS;
6583             goto done;
6584         }
6585
6586         /* If we are appending but the string was empty, strip ; */
6587         if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6588
6589         size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6590         newval = strdupW(value);
6591         if (!newval)
6592         {
6593             res = ERROR_OUTOFMEMORY;
6594             goto done;
6595         }
6596     }
6597     else
6598     {
6599         action = 0x1;
6600
6601         /* Contrary to MSDN, +-variable to [~];path works */
6602         if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6603         {
6604             res = ERROR_SUCCESS;
6605             goto done;
6606         }
6607
6608         data = msi_alloc(size);
6609         if (!data)
6610         {
6611             RegCloseKey(env);
6612             return ERROR_OUTOFMEMORY;
6613         }
6614
6615         res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6616         if (res != ERROR_SUCCESS)
6617             goto done;
6618
6619         if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6620         {
6621             action = 0x4;
6622             res = RegDeleteValueW(env, name);
6623             if (res != ERROR_SUCCESS)
6624                 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6625             goto done;
6626         }
6627
6628         size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6629         if (flags & ENV_MOD_MASK)
6630         {
6631             DWORD mod_size;
6632             int multiplier = 0;
6633             if (flags & ENV_MOD_APPEND) multiplier++;
6634             if (flags & ENV_MOD_PREFIX) multiplier++;
6635             mod_size = lstrlenW(value) * multiplier;
6636             size += mod_size * sizeof(WCHAR);
6637         }
6638
6639         newval = msi_alloc(size);
6640         ptr = newval;
6641         if (!newval)
6642         {
6643             res = ERROR_OUTOFMEMORY;
6644             goto done;
6645         }
6646
6647         if (flags & ENV_MOD_PREFIX)
6648         {
6649             lstrcpyW(newval, value);
6650             ptr = newval + lstrlenW(value);
6651             action |= 0x80000000;
6652         }
6653
6654         lstrcpyW(ptr, data);
6655
6656         if (flags & ENV_MOD_APPEND)
6657         {
6658             lstrcatW(newval, value);
6659             action |= 0x40000000;
6660         }
6661     }
6662     TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6663     res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6664     if (res)
6665     {
6666         WARN("Failed to set %s to %s (%d)\n",  debugstr_w(name), debugstr_w(newval), res);
6667     }
6668
6669 done:
6670     uirow = MSI_CreateRecord( 3 );
6671     MSI_RecordSetStringW( uirow, 1, name );
6672     MSI_RecordSetStringW( uirow, 2, newval );
6673     MSI_RecordSetInteger( uirow, 3, action );
6674     msi_ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6675     msiobj_release( &uirow->hdr );
6676
6677     if (env) RegCloseKey(env);
6678     msi_free(deformatted);
6679     msi_free(data);
6680     msi_free(newval);
6681     return res;
6682 }
6683
6684 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6685 {
6686     static const WCHAR query[] = {
6687         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6688         '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6689     MSIQUERY *view;
6690     UINT rc;
6691
6692     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
6693     if (rc != ERROR_SUCCESS)
6694         return ERROR_SUCCESS;
6695
6696     rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6697     msiobj_release(&view->hdr);
6698     return rc;
6699 }
6700
6701 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6702 {
6703     MSIPACKAGE *package = param;
6704     LPCWSTR name, value, component;
6705     LPWSTR deformatted = NULL;
6706     DWORD flags;
6707     HKEY env;
6708     MSICOMPONENT *comp;
6709     MSIRECORD *uirow;
6710     int action = 0;
6711     LONG res;
6712     UINT r;
6713
6714     component = MSI_RecordGetString( rec, 4 );
6715     comp = msi_get_loaded_component( package, component );
6716     if (!comp)
6717         return ERROR_SUCCESS;
6718
6719     comp->Action = msi_get_component_action( package, comp );
6720     if (comp->Action != INSTALLSTATE_ABSENT)
6721     {
6722         TRACE("component not scheduled for removal %s\n", debugstr_w(component));
6723         return ERROR_SUCCESS;
6724     }
6725     name = MSI_RecordGetString( rec, 2 );
6726     value = MSI_RecordGetString( rec, 3 );
6727
6728     TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6729
6730     r = env_parse_flags( &name, &value, &flags );
6731     if (r != ERROR_SUCCESS)
6732        return r;
6733
6734     if (!(flags & ENV_ACT_REMOVE))
6735     {
6736         TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6737         return ERROR_SUCCESS;
6738     }
6739
6740     if (value && !deformat_string( package, value, &deformatted ))
6741         return ERROR_OUTOFMEMORY;
6742
6743     value = deformatted;
6744
6745     r = open_env_key( flags, &env );
6746     if (r != ERROR_SUCCESS)
6747     {
6748         r = ERROR_SUCCESS;
6749         goto done;
6750     }
6751
6752     if (flags & ENV_MOD_MACHINE)
6753         action |= 0x20000000;
6754
6755     TRACE("Removing %s\n", debugstr_w(name));
6756
6757     res = RegDeleteValueW( env, name );
6758     if (res != ERROR_SUCCESS)
6759     {
6760         WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6761         r = ERROR_SUCCESS;
6762     }
6763
6764 done:
6765     uirow = MSI_CreateRecord( 3 );
6766     MSI_RecordSetStringW( uirow, 1, name );
6767     MSI_RecordSetStringW( uirow, 2, value );
6768     MSI_RecordSetInteger( uirow, 3, action );
6769     msi_ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6770     msiobj_release( &uirow->hdr );
6771
6772     if (env) RegCloseKey( env );
6773     msi_free( deformatted );
6774     return r;
6775 }
6776
6777 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6778 {
6779     static const WCHAR query[] = {
6780         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6781         '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6782     MSIQUERY *view;
6783     UINT rc;
6784
6785     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6786     if (rc != ERROR_SUCCESS)
6787         return ERROR_SUCCESS;
6788
6789     rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6790     msiobj_release( &view->hdr );
6791     return rc;
6792 }
6793
6794 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6795 {
6796     LPWSTR key, template, id;
6797     UINT r = ERROR_SUCCESS;
6798
6799     id = msi_dup_property( package->db, szProductID );
6800     if (id)
6801     {
6802         msi_free( id );
6803         return ERROR_SUCCESS;
6804     }
6805     template = msi_dup_property( package->db, szPIDTemplate );
6806     key = msi_dup_property( package->db, szPIDKEY );
6807
6808     if (key && template)
6809     {
6810         FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6811         r = msi_set_property( package->db, szProductID, key );
6812     }
6813     msi_free( template );
6814     msi_free( key );
6815     return r;
6816 }
6817
6818 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6819 {
6820     TRACE("\n");
6821     package->need_reboot = 1;
6822     return ERROR_SUCCESS;
6823 }
6824
6825 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6826 {
6827     static const WCHAR szAvailableFreeReg[] =
6828         {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6829     MSIRECORD *uirow;
6830     int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6831
6832     TRACE("%p %d kilobytes\n", package, space);
6833
6834     uirow = MSI_CreateRecord( 1 );
6835     MSI_RecordSetInteger( uirow, 1, space );
6836     msi_ui_actiondata( package, szAllocateRegistrySpace, uirow );
6837     msiobj_release( &uirow->hdr );
6838
6839     return ERROR_SUCCESS;
6840 }
6841
6842 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6843 {
6844     TRACE("%p\n", package);
6845
6846     msi_set_property( package->db, szRollbackDisabled, szOne );
6847     return ERROR_SUCCESS;
6848 }
6849
6850 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6851 {
6852     FIXME("%p\n", package);
6853     return ERROR_SUCCESS;
6854 }
6855
6856 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6857 {
6858     static const WCHAR driver_query[] = {
6859         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6860         'O','D','B','C','D','r','i','v','e','r',0};
6861     static const WCHAR translator_query[] = {
6862         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6863         'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0};
6864     MSIQUERY *view;
6865     UINT r, count;
6866
6867     r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6868     if (r == ERROR_SUCCESS)
6869     {
6870         count = 0;
6871         r = MSI_IterateRecords( view, &count, NULL, package );
6872         msiobj_release( &view->hdr );
6873         if (r != ERROR_SUCCESS)
6874             return r;
6875         if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6876     }
6877     r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6878     if (r == ERROR_SUCCESS)
6879     {
6880         count = 0;
6881         r = MSI_IterateRecords( view, &count, NULL, package );
6882         msiobj_release( &view->hdr );
6883         if (r != ERROR_SUCCESS)
6884             return r;
6885         if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6886     }
6887     return ERROR_SUCCESS;
6888 }
6889
6890 static UINT ITERATE_RemoveExistingProducts( MSIRECORD *rec, LPVOID param )
6891 {
6892     MSIPACKAGE *package = param;
6893     const WCHAR *property = MSI_RecordGetString( rec, 1 );
6894     WCHAR *value;
6895
6896     if ((value = msi_dup_property( package->db, property )))
6897     {
6898         FIXME("remove %s\n", debugstr_w(value));
6899         msi_free( value );
6900     }
6901     return ERROR_SUCCESS;
6902 }
6903
6904 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6905 {
6906     static const WCHAR query[] = {
6907         'S','E','L','E','C','T',' ','A','c','t','i','o','n','P','r','o','p','e','r','t','y',' ',
6908         'F','R','O','M',' ','U','p','g','r','a','d','e',0};
6909     MSIQUERY *view;
6910     UINT r;
6911
6912     r = MSI_DatabaseOpenViewW( package->db, query, &view );
6913     if (r == ERROR_SUCCESS)
6914     {
6915         r = MSI_IterateRecords( view, NULL, ITERATE_RemoveExistingProducts, package );
6916         msiobj_release( &view->hdr );
6917         if (r != ERROR_SUCCESS)
6918             return r;
6919     }
6920     return ERROR_SUCCESS;
6921 }
6922
6923 static UINT ITERATE_MigrateFeatureStates( MSIRECORD *rec, LPVOID param )
6924 {
6925     MSIPACKAGE *package = param;
6926     int attributes = MSI_RecordGetInteger( rec, 5 );
6927
6928     if (attributes & msidbUpgradeAttributesMigrateFeatures)
6929     {
6930         const WCHAR *upgrade_code = MSI_RecordGetString( rec, 1 );
6931         const WCHAR *version_min = MSI_RecordGetString( rec, 2 );
6932         const WCHAR *version_max = MSI_RecordGetString( rec, 3 );
6933         const WCHAR *language = MSI_RecordGetString( rec, 4 );
6934         HKEY hkey;
6935         UINT r;
6936
6937         if (package->Context == MSIINSTALLCONTEXT_MACHINE)
6938         {
6939             r = MSIREG_OpenClassesUpgradeCodesKey( upgrade_code, &hkey, FALSE );
6940             if (r != ERROR_SUCCESS)
6941                 return ERROR_SUCCESS;
6942         }
6943         else
6944         {
6945             r = MSIREG_OpenUserUpgradeCodesKey( upgrade_code, &hkey, FALSE );
6946             if (r != ERROR_SUCCESS)
6947                 return ERROR_SUCCESS;
6948         }
6949         RegCloseKey( hkey );
6950
6951         FIXME("migrate feature states from %s version min %s version max %s language %s\n",
6952               debugstr_w(upgrade_code), debugstr_w(version_min),
6953               debugstr_w(version_max), debugstr_w(language));
6954     }
6955     return ERROR_SUCCESS;
6956 }
6957
6958 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6959 {
6960     static const WCHAR query[] = {
6961         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6962         'U','p','g','r','a','d','e',0};
6963     MSIQUERY *view;
6964     UINT r;
6965
6966     if (msi_get_property_int( package->db, szInstalled, 0 ))
6967     {
6968         TRACE("product is installed, skipping action\n");
6969         return ERROR_SUCCESS;
6970     }
6971     if (msi_get_property_int( package->db, szPreselected, 0 ))
6972     {
6973         TRACE("Preselected property is set, not migrating feature states\n");
6974         return ERROR_SUCCESS;
6975     }
6976     r = MSI_DatabaseOpenViewW( package->db, query, &view );
6977     if (r == ERROR_SUCCESS)
6978     {
6979         r = MSI_IterateRecords( view, NULL, ITERATE_MigrateFeatureStates, package );
6980         msiobj_release( &view->hdr );
6981         if (r != ERROR_SUCCESS)
6982             return r;
6983     }
6984     return ERROR_SUCCESS;
6985 }
6986
6987 static void bind_image( const char *filename, const char *path )
6988 {
6989     if (!BindImageEx( 0, filename, path, NULL, NULL ))
6990     {
6991         WARN("failed to bind image %u\n", GetLastError());
6992     }
6993 }
6994
6995 static UINT ITERATE_BindImage( MSIRECORD *rec, LPVOID param )
6996 {
6997     UINT i;
6998     MSIFILE *file;
6999     MSIPACKAGE *package = param;
7000     const WCHAR *key = MSI_RecordGetString( rec, 1 );
7001     const WCHAR *paths = MSI_RecordGetString( rec, 2 );
7002     char *filenameA, *pathA;
7003     WCHAR *pathW, **path_list;
7004
7005     if (!(file = msi_get_loaded_file( package, key )))
7006     {
7007         WARN("file %s not found\n", debugstr_w(key));
7008         return ERROR_SUCCESS;
7009     }
7010     if (!(filenameA = strdupWtoA( file->TargetPath ))) return ERROR_SUCCESS;
7011     path_list = msi_split_string( paths, ';' );
7012     if (!path_list) bind_image( filenameA, NULL );
7013     else
7014     {
7015         for (i = 0; path_list[i] && path_list[i][0]; i++)
7016         {
7017             deformat_string( package, path_list[i], &pathW );
7018             if ((pathA = strdupWtoA( pathW )))
7019             {
7020                 bind_image( filenameA, pathA );
7021                 msi_free( pathA );
7022             }
7023             msi_free( pathW );
7024         }
7025     }
7026     msi_free( path_list );
7027     msi_free( filenameA );
7028     return ERROR_SUCCESS;
7029 }
7030
7031 static UINT ACTION_BindImage( MSIPACKAGE *package )
7032 {
7033     static const WCHAR query[] = {
7034         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7035         'B','i','n','d','I','m','a','g','e',0};
7036     MSIQUERY *view;
7037     UINT r;
7038
7039     r = MSI_DatabaseOpenViewW( package->db, query, &view );
7040     if (r == ERROR_SUCCESS)
7041     {
7042         r = MSI_IterateRecords( view, NULL, ITERATE_BindImage, package );
7043         msiobj_release( &view->hdr );
7044         if (r != ERROR_SUCCESS)
7045             return r;
7046     }
7047     return ERROR_SUCCESS;
7048 }
7049
7050 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package, LPCSTR action, LPCWSTR table )
7051 {
7052     static const WCHAR query[] = {
7053         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','`','%','s','`',0};
7054     MSIQUERY *view;
7055     DWORD count = 0;
7056     UINT r;
7057     
7058     r = MSI_OpenQuery( package->db, &view, query, table );
7059     if (r == ERROR_SUCCESS)
7060     {
7061         r = MSI_IterateRecords(view, &count, NULL, package);
7062         msiobj_release(&view->hdr);
7063         if (r != ERROR_SUCCESS)
7064             return r;
7065     }
7066     if (count) FIXME("%s: ignored %u rows from %s\n", action, count, debugstr_w(table));
7067     return ERROR_SUCCESS;
7068 }
7069
7070 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
7071 {
7072     static const WCHAR table[] = {
7073         'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
7074     return msi_unimplemented_action_stub( package, "IsolateComponents", table );
7075 }
7076
7077 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
7078 {
7079     static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
7080     return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
7081 }
7082
7083 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
7084 {
7085     static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7086     return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
7087 }
7088
7089 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
7090 {
7091     static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
7092     return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
7093 }
7094
7095 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
7096 {
7097     static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
7098     return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
7099 }
7100
7101 static const struct
7102 {
7103     const WCHAR *action;
7104     UINT (*handler)(MSIPACKAGE *);
7105     const WCHAR *action_rollback;
7106 }
7107 StandardActions[] =
7108 {
7109     { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace, NULL },
7110     { szAppSearch, ACTION_AppSearch, NULL },
7111     { szBindImage, ACTION_BindImage, NULL },
7112     { szCCPSearch, ACTION_CCPSearch, NULL },
7113     { szCostFinalize, ACTION_CostFinalize, NULL },
7114     { szCostInitialize, ACTION_CostInitialize, NULL },
7115     { szCreateFolders, ACTION_CreateFolders, szRemoveFolders },
7116     { szCreateShortcuts, ACTION_CreateShortcuts, szRemoveShortcuts },
7117     { szDeleteServices, ACTION_DeleteServices, szInstallServices },
7118     { szDisableRollback, ACTION_DisableRollback, NULL },
7119     { szDuplicateFiles, ACTION_DuplicateFiles, szRemoveDuplicateFiles },
7120     { szExecuteAction, ACTION_ExecuteAction, NULL },
7121     { szFileCost, ACTION_FileCost, NULL },
7122     { szFindRelatedProducts, ACTION_FindRelatedProducts, NULL },
7123     { szForceReboot, ACTION_ForceReboot, NULL },
7124     { szInstallAdminPackage, ACTION_InstallAdminPackage, NULL },
7125     { szInstallExecute, ACTION_InstallExecute, NULL },
7126     { szInstallExecuteAgain, ACTION_InstallExecute, NULL },
7127     { szInstallFiles, ACTION_InstallFiles, szRemoveFiles },
7128     { szInstallFinalize, ACTION_InstallFinalize, NULL },
7129     { szInstallInitialize, ACTION_InstallInitialize, NULL },
7130     { szInstallODBC, ACTION_InstallODBC, szRemoveODBC },
7131     { szInstallServices, ACTION_InstallServices, szDeleteServices },
7132     { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile, NULL },
7133     { szInstallValidate, ACTION_InstallValidate, NULL },
7134     { szIsolateComponents, ACTION_IsolateComponents, NULL },
7135     { szLaunchConditions, ACTION_LaunchConditions, NULL },
7136     { szMigrateFeatureStates, ACTION_MigrateFeatureStates, NULL },
7137     { szMoveFiles, ACTION_MoveFiles, NULL },
7138     { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies, szMsiUnpublishAssemblies },
7139     { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies, szMsiPublishAssemblies },
7140     { szPatchFiles, ACTION_PatchFiles, NULL },
7141     { szProcessComponents, ACTION_ProcessComponents, szProcessComponents },
7142     { szPublishComponents, ACTION_PublishComponents, szUnpublishComponents },
7143     { szPublishFeatures, ACTION_PublishFeatures, szUnpublishFeatures },
7144     { szPublishProduct, ACTION_PublishProduct, NULL },
7145     { szRegisterClassInfo, ACTION_RegisterClassInfo, szUnregisterClassInfo },
7146     { szRegisterComPlus, ACTION_RegisterComPlus, szUnregisterComPlus },
7147     { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo, szUnregisterExtensionInfo },
7148     { szRegisterFonts, ACTION_RegisterFonts, szUnregisterFonts },
7149     { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo, szUnregisterMIMEInfo },
7150     { szRegisterProduct, ACTION_RegisterProduct, NULL },
7151     { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo, szUnregisterProgIdInfo },
7152     { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries, szUnregisterTypeLibraries },
7153     { szRegisterUser, ACTION_RegisterUser, NULL },
7154     { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles, szDuplicateFiles },
7155     { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings, szWriteEnvironmentStrings },
7156     { szRemoveExistingProducts, ACTION_RemoveExistingProducts, NULL },
7157     { szRemoveFiles, ACTION_RemoveFiles, szInstallFiles },
7158     { szRemoveFolders, ACTION_RemoveFolders, szCreateFolders },
7159     { szRemoveIniValues, ACTION_RemoveIniValues, szWriteIniValues },
7160     { szRemoveODBC, ACTION_RemoveODBC, szInstallODBC },
7161     { szRemoveRegistryValues, ACTION_RemoveRegistryValues, szWriteRegistryValues },
7162     { szRemoveShortcuts, ACTION_RemoveShortcuts, szCreateShortcuts },
7163     { szResolveSource, ACTION_ResolveSource, NULL },
7164     { szRMCCPSearch, ACTION_RMCCPSearch, NULL },
7165     { szScheduleReboot, ACTION_ScheduleReboot, NULL },
7166     { szSelfRegModules, ACTION_SelfRegModules, szSelfUnregModules },
7167     { szSelfUnregModules, ACTION_SelfUnregModules, szSelfUnregModules },
7168     { szSetODBCFolders, ACTION_SetODBCFolders, NULL },
7169     { szStartServices, ACTION_StartServices, szStopServices },
7170     { szStopServices, ACTION_StopServices, szStartServices },
7171     { szUnpublishComponents, ACTION_UnpublishComponents, szPublishComponents },
7172     { szUnpublishFeatures, ACTION_UnpublishFeatures, szPublishFeatures },
7173     { szUnregisterClassInfo, ACTION_UnregisterClassInfo, szRegisterClassInfo },
7174     { szUnregisterComPlus, ACTION_UnregisterComPlus, szRegisterComPlus },
7175     { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo, szRegisterExtensionInfo },
7176     { szUnregisterFonts, ACTION_UnregisterFonts, szRegisterFonts },
7177     { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo, szRegisterMIMEInfo },
7178     { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo, szRegisterProgIdInfo },
7179     { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries, szRegisterTypeLibraries },
7180     { szValidateProductID, ACTION_ValidateProductID, NULL },
7181     { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings, szRemoveEnvironmentStrings },
7182     { szWriteIniValues, ACTION_WriteIniValues, szRemoveIniValues },
7183     { szWriteRegistryValues, ACTION_WriteRegistryValues, szRemoveRegistryValues },
7184     { NULL, NULL, NULL }
7185 };
7186
7187 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
7188 {
7189     BOOL ret = FALSE;
7190     UINT i;
7191
7192     i = 0;
7193     while (StandardActions[i].action != NULL)
7194     {
7195         if (!strcmpW( StandardActions[i].action, action ))
7196         {
7197             ui_actionstart( package, action );
7198             if (StandardActions[i].handler)
7199             {
7200                 ui_actioninfo( package, action, TRUE, 0 );
7201                 *rc = StandardActions[i].handler( package );
7202                 ui_actioninfo( package, action, FALSE, *rc );
7203
7204                 if (StandardActions[i].action_rollback && !package->need_rollback)
7205                 {
7206                     TRACE("scheduling rollback action\n");
7207                     msi_schedule_action( package, ROLLBACK_SCRIPT, StandardActions[i].action_rollback );
7208                 }
7209             }
7210             else
7211             {
7212                 FIXME("unhandled standard action %s\n", debugstr_w(action));
7213                 *rc = ERROR_SUCCESS;
7214             }
7215             ret = TRUE;
7216             break;
7217         }
7218         i++;
7219     }
7220     return ret;
7221 }
7222
7223 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7224 {
7225     UINT rc = ERROR_SUCCESS;
7226     BOOL handled;
7227
7228     TRACE("Performing action (%s)\n", debugstr_w(action));
7229
7230     handled = ACTION_HandleStandardAction(package, action, &rc);
7231
7232     if (!handled)
7233         handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7234
7235     if (!handled)
7236     {
7237         WARN("unhandled msi action %s\n", debugstr_w(action));
7238         rc = ERROR_FUNCTION_NOT_CALLED;
7239     }
7240
7241     return rc;
7242 }
7243
7244 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7245 {
7246     UINT rc = ERROR_SUCCESS;
7247     BOOL handled = FALSE;
7248
7249     TRACE("Performing action (%s)\n", debugstr_w(action));
7250
7251     handled = ACTION_HandleStandardAction(package, action, &rc);
7252
7253     if (!handled)
7254         handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7255
7256     if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7257         handled = TRUE;
7258
7259     if (!handled)
7260     {
7261         WARN("unhandled msi action %s\n", debugstr_w(action));
7262         rc = ERROR_FUNCTION_NOT_CALLED;
7263     }
7264
7265     return rc;
7266 }
7267
7268 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7269 {
7270     UINT rc = ERROR_SUCCESS;
7271     MSIRECORD *row;
7272
7273     static const WCHAR query[] =
7274         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7275          '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7276          'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7277          '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7278     static const WCHAR ui_query[] =
7279         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7280      '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7281      '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7282          ' ', '=',' ','%','i',0};
7283
7284     if (needs_ui_sequence(package))
7285         row = MSI_QueryGetRecord(package->db, ui_query, seq);
7286     else
7287         row = MSI_QueryGetRecord(package->db, query, seq);
7288
7289     if (row)
7290     {
7291         LPCWSTR action, cond;
7292
7293         TRACE("Running the actions\n");
7294
7295         /* check conditions */
7296         cond = MSI_RecordGetString(row, 2);
7297
7298         /* this is a hack to skip errors in the condition code */
7299         if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7300         {
7301             msiobj_release(&row->hdr);
7302             return ERROR_SUCCESS;
7303         }
7304
7305         action = MSI_RecordGetString(row, 1);
7306         if (!action)
7307         {
7308             ERR("failed to fetch action\n");
7309             msiobj_release(&row->hdr);
7310             return ERROR_FUNCTION_FAILED;
7311         }
7312
7313         if (needs_ui_sequence(package))
7314             rc = ACTION_PerformUIAction(package, action, -1);
7315         else
7316             rc = ACTION_PerformAction(package, action, -1);
7317
7318         msiobj_release(&row->hdr);
7319     }
7320
7321     return rc;
7322 }
7323
7324 /****************************************************
7325  * TOP level entry points
7326  *****************************************************/
7327
7328 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7329                          LPCWSTR szCommandLine )
7330 {
7331     UINT rc;
7332     BOOL ui_exists;
7333     static const WCHAR szDisableRollback[] = {'D','I','S','A','B','L','E','R','O','L','L','B','A','C','K',0};
7334     static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7335     static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7336
7337     msi_set_property( package->db, szAction, szInstall );
7338
7339     package->script->InWhatSequence = SEQUENCE_INSTALL;
7340
7341     if (szPackagePath)
7342     {
7343         LPWSTR p, dir;
7344         LPCWSTR file;
7345
7346         dir = strdupW(szPackagePath);
7347         p = strrchrW(dir, '\\');
7348         if (p)
7349         {
7350             *(++p) = 0;
7351             file = szPackagePath + (p - dir);
7352         }
7353         else
7354         {
7355             msi_free(dir);
7356             dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7357             GetCurrentDirectoryW(MAX_PATH, dir);
7358             lstrcatW(dir, szBackSlash);
7359             file = szPackagePath;
7360         }
7361
7362         msi_free( package->PackagePath );
7363         package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7364         if (!package->PackagePath)
7365         {
7366             msi_free(dir);
7367             return ERROR_OUTOFMEMORY;
7368         }
7369
7370         lstrcpyW(package->PackagePath, dir);
7371         lstrcatW(package->PackagePath, file);
7372         msi_free(dir);
7373
7374         msi_set_sourcedir_props(package, FALSE);
7375     }
7376
7377     rc = msi_parse_command_line( package, szCommandLine, FALSE );
7378     if (rc != ERROR_SUCCESS)
7379         return rc;
7380
7381     msi_apply_transforms( package );
7382     msi_apply_patches( package );
7383
7384     if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7385     {
7386         TRACE("setting reinstall property\n");
7387         msi_set_property( package->db, szReinstall, szAll );
7388     }
7389
7390     /* properties may have been added by a transform */
7391     msi_clone_properties( package );
7392
7393     msi_parse_command_line( package, szCommandLine, FALSE );
7394     msi_adjust_privilege_properties( package );
7395     msi_set_context( package );
7396
7397     if (msi_get_property_int( package->db, szInstalled, 0 ))
7398     {
7399         HKEY hkey;
7400         DeleteFileW( package->localfile );
7401         msi_free( package->localfile );
7402         MSIREG_OpenInstallProps( package->ProductCode, package->Context, NULL, &hkey, FALSE );
7403         package->localfile = msi_reg_get_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW );
7404         RegCloseKey( hkey );
7405     }
7406     if (msi_get_property_int( package->db, szDisableRollback, 0 ))
7407     {
7408         TRACE("disabling rollback\n");
7409         msi_set_property( package->db, szRollbackDisabled, szOne );
7410     }
7411
7412     if (needs_ui_sequence( package))
7413     {
7414         package->script->InWhatSequence |= SEQUENCE_UI;
7415         rc = ACTION_ProcessUISequence(package);
7416         ui_exists = ui_sequence_exists(package);
7417         if (rc == ERROR_SUCCESS || !ui_exists)
7418         {
7419             package->script->InWhatSequence |= SEQUENCE_EXEC;
7420             rc = ACTION_ProcessExecSequence(package, ui_exists);
7421         }
7422     }
7423     else
7424         rc = ACTION_ProcessExecSequence(package, FALSE);
7425
7426     package->script->CurrentlyScripting = FALSE;
7427
7428     /* process the ending type action */
7429     if (rc == ERROR_SUCCESS)
7430         ACTION_PerformActionSequence(package, -1);
7431     else if (rc == ERROR_INSTALL_USEREXIT)
7432         ACTION_PerformActionSequence(package, -2);
7433     else if (rc == ERROR_INSTALL_SUSPEND)
7434         ACTION_PerformActionSequence(package, -4);
7435     else  /* failed */
7436     {
7437         ACTION_PerformActionSequence(package, -3);
7438         if (!msi_get_property_int( package->db, szRollbackDisabled, 0 ))
7439         {
7440             package->need_rollback = TRUE;
7441         }
7442     }
7443
7444     /* finish up running custom actions */
7445     ACTION_FinishCustomActions(package);
7446
7447     if (package->need_rollback)
7448     {
7449         WARN("installation failed, running rollback script\n");
7450         execute_script( package, ROLLBACK_SCRIPT );
7451     }
7452
7453     if (rc == ERROR_SUCCESS && package->need_reboot)
7454         return ERROR_SUCCESS_REBOOT_REQUIRED;
7455
7456     return rc;
7457 }