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