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