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