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