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