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