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