activeds: Properly stub some exports.
[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                 file = get_loaded_file(package, comp->KeyPath);
3249                 if (!file)
3250                     continue;
3251
3252                 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
3253                 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
3254                 ptr2 = strrchrW(source, '\\') + 1;
3255                 msiobj_release(&row->hdr);
3256
3257                 lstrcpyW(base, package->PackagePath);
3258                 ptr = strrchrW(base, '\\');
3259                 *(ptr + 1) = '\0';
3260
3261                 sourcepath = resolve_file_source(package, file);
3262                 ptr = sourcepath + lstrlenW(base);
3263                 lstrcpyW(ptr2, ptr);
3264                 msi_free(sourcepath);
3265
3266                 msi_reg_set_val_str(hkey, squished_pc, source);
3267             }
3268             RegCloseKey(hkey);
3269         }
3270         else if (comp->ActionRequest == INSTALLSTATE_ABSENT)
3271         {
3272             if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3273                 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
3274             else
3275                 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
3276         }
3277         comp->Action = comp->ActionRequest;
3278
3279         /* UI stuff */
3280         uirow = MSI_CreateRecord(3);
3281         MSI_RecordSetStringW(uirow,1,package->ProductCode);
3282         MSI_RecordSetStringW(uirow,2,comp->ComponentId);
3283         MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
3284         ui_actiondata(package,szProcessComponents,uirow);
3285         msiobj_release( &uirow->hdr );
3286     }
3287
3288     return ERROR_SUCCESS;
3289 }
3290
3291 typedef struct {
3292     CLSID       clsid;
3293     LPWSTR      source;
3294
3295     LPWSTR      path;
3296     ITypeLib    *ptLib;
3297 } typelib_struct;
3298
3299 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType, 
3300                                        LPWSTR lpszName, LONG_PTR lParam)
3301 {
3302     TLIBATTR *attr;
3303     typelib_struct *tl_struct = (typelib_struct*) lParam;
3304     static const WCHAR fmt[] = {'%','s','\\','%','i',0};
3305     int sz; 
3306     HRESULT res;
3307
3308     if (!IS_INTRESOURCE(lpszName))
3309     {
3310         ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
3311         return TRUE;
3312     }
3313
3314     sz = strlenW(tl_struct->source)+4;
3315     sz *= sizeof(WCHAR);
3316
3317     if ((INT_PTR)lpszName == 1)
3318         tl_struct->path = strdupW(tl_struct->source);
3319     else
3320     {
3321         tl_struct->path = msi_alloc(sz);
3322         sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
3323     }
3324
3325     TRACE("trying %s\n", debugstr_w(tl_struct->path));
3326     res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
3327     if (FAILED(res))
3328     {
3329         msi_free(tl_struct->path);
3330         tl_struct->path = NULL;
3331
3332         return TRUE;
3333     }
3334
3335     ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
3336     if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
3337     {
3338         ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3339         return FALSE;
3340     }
3341
3342     msi_free(tl_struct->path);
3343     tl_struct->path = NULL;
3344
3345     ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
3346     ITypeLib_Release(tl_struct->ptLib);
3347
3348     return TRUE;
3349 }
3350
3351 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
3352 {
3353     MSIPACKAGE* package = param;
3354     LPCWSTR component;
3355     MSICOMPONENT *comp;
3356     MSIFILE *file;
3357     typelib_struct tl_struct;
3358     ITypeLib *tlib;
3359     HMODULE module;
3360     HRESULT hr;
3361
3362     component = MSI_RecordGetString(row,3);
3363     comp = get_loaded_component(package,component);
3364     if (!comp)
3365         return ERROR_SUCCESS;
3366
3367     if (!comp->Enabled)
3368     {
3369         TRACE("component is disabled\n");
3370         return ERROR_SUCCESS;
3371     }
3372
3373     if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3374     {
3375         TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
3376         comp->Action = comp->Installed;
3377         return ERROR_SUCCESS;
3378     }
3379     comp->Action = INSTALLSTATE_LOCAL;
3380
3381     if (!comp->KeyPath || !(file = get_loaded_file( package, comp->KeyPath )))
3382     {
3383         TRACE("component has no key path\n");
3384         return ERROR_SUCCESS;
3385     }
3386     ui_actiondata( package, szRegisterTypeLibraries, row );
3387
3388     module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
3389     if (module)
3390     {
3391         LPCWSTR guid;
3392         guid = MSI_RecordGetString(row,1);
3393         CLSIDFromString((LPCWSTR)guid, &tl_struct.clsid);
3394         tl_struct.source = strdupW( file->TargetPath );
3395         tl_struct.path = NULL;
3396
3397         EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
3398                         (LONG_PTR)&tl_struct);
3399
3400         if (tl_struct.path)
3401         {
3402             LPWSTR help = NULL;
3403             LPCWSTR helpid;
3404             HRESULT res;
3405
3406             helpid = MSI_RecordGetString(row,6);
3407
3408             if (helpid)
3409                 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
3410             res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
3411             msi_free(help);
3412
3413             if (FAILED(res))
3414                 ERR("Failed to register type library %s\n",
3415                         debugstr_w(tl_struct.path));
3416             else
3417                 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
3418
3419             ITypeLib_Release(tl_struct.ptLib);
3420             msi_free(tl_struct.path);
3421         }
3422         else
3423             ERR("Failed to load type library %s\n",
3424                     debugstr_w(tl_struct.source));
3425
3426         FreeLibrary(module);
3427         msi_free(tl_struct.source);
3428     }
3429     else
3430     {
3431         hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
3432         if (FAILED(hr))
3433         {
3434             ERR("Failed to load type library: %08x\n", hr);
3435             return ERROR_INSTALL_FAILURE;
3436         }
3437
3438         ITypeLib_Release(tlib);
3439     }
3440
3441     return ERROR_SUCCESS;
3442 }
3443
3444 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
3445 {
3446     /* 
3447      * OK this is a bit confusing.. I am given a _Component key and I believe
3448      * that the file that is being registered as a type library is the "key file
3449      * of that component" which I interpret to mean "The file in the KeyPath of
3450      * that component".
3451      */
3452     UINT rc;
3453     MSIQUERY * view;
3454     static const WCHAR Query[] =
3455         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3456          '`','T','y','p','e','L','i','b','`',0};
3457
3458     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3459     if (rc != ERROR_SUCCESS)
3460         return ERROR_SUCCESS;
3461
3462     rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
3463     msiobj_release(&view->hdr);
3464     return rc;
3465 }
3466
3467 static UINT ITERATE_UnregisterTypeLibraries( MSIRECORD *row, LPVOID param )
3468 {
3469     MSIPACKAGE *package = param;
3470     LPCWSTR component, guid;
3471     MSICOMPONENT *comp;
3472     GUID libid;
3473     UINT version;
3474     LCID language;
3475     SYSKIND syskind;
3476     HRESULT hr;
3477
3478     component = MSI_RecordGetString( row, 3 );
3479     comp = get_loaded_component( package, component );
3480     if (!comp)
3481         return ERROR_SUCCESS;
3482
3483     if (!comp->Enabled)
3484     {
3485         TRACE("component is disabled\n");
3486         return ERROR_SUCCESS;
3487     }
3488
3489     if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3490     {
3491         TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3492         comp->Action = comp->Installed;
3493         return ERROR_SUCCESS;
3494     }
3495     comp->Action = INSTALLSTATE_ABSENT;
3496
3497     ui_actiondata( package, szUnregisterTypeLibraries, row );
3498
3499     guid = MSI_RecordGetString( row, 1 );
3500     CLSIDFromString( (LPCWSTR)guid, &libid );
3501     version = MSI_RecordGetInteger( row, 4 );
3502     language = MSI_RecordGetInteger( row, 2 );
3503
3504 #ifdef _WIN64
3505     syskind = SYS_WIN64;
3506 #else
3507     syskind = SYS_WIN32;
3508 #endif
3509
3510     hr = UnRegisterTypeLib( &libid, (version >> 8) & 0xffff, version & 0xff, language, syskind );
3511     if (FAILED(hr))
3512     {
3513         WARN("Failed to unregister typelib: %08x\n", hr);
3514     }
3515
3516     return ERROR_SUCCESS;
3517 }
3518
3519 static UINT ACTION_UnregisterTypeLibraries( MSIPACKAGE *package )
3520 {
3521     UINT rc;
3522     MSIQUERY *view;
3523     static const WCHAR query[] =
3524         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3525          '`','T','y','p','e','L','i','b','`',0};
3526
3527     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3528     if (rc != ERROR_SUCCESS)
3529         return ERROR_SUCCESS;
3530
3531     rc = MSI_IterateRecords( view, NULL, ITERATE_UnregisterTypeLibraries, package );
3532     msiobj_release( &view->hdr );
3533     return rc;
3534 }
3535
3536 static WCHAR *get_link_file( MSIPACKAGE *package, MSIRECORD *row )
3537 {
3538     static const WCHAR szlnk[] = {'.','l','n','k',0};
3539     LPCWSTR directory, extension;
3540     LPWSTR link_folder, link_file, filename;
3541
3542     directory = MSI_RecordGetString( row, 2 );
3543     link_folder = resolve_folder( package, directory, FALSE, FALSE, TRUE, NULL );
3544
3545     /* may be needed because of a bug somewhere else */
3546     create_full_pathW( link_folder );
3547
3548     filename = msi_dup_record_field( row, 3 );
3549     reduce_to_longfilename( filename );
3550
3551     extension = strchrW( filename, '.' );
3552     if (!extension || strcmpiW( extension, szlnk ))
3553     {
3554         int len = strlenW( filename );
3555         filename = msi_realloc( filename, len * sizeof(WCHAR) + sizeof(szlnk) );
3556         memcpy( filename + len, szlnk, sizeof(szlnk) );
3557     }
3558     link_file = build_directory_name( 2, link_folder, filename );
3559     msi_free( link_folder );
3560     msi_free( filename );
3561
3562     return link_file;
3563 }
3564
3565 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
3566 {
3567     MSIPACKAGE *package = param;
3568     LPWSTR link_file, deformated, path;
3569     LPCWSTR component, target;
3570     MSICOMPONENT *comp;
3571     IShellLinkW *sl = NULL;
3572     IPersistFile *pf = NULL;
3573     HRESULT res;
3574
3575     component = MSI_RecordGetString(row, 4);
3576     comp = get_loaded_component(package, component);
3577     if (!comp)
3578         return ERROR_SUCCESS;
3579
3580     if (!comp->Enabled)
3581     {
3582         TRACE("component is disabled\n");
3583         return ERROR_SUCCESS;
3584     }
3585
3586     if (comp->ActionRequest != INSTALLSTATE_LOCAL)
3587     {
3588         TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
3589         comp->Action = comp->Installed;
3590         return ERROR_SUCCESS;
3591     }
3592     comp->Action = INSTALLSTATE_LOCAL;
3593
3594     ui_actiondata(package,szCreateShortcuts,row);
3595
3596     res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
3597                     &IID_IShellLinkW, (LPVOID *) &sl );
3598
3599     if (FAILED( res ))
3600     {
3601         ERR("CLSID_ShellLink not available\n");
3602         goto err;
3603     }
3604
3605     res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
3606     if (FAILED( res ))
3607     {
3608         ERR("QueryInterface(IID_IPersistFile) failed\n");
3609         goto err;
3610     }
3611
3612     target = MSI_RecordGetString(row, 5);
3613     if (strchrW(target, '['))
3614     {
3615         deformat_string(package, target, &deformated);
3616         IShellLinkW_SetPath(sl,deformated);
3617         msi_free(deformated);
3618     }
3619     else
3620     {
3621         FIXME("poorly handled shortcut format, advertised shortcut\n");
3622         IShellLinkW_SetPath(sl,comp->FullKeypath);
3623     }
3624
3625     if (!MSI_RecordIsNull(row,6))
3626     {
3627         LPCWSTR arguments = MSI_RecordGetString(row, 6);
3628         deformat_string(package, arguments, &deformated);
3629         IShellLinkW_SetArguments(sl,deformated);
3630         msi_free(deformated);
3631     }
3632
3633     if (!MSI_RecordIsNull(row,7))
3634     {
3635         LPCWSTR description = MSI_RecordGetString(row, 7);
3636         IShellLinkW_SetDescription(sl, description);
3637     }
3638
3639     if (!MSI_RecordIsNull(row,8))
3640         IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3641
3642     if (!MSI_RecordIsNull(row,9))
3643     {
3644         INT index; 
3645         LPCWSTR icon = MSI_RecordGetString(row, 9);
3646
3647         path = build_icon_path(package, icon);
3648         index = MSI_RecordGetInteger(row,10);
3649
3650         /* no value means 0 */
3651         if (index == MSI_NULL_INTEGER)
3652             index = 0;
3653
3654         IShellLinkW_SetIconLocation(sl, path, index);
3655         msi_free(path);
3656     }
3657
3658     if (!MSI_RecordIsNull(row,11))
3659         IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3660
3661     if (!MSI_RecordIsNull(row,12))
3662     {
3663         LPCWSTR wkdir = MSI_RecordGetString(row, 12);
3664         path = resolve_folder(package, wkdir, FALSE, FALSE, TRUE, NULL);
3665         if (path)
3666             IShellLinkW_SetWorkingDirectory(sl, path);
3667         msi_free(path);
3668     }
3669
3670     link_file = get_link_file(package, row);
3671
3672     TRACE("Writing shortcut to %s\n", debugstr_w(link_file));
3673     IPersistFile_Save(pf, link_file, FALSE);
3674
3675     msi_free(link_file);
3676
3677 err:
3678     if (pf)
3679         IPersistFile_Release( pf );
3680     if (sl)
3681         IShellLinkW_Release( sl );
3682
3683     return ERROR_SUCCESS;
3684 }
3685
3686 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3687 {
3688     UINT rc;
3689     HRESULT res;
3690     MSIQUERY * view;
3691     static const WCHAR Query[] =
3692         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3693          '`','S','h','o','r','t','c','u','t','`',0};
3694
3695     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3696     if (rc != ERROR_SUCCESS)
3697         return ERROR_SUCCESS;
3698
3699     res = CoInitialize( NULL );
3700
3701     rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3702     msiobj_release(&view->hdr);
3703
3704     if (SUCCEEDED(res))
3705         CoUninitialize();
3706
3707     return rc;
3708 }
3709
3710 static UINT ITERATE_RemoveShortcuts( MSIRECORD *row, LPVOID param )
3711 {
3712     MSIPACKAGE *package = param;
3713     LPWSTR link_file;
3714     LPCWSTR component;
3715     MSICOMPONENT *comp;
3716
3717     component = MSI_RecordGetString( row, 4 );
3718     comp = get_loaded_component( package, component );
3719     if (!comp)
3720         return ERROR_SUCCESS;
3721
3722     if (!comp->Enabled)
3723     {
3724         TRACE("component is disabled\n");
3725         return ERROR_SUCCESS;
3726     }
3727
3728     if (comp->ActionRequest != INSTALLSTATE_ABSENT)
3729     {
3730         TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
3731         comp->Action = comp->Installed;
3732         return ERROR_SUCCESS;
3733     }
3734     comp->Action = INSTALLSTATE_ABSENT;
3735
3736     ui_actiondata( package, szRemoveShortcuts, row );
3737
3738     link_file = get_link_file( package, row );
3739
3740     TRACE("Removing shortcut file %s\n", debugstr_w( link_file ));
3741     if (!DeleteFileW( link_file ))
3742     {
3743         WARN("Failed to remove shortcut file %u\n", GetLastError());
3744     }
3745     msi_free( link_file );
3746
3747     return ERROR_SUCCESS;
3748 }
3749
3750 static UINT ACTION_RemoveShortcuts( MSIPACKAGE *package )
3751 {
3752     UINT rc;
3753     MSIQUERY *view;
3754     static const WCHAR query[] =
3755         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3756          '`','S','h','o','r','t','c','u','t','`',0};
3757
3758     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
3759     if (rc != ERROR_SUCCESS)
3760         return ERROR_SUCCESS;
3761
3762     rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveShortcuts, package );
3763     msiobj_release( &view->hdr );
3764
3765     return rc;
3766 }
3767
3768 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3769 {
3770     MSIPACKAGE* package = param;
3771     HANDLE the_file;
3772     LPWSTR FilePath;
3773     LPCWSTR FileName;
3774     CHAR buffer[1024];
3775     DWORD sz;
3776     UINT rc;
3777
3778     FileName = MSI_RecordGetString(row,1);
3779     if (!FileName)
3780     {
3781         ERR("Unable to get FileName\n");
3782         return ERROR_SUCCESS;
3783     }
3784
3785     FilePath = build_icon_path(package,FileName);
3786
3787     TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3788
3789     the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3790                         FILE_ATTRIBUTE_NORMAL, NULL);
3791
3792     if (the_file == INVALID_HANDLE_VALUE)
3793     {
3794         ERR("Unable to create file %s\n",debugstr_w(FilePath));
3795         msi_free(FilePath);
3796         return ERROR_SUCCESS;
3797     }
3798
3799     do 
3800     {
3801         DWORD write;
3802         sz = 1024;
3803         rc = MSI_RecordReadStream(row,2,buffer,&sz);
3804         if (rc != ERROR_SUCCESS)
3805         {
3806             ERR("Failed to get stream\n");
3807             CloseHandle(the_file);  
3808             DeleteFileW(FilePath);
3809             break;
3810         }
3811         WriteFile(the_file,buffer,sz,&write,NULL);
3812     } while (sz == 1024);
3813
3814     msi_free(FilePath);
3815     CloseHandle(the_file);
3816
3817     return ERROR_SUCCESS;
3818 }
3819
3820 static UINT msi_publish_icons(MSIPACKAGE *package)
3821 {
3822     UINT r;
3823     MSIQUERY *view;
3824
3825     static const WCHAR query[]= {
3826         'S','E','L','E','C','T',' ','*',' ',
3827         'F','R','O','M',' ','`','I','c','o','n','`',0};
3828
3829     r = MSI_DatabaseOpenViewW(package->db, query, &view);
3830     if (r == ERROR_SUCCESS)
3831     {
3832         MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3833         msiobj_release(&view->hdr);
3834     }
3835
3836     return ERROR_SUCCESS;
3837 }
3838
3839 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3840 {
3841     UINT r;
3842     HKEY source;
3843     LPWSTR buffer;
3844     MSIMEDIADISK *disk;
3845     MSISOURCELISTINFO *info;
3846
3847     r = RegCreateKeyW(hkey, szSourceList, &source);
3848     if (r != ERROR_SUCCESS)
3849         return r;
3850
3851     RegCloseKey(source);
3852
3853     buffer = strrchrW(package->PackagePath, '\\') + 1;
3854     r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3855                               package->Context, MSICODE_PRODUCT,
3856                               INSTALLPROPERTY_PACKAGENAMEW, buffer);
3857     if (r != ERROR_SUCCESS)
3858         return r;
3859
3860     r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3861                               package->Context, MSICODE_PRODUCT,
3862                               INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3863     if (r != ERROR_SUCCESS)
3864         return r;
3865
3866     r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3867                               package->Context, MSICODE_PRODUCT,
3868                               INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3869     if (r != ERROR_SUCCESS)
3870         return r;
3871
3872     LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3873     {
3874         if (!strcmpW( info->property, INSTALLPROPERTY_LASTUSEDSOURCEW ))
3875             msi_set_last_used_source(package->ProductCode, NULL, info->context,
3876                                      info->options, info->value);
3877         else
3878             MsiSourceListSetInfoW(package->ProductCode, NULL,
3879                                   info->context, info->options,
3880                                   info->property, info->value);
3881     }
3882
3883     LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3884     {
3885         MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3886                                    disk->context, disk->options,
3887                                    disk->disk_id, disk->volume_label, disk->disk_prompt);
3888     }
3889
3890     return ERROR_SUCCESS;
3891 }
3892
3893 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3894 {
3895     MSIHANDLE hdb, suminfo;
3896     WCHAR guids[MAX_PATH];
3897     WCHAR packcode[SQUISH_GUID_SIZE];
3898     LPWSTR buffer;
3899     LPWSTR ptr;
3900     DWORD langid;
3901     DWORD size;
3902     UINT r;
3903
3904     static const WCHAR szProductLanguage[] =
3905         {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3906     static const WCHAR szARPProductIcon[] =
3907         {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3908     static const WCHAR szProductVersion[] =
3909         {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3910     static const WCHAR szAssignment[] =
3911         {'A','s','s','i','g','n','m','e','n','t',0};
3912     static const WCHAR szAdvertiseFlags[] =
3913         {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3914     static const WCHAR szClients[] =
3915         {'C','l','i','e','n','t','s',0};
3916     static const WCHAR szColon[] = {':',0};
3917
3918     buffer = msi_dup_property(package->db, INSTALLPROPERTY_PRODUCTNAMEW);
3919     msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3920     msi_free(buffer);
3921
3922     langid = msi_get_property_int(package->db, szProductLanguage, 0);
3923     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3924
3925     /* FIXME */
3926     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3927
3928     buffer = msi_dup_property(package->db, szARPProductIcon);
3929     if (buffer)
3930     {
3931         LPWSTR path = build_icon_path(package,buffer);
3932         msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3933         msi_free(path);
3934         msi_free(buffer);
3935     }
3936
3937     buffer = msi_dup_property(package->db, szProductVersion);
3938     if (buffer)
3939     {
3940         DWORD verdword = msi_version_str_to_dword(buffer);
3941         msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3942         msi_free(buffer);
3943     }
3944
3945     msi_reg_set_val_dword(hkey, szAssignment, 0);
3946     msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3947     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3948     msi_reg_set_val_str(hkey, szClients, szColon);
3949
3950     hdb = alloc_msihandle(&package->db->hdr);
3951     if (!hdb)
3952         return ERROR_NOT_ENOUGH_MEMORY;
3953
3954     r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3955     MsiCloseHandle(hdb);
3956     if (r != ERROR_SUCCESS)
3957         goto done;
3958
3959     size = MAX_PATH;
3960     r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3961                                    NULL, guids, &size);
3962     if (r != ERROR_SUCCESS)
3963         goto done;
3964
3965     ptr = strchrW(guids, ';');
3966     if (ptr) *ptr = 0;
3967     squash_guid(guids, packcode);
3968     msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3969
3970 done:
3971     MsiCloseHandle(suminfo);
3972     return ERROR_SUCCESS;
3973 }
3974
3975 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3976 {
3977     UINT r;
3978     HKEY hkey;
3979     LPWSTR upgrade;
3980     WCHAR squashed_pc[SQUISH_GUID_SIZE];
3981
3982     upgrade = msi_dup_property(package->db, szUpgradeCode);
3983     if (!upgrade)
3984         return ERROR_SUCCESS;
3985
3986     if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3987     {
3988         r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3989         if (r != ERROR_SUCCESS)
3990             goto done;
3991     }
3992     else
3993     {
3994         r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3995         if (r != ERROR_SUCCESS)
3996             goto done;
3997     }
3998
3999     squash_guid(package->ProductCode, squashed_pc);
4000     msi_reg_set_val_str(hkey, squashed_pc, NULL);
4001
4002     RegCloseKey(hkey);
4003
4004 done:
4005     msi_free(upgrade);
4006     return r;
4007 }
4008
4009 static BOOL msi_check_publish(MSIPACKAGE *package)
4010 {
4011     MSIFEATURE *feature;
4012
4013     LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4014     {
4015         if (feature->ActionRequest == INSTALLSTATE_LOCAL)
4016             return TRUE;
4017     }
4018
4019     return FALSE;
4020 }
4021
4022 static BOOL msi_check_unpublish(MSIPACKAGE *package)
4023 {
4024     MSIFEATURE *feature;
4025
4026     LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4027     {
4028         if (feature->ActionRequest != INSTALLSTATE_ABSENT)
4029             return FALSE;
4030     }
4031
4032     return TRUE;
4033 }
4034
4035 static UINT msi_publish_patches( MSIPACKAGE *package )
4036 {
4037     static const WCHAR szAllPatches[] = {'A','l','l','P','a','t','c','h','e','s',0};
4038     WCHAR patch_squashed[GUID_SIZE];
4039     HKEY patches_key = NULL, product_patches_key = NULL, product_key;
4040     LONG res;
4041     MSIPATCHINFO *patch;
4042     UINT r;
4043     WCHAR *p, *all_patches = NULL;
4044     DWORD len = 0;
4045
4046     r = MSIREG_OpenProductKey( package->ProductCode, NULL, package->Context, &product_key, TRUE );
4047     if (r != ERROR_SUCCESS)
4048         return ERROR_FUNCTION_FAILED;
4049
4050     res = RegCreateKeyExW( product_key, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patches_key, NULL );
4051     if (res != ERROR_SUCCESS)
4052     {
4053         r = ERROR_FUNCTION_FAILED;
4054         goto done;
4055     }
4056
4057     r = MSIREG_OpenUserDataProductPatchesKey( package->ProductCode, package->Context, &product_patches_key, TRUE );
4058     if (r != ERROR_SUCCESS)
4059         goto done;
4060
4061     LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4062     {
4063         squash_guid( patch->patchcode, patch_squashed );
4064         len += strlenW( patch_squashed ) + 1;
4065     }
4066
4067     p = all_patches = msi_alloc( (len + 1) * sizeof(WCHAR) );
4068     if (!all_patches)
4069         goto done;
4070
4071     LIST_FOR_EACH_ENTRY( patch, &package->patches, MSIPATCHINFO, entry )
4072     {
4073         HKEY patch_key;
4074
4075         squash_guid( patch->patchcode, p );
4076         p += strlenW( p ) + 1;
4077
4078         res = RegSetValueExW( patches_key, patch_squashed, 0, REG_SZ,
4079                               (const BYTE *)patch->transforms,
4080                               (strlenW(patch->transforms) + 1) * sizeof(WCHAR) );
4081         if (res != ERROR_SUCCESS)
4082             goto done;
4083
4084         r = MSIREG_OpenUserDataPatchKey( patch->patchcode, package->Context, &patch_key, TRUE );
4085         if (r != ERROR_SUCCESS)
4086             goto done;
4087
4088         res = RegSetValueExW( patch_key, szLocalPackage, 0, REG_SZ,
4089                               (const BYTE *)patch->localfile,
4090                               (strlenW(patch->localfile) + 1) * sizeof(WCHAR) );
4091         RegCloseKey( patch_key );
4092         if (res != ERROR_SUCCESS)
4093             goto done;
4094
4095         res = RegCreateKeyExW( product_patches_key, patch_squashed, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &patch_key, NULL );
4096         if (res != ERROR_SUCCESS)
4097             goto done;
4098
4099         res = RegSetValueExW( patch_key, szState, 0, REG_DWORD, (const BYTE *)&patch->state, sizeof(patch->state) );
4100         RegCloseKey( patch_key );
4101         if (res != ERROR_SUCCESS)
4102             goto done;
4103     }
4104
4105     all_patches[len] = 0;
4106     res = RegSetValueExW( patches_key, szPatches, 0, REG_MULTI_SZ,
4107                           (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4108     if (res != ERROR_SUCCESS)
4109         goto done;
4110
4111     res = RegSetValueExW( product_patches_key, szAllPatches, 0, REG_MULTI_SZ,
4112                           (const BYTE *)all_patches, (len + 1) * sizeof(WCHAR) );
4113     if (res != ERROR_SUCCESS)
4114         r = ERROR_FUNCTION_FAILED;
4115
4116 done:
4117     RegCloseKey( product_patches_key );
4118     RegCloseKey( patches_key );
4119     RegCloseKey( product_key );
4120     msi_free( all_patches );
4121     return r;
4122 }
4123
4124 /*
4125  * 99% of the work done here is only done for 
4126  * advertised installs. However this is where the
4127  * Icon table is processed and written out
4128  * so that is what I am going to do here.
4129  */
4130 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
4131 {
4132     UINT rc;
4133     HKEY hukey = NULL, hudkey = NULL;
4134     MSIRECORD *uirow;
4135
4136     if (!list_empty(&package->patches))
4137     {
4138         rc = msi_publish_patches(package);
4139         if (rc != ERROR_SUCCESS)
4140             goto end;
4141     }
4142
4143     /* FIXME: also need to publish if the product is in advertise mode */
4144     if (!msi_check_publish(package))
4145         return ERROR_SUCCESS;
4146
4147     rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
4148                                &hukey, TRUE);
4149     if (rc != ERROR_SUCCESS)
4150         goto end;
4151
4152     rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
4153                                        NULL, &hudkey, TRUE);
4154     if (rc != ERROR_SUCCESS)
4155         goto end;
4156
4157     rc = msi_publish_upgrade_code(package);
4158     if (rc != ERROR_SUCCESS)
4159         goto end;
4160
4161     rc = msi_publish_product_properties(package, hukey);
4162     if (rc != ERROR_SUCCESS)
4163         goto end;
4164
4165     rc = msi_publish_sourcelist(package, hukey);
4166     if (rc != ERROR_SUCCESS)
4167         goto end;
4168
4169     rc = msi_publish_icons(package);
4170
4171 end:
4172     uirow = MSI_CreateRecord( 1 );
4173     MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4174     ui_actiondata( package, szPublishProduct, uirow );
4175     msiobj_release( &uirow->hdr );
4176
4177     RegCloseKey(hukey);
4178     RegCloseKey(hudkey);
4179
4180     return rc;
4181 }
4182
4183 static WCHAR *get_ini_file_name( MSIPACKAGE *package, MSIRECORD *row )
4184 {
4185     WCHAR *filename, *ptr, *folder, *ret;
4186     const WCHAR *dirprop;
4187
4188     filename = msi_dup_record_field( row, 2 );
4189     if (filename && (ptr = strchrW( filename, '|' )))
4190         ptr++;
4191     else
4192         ptr = filename;
4193
4194     dirprop = MSI_RecordGetString( row, 3 );
4195     if (dirprop)
4196     {
4197         folder = resolve_folder( package, dirprop, FALSE, FALSE, TRUE, NULL );
4198         if (!folder)
4199             folder = msi_dup_property( package->db, dirprop );
4200     }
4201     else
4202         folder = msi_dup_property( package->db, szWindowsFolder );
4203
4204     if (!folder)
4205     {
4206         ERR("Unable to resolve folder %s\n", debugstr_w(dirprop));
4207         msi_free( filename );
4208         return NULL;
4209     }
4210
4211     ret = build_directory_name( 2, folder, ptr );
4212
4213     msi_free( filename );
4214     msi_free( folder );
4215     return ret;
4216 }
4217
4218 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
4219 {
4220     MSIPACKAGE *package = param;
4221     LPCWSTR component, section, key, value, identifier;
4222     LPWSTR deformated_section, deformated_key, deformated_value, fullname;
4223     MSIRECORD * uirow;
4224     INT action;
4225     MSICOMPONENT *comp;
4226
4227     component = MSI_RecordGetString(row, 8);
4228     comp = get_loaded_component(package,component);
4229     if (!comp)
4230         return ERROR_SUCCESS;
4231
4232     if (!comp->Enabled)
4233     {
4234         TRACE("component is disabled\n");
4235         return ERROR_SUCCESS;
4236     }
4237
4238     if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4239     {
4240         TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4241         comp->Action = comp->Installed;
4242         return ERROR_SUCCESS;
4243     }
4244     comp->Action = INSTALLSTATE_LOCAL;
4245
4246     identifier = MSI_RecordGetString(row,1); 
4247     section = MSI_RecordGetString(row,4);
4248     key = MSI_RecordGetString(row,5);
4249     value = MSI_RecordGetString(row,6);
4250     action = MSI_RecordGetInteger(row,7);
4251
4252     deformat_string(package,section,&deformated_section);
4253     deformat_string(package,key,&deformated_key);
4254     deformat_string(package,value,&deformated_value);
4255
4256     fullname = get_ini_file_name(package, row);
4257
4258     if (action == 0)
4259     {
4260         TRACE("Adding value %s to section %s in %s\n",
4261                 debugstr_w(deformated_key), debugstr_w(deformated_section),
4262                 debugstr_w(fullname));
4263         WritePrivateProfileStringW(deformated_section, deformated_key,
4264                                    deformated_value, fullname);
4265     }
4266     else if (action == 1)
4267     {
4268         WCHAR returned[10];
4269         GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
4270                                  returned, 10, fullname);
4271         if (returned[0] == 0)
4272         {
4273             TRACE("Adding value %s to section %s in %s\n",
4274                     debugstr_w(deformated_key), debugstr_w(deformated_section),
4275                     debugstr_w(fullname));
4276
4277             WritePrivateProfileStringW(deformated_section, deformated_key,
4278                                        deformated_value, fullname);
4279         }
4280     }
4281     else if (action == 3)
4282         FIXME("Append to existing section not yet implemented\n");
4283
4284     uirow = MSI_CreateRecord(4);
4285     MSI_RecordSetStringW(uirow,1,identifier);
4286     MSI_RecordSetStringW(uirow,2,deformated_section);
4287     MSI_RecordSetStringW(uirow,3,deformated_key);
4288     MSI_RecordSetStringW(uirow,4,deformated_value);
4289     ui_actiondata(package,szWriteIniValues,uirow);
4290     msiobj_release( &uirow->hdr );
4291
4292     msi_free(fullname);
4293     msi_free(deformated_key);
4294     msi_free(deformated_value);
4295     msi_free(deformated_section);
4296     return ERROR_SUCCESS;
4297 }
4298
4299 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
4300 {
4301     UINT rc;
4302     MSIQUERY * view;
4303     static const WCHAR ExecSeqQuery[] = 
4304         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4305          '`','I','n','i','F','i','l','e','`',0};
4306
4307     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4308     if (rc != ERROR_SUCCESS)
4309     {
4310         TRACE("no IniFile table\n");
4311         return ERROR_SUCCESS;
4312     }
4313
4314     rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
4315     msiobj_release(&view->hdr);
4316     return rc;
4317 }
4318
4319 static UINT ITERATE_RemoveIniValuesOnUninstall( MSIRECORD *row, LPVOID param )
4320 {
4321     MSIPACKAGE *package = param;
4322     LPCWSTR component, section, key, value, identifier;
4323     LPWSTR deformated_section, deformated_key, deformated_value, filename;
4324     MSICOMPONENT *comp;
4325     MSIRECORD *uirow;
4326     INT action;
4327
4328     component = MSI_RecordGetString( row, 8 );
4329     comp = get_loaded_component( package, component );
4330     if (!comp)
4331         return ERROR_SUCCESS;
4332
4333     if (!comp->Enabled)
4334     {
4335         TRACE("component is disabled\n");
4336         return ERROR_SUCCESS;
4337     }
4338
4339     if (comp->ActionRequest != INSTALLSTATE_ABSENT)
4340     {
4341         TRACE("Component not scheduled for removal %s\n", debugstr_w(component));
4342         comp->Action = comp->Installed;
4343         return ERROR_SUCCESS;
4344     }
4345     comp->Action = INSTALLSTATE_ABSENT;
4346
4347     identifier = MSI_RecordGetString( row, 1 );
4348     section = MSI_RecordGetString( row, 4 );
4349     key = MSI_RecordGetString( row, 5 );
4350     value = MSI_RecordGetString( row, 6 );
4351     action = MSI_RecordGetInteger( row, 7 );
4352
4353     deformat_string( package, section, &deformated_section );
4354     deformat_string( package, key, &deformated_key );
4355     deformat_string( package, value, &deformated_value );
4356
4357     if (action == msidbIniFileActionAddLine || action == msidbIniFileActionCreateLine)
4358     {
4359         filename = get_ini_file_name( package, row );
4360
4361         TRACE("Removing key %s from section %s in %s\n",
4362                debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4363
4364         if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4365         {
4366             WARN("Unable to remove key %u\n", GetLastError());
4367         }
4368         msi_free( filename );
4369     }
4370     else
4371         FIXME("Unsupported action %d\n", action);
4372
4373
4374     uirow = MSI_CreateRecord( 4 );
4375     MSI_RecordSetStringW( uirow, 1, identifier );
4376     MSI_RecordSetStringW( uirow, 2, deformated_section );
4377     MSI_RecordSetStringW( uirow, 3, deformated_key );
4378     MSI_RecordSetStringW( uirow, 4, deformated_value );
4379     ui_actiondata( package, szRemoveIniValues, uirow );
4380     msiobj_release( &uirow->hdr );
4381
4382     msi_free( deformated_key );
4383     msi_free( deformated_value );
4384     msi_free( deformated_section );
4385     return ERROR_SUCCESS;
4386 }
4387
4388 static UINT ITERATE_RemoveIniValuesOnInstall( MSIRECORD *row, LPVOID param )
4389 {
4390     MSIPACKAGE *package = param;
4391     LPCWSTR component, section, key, value, identifier;
4392     LPWSTR deformated_section, deformated_key, deformated_value, filename;
4393     MSICOMPONENT *comp;
4394     MSIRECORD *uirow;
4395     INT action;
4396
4397     component = MSI_RecordGetString( row, 8 );
4398     comp = get_loaded_component( package, component );
4399     if (!comp)
4400         return ERROR_SUCCESS;
4401
4402     if (!comp->Enabled)
4403     {
4404         TRACE("component is disabled\n");
4405         return ERROR_SUCCESS;
4406     }
4407
4408     if (comp->ActionRequest != INSTALLSTATE_LOCAL)
4409     {
4410         TRACE("Component not scheduled for installation %s\n", debugstr_w(component));
4411         comp->Action = comp->Installed;
4412         return ERROR_SUCCESS;
4413     }
4414     comp->Action = INSTALLSTATE_LOCAL;
4415
4416     identifier = MSI_RecordGetString( row, 1 );
4417     section = MSI_RecordGetString( row, 4 );
4418     key = MSI_RecordGetString( row, 5 );
4419     value = MSI_RecordGetString( row, 6 );
4420     action = MSI_RecordGetInteger( row, 7 );
4421
4422     deformat_string( package, section, &deformated_section );
4423     deformat_string( package, key, &deformated_key );
4424     deformat_string( package, value, &deformated_value );
4425
4426     if (action == msidbIniFileActionRemoveLine)
4427     {
4428         filename = get_ini_file_name( package, row );
4429
4430         TRACE("Removing key %s from section %s in %s\n",
4431                debugstr_w(deformated_key), debugstr_w(deformated_section), debugstr_w(filename));
4432
4433         if (!WritePrivateProfileStringW( deformated_section, deformated_key, NULL, filename ))
4434         {
4435             WARN("Unable to remove key %u\n", GetLastError());
4436         }
4437         msi_free( filename );
4438     }
4439     else
4440         FIXME("Unsupported action %d\n", action);
4441
4442     uirow = MSI_CreateRecord( 4 );
4443     MSI_RecordSetStringW( uirow, 1, identifier );
4444     MSI_RecordSetStringW( uirow, 2, deformated_section );
4445     MSI_RecordSetStringW( uirow, 3, deformated_key );
4446     MSI_RecordSetStringW( uirow, 4, deformated_value );
4447     ui_actiondata( package, szRemoveIniValues, uirow );
4448     msiobj_release( &uirow->hdr );
4449
4450     msi_free( deformated_key );
4451     msi_free( deformated_value );
4452     msi_free( deformated_section );
4453     return ERROR_SUCCESS;
4454 }
4455
4456 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4457 {
4458     UINT rc;
4459     MSIQUERY *view;
4460     static const WCHAR query[] =
4461         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4462          '`','I','n','i','F','i','l','e','`',0};
4463     static const WCHAR remove_query[] =
4464         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4465          '`','R','e','m','o','v','e','I','n','i','F','i','l','e','`',0};
4466
4467     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4468     if (rc == ERROR_SUCCESS)
4469     {
4470         rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnUninstall, package );
4471         msiobj_release( &view->hdr );
4472         if (rc != ERROR_SUCCESS)
4473             return rc;
4474     }
4475
4476     rc = MSI_DatabaseOpenViewW( package->db, remove_query, &view );
4477     if (rc == ERROR_SUCCESS)
4478     {
4479         rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveIniValuesOnInstall, package );
4480         msiobj_release( &view->hdr );
4481         if (rc != ERROR_SUCCESS)
4482             return rc;
4483     }
4484
4485     return ERROR_SUCCESS;
4486 }
4487
4488 static void register_dll( const WCHAR *dll, BOOL unregister )
4489 {
4490     HMODULE hmod;
4491
4492     hmod = LoadLibraryExW( dll, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
4493     if (hmod)
4494     {
4495         HRESULT (WINAPI *func_ptr)( void );
4496         const char *func = unregister ? "DllUnregisterServer" : "DllRegisterServer";
4497
4498         func_ptr = (void *)GetProcAddress( hmod, func );
4499         if (func_ptr)
4500         {
4501             HRESULT hr = func_ptr();
4502             if (FAILED( hr ))
4503                 WARN("failed to register dll 0x%08x\n", hr);
4504         }
4505         else
4506             WARN("entry point %s not found\n", func);
4507         FreeLibrary( hmod );
4508         return;
4509     }
4510     WARN("failed to load library %u\n", GetLastError());
4511 }
4512
4513 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
4514 {
4515     MSIPACKAGE *package = param;
4516     LPCWSTR filename;
4517     MSIFILE *file;
4518     MSIRECORD *uirow;
4519
4520     filename = MSI_RecordGetString(row,1);
4521     file = get_loaded_file( package, filename );
4522
4523     if (!file)
4524     {
4525         ERR("Unable to find file id %s\n",debugstr_w(filename));
4526         return ERROR_SUCCESS;
4527     }
4528
4529     TRACE("Registering %s\n", debugstr_w( file->TargetPath ));
4530
4531     register_dll( file->TargetPath, FALSE );
4532
4533     uirow = MSI_CreateRecord( 2 );
4534     MSI_RecordSetStringW( uirow, 1, filename );
4535     MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4536     ui_actiondata( package, szSelfRegModules, uirow );
4537     msiobj_release( &uirow->hdr );
4538
4539     return ERROR_SUCCESS;
4540 }
4541
4542 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
4543 {
4544     UINT rc;
4545     MSIQUERY * view;
4546     static const WCHAR ExecSeqQuery[] = 
4547         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4548          '`','S','e','l','f','R','e','g','`',0};
4549
4550     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4551     if (rc != ERROR_SUCCESS)
4552     {
4553         TRACE("no SelfReg table\n");
4554         return ERROR_SUCCESS;
4555     }
4556
4557     MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
4558     msiobj_release(&view->hdr);
4559
4560     return ERROR_SUCCESS;
4561 }
4562
4563 static UINT ITERATE_SelfUnregModules( MSIRECORD *row, LPVOID param )
4564 {
4565     MSIPACKAGE *package = param;
4566     LPCWSTR filename;
4567     MSIFILE *file;
4568     MSIRECORD *uirow;
4569
4570     filename = MSI_RecordGetString( row, 1 );
4571     file = get_loaded_file( package, filename );
4572
4573     if (!file)
4574     {
4575         ERR("Unable to find file id %s\n", debugstr_w(filename));
4576         return ERROR_SUCCESS;
4577     }
4578
4579     TRACE("Unregistering %s\n", debugstr_w( file->TargetPath ));
4580
4581     register_dll( file->TargetPath, TRUE );
4582
4583     uirow = MSI_CreateRecord( 2 );
4584     MSI_RecordSetStringW( uirow, 1, filename );
4585     MSI_RecordSetStringW( uirow, 2, file->Component->Directory );
4586     ui_actiondata( package, szSelfUnregModules, uirow );
4587     msiobj_release( &uirow->hdr );
4588
4589     return ERROR_SUCCESS;
4590 }
4591
4592 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4593 {
4594     UINT rc;
4595     MSIQUERY *view;
4596     static const WCHAR query[] =
4597         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4598          '`','S','e','l','f','R','e','g','`',0};
4599
4600     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
4601     if (rc != ERROR_SUCCESS)
4602     {
4603         TRACE("no SelfReg table\n");
4604         return ERROR_SUCCESS;
4605     }
4606
4607     MSI_IterateRecords( view, NULL, ITERATE_SelfUnregModules, package );
4608     msiobj_release( &view->hdr );
4609
4610     return ERROR_SUCCESS;
4611 }
4612
4613 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
4614 {
4615     MSIFEATURE *feature;
4616     UINT rc;
4617     HKEY hkey = NULL, userdata = NULL;
4618
4619     if (!msi_check_publish(package))
4620         return ERROR_SUCCESS;
4621
4622     rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4623                                 &hkey, TRUE);
4624     if (rc != ERROR_SUCCESS)
4625         goto end;
4626
4627     rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4628                                         &userdata, TRUE);
4629     if (rc != ERROR_SUCCESS)
4630         goto end;
4631
4632     /* here the guids are base 85 encoded */
4633     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
4634     {
4635         ComponentList *cl;
4636         LPWSTR data = NULL;
4637         GUID clsid;
4638         INT size;
4639         BOOL absent = FALSE;
4640         MSIRECORD *uirow;
4641
4642         if (feature->ActionRequest != INSTALLSTATE_LOCAL &&
4643             feature->ActionRequest != INSTALLSTATE_SOURCE &&
4644             feature->ActionRequest != INSTALLSTATE_ADVERTISED) absent = TRUE;
4645
4646         size = 1;
4647         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4648         {
4649             size += 21;
4650         }
4651         if (feature->Feature_Parent)
4652             size += strlenW( feature->Feature_Parent )+2;
4653
4654         data = msi_alloc(size * sizeof(WCHAR));
4655
4656         data[0] = 0;
4657         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
4658         {
4659             MSICOMPONENT* component = cl->component;
4660             WCHAR buf[21];
4661
4662             buf[0] = 0;
4663             if (component->ComponentId)
4664             {
4665                 TRACE("From %s\n",debugstr_w(component->ComponentId));
4666                 CLSIDFromString(component->ComponentId, &clsid);
4667                 encode_base85_guid(&clsid,buf);
4668                 TRACE("to %s\n",debugstr_w(buf));
4669                 strcatW(data,buf);
4670             }
4671         }
4672
4673         if (feature->Feature_Parent)
4674         {
4675             static const WCHAR sep[] = {'\2',0};
4676             strcatW(data,sep);
4677             strcatW(data,feature->Feature_Parent);
4678         }
4679
4680         msi_reg_set_val_str( userdata, feature->Feature, data );
4681         msi_free(data);
4682
4683         size = 0;
4684         if (feature->Feature_Parent)
4685             size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
4686         if (!absent)
4687         {
4688             size += sizeof(WCHAR);
4689             RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4690                            (const BYTE*)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
4691         }
4692         else
4693         {
4694             size += 2*sizeof(WCHAR);
4695             data = msi_alloc(size);
4696             data[0] = 0x6;
4697             data[1] = 0;
4698             if (feature->Feature_Parent)
4699                 strcpyW( &data[1], feature->Feature_Parent );
4700             RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
4701                        (LPBYTE)data,size);
4702             msi_free(data);
4703         }
4704
4705         /* the UI chunk */
4706         uirow = MSI_CreateRecord( 1 );
4707         MSI_RecordSetStringW( uirow, 1, feature->Feature );
4708         ui_actiondata( package, szPublishFeatures, uirow);
4709         msiobj_release( &uirow->hdr );
4710         /* FIXME: call ui_progress? */
4711     }
4712
4713 end:
4714     RegCloseKey(hkey);
4715     RegCloseKey(userdata);
4716     return rc;
4717 }
4718
4719 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
4720 {
4721     UINT r;
4722     HKEY hkey;
4723     MSIRECORD *uirow;
4724
4725     TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
4726
4727     r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
4728                                &hkey, FALSE);
4729     if (r == ERROR_SUCCESS)
4730     {
4731         RegDeleteValueW(hkey, feature->Feature);
4732         RegCloseKey(hkey);
4733     }
4734
4735     r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
4736                                        &hkey, FALSE);
4737     if (r == ERROR_SUCCESS)
4738     {
4739         RegDeleteValueW(hkey, feature->Feature);
4740         RegCloseKey(hkey);
4741     }
4742
4743     uirow = MSI_CreateRecord( 1 );
4744     MSI_RecordSetStringW( uirow, 1, feature->Feature );
4745     ui_actiondata( package, szUnpublishFeatures, uirow );
4746     msiobj_release( &uirow->hdr );
4747
4748     return ERROR_SUCCESS;
4749 }
4750
4751 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
4752 {
4753     MSIFEATURE *feature;
4754
4755     if (!msi_check_unpublish(package))
4756         return ERROR_SUCCESS;
4757
4758     LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4759     {
4760         msi_unpublish_feature(package, feature);
4761     }
4762
4763     return ERROR_SUCCESS;
4764 }
4765
4766 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
4767 {
4768     SYSTEMTIME systime;
4769     DWORD size, langid;
4770     WCHAR date[9], *val, *buffer;
4771     const WCHAR *prop, *key;
4772
4773     static const WCHAR date_fmt[] = {'%','i','%','0','2','i','%','0','2','i',0};
4774     static const WCHAR szWindowsInstaller[] =
4775         {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
4776     static const WCHAR modpath_fmt[] =
4777         {'M','s','i','E','x','e','c','.','e','x','e',' ',
4778          '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
4779     static const WCHAR szModifyPath[] =
4780         {'M','o','d','i','f','y','P','a','t','h',0};
4781     static const WCHAR szUninstallString[] =
4782         {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
4783     static const WCHAR szEstimatedSize[] =
4784         {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
4785     static const WCHAR szProductLanguage[] =
4786         {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
4787     static const WCHAR szProductVersion[] =
4788         {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
4789     static const WCHAR szDisplayVersion[] =
4790         {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
4791     static const WCHAR szInstallSource[] =
4792         {'I','n','s','t','a','l','l','S','o','u','r','c','e',0};
4793     static const WCHAR szARPAUTHORIZEDCDFPREFIX[] =
4794         {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0};
4795     static const WCHAR szAuthorizedCDFPrefix[] =
4796         {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0};
4797     static const WCHAR szARPCONTACT[] =
4798         {'A','R','P','C','O','N','T','A','C','T',0};
4799     static const WCHAR szContact[] =
4800         {'C','o','n','t','a','c','t',0};
4801     static const WCHAR szARPCOMMENTS[] =
4802         {'A','R','P','C','O','M','M','E','N','T','S',0};
4803     static const WCHAR szComments[] =
4804         {'C','o','m','m','e','n','t','s',0};
4805     static const WCHAR szProductName[] =
4806         {'P','r','o','d','u','c','t','N','a','m','e',0};
4807     static const WCHAR szDisplayName[] =
4808         {'D','i','s','p','l','a','y','N','a','m','e',0};
4809     static const WCHAR szARPHELPLINK[] =
4810         {'A','R','P','H','E','L','P','L','I','N','K',0};
4811     static const WCHAR szHelpLink[] =
4812         {'H','e','l','p','L','i','n','k',0};
4813     static const WCHAR szARPHELPTELEPHONE[] =
4814         {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0};
4815     static const WCHAR szHelpTelephone[] =
4816         {'H','e','l','p','T','e','l','e','p','h','o','n','e',0};
4817     static const WCHAR szARPINSTALLLOCATION[] =
4818         {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0};
4819     static const WCHAR szInstallLocation[] =
4820         {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0};
4821     static const WCHAR szManufacturer[] =
4822         {'M','a','n','u','f','a','c','t','u','r','e','r',0};
4823     static const WCHAR szPublisher[] =
4824         {'P','u','b','l','i','s','h','e','r',0};
4825     static const WCHAR szARPREADME[] =
4826         {'A','R','P','R','E','A','D','M','E',0};
4827     static const WCHAR szReadme[] =
4828         {'R','e','a','d','M','e',0};
4829     static const WCHAR szARPSIZE[] =
4830         {'A','R','P','S','I','Z','E',0};
4831     static const WCHAR szSize[] =
4832         {'S','i','z','e',0};
4833     static const WCHAR szARPURLINFOABOUT[] =
4834         {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0};
4835     static const WCHAR szURLInfoAbout[] =
4836         {'U','R','L','I','n','f','o','A','b','o','u','t',0};
4837     static const WCHAR szARPURLUPDATEINFO[] =
4838         {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0};
4839     static const WCHAR szURLUpdateInfo[] =
4840         {'U','R','L','U','p','d','a','t','e','I','n','f','o',0};
4841
4842     static const WCHAR *propval[] = {
4843         szARPAUTHORIZEDCDFPREFIX, szAuthorizedCDFPrefix,
4844         szARPCONTACT,             szContact,
4845         szARPCOMMENTS,            szComments,
4846         szProductName,            szDisplayName,
4847         szARPHELPLINK,            szHelpLink,
4848         szARPHELPTELEPHONE,       szHelpTelephone,
4849         szARPINSTALLLOCATION,     szInstallLocation,
4850         cszSourceDir,             szInstallSource,
4851         szManufacturer,           szPublisher,
4852         szARPREADME,              szReadme,
4853         szARPSIZE,                szSize,
4854         szARPURLINFOABOUT,        szURLInfoAbout,
4855         szARPURLUPDATEINFO,       szURLUpdateInfo,
4856         NULL
4857     };
4858     const WCHAR **p = propval;
4859
4860     while (*p)
4861     {
4862         prop = *p++;
4863         key = *p++;
4864         val = msi_dup_property(package->db, prop);
4865         msi_reg_set_val_str(hkey, key, val);
4866         msi_free(val);
4867     }
4868
4869     msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
4870
4871     size = deformat_string(package, modpath_fmt, &buffer);
4872     RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4873     RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
4874     msi_free(buffer);
4875
4876     /* FIXME: Write real Estimated Size when we have it */
4877     msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
4878
4879     GetLocalTime(&systime);
4880     sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
4881     msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
4882
4883     langid = msi_get_property_int(package->db, szProductLanguage, 0);
4884     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
4885
4886     buffer = msi_dup_property(package->db, szProductVersion);
4887     msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
4888     if (buffer)
4889     {
4890         DWORD verdword = msi_version_str_to_dword(buffer);
4891
4892         msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
4893         msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
4894         msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
4895         msi_free(buffer);
4896     }
4897
4898     return ERROR_SUCCESS;
4899 }
4900
4901 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
4902 {
4903     WCHAR squashed_pc[SQUISH_GUID_SIZE];
4904     MSIRECORD *uirow;
4905     LPWSTR upgrade_code;
4906     HKEY hkey, props;
4907     HKEY upgrade;
4908     UINT rc;
4909
4910     /* FIXME: also need to publish if the product is in advertise mode */
4911     if (!msi_check_publish(package))
4912         return ERROR_SUCCESS;
4913
4914     rc = MSIREG_OpenUninstallKey(package, &hkey, TRUE);
4915     if (rc != ERROR_SUCCESS)
4916         return rc;
4917
4918     rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
4919                                  NULL, &props, TRUE);
4920     if (rc != ERROR_SUCCESS)
4921         goto done;
4922
4923     msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
4924     msi_free( package->db->localfile );
4925     package->db->localfile = NULL;
4926
4927     rc = msi_publish_install_properties(package, hkey);
4928     if (rc != ERROR_SUCCESS)
4929         goto done;
4930
4931     rc = msi_publish_install_properties(package, props);
4932     if (rc != ERROR_SUCCESS)
4933         goto done;
4934
4935     upgrade_code = msi_dup_property(package->db, szUpgradeCode);
4936     if (upgrade_code)
4937     {
4938         MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
4939         squash_guid(package->ProductCode, squashed_pc);
4940         msi_reg_set_val_str(upgrade, squashed_pc, NULL);
4941         RegCloseKey(upgrade);
4942         msi_free(upgrade_code);
4943     }
4944
4945 done:
4946     uirow = MSI_CreateRecord( 1 );
4947     MSI_RecordSetStringW( uirow, 1, package->ProductCode );
4948     ui_actiondata( package, szRegisterProduct, uirow );
4949     msiobj_release( &uirow->hdr );
4950
4951     RegCloseKey(hkey);
4952     return ERROR_SUCCESS;
4953 }
4954
4955 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
4956 {
4957     return execute_script(package,INSTALL_SCRIPT);
4958 }
4959
4960 static UINT msi_unpublish_product(MSIPACKAGE *package, WCHAR *remove)
4961 {
4962     WCHAR *upgrade, **features;
4963     BOOL full_uninstall = TRUE;
4964     MSIFEATURE *feature;
4965     MSIPATCHINFO *patch;
4966
4967     static const WCHAR szUpgradeCode[] =
4968         {'U','p','g','r','a','d','e','C','o','d','e',0};
4969
4970     features = msi_split_string(remove, ',');
4971     if (!features)
4972     {
4973         ERR("REMOVE feature list is empty!\n");
4974         return ERROR_FUNCTION_FAILED;
4975     }
4976
4977     if (!strcmpW( features[0], szAll ))
4978         full_uninstall = TRUE;
4979     else
4980     {
4981         LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
4982         {
4983             if (feature->Action != INSTALLSTATE_ABSENT)
4984                 full_uninstall = FALSE;
4985         }
4986     }
4987     msi_free(features);
4988
4989     if (!full_uninstall)
4990         return ERROR_SUCCESS;
4991
4992     MSIREG_DeleteProductKey(package->ProductCode);
4993     MSIREG_DeleteUserDataProductKey(package->ProductCode);
4994     MSIREG_DeleteUninstallKey(package);
4995
4996     if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4997     {
4998         MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4999         MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
5000     }
5001     else
5002     {
5003         MSIREG_DeleteUserProductKey(package->ProductCode);
5004         MSIREG_DeleteUserFeaturesKey(package->ProductCode);
5005     }
5006
5007     upgrade = msi_dup_property(package->db, szUpgradeCode);
5008     if (upgrade)
5009     {
5010         MSIREG_DeleteUserUpgradeCodesKey(upgrade);
5011         msi_free(upgrade);
5012     }
5013
5014     LIST_FOR_EACH_ENTRY(patch, &package->patches, MSIPATCHINFO, entry)
5015     {
5016         MSIREG_DeleteUserDataPatchKey(patch->patchcode, package->Context);
5017     }
5018
5019     return ERROR_SUCCESS;
5020 }
5021
5022 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
5023 {
5024     UINT rc;
5025     WCHAR *remove;
5026
5027     /* turn off scheduling */
5028     package->script->CurrentlyScripting= FALSE;
5029
5030     /* first do the same as an InstallExecute */
5031     rc = ACTION_InstallExecute(package);
5032     if (rc != ERROR_SUCCESS)
5033         return rc;
5034
5035     /* then handle Commit Actions */
5036     rc = execute_script(package,COMMIT_SCRIPT);
5037     if (rc != ERROR_SUCCESS)
5038         return rc;
5039
5040     remove = msi_dup_property(package->db, szRemove);
5041     if (remove)
5042         rc = msi_unpublish_product(package, remove);
5043
5044     msi_free(remove);
5045     return rc;
5046 }
5047
5048 UINT ACTION_ForceReboot(MSIPACKAGE *package)
5049 {
5050     static const WCHAR RunOnce[] = {
5051     'S','o','f','t','w','a','r','e','\\',
5052     'M','i','c','r','o','s','o','f','t','\\',
5053     'W','i','n','d','o','w','s','\\',
5054     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5055     'R','u','n','O','n','c','e',0};
5056     static const WCHAR InstallRunOnce[] = {
5057     'S','o','f','t','w','a','r','e','\\',
5058     'M','i','c','r','o','s','o','f','t','\\',
5059     'W','i','n','d','o','w','s','\\',
5060     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
5061     'I','n','s','t','a','l','l','e','r','\\',
5062     'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
5063
5064     static const WCHAR msiexec_fmt[] = {
5065     '%','s',
5066     '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
5067     '\"','%','s','\"',0};
5068     static const WCHAR install_fmt[] = {
5069     '/','I',' ','\"','%','s','\"',' ',
5070     'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
5071     'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
5072     WCHAR buffer[256], sysdir[MAX_PATH];
5073     HKEY hkey;
5074     WCHAR squished_pc[100];
5075
5076     squash_guid(package->ProductCode,squished_pc);
5077
5078     GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
5079     RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
5080     snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
5081      squished_pc);
5082
5083     msi_reg_set_val_str( hkey, squished_pc, buffer );
5084     RegCloseKey(hkey);
5085
5086     TRACE("Reboot command %s\n",debugstr_w(buffer));
5087
5088     RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
5089     sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
5090
5091     msi_reg_set_val_str( hkey, squished_pc, buffer );
5092     RegCloseKey(hkey);
5093
5094     return ERROR_INSTALL_SUSPEND;
5095 }
5096
5097 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
5098 {
5099     DWORD attrib;
5100     UINT rc;
5101
5102     /*
5103      * We are currently doing what should be done here in the top level Install
5104      * however for Administrative and uninstalls this step will be needed
5105      */
5106     if (!package->PackagePath)
5107         return ERROR_SUCCESS;
5108
5109     msi_set_sourcedir_props(package, TRUE);
5110
5111     attrib = GetFileAttributesW(package->db->path);
5112     if (attrib == INVALID_FILE_ATTRIBUTES)
5113     {
5114         LPWSTR prompt;
5115         LPWSTR msg;
5116         DWORD size = 0;
5117
5118         rc = MsiSourceListGetInfoW(package->ProductCode, NULL, 
5119                 package->Context, MSICODE_PRODUCT,
5120                 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
5121         if (rc == ERROR_MORE_DATA)
5122         {
5123             prompt = msi_alloc(size * sizeof(WCHAR));
5124             MsiSourceListGetInfoW(package->ProductCode, NULL, 
5125                     package->Context, MSICODE_PRODUCT,
5126                     INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
5127         }
5128         else
5129             prompt = strdupW(package->db->path);
5130
5131         msg = generate_error_string(package,1302,1,prompt);
5132         while(attrib == INVALID_FILE_ATTRIBUTES)
5133         {
5134             rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
5135             if (rc == IDCANCEL)
5136             {
5137                 rc = ERROR_INSTALL_USEREXIT;
5138                 break;
5139             }
5140             attrib = GetFileAttributesW(package->db->path);
5141         }
5142         msi_free(prompt);
5143         rc = ERROR_SUCCESS;
5144     }
5145     else
5146         return ERROR_SUCCESS;
5147
5148     return rc;
5149 }
5150
5151 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
5152 {
5153     HKEY hkey = 0;
5154     LPWSTR buffer, productid = NULL;
5155     UINT i, rc = ERROR_SUCCESS;
5156     MSIRECORD *uirow;
5157
5158     static const WCHAR szPropKeys[][80] = 
5159     {
5160         {'P','r','o','d','u','c','t','I','D',0},
5161         {'U','S','E','R','N','A','M','E',0},
5162         {'C','O','M','P','A','N','Y','N','A','M','E',0},
5163         {0},
5164     };
5165
5166     static const WCHAR szRegKeys[][80] = 
5167     {
5168         {'P','r','o','d','u','c','t','I','D',0},
5169         {'R','e','g','O','w','n','e','r',0},
5170         {'R','e','g','C','o','m','p','a','n','y',0},
5171         {0},
5172     };
5173
5174     if (msi_check_unpublish(package))
5175     {
5176         MSIREG_DeleteUserDataProductKey(package->ProductCode);
5177         goto end;
5178     }
5179
5180     productid = msi_dup_property( package->db, INSTALLPROPERTY_PRODUCTIDW );
5181     if (!productid)
5182         goto end;
5183
5184     rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
5185                                  NULL, &hkey, TRUE);
5186     if (rc != ERROR_SUCCESS)
5187         goto end;
5188
5189     for( i = 0; szPropKeys[i][0]; i++ )
5190     {
5191         buffer = msi_dup_property( package->db, szPropKeys[i] );
5192         msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
5193         msi_free( buffer );
5194     }
5195
5196 end:
5197     uirow = MSI_CreateRecord( 1 );
5198     MSI_RecordSetStringW( uirow, 1, productid );
5199     ui_actiondata( package, szRegisterUser, uirow );
5200     msiobj_release( &uirow->hdr );
5201
5202     msi_free(productid);
5203     RegCloseKey(hkey);
5204     return rc;
5205 }
5206
5207
5208 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
5209 {
5210     UINT rc;
5211
5212     package->script->InWhatSequence |= SEQUENCE_EXEC;
5213     rc = ACTION_ProcessExecSequence(package,FALSE);
5214     return rc;
5215 }
5216
5217
5218 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
5219 {
5220     MSIPACKAGE *package = param;
5221     LPCWSTR compgroupid, component, feature, qualifier, text;
5222     LPWSTR advertise = NULL, output = NULL;
5223     HKEY hkey = NULL;
5224     UINT rc;
5225     MSICOMPONENT *comp;
5226     MSIFEATURE *feat;
5227     DWORD sz;
5228     MSIRECORD *uirow;
5229
5230     feature = MSI_RecordGetString(rec, 5);
5231     feat = get_loaded_feature(package, feature);
5232     if (!feat)
5233         return ERROR_SUCCESS;
5234
5235     if (feat->ActionRequest != INSTALLSTATE_LOCAL &&
5236         feat->ActionRequest != INSTALLSTATE_SOURCE &&
5237         feat->ActionRequest != INSTALLSTATE_ADVERTISED)
5238     {
5239         TRACE("Feature %s not scheduled for installation\n", debugstr_w(feature));
5240         feat->Action = feat->Installed;
5241         return ERROR_SUCCESS;
5242     }
5243
5244     component = MSI_RecordGetString(rec, 3);
5245     comp = get_loaded_component(package, component);
5246     if (!comp)
5247         return ERROR_SUCCESS;
5248
5249     compgroupid = MSI_RecordGetString(rec,1);
5250     qualifier = MSI_RecordGetString(rec,2);
5251
5252     rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
5253     if (rc != ERROR_SUCCESS)
5254         goto end;
5255     
5256     text = MSI_RecordGetString(rec,4);
5257     advertise = create_component_advertise_string(package, comp, feature);
5258
5259     sz = strlenW(advertise);
5260
5261     if (text)
5262         sz += lstrlenW(text);
5263
5264     sz+=3;
5265     sz *= sizeof(WCHAR);
5266            
5267     output = msi_alloc_zero(sz);
5268     strcpyW(output,advertise);
5269     msi_free(advertise);
5270
5271     if (text)
5272         strcatW(output,text);
5273
5274     msi_reg_set_val_multi_str( hkey, qualifier, output );
5275     
5276 end:
5277     RegCloseKey(hkey);
5278     msi_free(output);
5279
5280     /* the UI chunk */
5281     uirow = MSI_CreateRecord( 2 );
5282     MSI_RecordSetStringW( uirow, 1, compgroupid );
5283     MSI_RecordSetStringW( uirow, 2, qualifier);
5284     ui_actiondata( package, szPublishComponents, uirow);
5285     msiobj_release( &uirow->hdr );
5286     /* FIXME: call ui_progress? */
5287
5288     return rc;
5289 }
5290
5291 /*
5292  * At present I am ignorning the advertised components part of this and only
5293  * focusing on the qualified component sets
5294  */
5295 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
5296 {
5297     UINT rc;
5298     MSIQUERY * view;
5299     static const WCHAR ExecSeqQuery[] =
5300         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5301          '`','P','u','b','l','i','s','h',
5302          'C','o','m','p','o','n','e','n','t','`',0};
5303     
5304     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5305     if (rc != ERROR_SUCCESS)
5306         return ERROR_SUCCESS;
5307
5308     rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
5309     msiobj_release(&view->hdr);
5310
5311     return rc;
5312 }
5313
5314 static UINT ITERATE_UnpublishComponent( MSIRECORD *rec, LPVOID param )
5315 {
5316     static const WCHAR szInstallerComponents[] = {
5317         'S','o','f','t','w','a','r','e','\\',
5318         'M','i','c','r','o','s','o','f','t','\\',
5319         'I','n','s','t','a','l','l','e','r','\\',
5320         'C','o','m','p','o','n','e','n','t','s','\\',0};
5321
5322     MSIPACKAGE *package = param;
5323     LPCWSTR compgroupid, component, feature, qualifier;
5324     MSICOMPONENT *comp;
5325     MSIFEATURE *feat;
5326     MSIRECORD *uirow;
5327     WCHAR squashed[GUID_SIZE], keypath[MAX_PATH];
5328     LONG res;
5329
5330     feature = MSI_RecordGetString( rec, 5 );
5331     feat = get_loaded_feature( package, feature );
5332     if (!feat)
5333         return ERROR_SUCCESS;
5334
5335     if (feat->ActionRequest != INSTALLSTATE_ABSENT)
5336     {
5337         TRACE("Feature %s not scheduled for removal\n", debugstr_w(feature));
5338         feat->Action = feat->Installed;
5339         return ERROR_SUCCESS;
5340     }
5341
5342     component = MSI_RecordGetString( rec, 3 );
5343     comp = get_loaded_component( package, component );
5344     if (!comp)
5345         return ERROR_SUCCESS;
5346
5347     compgroupid = MSI_RecordGetString( rec, 1 );
5348     qualifier = MSI_RecordGetString( rec, 2 );
5349
5350     squash_guid( compgroupid, squashed );
5351     strcpyW( keypath, szInstallerComponents );
5352     strcatW( keypath, squashed );
5353
5354     res = RegDeleteKeyW( HKEY_CURRENT_USER, keypath );
5355     if (res != ERROR_SUCCESS)
5356     {
5357         WARN("Unable to delete component key %d\n", res);
5358     }
5359
5360     uirow = MSI_CreateRecord( 2 );
5361     MSI_RecordSetStringW( uirow, 1, compgroupid );
5362     MSI_RecordSetStringW( uirow, 2, qualifier );
5363     ui_actiondata( package, szUnpublishComponents, uirow );
5364     msiobj_release( &uirow->hdr );
5365
5366     return ERROR_SUCCESS;
5367 }
5368
5369 static UINT ACTION_UnpublishComponents( MSIPACKAGE *package )
5370 {
5371     UINT rc;
5372     MSIQUERY *view;
5373     static const WCHAR query[] =
5374         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5375          '`','P','u','b','l','i','s','h',
5376          'C','o','m','p','o','n','e','n','t','`',0};
5377
5378     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5379     if (rc != ERROR_SUCCESS)
5380         return ERROR_SUCCESS;
5381
5382     rc = MSI_IterateRecords( view, NULL, ITERATE_UnpublishComponent, package );
5383     msiobj_release( &view->hdr );
5384
5385     return rc;
5386 }
5387
5388 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
5389 {
5390     MSIPACKAGE *package = param;
5391     MSIRECORD *row;
5392     MSIFILE *file;
5393     SC_HANDLE hscm, service = NULL;
5394     LPCWSTR comp, key;
5395     LPWSTR name = NULL, disp = NULL, load_order = NULL, serv_name = NULL;
5396     LPWSTR depends = NULL, pass = NULL, args = NULL, image_path = NULL;
5397     DWORD serv_type, start_type, err_control;
5398     SERVICE_DESCRIPTIONW sd = {NULL};
5399
5400     static const WCHAR query[] =
5401         {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
5402          '`','C','o','m','p','o','n','e','n','t','`',' ',
5403          'W','H','E','R','E',' ',
5404          '`','C','o','m','p','o','n','e','n','t','`',' ',
5405          '=','\'','%','s','\'',0};
5406
5407     hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
5408     if (!hscm)
5409     {
5410         ERR("Failed to open the SC Manager!\n");
5411         goto done;
5412     }
5413
5414     start_type = MSI_RecordGetInteger(rec, 5);
5415     if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
5416         goto done;
5417
5418     deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5419     deformat_string(package, MSI_RecordGetString(rec, 3), &disp);
5420     serv_type = MSI_RecordGetInteger(rec, 4);
5421     err_control = MSI_RecordGetInteger(rec, 6);
5422     deformat_string(package, MSI_RecordGetString(rec, 7), &load_order);
5423     deformat_string(package, MSI_RecordGetString(rec, 8), &depends);
5424     deformat_string(package, MSI_RecordGetString(rec, 9), &serv_name);
5425     deformat_string(package, MSI_RecordGetString(rec, 10), &pass);
5426     deformat_string(package, MSI_RecordGetString(rec, 11), &args);
5427     comp = MSI_RecordGetString(rec, 12);
5428     deformat_string(package, MSI_RecordGetString(rec, 13), &sd.lpDescription);
5429
5430     /* fetch the service path */
5431     row = MSI_QueryGetRecord(package->db, query, comp);
5432     if (!row)
5433     {
5434         ERR("Control query failed!\n");
5435         goto done;
5436     }
5437     key = MSI_RecordGetString(row, 6);
5438
5439     file = get_loaded_file(package, key);
5440     msiobj_release(&row->hdr);
5441     if (!file)
5442     {
5443         ERR("Failed to load the service file\n");
5444         goto done;
5445     }
5446
5447     if (!args || !args[0]) image_path = file->TargetPath;
5448     else
5449     {
5450         int len = strlenW(file->TargetPath) + strlenW(args) + 2;
5451         if (!(image_path = msi_alloc(len * sizeof(WCHAR))))
5452             return ERROR_OUTOFMEMORY;
5453
5454         strcpyW(image_path, file->TargetPath);
5455         strcatW(image_path, szSpace);
5456         strcatW(image_path, args);
5457     }
5458     service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
5459                              start_type, err_control, image_path, load_order,
5460                              NULL, depends, serv_name, pass);
5461
5462     if (!service)
5463     {
5464         if (GetLastError() != ERROR_SERVICE_EXISTS)
5465             ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
5466     }
5467     else if (sd.lpDescription)
5468     {
5469         if (!ChangeServiceConfig2W(service, SERVICE_CONFIG_DESCRIPTION, &sd))
5470             WARN("failed to set service description %u\n", GetLastError());
5471     }
5472
5473     if (image_path != file->TargetPath) msi_free(image_path);
5474 done:
5475     CloseServiceHandle(service);
5476     CloseServiceHandle(hscm);
5477     msi_free(name);
5478     msi_free(disp);
5479     msi_free(sd.lpDescription);
5480     msi_free(load_order);
5481     msi_free(serv_name);
5482     msi_free(pass);
5483     msi_free(depends);
5484     msi_free(args);
5485
5486     return ERROR_SUCCESS;
5487 }
5488
5489 static UINT ACTION_InstallServices( MSIPACKAGE *package )
5490 {
5491     UINT rc;
5492     MSIQUERY * view;
5493     static const WCHAR ExecSeqQuery[] =
5494         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5495          'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
5496     
5497     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5498     if (rc != ERROR_SUCCESS)
5499         return ERROR_SUCCESS;
5500
5501     rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
5502     msiobj_release(&view->hdr);
5503
5504     return rc;
5505 }
5506
5507 /* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */
5508 static LPCWSTR *msi_service_args_to_vector(LPWSTR args, DWORD *numargs)
5509 {
5510     LPCWSTR *vector, *temp_vector;
5511     LPWSTR p, q;
5512     DWORD sep_len;
5513
5514     static const WCHAR separator[] = {'[','~',']',0};
5515
5516     *numargs = 0;
5517     sep_len = sizeof(separator) / sizeof(WCHAR) - 1;
5518
5519     if (!args)
5520         return NULL;
5521
5522     vector = msi_alloc(sizeof(LPWSTR));
5523     if (!vector)
5524         return NULL;
5525
5526     p = args;
5527     do
5528     {
5529         (*numargs)++;
5530         vector[*numargs - 1] = p;
5531
5532         if ((q = strstrW(p, separator)))
5533         {
5534             *q = '\0';
5535
5536             temp_vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR));
5537             if (!temp_vector)
5538             {
5539                 msi_free(vector);
5540                 return NULL;
5541             }
5542             vector = temp_vector;
5543
5544             p = q + sep_len;
5545         }
5546     } while (q);
5547
5548     return vector;
5549 }
5550
5551 static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param)
5552 {
5553     MSIPACKAGE *package = param;
5554     MSICOMPONENT *comp;
5555     MSIRECORD *uirow;
5556     SC_HANDLE scm = NULL, service = NULL;
5557     LPCWSTR component, *vector = NULL;
5558     LPWSTR name, args, display_name = NULL;
5559     DWORD event, numargs, len;
5560     UINT r = ERROR_FUNCTION_FAILED;
5561
5562     component = MSI_RecordGetString(rec, 6);
5563     comp = get_loaded_component(package, component);
5564     if (!comp)
5565         return ERROR_SUCCESS;
5566
5567     if (!comp->Enabled)
5568     {
5569         TRACE("component is disabled\n");
5570         return ERROR_SUCCESS;
5571     }
5572
5573     if (comp->ActionRequest != INSTALLSTATE_LOCAL)
5574     {
5575         TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
5576         comp->Action = comp->Installed;
5577         return ERROR_SUCCESS;
5578     }
5579     comp->Action = INSTALLSTATE_LOCAL;
5580
5581     deformat_string(package, MSI_RecordGetString(rec, 2), &name);
5582     deformat_string(package, MSI_RecordGetString(rec, 4), &args);
5583     event = MSI_RecordGetInteger(rec, 3);
5584
5585     if (!(event & msidbServiceControlEventStart))
5586     {
5587         r = ERROR_SUCCESS;
5588         goto done;
5589     }
5590
5591     scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
5592     if (!scm)
5593     {
5594         ERR("Failed to open the service control manager\n");
5595         goto done;
5596     }
5597
5598     len = 0;
5599     if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5600         GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5601     {
5602         if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5603             GetServiceDisplayNameW( scm, name, display_name, &len );
5604     }
5605
5606     service = OpenServiceW(scm, name, SERVICE_START);
5607     if (!service)
5608     {
5609         ERR("Failed to open service %s (%u)\n", debugstr_w(name), GetLastError());
5610         goto done;
5611     }
5612
5613     vector = msi_service_args_to_vector(args, &numargs);
5614
5615     if (!StartServiceW(service, numargs, vector) &&
5616         GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
5617     {
5618         ERR("Failed to start service %s (%u)\n", debugstr_w(name), GetLastError());
5619         goto done;
5620     }
5621
5622     r = ERROR_SUCCESS;
5623
5624 done:
5625     uirow = MSI_CreateRecord( 2 );
5626     MSI_RecordSetStringW( uirow, 1, display_name );
5627     MSI_RecordSetStringW( uirow, 2, name );
5628     ui_actiondata( package, szStartServices, uirow );
5629     msiobj_release( &uirow->hdr );
5630
5631     CloseServiceHandle(service);
5632     CloseServiceHandle(scm);
5633
5634     msi_free(name);
5635     msi_free(args);
5636     msi_free(vector);
5637     msi_free(display_name);
5638     return r;
5639 }
5640
5641 static UINT ACTION_StartServices( MSIPACKAGE *package )
5642 {
5643     UINT rc;
5644     MSIQUERY *view;
5645
5646     static const WCHAR query[] = {
5647         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5648         'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5649
5650     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5651     if (rc != ERROR_SUCCESS)
5652         return ERROR_SUCCESS;
5653
5654     rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package);
5655     msiobj_release(&view->hdr);
5656
5657     return rc;
5658 }
5659
5660 static BOOL stop_service_dependents(SC_HANDLE scm, SC_HANDLE service)
5661 {
5662     DWORD i, needed, count;
5663     ENUM_SERVICE_STATUSW *dependencies;
5664     SERVICE_STATUS ss;
5665     SC_HANDLE depserv;
5666
5667     if (EnumDependentServicesW(service, SERVICE_ACTIVE, NULL,
5668                                0, &needed, &count))
5669         return TRUE;
5670
5671     if (GetLastError() != ERROR_MORE_DATA)
5672         return FALSE;
5673
5674     dependencies = msi_alloc(needed);
5675     if (!dependencies)
5676         return FALSE;
5677
5678     if (!EnumDependentServicesW(service, SERVICE_ACTIVE, dependencies,
5679                                 needed, &needed, &count))
5680         goto error;
5681
5682     for (i = 0; i < count; i++)
5683     {
5684         depserv = OpenServiceW(scm, dependencies[i].lpServiceName,
5685                                SERVICE_STOP | SERVICE_QUERY_STATUS);
5686         if (!depserv)
5687             goto error;
5688
5689         if (!ControlService(depserv, SERVICE_CONTROL_STOP, &ss))
5690             goto error;
5691     }
5692
5693     return TRUE;
5694
5695 error:
5696     msi_free(dependencies);
5697     return FALSE;
5698 }
5699
5700 static UINT stop_service( LPCWSTR name )
5701 {
5702     SC_HANDLE scm = NULL, service = NULL;
5703     SERVICE_STATUS status;
5704     SERVICE_STATUS_PROCESS ssp;
5705     DWORD needed;
5706
5707     scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
5708     if (!scm)
5709     {
5710         WARN("Failed to open the SCM: %d\n", GetLastError());
5711         goto done;
5712     }
5713
5714     service = OpenServiceW(scm, name,
5715                            SERVICE_STOP |
5716                            SERVICE_QUERY_STATUS |
5717                            SERVICE_ENUMERATE_DEPENDENTS);
5718     if (!service)
5719     {
5720         WARN("Failed to open service (%s): %d\n", debugstr_w(name), GetLastError());
5721         goto done;
5722     }
5723
5724     if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
5725                               sizeof(SERVICE_STATUS_PROCESS), &needed))
5726     {
5727         WARN("Failed to query service status (%s): %d\n", debugstr_w(name), GetLastError());
5728         goto done;
5729     }
5730
5731     if (ssp.dwCurrentState == SERVICE_STOPPED)
5732         goto done;
5733
5734     stop_service_dependents(scm, service);
5735
5736     if (!ControlService(service, SERVICE_CONTROL_STOP, &status))
5737         WARN("Failed to stop service (%s): %d\n", debugstr_w(name), GetLastError());
5738
5739 done:
5740     CloseServiceHandle(service);
5741     CloseServiceHandle(scm);
5742
5743     return ERROR_SUCCESS;
5744 }
5745
5746 static UINT ITERATE_StopService( MSIRECORD *rec, LPVOID param )
5747 {
5748     MSIPACKAGE *package = param;
5749     MSICOMPONENT *comp;
5750     MSIRECORD *uirow;
5751     LPCWSTR component;
5752     LPWSTR name = NULL, display_name = NULL;
5753     DWORD event, len;
5754     SC_HANDLE scm;
5755
5756     event = MSI_RecordGetInteger( rec, 3 );
5757     if (!(event & msidbServiceControlEventStop))
5758         return ERROR_SUCCESS;
5759
5760     component = MSI_RecordGetString( rec, 6 );
5761     comp = get_loaded_component( package, component );
5762     if (!comp)
5763         return ERROR_SUCCESS;
5764
5765     if (!comp->Enabled)
5766     {
5767         TRACE("component is disabled\n");
5768         return ERROR_SUCCESS;
5769     }
5770
5771     if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5772     {
5773         TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5774         comp->Action = comp->Installed;
5775         return ERROR_SUCCESS;
5776     }
5777     comp->Action = INSTALLSTATE_ABSENT;
5778
5779     scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
5780     if (!scm)
5781     {
5782         ERR("Failed to open the service control manager\n");
5783         goto done;
5784     }
5785
5786     len = 0;
5787     if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5788         GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5789     {
5790         if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5791             GetServiceDisplayNameW( scm, name, display_name, &len );
5792     }
5793     CloseServiceHandle( scm );
5794
5795     deformat_string( package, MSI_RecordGetString( rec, 2 ), &name );
5796     stop_service( name );
5797
5798 done:
5799     uirow = MSI_CreateRecord( 2 );
5800     MSI_RecordSetStringW( uirow, 1, display_name );
5801     MSI_RecordSetStringW( uirow, 2, name );
5802     ui_actiondata( package, szStopServices, uirow );
5803     msiobj_release( &uirow->hdr );
5804
5805     msi_free( name );
5806     msi_free( display_name );
5807     return ERROR_SUCCESS;
5808 }
5809
5810 static UINT ACTION_StopServices( MSIPACKAGE *package )
5811 {
5812     UINT rc;
5813     MSIQUERY *view;
5814
5815     static const WCHAR query[] = {
5816         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5817         'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5818
5819     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
5820     if (rc != ERROR_SUCCESS)
5821         return ERROR_SUCCESS;
5822
5823     rc = MSI_IterateRecords(view, NULL, ITERATE_StopService, package);
5824     msiobj_release(&view->hdr);
5825
5826     return rc;
5827 }
5828
5829 static UINT ITERATE_DeleteService( MSIRECORD *rec, LPVOID param )
5830 {
5831     MSIPACKAGE *package = param;
5832     MSICOMPONENT *comp;
5833     MSIRECORD *uirow;
5834     LPCWSTR component;
5835     LPWSTR name = NULL, display_name = NULL;
5836     DWORD event, len;
5837     SC_HANDLE scm = NULL, service = NULL;
5838
5839     event = MSI_RecordGetInteger( rec, 3 );
5840     if (!(event & msidbServiceControlEventDelete))
5841         return ERROR_SUCCESS;
5842
5843     component = MSI_RecordGetString(rec, 6);
5844     comp = get_loaded_component(package, component);
5845     if (!comp)
5846         return ERROR_SUCCESS;
5847
5848     if (!comp->Enabled)
5849     {
5850         TRACE("component is disabled\n");
5851         return ERROR_SUCCESS;
5852     }
5853
5854     if (comp->ActionRequest != INSTALLSTATE_ABSENT)
5855     {
5856         TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
5857         comp->Action = comp->Installed;
5858         return ERROR_SUCCESS;
5859     }
5860     comp->Action = INSTALLSTATE_ABSENT;
5861
5862     deformat_string( package, MSI_RecordGetString(rec, 2), &name );
5863     stop_service( name );
5864
5865     scm = OpenSCManagerW( NULL, NULL, SC_MANAGER_ALL_ACCESS );
5866     if (!scm)
5867     {
5868         WARN("Failed to open the SCM: %d\n", GetLastError());
5869         goto done;
5870     }
5871
5872     len = 0;
5873     if (!GetServiceDisplayNameW( scm, name, NULL, &len ) &&
5874         GetLastError() == ERROR_INSUFFICIENT_BUFFER)
5875     {
5876         if ((display_name = msi_alloc( ++len * sizeof(WCHAR ))))
5877             GetServiceDisplayNameW( scm, name, display_name, &len );
5878     }
5879
5880     service = OpenServiceW( scm, name, DELETE );
5881     if (!service)
5882     {
5883         WARN("Failed to open service (%s): %u\n", debugstr_w(name), GetLastError());
5884         goto done;
5885     }
5886
5887     if (!DeleteService( service ))
5888         WARN("Failed to delete service (%s): %u\n", debugstr_w(name), GetLastError());
5889
5890 done:
5891     uirow = MSI_CreateRecord( 2 );
5892     MSI_RecordSetStringW( uirow, 1, display_name );
5893     MSI_RecordSetStringW( uirow, 2, name );
5894     ui_actiondata( package, szDeleteServices, uirow );
5895     msiobj_release( &uirow->hdr );
5896
5897     CloseServiceHandle( service );
5898     CloseServiceHandle( scm );
5899     msi_free( name );
5900     msi_free( display_name );
5901
5902     return ERROR_SUCCESS;
5903 }
5904
5905 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
5906 {
5907     UINT rc;
5908     MSIQUERY *view;
5909
5910     static const WCHAR query[] = {
5911         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5912         'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
5913
5914     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
5915     if (rc != ERROR_SUCCESS)
5916         return ERROR_SUCCESS;
5917
5918     rc = MSI_IterateRecords( view, NULL, ITERATE_DeleteService, package );
5919     msiobj_release( &view->hdr );
5920
5921     return rc;
5922 }
5923
5924 static UINT ITERATE_InstallODBCDriver( MSIRECORD *rec, LPVOID param )
5925 {
5926     MSIPACKAGE *package = param;
5927     LPWSTR driver, driver_path, ptr;
5928     WCHAR outpath[MAX_PATH];
5929     MSIFILE *driver_file = NULL, *setup_file = NULL;
5930     MSIRECORD *uirow;
5931     LPCWSTR desc, file_key;
5932     DWORD len, usage;
5933     UINT r = ERROR_SUCCESS;
5934
5935     static const WCHAR driver_fmt[] = {
5936         'D','r','i','v','e','r','=','%','s',0};
5937     static const WCHAR setup_fmt[] = {
5938         'S','e','t','u','p','=','%','s',0};
5939     static const WCHAR usage_fmt[] = {
5940         'F','i','l','e','U','s','a','g','e','=','1',0};
5941
5942     desc = MSI_RecordGetString(rec, 3);
5943
5944     file_key = MSI_RecordGetString( rec, 4 );
5945     if (file_key) driver_file = get_loaded_file( package, file_key );
5946
5947     file_key = MSI_RecordGetString( rec, 5 );
5948     if (file_key) setup_file = get_loaded_file( package, file_key );
5949
5950     if (!driver_file)
5951     {
5952         ERR("ODBC Driver entry not found!\n");
5953         return ERROR_FUNCTION_FAILED;
5954     }
5955
5956     len = lstrlenW(desc) + lstrlenW(driver_fmt) + lstrlenW(driver_file->FileName);
5957     if (setup_file)
5958         len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
5959     len += lstrlenW(usage_fmt) + 2; /* \0\0 */
5960
5961     driver = msi_alloc(len * sizeof(WCHAR));
5962     if (!driver)
5963         return ERROR_OUTOFMEMORY;
5964
5965     ptr = driver;
5966     lstrcpyW(ptr, desc);
5967     ptr += lstrlenW(ptr) + 1;
5968
5969     len = sprintfW(ptr, driver_fmt, driver_file->FileName);
5970     ptr += len + 1;
5971
5972     if (setup_file)
5973     {
5974         len = sprintfW(ptr, setup_fmt, setup_file->FileName);
5975         ptr += len + 1;
5976     }
5977
5978     lstrcpyW(ptr, usage_fmt);
5979     ptr += lstrlenW(ptr) + 1;
5980     *ptr = '\0';
5981
5982     driver_path = strdupW(driver_file->TargetPath);
5983     ptr = strrchrW(driver_path, '\\');
5984     if (ptr) *ptr = '\0';
5985
5986     if (!SQLInstallDriverExW(driver, driver_path, outpath, MAX_PATH,
5987                              NULL, ODBC_INSTALL_COMPLETE, &usage))
5988     {
5989         ERR("Failed to install SQL driver!\n");
5990         r = ERROR_FUNCTION_FAILED;
5991     }
5992
5993     uirow = MSI_CreateRecord( 5 );
5994     MSI_RecordSetStringW( uirow, 1, desc );
5995     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
5996     MSI_RecordSetStringW( uirow, 3, driver_file->Component->Directory );
5997     ui_actiondata( package, szInstallODBC, uirow );
5998     msiobj_release( &uirow->hdr );
5999
6000     msi_free(driver);
6001     msi_free(driver_path);
6002
6003     return r;
6004 }
6005
6006 static UINT ITERATE_InstallODBCTranslator( MSIRECORD *rec, LPVOID param )
6007 {
6008     MSIPACKAGE *package = param;
6009     LPWSTR translator, translator_path, ptr;
6010     WCHAR outpath[MAX_PATH];
6011     MSIFILE *translator_file = NULL, *setup_file = NULL;
6012     MSIRECORD *uirow;
6013     LPCWSTR desc, file_key;
6014     DWORD len, usage;
6015     UINT r = ERROR_SUCCESS;
6016
6017     static const WCHAR translator_fmt[] = {
6018         'T','r','a','n','s','l','a','t','o','r','=','%','s',0};
6019     static const WCHAR setup_fmt[] = {
6020         'S','e','t','u','p','=','%','s',0};
6021
6022     desc = MSI_RecordGetString(rec, 3);
6023
6024     file_key = MSI_RecordGetString( rec, 4 );
6025     if (file_key) translator_file = get_loaded_file( package, file_key );
6026
6027     file_key = MSI_RecordGetString( rec, 5 );
6028     if (file_key) setup_file = get_loaded_file( package, file_key );
6029
6030     if (!translator_file)
6031     {
6032         ERR("ODBC Translator entry not found!\n");
6033         return ERROR_FUNCTION_FAILED;
6034     }
6035
6036     len = lstrlenW(desc) + lstrlenW(translator_fmt) + lstrlenW(translator_file->FileName) + 2; /* \0\0 */
6037     if (setup_file)
6038         len += lstrlenW(setup_fmt) + lstrlenW(setup_file->FileName);
6039
6040     translator = msi_alloc(len * sizeof(WCHAR));
6041     if (!translator)
6042         return ERROR_OUTOFMEMORY;
6043
6044     ptr = translator;
6045     lstrcpyW(ptr, desc);
6046     ptr += lstrlenW(ptr) + 1;
6047
6048     len = sprintfW(ptr, translator_fmt, translator_file->FileName);
6049     ptr += len + 1;
6050
6051     if (setup_file)
6052     {
6053         len = sprintfW(ptr, setup_fmt, setup_file->FileName);
6054         ptr += len + 1;
6055     }
6056     *ptr = '\0';
6057
6058     translator_path = strdupW(translator_file->TargetPath);
6059     ptr = strrchrW(translator_path, '\\');
6060     if (ptr) *ptr = '\0';
6061
6062     if (!SQLInstallTranslatorExW(translator, translator_path, outpath, MAX_PATH,
6063                                  NULL, ODBC_INSTALL_COMPLETE, &usage))
6064     {
6065         ERR("Failed to install SQL translator!\n");
6066         r = ERROR_FUNCTION_FAILED;
6067     }
6068
6069     uirow = MSI_CreateRecord( 5 );
6070     MSI_RecordSetStringW( uirow, 1, desc );
6071     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6072     MSI_RecordSetStringW( uirow, 3, translator_file->Component->Directory );
6073     ui_actiondata( package, szInstallODBC, uirow );
6074     msiobj_release( &uirow->hdr );
6075
6076     msi_free(translator);
6077     msi_free(translator_path);
6078
6079     return r;
6080 }
6081
6082 static UINT ITERATE_InstallODBCDataSource( MSIRECORD *rec, LPVOID param )
6083 {
6084     MSIPACKAGE *package = param;
6085     LPWSTR attrs;
6086     LPCWSTR desc, driver;
6087     WORD request = ODBC_ADD_SYS_DSN;
6088     INT registration;
6089     DWORD len;
6090     UINT r = ERROR_SUCCESS;
6091     MSIRECORD *uirow;
6092
6093     static const WCHAR attrs_fmt[] = {
6094         'D','S','N','=','%','s',0 };
6095
6096     desc = MSI_RecordGetString(rec, 3);
6097     driver = MSI_RecordGetString(rec, 4);
6098     registration = MSI_RecordGetInteger(rec, 5);
6099
6100     if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_ADD_SYS_DSN;
6101     else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_ADD_DSN;
6102
6103     len = lstrlenW(attrs_fmt) + lstrlenW(desc) + 2; /* \0\0 */
6104     attrs = msi_alloc(len * sizeof(WCHAR));
6105     if (!attrs)
6106         return ERROR_OUTOFMEMORY;
6107
6108     len = sprintfW(attrs, attrs_fmt, desc);
6109     attrs[len + 1] = 0;
6110
6111     if (!SQLConfigDataSourceW(NULL, request, driver, attrs))
6112     {
6113         ERR("Failed to install SQL data source!\n");
6114         r = ERROR_FUNCTION_FAILED;
6115     }
6116
6117     uirow = MSI_CreateRecord( 5 );
6118     MSI_RecordSetStringW( uirow, 1, desc );
6119     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6120     MSI_RecordSetInteger( uirow, 3, request );
6121     ui_actiondata( package, szInstallODBC, uirow );
6122     msiobj_release( &uirow->hdr );
6123
6124     msi_free(attrs);
6125
6126     return r;
6127 }
6128
6129 static UINT ACTION_InstallODBC( MSIPACKAGE *package )
6130 {
6131     UINT rc;
6132     MSIQUERY *view;
6133
6134     static const WCHAR driver_query[] = {
6135         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6136         'O','D','B','C','D','r','i','v','e','r',0 };
6137
6138     static const WCHAR translator_query[] = {
6139         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6140         'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6141
6142     static const WCHAR source_query[] = {
6143         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6144         'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6145
6146     rc = MSI_DatabaseOpenViewW(package->db, driver_query, &view);
6147     if (rc != ERROR_SUCCESS)
6148         return ERROR_SUCCESS;
6149
6150     rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDriver, package);
6151     msiobj_release(&view->hdr);
6152
6153     rc = MSI_DatabaseOpenViewW(package->db, translator_query, &view);
6154     if (rc != ERROR_SUCCESS)
6155         return ERROR_SUCCESS;
6156
6157     rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCTranslator, package);
6158     msiobj_release(&view->hdr);
6159
6160     rc = MSI_DatabaseOpenViewW(package->db, source_query, &view);
6161     if (rc != ERROR_SUCCESS)
6162         return ERROR_SUCCESS;
6163
6164     rc = MSI_IterateRecords(view, NULL, ITERATE_InstallODBCDataSource, package);
6165     msiobj_release(&view->hdr);
6166
6167     return rc;
6168 }
6169
6170 static UINT ITERATE_RemoveODBCDriver( MSIRECORD *rec, LPVOID param )
6171 {
6172     MSIPACKAGE *package = param;
6173     MSIRECORD *uirow;
6174     DWORD usage;
6175     LPCWSTR desc;
6176
6177     desc = MSI_RecordGetString( rec, 3 );
6178     if (!SQLRemoveDriverW( desc, FALSE, &usage ))
6179     {
6180         WARN("Failed to remove ODBC driver\n");
6181     }
6182     else if (!usage)
6183     {
6184         FIXME("Usage count reached 0\n");
6185     }
6186
6187     uirow = MSI_CreateRecord( 2 );
6188     MSI_RecordSetStringW( uirow, 1, desc );
6189     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6190     ui_actiondata( package, szRemoveODBC, uirow );
6191     msiobj_release( &uirow->hdr );
6192
6193     return ERROR_SUCCESS;
6194 }
6195
6196 static UINT ITERATE_RemoveODBCTranslator( MSIRECORD *rec, LPVOID param )
6197 {
6198     MSIPACKAGE *package = param;
6199     MSIRECORD *uirow;
6200     DWORD usage;
6201     LPCWSTR desc;
6202
6203     desc = MSI_RecordGetString( rec, 3 );
6204     if (!SQLRemoveTranslatorW( desc, &usage ))
6205     {
6206         WARN("Failed to remove ODBC translator\n");
6207     }
6208     else if (!usage)
6209     {
6210         FIXME("Usage count reached 0\n");
6211     }
6212
6213     uirow = MSI_CreateRecord( 2 );
6214     MSI_RecordSetStringW( uirow, 1, desc );
6215     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6216     ui_actiondata( package, szRemoveODBC, uirow );
6217     msiobj_release( &uirow->hdr );
6218
6219     return ERROR_SUCCESS;
6220 }
6221
6222 static UINT ITERATE_RemoveODBCDataSource( MSIRECORD *rec, LPVOID param )
6223 {
6224     MSIPACKAGE *package = param;
6225     MSIRECORD *uirow;
6226     LPWSTR attrs;
6227     LPCWSTR desc, driver;
6228     WORD request = ODBC_REMOVE_SYS_DSN;
6229     INT registration;
6230     DWORD len;
6231
6232     static const WCHAR attrs_fmt[] = {
6233         'D','S','N','=','%','s',0 };
6234
6235     desc = MSI_RecordGetString( rec, 3 );
6236     driver = MSI_RecordGetString( rec, 4 );
6237     registration = MSI_RecordGetInteger( rec, 5 );
6238
6239     if (registration == msidbODBCDataSourceRegistrationPerMachine) request = ODBC_REMOVE_SYS_DSN;
6240     else if (registration == msidbODBCDataSourceRegistrationPerUser) request = ODBC_REMOVE_DSN;
6241
6242     len = strlenW( attrs_fmt ) + strlenW( desc ) + 2; /* \0\0 */
6243     attrs = msi_alloc( len * sizeof(WCHAR) );
6244     if (!attrs)
6245         return ERROR_OUTOFMEMORY;
6246
6247     FIXME("Use ODBCSourceAttribute table\n");
6248
6249     len = sprintfW( attrs, attrs_fmt, desc );
6250     attrs[len + 1] = 0;
6251
6252     if (!SQLConfigDataSourceW( NULL, request, driver, attrs ))
6253     {
6254         WARN("Failed to remove ODBC data source\n");
6255     }
6256     msi_free( attrs );
6257
6258     uirow = MSI_CreateRecord( 3 );
6259     MSI_RecordSetStringW( uirow, 1, desc );
6260     MSI_RecordSetStringW( uirow, 2, MSI_RecordGetString(rec, 2) );
6261     MSI_RecordSetInteger( uirow, 3, request );
6262     ui_actiondata( package, szRemoveODBC, uirow );
6263     msiobj_release( &uirow->hdr );
6264
6265     return ERROR_SUCCESS;
6266 }
6267
6268 static UINT ACTION_RemoveODBC( MSIPACKAGE *package )
6269 {
6270     UINT rc;
6271     MSIQUERY *view;
6272
6273     static const WCHAR driver_query[] = {
6274         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6275         'O','D','B','C','D','r','i','v','e','r',0 };
6276
6277     static const WCHAR translator_query[] = {
6278         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6279         'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6280
6281     static const WCHAR source_query[] = {
6282         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6283         'O','D','B','C','D','a','t','a','S','o','u','r','c','e',0 };
6284
6285     rc = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6286     if (rc != ERROR_SUCCESS)
6287         return ERROR_SUCCESS;
6288
6289     rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDriver, package );
6290     msiobj_release( &view->hdr );
6291
6292     rc = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6293     if (rc != ERROR_SUCCESS)
6294         return ERROR_SUCCESS;
6295
6296     rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCTranslator, package );
6297     msiobj_release( &view->hdr );
6298
6299     rc = MSI_DatabaseOpenViewW( package->db, source_query, &view );
6300     if (rc != ERROR_SUCCESS)
6301         return ERROR_SUCCESS;
6302
6303     rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveODBCDataSource, package );
6304     msiobj_release( &view->hdr );
6305
6306     return rc;
6307 }
6308
6309 #define ENV_ACT_SETALWAYS   0x1
6310 #define ENV_ACT_SETABSENT   0x2
6311 #define ENV_ACT_REMOVE      0x4
6312 #define ENV_ACT_REMOVEMATCH 0x8
6313
6314 #define ENV_MOD_MACHINE     0x20000000
6315 #define ENV_MOD_APPEND      0x40000000
6316 #define ENV_MOD_PREFIX      0x80000000
6317 #define ENV_MOD_MASK        0xC0000000
6318
6319 #define check_flag_combo(x, y) ((x) & ~(y)) == (y)
6320
6321 static UINT env_parse_flags( LPCWSTR *name, LPCWSTR *value, DWORD *flags )
6322 {
6323     LPCWSTR cptr = *name;
6324
6325     static const WCHAR prefix[] = {'[','~',']',0};
6326     static const int prefix_len = 3;
6327
6328     *flags = 0;
6329     while (*cptr)
6330     {
6331         if (*cptr == '=')
6332             *flags |= ENV_ACT_SETALWAYS;
6333         else if (*cptr == '+')
6334             *flags |= ENV_ACT_SETABSENT;
6335         else if (*cptr == '-')
6336             *flags |= ENV_ACT_REMOVE;
6337         else if (*cptr == '!')
6338             *flags |= ENV_ACT_REMOVEMATCH;
6339         else if (*cptr == '*')
6340             *flags |= ENV_MOD_MACHINE;
6341         else
6342             break;
6343
6344         cptr++;
6345         (*name)++;
6346     }
6347
6348     if (!*cptr)
6349     {
6350         ERR("Missing environment variable\n");
6351         return ERROR_FUNCTION_FAILED;
6352     }
6353
6354     if (*value)
6355     {
6356         LPCWSTR ptr = *value;
6357         if (!strncmpW(ptr, prefix, prefix_len))
6358         {
6359             if (ptr[prefix_len] == szSemiColon[0])
6360             {
6361                 *flags |= ENV_MOD_APPEND;
6362                 *value += lstrlenW(prefix);
6363             }
6364             else
6365             {
6366                 *value = NULL;
6367             }
6368         }
6369         else if (lstrlenW(*value) >= prefix_len)
6370         {
6371             ptr += lstrlenW(ptr) - prefix_len;
6372             if (!strcmpW( ptr, prefix ))
6373             {
6374                 if ((ptr-1) > *value && *(ptr-1) == szSemiColon[0])
6375                 {
6376                     *flags |= ENV_MOD_PREFIX;
6377                     /* the "[~]" will be removed by deformat_string */;
6378                 }
6379                 else
6380                 {
6381                     *value = NULL;
6382                 }
6383             }
6384         }
6385     }
6386
6387     if (check_flag_combo(*flags, ENV_ACT_SETALWAYS | ENV_ACT_SETABSENT) ||
6388         check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETABSENT) ||
6389         check_flag_combo(*flags, ENV_ACT_REMOVEMATCH | ENV_ACT_SETALWAYS) ||
6390         check_flag_combo(*flags, ENV_ACT_SETABSENT | ENV_MOD_MASK))
6391     {
6392         ERR("Invalid flags: %08x\n", *flags);
6393         return ERROR_FUNCTION_FAILED;
6394     }
6395
6396     if (!*flags)
6397         *flags = ENV_ACT_SETALWAYS | ENV_ACT_REMOVE;
6398
6399     return ERROR_SUCCESS;
6400 }
6401
6402 static UINT open_env_key( DWORD flags, HKEY *key )
6403 {
6404     static const WCHAR user_env[] =
6405         {'E','n','v','i','r','o','n','m','e','n','t',0};
6406     static const WCHAR machine_env[] =
6407         {'S','y','s','t','e','m','\\',
6408          'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
6409          'C','o','n','t','r','o','l','\\',
6410          'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r','\\',
6411          'E','n','v','i','r','o','n','m','e','n','t',0};
6412     const WCHAR *env;
6413     HKEY root;
6414     LONG res;
6415
6416     if (flags & ENV_MOD_MACHINE)
6417     {
6418         env = machine_env;
6419         root = HKEY_LOCAL_MACHINE;
6420     }
6421     else
6422     {
6423         env = user_env;
6424         root = HKEY_CURRENT_USER;
6425     }
6426
6427     res = RegOpenKeyExW( root, env, 0, KEY_ALL_ACCESS, key );
6428     if (res != ERROR_SUCCESS)
6429     {
6430         WARN("Failed to open key %s (%d)\n", debugstr_w(env), res);
6431         return ERROR_FUNCTION_FAILED;
6432     }
6433
6434     return ERROR_SUCCESS;
6435 }
6436
6437 static UINT ITERATE_WriteEnvironmentString( MSIRECORD *rec, LPVOID param )
6438 {
6439     MSIPACKAGE *package = param;
6440     LPCWSTR name, value, component;
6441     LPWSTR data = NULL, newval = NULL, deformatted = NULL, ptr;
6442     DWORD flags, type, size;
6443     UINT res;
6444     HKEY env = NULL;
6445     MSICOMPONENT *comp;
6446     MSIRECORD *uirow;
6447     int action = 0;
6448
6449     component = MSI_RecordGetString(rec, 4);
6450     comp = get_loaded_component(package, component);
6451     if (!comp)
6452         return ERROR_SUCCESS;
6453
6454     if (!comp->Enabled)
6455     {
6456         TRACE("component is disabled\n");
6457         return ERROR_SUCCESS;
6458     }
6459
6460     if (comp->ActionRequest != INSTALLSTATE_LOCAL)
6461     {
6462         TRACE("Component not scheduled for installation: %s\n", debugstr_w(component));
6463         comp->Action = comp->Installed;
6464         return ERROR_SUCCESS;
6465     }
6466     comp->Action = INSTALLSTATE_LOCAL;
6467
6468     name = MSI_RecordGetString(rec, 2);
6469     value = MSI_RecordGetString(rec, 3);
6470
6471     TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6472
6473     res = env_parse_flags(&name, &value, &flags);
6474     if (res != ERROR_SUCCESS || !value)
6475        goto done;
6476
6477     if (value && !deformat_string(package, value, &deformatted))
6478     {
6479         res = ERROR_OUTOFMEMORY;
6480         goto done;
6481     }
6482
6483     value = deformatted;
6484
6485     res = open_env_key( flags, &env );
6486     if (res != ERROR_SUCCESS)
6487         goto done;
6488
6489     if (flags & ENV_MOD_MACHINE)
6490         action |= 0x20000000;
6491
6492     size = 0;
6493     type = REG_SZ;
6494     res = RegQueryValueExW(env, name, NULL, &type, NULL, &size);
6495     if ((res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND) ||
6496         (res == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ))
6497         goto done;
6498
6499     if ((res == ERROR_FILE_NOT_FOUND || !(flags & ENV_MOD_MASK)))
6500     {
6501         action = 0x2;
6502
6503         /* Nothing to do. */
6504         if (!value)
6505         {
6506             res = ERROR_SUCCESS;
6507             goto done;
6508         }
6509
6510         /* If we are appending but the string was empty, strip ; */
6511         if ((flags & ENV_MOD_APPEND) && (value[0] == szSemiColon[0])) value++;
6512
6513         size = (lstrlenW(value) + 1) * sizeof(WCHAR);
6514         newval = strdupW(value);
6515         if (!newval)
6516         {
6517             res = ERROR_OUTOFMEMORY;
6518             goto done;
6519         }
6520     }
6521     else
6522     {
6523         action = 0x1;
6524
6525         /* Contrary to MSDN, +-variable to [~];path works */
6526         if (flags & ENV_ACT_SETABSENT && !(flags & ENV_MOD_MASK))
6527         {
6528             res = ERROR_SUCCESS;
6529             goto done;
6530         }
6531
6532         data = msi_alloc(size);
6533         if (!data)
6534         {
6535             RegCloseKey(env);
6536             return ERROR_OUTOFMEMORY;
6537         }
6538
6539         res = RegQueryValueExW(env, name, NULL, &type, (LPVOID)data, &size);
6540         if (res != ERROR_SUCCESS)
6541             goto done;
6542
6543         if (flags & ENV_ACT_REMOVEMATCH && (!value || !strcmpW( data, value )))
6544         {
6545             action = 0x4;
6546             res = RegDeleteValueW(env, name);
6547             if (res != ERROR_SUCCESS)
6548                 WARN("Failed to remove value %s (%d)\n", debugstr_w(name), res);
6549             goto done;
6550         }
6551
6552         size = (lstrlenW(data) + 1) * sizeof(WCHAR);
6553         if (flags & ENV_MOD_MASK)
6554         {
6555             DWORD mod_size;
6556             int multiplier = 0;
6557             if (flags & ENV_MOD_APPEND) multiplier++;
6558             if (flags & ENV_MOD_PREFIX) multiplier++;
6559             mod_size = lstrlenW(value) * multiplier;
6560             size += mod_size * sizeof(WCHAR);
6561         }
6562
6563         newval = msi_alloc(size);
6564         ptr = newval;
6565         if (!newval)
6566         {
6567             res = ERROR_OUTOFMEMORY;
6568             goto done;
6569         }
6570
6571         if (flags & ENV_MOD_PREFIX)
6572         {
6573             lstrcpyW(newval, value);
6574             ptr = newval + lstrlenW(value);
6575             action |= 0x80000000;
6576         }
6577
6578         lstrcpyW(ptr, data);
6579
6580         if (flags & ENV_MOD_APPEND)
6581         {
6582             lstrcatW(newval, value);
6583             action |= 0x40000000;
6584         }
6585     }
6586     TRACE("setting %s to %s\n", debugstr_w(name), debugstr_w(newval));
6587     res = RegSetValueExW(env, name, 0, type, (LPVOID)newval, size);
6588     if (res)
6589     {
6590         WARN("Failed to set %s to %s (%d)\n",  debugstr_w(name), debugstr_w(newval), res);
6591     }
6592
6593 done:
6594     uirow = MSI_CreateRecord( 3 );
6595     MSI_RecordSetStringW( uirow, 1, name );
6596     MSI_RecordSetStringW( uirow, 2, newval );
6597     MSI_RecordSetInteger( uirow, 3, action );
6598     ui_actiondata( package, szWriteEnvironmentStrings, uirow );
6599     msiobj_release( &uirow->hdr );
6600
6601     if (env) RegCloseKey(env);
6602     msi_free(deformatted);
6603     msi_free(data);
6604     msi_free(newval);
6605     return res;
6606 }
6607
6608 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
6609 {
6610     UINT rc;
6611     MSIQUERY * view;
6612     static const WCHAR ExecSeqQuery[] =
6613         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6614          '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6615     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6616     if (rc != ERROR_SUCCESS)
6617         return ERROR_SUCCESS;
6618
6619     rc = MSI_IterateRecords(view, NULL, ITERATE_WriteEnvironmentString, package);
6620     msiobj_release(&view->hdr);
6621
6622     return rc;
6623 }
6624
6625 static UINT ITERATE_RemoveEnvironmentString( MSIRECORD *rec, LPVOID param )
6626 {
6627     MSIPACKAGE *package = param;
6628     LPCWSTR name, value, component;
6629     LPWSTR deformatted = NULL;
6630     DWORD flags;
6631     HKEY env;
6632     MSICOMPONENT *comp;
6633     MSIRECORD *uirow;
6634     int action = 0;
6635     LONG res;
6636     UINT r;
6637
6638     component = MSI_RecordGetString( rec, 4 );
6639     comp = get_loaded_component( package, component );
6640     if (!comp)
6641         return ERROR_SUCCESS;
6642
6643     if (!comp->Enabled)
6644     {
6645         TRACE("component is disabled\n");
6646         return ERROR_SUCCESS;
6647     }
6648
6649     if (comp->ActionRequest != INSTALLSTATE_ABSENT)
6650     {
6651         TRACE("Component not scheduled for removal: %s\n", debugstr_w(component));
6652         comp->Action = comp->Installed;
6653         return ERROR_SUCCESS;
6654     }
6655     comp->Action = INSTALLSTATE_ABSENT;
6656
6657     name = MSI_RecordGetString( rec, 2 );
6658     value = MSI_RecordGetString( rec, 3 );
6659
6660     TRACE("name %s value %s\n", debugstr_w(name), debugstr_w(value));
6661
6662     r = env_parse_flags( &name, &value, &flags );
6663     if (r != ERROR_SUCCESS)
6664        return r;
6665
6666     if (!(flags & ENV_ACT_REMOVE))
6667     {
6668         TRACE("Environment variable %s not marked for removal\n", debugstr_w(name));
6669         return ERROR_SUCCESS;
6670     }
6671
6672     if (value && !deformat_string( package, value, &deformatted ))
6673         return ERROR_OUTOFMEMORY;
6674
6675     value = deformatted;
6676
6677     r = open_env_key( flags, &env );
6678     if (r != ERROR_SUCCESS)
6679     {
6680         r = ERROR_SUCCESS;
6681         goto done;
6682     }
6683
6684     if (flags & ENV_MOD_MACHINE)
6685         action |= 0x20000000;
6686
6687     TRACE("Removing %s\n", debugstr_w(name));
6688
6689     res = RegDeleteValueW( env, name );
6690     if (res != ERROR_SUCCESS)
6691     {
6692         WARN("Failed to delete value %s (%d)\n", debugstr_w(name), res);
6693         r = ERROR_SUCCESS;
6694     }
6695
6696 done:
6697     uirow = MSI_CreateRecord( 3 );
6698     MSI_RecordSetStringW( uirow, 1, name );
6699     MSI_RecordSetStringW( uirow, 2, value );
6700     MSI_RecordSetInteger( uirow, 3, action );
6701     ui_actiondata( package, szRemoveEnvironmentStrings, uirow );
6702     msiobj_release( &uirow->hdr );
6703
6704     if (env) RegCloseKey( env );
6705     msi_free( deformatted );
6706     return r;
6707 }
6708
6709 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
6710 {
6711     UINT rc;
6712     MSIQUERY *view;
6713     static const WCHAR query[] =
6714         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6715          '`','E','n','v','i','r','o','n','m','e','n','t','`',0};
6716
6717     rc = MSI_DatabaseOpenViewW( package->db, query, &view );
6718     if (rc != ERROR_SUCCESS)
6719         return ERROR_SUCCESS;
6720
6721     rc = MSI_IterateRecords( view, NULL, ITERATE_RemoveEnvironmentString, package );
6722     msiobj_release( &view->hdr );
6723
6724     return rc;
6725 }
6726
6727 static UINT ACTION_ValidateProductID( MSIPACKAGE *package )
6728 {
6729     LPWSTR key, template, id;
6730     UINT r = ERROR_SUCCESS;
6731
6732     id = msi_dup_property( package->db, szProductID );
6733     if (id)
6734     {
6735         msi_free( id );
6736         return ERROR_SUCCESS;
6737     }
6738     template = msi_dup_property( package->db, szPIDTemplate );
6739     key = msi_dup_property( package->db, szPIDKEY );
6740
6741     if (key && template)
6742     {
6743         FIXME( "partial stub: template %s key %s\n", debugstr_w(template), debugstr_w(key) );
6744         r = msi_set_property( package->db, szProductID, key );
6745     }
6746     msi_free( template );
6747     msi_free( key );
6748     return r;
6749 }
6750
6751 static UINT ACTION_ScheduleReboot( MSIPACKAGE *package )
6752 {
6753     TRACE("\n");
6754     package->need_reboot = 1;
6755     return ERROR_SUCCESS;
6756 }
6757
6758 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
6759 {
6760     static const WCHAR szAvailableFreeReg[] =
6761         {'A','V','A','I','L','A','B','L','E','F','R','E','E','R','E','G',0};
6762     MSIRECORD *uirow;
6763     int space = msi_get_property_int( package->db, szAvailableFreeReg, 0 );
6764
6765     TRACE("%p %d kilobytes\n", package, space);
6766
6767     uirow = MSI_CreateRecord( 1 );
6768     MSI_RecordSetInteger( uirow, 1, space );
6769     ui_actiondata( package, szAllocateRegistrySpace, uirow );
6770     msiobj_release( &uirow->hdr );
6771
6772     return ERROR_SUCCESS;
6773 }
6774
6775 static UINT ACTION_DisableRollback( MSIPACKAGE *package )
6776 {
6777     FIXME("%p\n", package);
6778     return ERROR_SUCCESS;
6779 }
6780
6781 static UINT ACTION_InstallAdminPackage( MSIPACKAGE *package )
6782 {
6783     FIXME("%p\n", package);
6784     return ERROR_SUCCESS;
6785 }
6786
6787 static UINT ACTION_SetODBCFolders( MSIPACKAGE *package )
6788 {
6789     UINT r, count;
6790     MSIQUERY *view;
6791
6792     static const WCHAR driver_query[] = {
6793         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6794         'O','D','B','C','D','r','i','v','e','r',0 };
6795
6796     static const WCHAR translator_query[] = {
6797         'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6798         'O','D','B','C','T','r','a','n','s','l','a','t','o','r',0 };
6799
6800     r = MSI_DatabaseOpenViewW( package->db, driver_query, &view );
6801     if (r == ERROR_SUCCESS)
6802     {
6803         count = 0;
6804         r = MSI_IterateRecords( view, &count, NULL, package );
6805         msiobj_release( &view->hdr );
6806         if (count) FIXME("ignored %u rows in ODBCDriver table\n", count);
6807     }
6808
6809     r = MSI_DatabaseOpenViewW( package->db, translator_query, &view );
6810     if (r == ERROR_SUCCESS)
6811     {
6812         count = 0;
6813         r = MSI_IterateRecords( view, &count, NULL, package );
6814         msiobj_release( &view->hdr );
6815         if (count) FIXME("ignored %u rows in ODBCTranslator table\n", count);
6816     }
6817
6818     return ERROR_SUCCESS;
6819 }
6820
6821 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
6822                                            LPCSTR action, LPCWSTR table )
6823 {
6824     static const WCHAR query[] = {
6825         'S','E','L','E','C','T',' ','*',' ',
6826         'F','R','O','M',' ','`','%','s','`',0 };
6827     MSIQUERY *view = NULL;
6828     DWORD count = 0;
6829     UINT r;
6830     
6831     r = MSI_OpenQuery( package->db, &view, query, table );
6832     if (r == ERROR_SUCCESS)
6833     {
6834         r = MSI_IterateRecords(view, &count, NULL, package);
6835         msiobj_release(&view->hdr);
6836     }
6837
6838     if (count)
6839         FIXME("%s -> %u ignored %s table values\n",
6840               action, count, debugstr_w(table));
6841
6842     return ERROR_SUCCESS;
6843 }
6844
6845 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
6846 {
6847     static const WCHAR table[] = { 'P','a','t','c','h',0 };
6848     return msi_unimplemented_action_stub( package, "PatchFiles", table );
6849 }
6850
6851 static UINT ACTION_BindImage( MSIPACKAGE *package )
6852 {
6853     static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
6854     return msi_unimplemented_action_stub( package, "BindImage", table );
6855 }
6856
6857 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
6858 {
6859     static const WCHAR table[] = {
6860         'I','s','o','l','a','t','e','d','C','o','m','p','o','n','e','n','t',0 };
6861     return msi_unimplemented_action_stub( package, "IsolateComponents", table );
6862 }
6863
6864 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
6865 {
6866     static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6867     return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
6868 }
6869
6870 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
6871 {
6872     static const WCHAR table[] = {
6873         'M','s','i','A','s','s','e','m','b','l','y',0 };
6874     return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
6875 }
6876
6877 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
6878 {
6879     static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
6880     return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
6881 }
6882
6883 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
6884 {
6885     static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6886     return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
6887 }
6888
6889 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
6890 {
6891     static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
6892     return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
6893 }
6894
6895 static UINT ACTION_InstallSFPCatalogFile( MSIPACKAGE *package )
6896 {
6897     static const WCHAR table[] = { 'S','F','P','C','a','t','a','l','o','g',0 };
6898     return msi_unimplemented_action_stub( package, "InstallSFPCatalogFile", table );
6899 }
6900
6901 static UINT ACTION_RemoveExistingProducts( MSIPACKAGE *package )
6902 {
6903     static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
6904     return msi_unimplemented_action_stub( package, "RemoveExistingProducts", table );
6905 }
6906
6907 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
6908
6909 static const struct
6910 {
6911     const WCHAR *action;
6912     UINT (*handler)(MSIPACKAGE *);
6913 }
6914 StandardActions[] =
6915 {
6916     { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
6917     { szAppSearch, ACTION_AppSearch },
6918     { szBindImage, ACTION_BindImage },
6919     { szCCPSearch, ACTION_CCPSearch },
6920     { szCostFinalize, ACTION_CostFinalize },
6921     { szCostInitialize, ACTION_CostInitialize },
6922     { szCreateFolders, ACTION_CreateFolders },
6923     { szCreateShortcuts, ACTION_CreateShortcuts },
6924     { szDeleteServices, ACTION_DeleteServices },
6925     { szDisableRollback, ACTION_DisableRollback },
6926     { szDuplicateFiles, ACTION_DuplicateFiles },
6927     { szExecuteAction, ACTION_ExecuteAction },
6928     { szFileCost, ACTION_FileCost },
6929     { szFindRelatedProducts, ACTION_FindRelatedProducts },
6930     { szForceReboot, ACTION_ForceReboot },
6931     { szInstallAdminPackage, ACTION_InstallAdminPackage },
6932     { szInstallExecute, ACTION_InstallExecute },
6933     { szInstallExecuteAgain, ACTION_InstallExecute },
6934     { szInstallFiles, ACTION_InstallFiles},
6935     { szInstallFinalize, ACTION_InstallFinalize },
6936     { szInstallInitialize, ACTION_InstallInitialize },
6937     { szInstallSFPCatalogFile, ACTION_InstallSFPCatalogFile },
6938     { szInstallValidate, ACTION_InstallValidate },
6939     { szIsolateComponents, ACTION_IsolateComponents },
6940     { szLaunchConditions, ACTION_LaunchConditions },
6941     { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
6942     { szMoveFiles, ACTION_MoveFiles },
6943     { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
6944     { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
6945     { szInstallODBC, ACTION_InstallODBC },
6946     { szInstallServices, ACTION_InstallServices },
6947     { szPatchFiles, ACTION_PatchFiles },
6948     { szProcessComponents, ACTION_ProcessComponents },
6949     { szPublishComponents, ACTION_PublishComponents },
6950     { szPublishFeatures, ACTION_PublishFeatures },
6951     { szPublishProduct, ACTION_PublishProduct },
6952     { szRegisterClassInfo, ACTION_RegisterClassInfo },
6953     { szRegisterComPlus, ACTION_RegisterComPlus},
6954     { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
6955     { szRegisterFonts, ACTION_RegisterFonts },
6956     { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
6957     { szRegisterProduct, ACTION_RegisterProduct },
6958     { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
6959     { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
6960     { szRegisterUser, ACTION_RegisterUser },
6961     { szRemoveDuplicateFiles, ACTION_RemoveDuplicateFiles },
6962     { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
6963     { szRemoveExistingProducts, ACTION_RemoveExistingProducts },
6964     { szRemoveFiles, ACTION_RemoveFiles },
6965     { szRemoveFolders, ACTION_RemoveFolders },
6966     { szRemoveIniValues, ACTION_RemoveIniValues },
6967     { szRemoveODBC, ACTION_RemoveODBC },
6968     { szRemoveRegistryValues, ACTION_RemoveRegistryValues },
6969     { szRemoveShortcuts, ACTION_RemoveShortcuts },
6970     { szResolveSource, ACTION_ResolveSource },
6971     { szRMCCPSearch, ACTION_RMCCPSearch },
6972     { szScheduleReboot, ACTION_ScheduleReboot },
6973     { szSelfRegModules, ACTION_SelfRegModules },
6974     { szSelfUnregModules, ACTION_SelfUnregModules },
6975     { szSetODBCFolders, ACTION_SetODBCFolders },
6976     { szStartServices, ACTION_StartServices },
6977     { szStopServices, ACTION_StopServices },
6978     { szUnpublishComponents, ACTION_UnpublishComponents },
6979     { szUnpublishFeatures, ACTION_UnpublishFeatures },
6980     { szUnregisterClassInfo, ACTION_UnregisterClassInfo },
6981     { szUnregisterComPlus, ACTION_UnregisterComPlus },
6982     { szUnregisterExtensionInfo, ACTION_UnregisterExtensionInfo },
6983     { szUnregisterFonts, ACTION_UnregisterFonts },
6984     { szUnregisterMIMEInfo, ACTION_UnregisterMIMEInfo },
6985     { szUnregisterProgIdInfo, ACTION_UnregisterProgIdInfo },
6986     { szUnregisterTypeLibraries, ACTION_UnregisterTypeLibraries },
6987     { szValidateProductID, ACTION_ValidateProductID },
6988     { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
6989     { szWriteIniValues, ACTION_WriteIniValues },
6990     { szWriteRegistryValues, ACTION_WriteRegistryValues },
6991     { NULL, NULL },
6992 };
6993
6994 static BOOL ACTION_HandleStandardAction( MSIPACKAGE *package, LPCWSTR action, UINT *rc )
6995 {
6996     BOOL ret = FALSE;
6997     UINT i;
6998
6999     i = 0;
7000     while (StandardActions[i].action != NULL)
7001     {
7002         if (!strcmpW( StandardActions[i].action, action ))
7003         {
7004             ui_actionstart( package, action );
7005             if (StandardActions[i].handler)
7006             {
7007                 ui_actioninfo( package, action, TRUE, 0 );
7008                 *rc = StandardActions[i].handler( package );
7009                 ui_actioninfo( package, action, FALSE, *rc );
7010             }
7011             else
7012             {
7013                 FIXME("unhandled standard action %s\n", debugstr_w(action));
7014                 *rc = ERROR_SUCCESS;
7015             }
7016             ret = TRUE;
7017             break;
7018         }
7019         i++;
7020     }
7021     return ret;
7022 }
7023
7024 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7025 {
7026     UINT rc = ERROR_SUCCESS;
7027     BOOL handled;
7028
7029     TRACE("Performing action (%s)\n", debugstr_w(action));
7030
7031     handled = ACTION_HandleStandardAction(package, action, &rc);
7032
7033     if (!handled)
7034         handled = ACTION_HandleCustomAction(package, action, &rc, script, TRUE);
7035
7036     if (!handled)
7037     {
7038         WARN("unhandled msi action %s\n", debugstr_w(action));
7039         rc = ERROR_FUNCTION_NOT_CALLED;
7040     }
7041
7042     return rc;
7043 }
7044
7045 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action, UINT script)
7046 {
7047     UINT rc = ERROR_SUCCESS;
7048     BOOL handled = FALSE;
7049
7050     TRACE("Performing action (%s)\n", debugstr_w(action));
7051
7052     handled = ACTION_HandleStandardAction(package, action, &rc);
7053
7054     if (!handled)
7055         handled = ACTION_HandleCustomAction(package, action, &rc, script, FALSE);
7056
7057     if( !handled && ACTION_DialogBox(package, action) == ERROR_SUCCESS )
7058         handled = TRUE;
7059
7060     if (!handled)
7061     {
7062         WARN("unhandled msi action %s\n", debugstr_w(action));
7063         rc = ERROR_FUNCTION_NOT_CALLED;
7064     }
7065
7066     return rc;
7067 }
7068
7069 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq)
7070 {
7071     UINT rc = ERROR_SUCCESS;
7072     MSIRECORD *row;
7073
7074     static const WCHAR ExecSeqQuery[] =
7075         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7076          '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
7077          'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
7078          '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
7079     static const WCHAR UISeqQuery[] =
7080         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7081      '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
7082      '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
7083          ' ', '=',' ','%','i',0};
7084
7085     if (needs_ui_sequence(package))
7086         row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
7087     else
7088         row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
7089
7090     if (row)
7091     {
7092         LPCWSTR action, cond;
7093
7094         TRACE("Running the actions\n");
7095
7096         /* check conditions */
7097         cond = MSI_RecordGetString(row, 2);
7098
7099         /* this is a hack to skip errors in the condition code */
7100         if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
7101         {
7102             msiobj_release(&row->hdr);
7103             return ERROR_SUCCESS;
7104         }
7105
7106         action = MSI_RecordGetString(row, 1);
7107         if (!action)
7108         {
7109             ERR("failed to fetch action\n");
7110             msiobj_release(&row->hdr);
7111             return ERROR_FUNCTION_FAILED;
7112         }
7113
7114         if (needs_ui_sequence(package))
7115             rc = ACTION_PerformUIAction(package, action, -1);
7116         else
7117             rc = ACTION_PerformAction(package, action, -1);
7118
7119         msiobj_release(&row->hdr);
7120     }
7121
7122     return rc;
7123 }
7124
7125 /****************************************************
7126  * TOP level entry points
7127  *****************************************************/
7128
7129 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
7130                          LPCWSTR szCommandLine )
7131 {
7132     UINT rc;
7133     BOOL ui_exists;
7134
7135     static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
7136     static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
7137
7138     msi_set_property( package->db, szAction, szInstall );
7139
7140     package->script->InWhatSequence = SEQUENCE_INSTALL;
7141
7142     if (szPackagePath)
7143     {
7144         LPWSTR p, dir;
7145         LPCWSTR file;
7146
7147         dir = strdupW(szPackagePath);
7148         p = strrchrW(dir, '\\');
7149         if (p)
7150         {
7151             *(++p) = 0;
7152             file = szPackagePath + (p - dir);
7153         }
7154         else
7155         {
7156             msi_free(dir);
7157             dir = msi_alloc(MAX_PATH * sizeof(WCHAR));
7158             GetCurrentDirectoryW(MAX_PATH, dir);
7159             lstrcatW(dir, szBackSlash);
7160             file = szPackagePath;
7161         }
7162
7163         msi_free( package->PackagePath );
7164         package->PackagePath = msi_alloc((lstrlenW(dir) + lstrlenW(file) + 1) * sizeof(WCHAR));
7165         if (!package->PackagePath)
7166         {
7167             msi_free(dir);
7168             return ERROR_OUTOFMEMORY;
7169         }
7170
7171         lstrcpyW(package->PackagePath, dir);
7172         lstrcatW(package->PackagePath, file);
7173         msi_free(dir);
7174
7175         msi_set_sourcedir_props(package, FALSE);
7176     }
7177
7178     msi_parse_command_line( package, szCommandLine, FALSE );
7179
7180     msi_apply_transforms( package );
7181     msi_apply_patches( package );
7182
7183     if (!szCommandLine && msi_get_property_int( package->db, szInstalled, 0 ))
7184     {
7185         TRACE("setting reinstall property\n");
7186         msi_set_property( package->db, szReinstall, szAll );
7187     }
7188
7189     /* properties may have been added by a transform */
7190     msi_clone_properties( package );
7191
7192     msi_parse_command_line( package, szCommandLine, FALSE );
7193     msi_adjust_privilege_properties( package );
7194     msi_set_context( package );
7195
7196     if (needs_ui_sequence( package))
7197     {
7198         package->script->InWhatSequence |= SEQUENCE_UI;
7199         rc = ACTION_ProcessUISequence(package);
7200         ui_exists = ui_sequence_exists(package);
7201         if (rc == ERROR_SUCCESS || !ui_exists)
7202         {
7203             package->script->InWhatSequence |= SEQUENCE_EXEC;
7204             rc = ACTION_ProcessExecSequence(package, ui_exists);
7205         }
7206     }
7207     else
7208         rc = ACTION_ProcessExecSequence(package, FALSE);
7209
7210     package->script->CurrentlyScripting = FALSE;
7211
7212     /* process the ending type action */
7213     if (rc == ERROR_SUCCESS)
7214         ACTION_PerformActionSequence(package, -1);
7215     else if (rc == ERROR_INSTALL_USEREXIT)
7216         ACTION_PerformActionSequence(package, -2);
7217     else if (rc == ERROR_INSTALL_SUSPEND)
7218         ACTION_PerformActionSequence(package, -4);
7219     else  /* failed */
7220         ACTION_PerformActionSequence(package, -3);
7221
7222     /* finish up running custom actions */
7223     ACTION_FinishCustomActions(package);
7224
7225     if (rc == ERROR_SUCCESS && package->need_reboot)
7226         return ERROR_SUCCESS_REBOOT_REQUIRED;
7227
7228     return rc;
7229 }