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