mshtml: Print wine_gecko version in load_wine_gecko.
[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 /*
22  * Pages I need
23  *
24 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
25
26 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
27  */
28
29 #include <stdarg.h>
30
31 #define COBJMACROS
32
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winerror.h"
36 #include "winreg.h"
37 #include "winsvc.h"
38 #include "wine/debug.h"
39 #include "msidefs.h"
40 #include "msipriv.h"
41 #include "winuser.h"
42 #include "shlobj.h"
43 #include "wine/unicode.h"
44 #include "winver.h"
45
46 #define REG_PROGRESS_VALUE 13200
47 #define COMPONENT_PROGRESS_VALUE 24000
48
49 WINE_DEFAULT_DEBUG_CHANNEL(msi);
50
51 /*
52  * Prototypes
53  */
54 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
55 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
56 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
57
58 /*
59  * consts and values used
60  */
61 static const WCHAR c_colon[] = {'C',':','\\',0};
62
63 static const WCHAR szCreateFolders[] =
64     {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
65 static const WCHAR szCostFinalize[] =
66     {'C','o','s','t','F','i','n','a','l','i','z','e',0};
67 const WCHAR szInstallFiles[] =
68     {'I','n','s','t','a','l','l','F','i','l','e','s',0};
69 const WCHAR szDuplicateFiles[] =
70     {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
71 static const WCHAR szWriteRegistryValues[] =
72     {'W','r','i','t','e','R','e','g','i','s','t','r','y',
73             'V','a','l','u','e','s',0};
74 static const WCHAR szCostInitialize[] =
75     {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
76 static const WCHAR szFileCost[] = 
77     {'F','i','l','e','C','o','s','t',0};
78 static const WCHAR szInstallInitialize[] = 
79     {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
80 static const WCHAR szInstallValidate[] = 
81     {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
82 static const WCHAR szLaunchConditions[] = 
83     {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
84 static const WCHAR szProcessComponents[] = 
85     {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
86 static const WCHAR szRegisterTypeLibraries[] = 
87     {'R','e','g','i','s','t','e','r','T','y','p','e',
88             'L','i','b','r','a','r','i','e','s',0};
89 const WCHAR szRegisterClassInfo[] = 
90     {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
91 const WCHAR szRegisterProgIdInfo[] = 
92     {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
93 static const WCHAR szCreateShortcuts[] = 
94     {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
95 static const WCHAR szPublishProduct[] = 
96     {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
97 static const WCHAR szWriteIniValues[] = 
98     {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
99 static const WCHAR szSelfRegModules[] = 
100     {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
101 static const WCHAR szPublishFeatures[] = 
102     {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
103 static const WCHAR szRegisterProduct[] = 
104     {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
105 static const WCHAR szInstallExecute[] = 
106     {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
107 static const WCHAR szInstallExecuteAgain[] = 
108     {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
109             'A','g','a','i','n',0};
110 static const WCHAR szInstallFinalize[] = 
111     {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
112 static const WCHAR szForceReboot[] = 
113     {'F','o','r','c','e','R','e','b','o','o','t',0};
114 static const WCHAR szResolveSource[] =
115     {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
116 static const WCHAR szAppSearch[] = 
117     {'A','p','p','S','e','a','r','c','h',0};
118 static const WCHAR szAllocateRegistrySpace[] = 
119     {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
120             'S','p','a','c','e',0};
121 static const WCHAR szBindImage[] = 
122     {'B','i','n','d','I','m','a','g','e',0};
123 static const WCHAR szCCPSearch[] = 
124     {'C','C','P','S','e','a','r','c','h',0};
125 static const WCHAR szDeleteServices[] = 
126     {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
127 static const WCHAR szDisableRollback[] = 
128     {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
129 static const WCHAR szExecuteAction[] = 
130     {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
131 const WCHAR szFindRelatedProducts[] = 
132     {'F','i','n','d','R','e','l','a','t','e','d',
133             'P','r','o','d','u','c','t','s',0};
134 static const WCHAR szInstallAdminPackage[] = 
135     {'I','n','s','t','a','l','l','A','d','m','i','n',
136             'P','a','c','k','a','g','e',0};
137 static const WCHAR szInstallSFPCatalogFile[] = 
138     {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
139             'F','i','l','e',0};
140 static const WCHAR szIsolateComponents[] = 
141     {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
142 const WCHAR szMigrateFeatureStates[] = 
143     {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
144             'S','t','a','t','e','s',0};
145 const WCHAR szMoveFiles[] = 
146     {'M','o','v','e','F','i','l','e','s',0};
147 static const WCHAR szMsiPublishAssemblies[] = 
148     {'M','s','i','P','u','b','l','i','s','h',
149             'A','s','s','e','m','b','l','i','e','s',0};
150 static const WCHAR szMsiUnpublishAssemblies[] = 
151     {'M','s','i','U','n','p','u','b','l','i','s','h',
152             'A','s','s','e','m','b','l','i','e','s',0};
153 static const WCHAR szInstallODBC[] = 
154     {'I','n','s','t','a','l','l','O','D','B','C',0};
155 static const WCHAR szInstallServices[] = 
156     {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
157 const WCHAR szPatchFiles[] = 
158     {'P','a','t','c','h','F','i','l','e','s',0};
159 static const WCHAR szPublishComponents[] = 
160     {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
161 static const WCHAR szRegisterComPlus[] =
162     {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
163 const WCHAR szRegisterExtensionInfo[] =
164     {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
165             'I','n','f','o',0};
166 static const WCHAR szRegisterFonts[] =
167     {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
168 const WCHAR szRegisterMIMEInfo[] =
169     {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
170 static const WCHAR szRegisterUser[] =
171     {'R','e','g','i','s','t','e','r','U','s','e','r',0};
172 const WCHAR szRemoveDuplicateFiles[] =
173     {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
174             'F','i','l','e','s',0};
175 static const WCHAR szRemoveEnvironmentStrings[] =
176     {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
177             'S','t','r','i','n','g','s',0};
178 const WCHAR szRemoveExistingProducts[] =
179     {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
180             'P','r','o','d','u','c','t','s',0};
181 const WCHAR szRemoveFiles[] =
182     {'R','e','m','o','v','e','F','i','l','e','s',0};
183 static const WCHAR szRemoveFolders[] =
184     {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
185 static const WCHAR szRemoveIniValues[] =
186     {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
187 static const WCHAR szRemoveODBC[] =
188     {'R','e','m','o','v','e','O','D','B','C',0};
189 static const WCHAR szRemoveRegistryValues[] =
190     {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
191             'V','a','l','u','e','s',0};
192 static const WCHAR szRemoveShortcuts[] =
193     {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
194 static const WCHAR szRMCCPSearch[] =
195     {'R','M','C','C','P','S','e','a','r','c','h',0};
196 static const WCHAR szScheduleReboot[] =
197     {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
198 static const WCHAR szSelfUnregModules[] =
199     {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
200 static const WCHAR szSetODBCFolders[] =
201     {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
202 static const WCHAR szStartServices[] =
203     {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
204 static const WCHAR szStopServices[] =
205     {'S','t','o','p','S','e','r','v','i','c','e','s',0};
206 static const WCHAR szUnpublishComponents[] =
207     {'U','n','p','u','b','l','i','s','h',
208             'C','o','m','p','o','n','e','n','t','s',0};
209 static const WCHAR szUnpublishFeatures[] =
210     {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
211 const WCHAR szUnregisterClassInfo[] =
212     {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
213             'I','n','f','o',0};
214 static const WCHAR szUnregisterComPlus[] =
215     {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
216 const WCHAR szUnregisterExtensionInfo[] =
217     {'U','n','r','e','g','i','s','t','e','r',
218             'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
219 static const WCHAR szUnregisterFonts[] =
220     {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
221 const WCHAR szUnregisterMIMEInfo[] =
222     {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
223 const WCHAR szUnregisterProgIdInfo[] =
224     {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
225             'I','n','f','o',0};
226 static const WCHAR szUnregisterTypeLibraries[] =
227     {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
228             'L','i','b','r','a','r','i','e','s',0};
229 static const WCHAR szValidateProductID[] =
230     {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
231 static const WCHAR szWriteEnvironmentStrings[] =
232     {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
233             'S','t','r','i','n','g','s',0};
234
235 /* action handlers */
236 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
237
238 struct _actions {
239     LPCWSTR action;
240     STANDARDACTIONHANDLER handler;
241 };
242
243 static struct _actions StandardActions[];
244
245
246 /********************************************************
247  * helper functions
248  ********************************************************/
249
250 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
251 {
252     static const WCHAR Query_t[] = 
253         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
254          '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
255          'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=', 
256          ' ','\'','%','s','\'',0};
257     MSIRECORD * row;
258
259     row = MSI_QueryGetRecord( package->db, Query_t, action );
260     if (!row)
261         return;
262     MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
263     msiobj_release(&row->hdr);
264 }
265
266 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start, 
267                           UINT rc)
268 {
269     MSIRECORD * row;
270     static const WCHAR template_s[]=
271         {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
272          '%','s', '.',0};
273     static const WCHAR template_e[]=
274         {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
275          '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
276          '%','i','.',0};
277     static const WCHAR format[] = 
278         {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
279     WCHAR message[1024];
280     WCHAR timet[0x100];
281
282     GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
283     if (start)
284         sprintfW(message,template_s,timet,action);
285     else
286         sprintfW(message,template_e,timet,action,rc);
287     
288     row = MSI_CreateRecord(1);
289     MSI_RecordSetStringW(row,1,message);
290  
291     MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
292     msiobj_release(&row->hdr);
293 }
294
295 static UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine )
296 {
297     LPCWSTR ptr,ptr2;
298     BOOL quote;
299     DWORD len;
300     LPWSTR prop = NULL, val = NULL;
301
302     if (!szCommandLine)
303         return ERROR_SUCCESS;
304
305     ptr = szCommandLine;
306        
307     while (*ptr)
308     {
309         if (*ptr==' ')
310         {
311             ptr++;
312             continue;
313         }
314
315         TRACE("Looking at %s\n",debugstr_w(ptr));
316
317         ptr2 = strchrW(ptr,'=');
318         if (!ptr2)
319         {
320             ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
321             break;
322         }
323  
324         quote = FALSE;
325
326         len = ptr2-ptr;
327         prop = msi_alloc((len+1)*sizeof(WCHAR));
328         memcpy(prop,ptr,len*sizeof(WCHAR));
329         prop[len]=0;
330         ptr2++;
331        
332         len = 0; 
333         ptr = ptr2; 
334         while (*ptr && (quote || (!quote && *ptr!=' ')))
335         {
336             if (*ptr == '"')
337                 quote = !quote;
338             ptr++;
339             len++;
340         }
341        
342         if (*ptr2=='"')
343         {
344             ptr2++;
345             len -= 2;
346         }
347         val = msi_alloc((len+1)*sizeof(WCHAR));
348         memcpy(val,ptr2,len*sizeof(WCHAR));
349         val[len] = 0;
350
351         if (lstrlenW(prop) > 0)
352         {
353             TRACE("Found commandline property (%s) = (%s)\n", 
354                    debugstr_w(prop), debugstr_w(val));
355             MSI_SetPropertyW(package,prop,val);
356         }
357         msi_free(val);
358         msi_free(prop);
359     }
360
361     return ERROR_SUCCESS;
362 }
363
364
365 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
366 {
367     LPCWSTR pc;
368     LPWSTR p, *ret = NULL;
369     UINT count = 0;
370
371     if (!str)
372         return ret;
373
374     /* count the number of substrings */
375     for ( pc = str, count = 0; pc; count++ )
376     {
377         pc = strchrW( pc, sep );
378         if (pc)
379             pc++;
380     }
381
382     /* allocate space for an array of substring pointers and the substrings */
383     ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
384                      (lstrlenW(str)+1) * sizeof(WCHAR) );
385     if (!ret)
386         return ret;
387
388     /* copy the string and set the pointers */
389     p = (LPWSTR) &ret[count+1];
390     lstrcpyW( p, str );
391     for( count = 0; (ret[count] = p); count++ )
392     {
393         p = strchrW( p, sep );
394         if (p)
395             *p++ = 0;
396     }
397
398     return ret;
399 }
400
401 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
402 {
403     WCHAR szProductCode[] = { 'P','r','o','d','u','c','t','C','o','d','e',0 };
404     LPWSTR prod_code, patch_product;
405     UINT ret;
406
407     prod_code = msi_dup_property( package, szProductCode );
408     patch_product = msi_get_suminfo_product( patch );
409
410     TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
411
412     if ( strstrW( patch_product, prod_code ) )
413         ret = ERROR_SUCCESS;
414     else
415         ret = ERROR_FUNCTION_FAILED;
416
417     msi_free( patch_product );
418     msi_free( prod_code );
419
420     return ret;
421 }
422
423 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
424                                  MSIDATABASE *patch_db, LPCWSTR name )
425 {
426     UINT ret = ERROR_FUNCTION_FAILED;
427     IStorage *stg = NULL;
428     HRESULT r;
429
430     TRACE("%p %s\n", package, debugstr_w(name) );
431
432     if (*name++ != ':')
433     {
434         ERR("expected a colon in %s\n", debugstr_w(name));
435         return ERROR_FUNCTION_FAILED;
436     }
437
438     r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
439     if (SUCCEEDED(r))
440     {
441         ret = msi_check_transform_applicable( package, stg );
442         if (ret == ERROR_SUCCESS)
443             msi_table_apply_transform( package->db, stg );
444         else
445             TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
446         IStorage_Release( stg );
447     }
448     else
449         ERR("failed to open substorage %s\n", debugstr_w(name));
450
451     return ERROR_SUCCESS;
452 }
453
454 static UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
455 {
456     static const WCHAR szProdID[] = { 'P','r','o','d','u','c','t','I','D',0 };
457     LPWSTR guid_list, *guids, product_id;
458     UINT i, ret = ERROR_FUNCTION_FAILED;
459
460     product_id = msi_dup_property( package, szProdID );
461     if (!product_id)
462     {
463         /* FIXME: the property ProductID should be written into the DB somewhere */
464         ERR("no product ID to check\n");
465         return ERROR_SUCCESS;
466     }
467
468     guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
469     guids = msi_split_string( guid_list, ';' );
470     for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
471     {
472         if (!lstrcmpW( guids[i], product_id ))
473             ret = ERROR_SUCCESS;
474     }
475     msi_free( guids );
476     msi_free( guid_list );
477     msi_free( product_id );
478
479     return ret;
480 }
481
482 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
483 {
484     MSISUMMARYINFO *si;
485     LPWSTR str, *substorage;
486     UINT i, r = ERROR_SUCCESS;
487
488     si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
489     if (!si)
490         return ERROR_FUNCTION_FAILED;
491
492     msi_check_patch_applicable( package, si );
493
494     /* enumerate the substorage */
495     str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
496     substorage = msi_split_string( str, ';' );
497     for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
498         r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
499     msi_free( substorage );
500     msi_free( str );
501
502     /* FIXME: parse the sources in PID_REVNUMBER and do something with them... */
503
504     msiobj_release( &si->hdr );
505
506     return r;
507 }
508
509 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
510 {
511     MSIDATABASE *patch_db = NULL;
512     UINT r;
513
514     TRACE("%p %s\n", package, debugstr_w( file ) );
515
516     /* FIXME:
517      *  We probably want to make sure we only open a patch collection here.
518      *  Patch collections (.msp) and databases (.msi) have different GUIDs
519      *  but currently MSI_OpenDatabaseW will accept both.
520      */
521     r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
522     if ( r != ERROR_SUCCESS )
523     {
524         ERR("failed to open patch collection %s\n", debugstr_w( file ) );
525         return r;
526     }
527
528     msi_parse_patch_summary( package, patch_db );
529     msiobj_release( &patch_db->hdr );
530
531     return ERROR_SUCCESS;
532 }
533
534 /* get the PATCH property, and apply all the patches it specifies */
535 static UINT msi_apply_patches( MSIPACKAGE *package )
536 {
537     static const WCHAR szPatch[] = { 'P','A','T','C','H',0 };
538     LPWSTR patch_list, *patches;
539     UINT i, r = ERROR_SUCCESS;
540
541     patch_list = msi_dup_property( package, szPatch );
542
543     TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
544
545     patches = msi_split_string( patch_list, ';' );
546     for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
547         r = msi_apply_patch_package( package, patches[i] );
548
549     msi_free( patches );
550     msi_free( patch_list );
551
552     return r;
553 }
554
555 static UINT msi_apply_transforms( MSIPACKAGE *package )
556 {
557     static const WCHAR szTransforms[] = {
558         'T','R','A','N','S','F','O','R','M','S',0 };
559     LPWSTR xform_list, *xforms;
560     UINT i, r = ERROR_SUCCESS;
561
562     xform_list = msi_dup_property( package, szTransforms );
563     xforms = msi_split_string( xform_list, ';' );
564
565     for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
566     {
567         if (xforms[i][0] == ':')
568             r = msi_apply_substorage_transform( package, package->db, &xforms[i][1] );
569         else
570             r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
571     }
572
573     msi_free( xforms );
574     msi_free( xform_list );
575
576     return r;
577 }
578
579 /****************************************************
580  * TOP level entry points 
581  *****************************************************/
582
583 UINT MSI_InstallPackage( MSIPACKAGE *package, LPCWSTR szPackagePath,
584                          LPCWSTR szCommandLine )
585 {
586     UINT rc;
587     BOOL ui = FALSE;
588     static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
589     static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
590     static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
591
592     MSI_SetPropertyW(package, szAction, szInstall);
593
594     package->script = msi_alloc_zero(sizeof(MSISCRIPT));
595
596     package->script->InWhatSequence = SEQUENCE_INSTALL;
597
598     if (szPackagePath)   
599     {
600         LPWSTR p, check, path;
601  
602         path = strdupW(szPackagePath);
603         p = strrchrW(path,'\\');    
604         if (p)
605         {
606             p++;
607             *p=0;
608         }
609         else
610         {
611             msi_free(path);
612             path = msi_alloc(MAX_PATH*sizeof(WCHAR));
613             GetCurrentDirectoryW(MAX_PATH,path);
614             strcatW(path,cszbs);
615         }
616
617         check = msi_dup_property( package, cszSourceDir );
618         if (!check)
619             MSI_SetPropertyW(package, cszSourceDir, path);
620
621         check = msi_dup_property( package, cszSOURCEDIR );
622         if (!check)
623             MSI_SetPropertyW(package, cszSOURCEDIR, path);
624
625         msi_free( package->PackagePath );
626         package->PackagePath = path;
627
628         msi_free(check);
629     }
630
631     msi_parse_command_line( package, szCommandLine );
632
633     msi_apply_transforms( package );
634     msi_apply_patches( package );
635
636     if ( msi_get_property_int(package, szUILevel, 0) >= INSTALLUILEVEL_REDUCED )
637     {
638         package->script->InWhatSequence |= SEQUENCE_UI;
639         rc = ACTION_ProcessUISequence(package);
640         ui = TRUE;
641         if (rc == ERROR_SUCCESS)
642         {
643             package->script->InWhatSequence |= SEQUENCE_EXEC;
644             rc = ACTION_ProcessExecSequence(package,TRUE);
645         }
646     }
647     else
648         rc = ACTION_ProcessExecSequence(package,FALSE);
649     
650     if (rc == -1)
651     {
652         /* install was halted but should be considered a success */
653         rc = ERROR_SUCCESS;
654     }
655
656     package->script->CurrentlyScripting= FALSE;
657
658     /* process the ending type action */
659     if (rc == ERROR_SUCCESS)
660         ACTION_PerformActionSequence(package,-1,ui);
661     else if (rc == ERROR_INSTALL_USEREXIT) 
662         ACTION_PerformActionSequence(package,-2,ui);
663     else if (rc == ERROR_INSTALL_SUSPEND) 
664         ACTION_PerformActionSequence(package,-4,ui);
665     else  /* failed */
666         ACTION_PerformActionSequence(package,-3,ui);
667
668     /* finish up running custom actions */
669     ACTION_FinishCustomActions(package);
670     
671     return rc;
672 }
673
674 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
675 {
676     UINT rc = ERROR_SUCCESS;
677     MSIRECORD * row = 0;
678     static const WCHAR ExecSeqQuery[] =
679         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
680          '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
681          'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
682          '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
683
684     static const WCHAR UISeqQuery[] =
685         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
686      '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
687      '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
688          ' ', '=',' ','%','i',0};
689
690     if (UI)
691         row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
692     else
693         row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
694
695     if (row)
696     {
697         LPCWSTR action, cond;
698
699         TRACE("Running the actions\n"); 
700
701         /* check conditions */
702         cond = MSI_RecordGetString(row,2);
703
704         /* this is a hack to skip errors in the condition code */
705         if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
706             goto end;
707
708         action = MSI_RecordGetString(row,1);
709         if (!action)
710         {
711             ERR("failed to fetch action\n");
712             rc = ERROR_FUNCTION_FAILED;
713             goto end;
714         }
715
716         if (UI)
717             rc = ACTION_PerformUIAction(package,action);
718         else
719             rc = ACTION_PerformAction(package,action,FALSE);
720 end:
721         msiobj_release(&row->hdr);
722     }
723     else
724         rc = ERROR_SUCCESS;
725
726     return rc;
727 }
728
729 typedef struct {
730     MSIPACKAGE* package;
731     BOOL UI;
732 } iterate_action_param;
733
734 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
735 {
736     iterate_action_param *iap= (iterate_action_param*)param;
737     UINT rc;
738     LPCWSTR cond, action;
739
740     action = MSI_RecordGetString(row,1);
741     if (!action)
742     {
743         ERR("Error is retrieving action name\n");
744         return ERROR_FUNCTION_FAILED;
745     }
746
747     /* check conditions */
748     cond = MSI_RecordGetString(row,2);
749
750     /* this is a hack to skip errors in the condition code */
751     if (MSI_EvaluateConditionW(iap->package, cond) == MSICONDITION_FALSE)
752     {
753         TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
754         return ERROR_SUCCESS;
755     }
756
757     if (iap->UI)
758         rc = ACTION_PerformUIAction(iap->package,action);
759     else
760         rc = ACTION_PerformAction(iap->package,action,FALSE);
761
762     msi_dialog_check_messages( NULL );
763
764     if (iap->package->CurrentInstallState != ERROR_SUCCESS )
765         rc = iap->package->CurrentInstallState;
766
767     if (rc == ERROR_FUNCTION_NOT_CALLED)
768         rc = ERROR_SUCCESS;
769
770     if (rc != ERROR_SUCCESS)
771         ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
772
773     return rc;
774 }
775
776 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
777 {
778     MSIQUERY * view;
779     UINT r;
780     static const WCHAR query[] =
781         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
782          '`','%','s','`',
783          ' ','W','H','E','R','E',' ', 
784          '`','S','e','q','u','e','n','c','e','`',' ',
785          '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
786          '`','S','e','q','u','e','n','c','e','`',0};
787     iterate_action_param iap;
788
789     /*
790      * FIXME: probably should be checking UILevel in the
791      *       ACTION_PerformUIAction/ACTION_PerformAction
792      *       rather than saving the UI level here. Those
793      *       two functions can be merged too.
794      */
795     iap.package = package;
796     iap.UI = TRUE;
797
798     TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
799
800     r = MSI_OpenQuery( package->db, &view, query, szTable );
801     if (r == ERROR_SUCCESS)
802     {
803         r = MSI_IterateRecords( view, NULL, ITERATE_Actions, &iap );
804         msiobj_release(&view->hdr);
805     }
806
807     return r;
808 }
809
810 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
811 {
812     MSIQUERY * view;
813     UINT rc;
814     static const WCHAR ExecSeqQuery[] =
815         {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
816          '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
817          'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
818          '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
819          'O','R','D','E','R',' ', 'B','Y',' ',
820          '`','S','e','q','u','e','n','c','e','`',0 };
821     MSIRECORD * row = 0;
822     static const WCHAR IVQuery[] =
823         {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
824          ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
825          'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
826          'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
827          ' ','\'', 'I','n','s','t','a','l','l',
828          'V','a','l','i','d','a','t','e','\'', 0};
829     INT seq = 0;
830     iterate_action_param iap;
831
832     iap.package = package;
833     iap.UI = FALSE;
834
835     if (package->script->ExecuteSequenceRun)
836     {
837         TRACE("Execute Sequence already Run\n");
838         return ERROR_SUCCESS;
839     }
840
841     package->script->ExecuteSequenceRun = TRUE;
842
843     /* get the sequence number */
844     if (UIran)
845     {
846         row = MSI_QueryGetRecord(package->db, IVQuery);
847         if( !row )
848             return ERROR_FUNCTION_FAILED;
849         seq = MSI_RecordGetInteger(row,1);
850         msiobj_release(&row->hdr);
851     }
852
853     rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
854     if (rc == ERROR_SUCCESS)
855     {
856         TRACE("Running the actions\n");
857
858         rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
859         msiobj_release(&view->hdr);
860     }
861
862     return rc;
863 }
864
865 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
866 {
867     MSIQUERY * view;
868     UINT rc;
869     static const WCHAR ExecSeqQuery [] =
870         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
871          '`','I','n','s','t','a','l','l',
872          'U','I','S','e','q','u','e','n','c','e','`',
873          ' ','W','H','E','R','E',' ', 
874          '`','S','e','q','u','e','n','c','e','`',' ',
875          '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
876          '`','S','e','q','u','e','n','c','e','`',0};
877     iterate_action_param iap;
878
879     iap.package = package;
880     iap.UI = TRUE;
881
882     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
883     
884     if (rc == ERROR_SUCCESS)
885     {
886         TRACE("Running the actions\n"); 
887
888         rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, &iap);
889         msiobj_release(&view->hdr);
890     }
891
892     return rc;
893 }
894
895 /********************************************************
896  * ACTION helper functions and functions that perform the actions
897  *******************************************************/
898 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, 
899                                         UINT* rc, BOOL force )
900 {
901     BOOL ret = FALSE; 
902     BOOL run = force;
903     int i;
904
905     if (!run && !package->script->CurrentlyScripting)
906         run = TRUE;
907    
908     if (!run)
909     {
910         if (strcmpW(action,szInstallFinalize) == 0 ||
911             strcmpW(action,szInstallExecute) == 0 ||
912             strcmpW(action,szInstallExecuteAgain) == 0) 
913                 run = TRUE;
914     }
915     
916     i = 0;
917     while (StandardActions[i].action != NULL)
918     {
919         if (strcmpW(StandardActions[i].action, action)==0)
920         {
921             if (!run)
922             {
923                 ui_actioninfo(package, action, TRUE, 0);
924                 *rc = schedule_action(package,INSTALL_SCRIPT,action);
925                 ui_actioninfo(package, action, FALSE, *rc);
926             }
927             else
928             {
929                 ui_actionstart(package, action);
930                 if (StandardActions[i].handler)
931                 {
932                     *rc = StandardActions[i].handler(package);
933                 }
934                 else
935                 {
936                     FIXME("unhandled standard action %s\n",debugstr_w(action));
937                     *rc = ERROR_SUCCESS;
938                 }
939             }
940             ret = TRUE;
941             break;
942         }
943         i++;
944     }
945     return ret;
946 }
947
948 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
949                                        UINT* rc, BOOL force )
950 {
951     BOOL ret=FALSE;
952     UINT arc;
953
954     arc = ACTION_CustomAction(package,action, force);
955
956     if (arc != ERROR_CALL_NOT_IMPLEMENTED)
957     {
958         *rc = arc;
959         ret = TRUE;
960     }
961     return ret;
962 }
963
964 /* 
965  * A lot of actions are really important even if they don't do anything
966  * explicit... Lots of properties are set at the beginning of the installation
967  * CostFinalize does a bunch of work to translate the directories and such
968  * 
969  * But until I get write access to the database that is hard, so I am going to
970  * hack it to see if I can get something to run.
971  */
972 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
973 {
974     UINT rc = ERROR_SUCCESS; 
975     BOOL handled;
976
977     TRACE("Performing action (%s)\n",debugstr_w(action));
978
979     handled = ACTION_HandleStandardAction(package, action, &rc, force);
980
981     if (!handled)
982         handled = ACTION_HandleCustomAction(package, action, &rc, force);
983
984     if (!handled)
985     {
986         FIXME("unhandled msi action %s\n",debugstr_w(action));
987         rc = ERROR_FUNCTION_NOT_CALLED;
988     }
989
990     return rc;
991 }
992
993 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
994 {
995     UINT rc = ERROR_SUCCESS;
996     BOOL handled = FALSE;
997
998     TRACE("Performing action (%s)\n",debugstr_w(action));
999
1000     handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1001
1002     if (!handled)
1003         handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
1004
1005     if( !handled && ACTION_DialogBox(package,action) == ERROR_SUCCESS )
1006         handled = TRUE;
1007
1008     if (!handled)
1009     {
1010         FIXME("unhandled msi action %s\n",debugstr_w(action));
1011         rc = ERROR_FUNCTION_NOT_CALLED;
1012     }
1013
1014     return rc;
1015 }
1016
1017
1018 /*
1019  * Actual Action Handlers
1020  */
1021
1022 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
1023 {
1024     MSIPACKAGE *package = (MSIPACKAGE*)param;
1025     LPCWSTR dir;
1026     LPWSTR full_path;
1027     MSIRECORD *uirow;
1028     MSIFOLDER *folder;
1029
1030     dir = MSI_RecordGetString(row,1);
1031     if (!dir)
1032     {
1033         ERR("Unable to get folder id\n");
1034         return ERROR_SUCCESS;
1035     }
1036
1037     full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1038     if (!full_path)
1039     {
1040         ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1041         return ERROR_SUCCESS;
1042     }
1043
1044     TRACE("Folder is %s\n",debugstr_w(full_path));
1045
1046     /* UI stuff */
1047     uirow = MSI_CreateRecord(1);
1048     MSI_RecordSetStringW(uirow,1,full_path);
1049     ui_actiondata(package,szCreateFolders,uirow);
1050     msiobj_release( &uirow->hdr );
1051
1052     if (folder->State == 0)
1053         create_full_pathW(full_path);
1054
1055     folder->State = 3;
1056
1057     msi_free(full_path);
1058     return ERROR_SUCCESS;
1059 }
1060
1061 /* FIXME: probably should merge this with the above function */
1062 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
1063 {
1064     UINT rc = ERROR_SUCCESS;
1065     MSIFOLDER *folder;
1066     LPWSTR install_path;
1067
1068     install_path = resolve_folder(package, dir, FALSE, FALSE, &folder);
1069     if (!install_path)
1070         return ERROR_FUNCTION_FAILED; 
1071
1072     /* create the path */
1073     if (folder->State == 0)
1074     {
1075         create_full_pathW(install_path);
1076         folder->State = 2;
1077     }
1078     msi_free(install_path);
1079
1080     return rc;
1081 }
1082
1083 UINT msi_create_component_directories( MSIPACKAGE *package )
1084 {
1085     MSICOMPONENT *comp;
1086
1087     /* create all the folders required by the components are going to install */
1088     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1089     {
1090         if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
1091             continue;
1092         msi_create_directory( package, comp->Directory );
1093     }
1094
1095     return ERROR_SUCCESS;
1096 }
1097
1098 /*
1099  * Also we cannot enable/disable components either, so for now I am just going 
1100  * to do all the directories for all the components.
1101  */
1102 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1103 {
1104     static const WCHAR ExecSeqQuery[] =
1105         {'S','E','L','E','C','T',' ',
1106          '`','D','i','r','e','c','t','o','r','y','_','`',
1107          ' ','F','R','O','M',' ',
1108          '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1109     UINT rc;
1110     MSIQUERY *view;
1111
1112     /* create all the empty folders specified in the CreateFolder table */
1113     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1114     if (rc != ERROR_SUCCESS)
1115         return ERROR_SUCCESS;
1116
1117     rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
1118     msiobj_release(&view->hdr);
1119
1120     msi_create_component_directories( package );
1121
1122     return rc;
1123 }
1124
1125 static UINT load_component( MSIRECORD *row, LPVOID param )
1126 {
1127     MSIPACKAGE *package = param;
1128     MSICOMPONENT *comp;
1129
1130     comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
1131     if (!comp)
1132         return ERROR_FUNCTION_FAILED;
1133
1134     list_add_tail( &package->components, &comp->entry );
1135
1136     /* fill in the data */
1137     comp->Component = msi_dup_record_field( row, 1 );
1138
1139     TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1140
1141     comp->ComponentId = msi_dup_record_field( row, 2 );
1142     comp->Directory = msi_dup_record_field( row, 3 );
1143     comp->Attributes = MSI_RecordGetInteger(row,4);
1144     comp->Condition = msi_dup_record_field( row, 5 );
1145     comp->KeyPath = msi_dup_record_field( row, 6 );
1146
1147     comp->Installed = INSTALLSTATE_UNKNOWN;
1148     msi_component_set_state( comp, INSTALLSTATE_UNKNOWN );
1149
1150     return ERROR_SUCCESS;
1151 }
1152
1153 static UINT load_all_components( MSIPACKAGE *package )
1154 {
1155     static const WCHAR query[] = {
1156         'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ', 
1157          '`','C','o','m','p','o','n','e','n','t','`',0 };
1158     MSIQUERY *view;
1159     UINT r;
1160
1161     if (!list_empty(&package->components))
1162         return ERROR_SUCCESS;
1163
1164     r = MSI_DatabaseOpenViewW( package->db, query, &view );
1165     if (r != ERROR_SUCCESS)
1166         return r;
1167
1168     r = MSI_IterateRecords(view, NULL, load_component, package);
1169     msiobj_release(&view->hdr);
1170     return r;
1171 }
1172
1173 typedef struct {
1174     MSIPACKAGE *package;
1175     MSIFEATURE *feature;
1176 } _ilfs;
1177
1178 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1179 {
1180     ComponentList *cl;
1181
1182     cl = msi_alloc( sizeof (*cl) );
1183     if ( !cl )
1184         return ERROR_NOT_ENOUGH_MEMORY;
1185     cl->component = comp;
1186     list_add_tail( &feature->Components, &cl->entry );
1187
1188     return ERROR_SUCCESS;
1189 }
1190
1191 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1192 {
1193     FeatureList *fl;
1194
1195     fl = msi_alloc( sizeof(*fl) );
1196     if ( !fl )
1197         return ERROR_NOT_ENOUGH_MEMORY;
1198     fl->feature = child;
1199     list_add_tail( &parent->Children, &fl->entry );
1200
1201     return ERROR_SUCCESS;
1202 }
1203
1204 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1205 {
1206     _ilfs* ilfs= (_ilfs*)param;
1207     LPCWSTR component;
1208     MSICOMPONENT *comp;
1209
1210     component = MSI_RecordGetString(row,1);
1211
1212     /* check to see if the component is already loaded */
1213     comp = get_loaded_component( ilfs->package, component );
1214     if (!comp)
1215     {
1216         ERR("unknown component %s\n", debugstr_w(component));
1217         return ERROR_FUNCTION_FAILED;
1218     }
1219
1220     add_feature_component( ilfs->feature, comp );
1221     comp->Enabled = TRUE;
1222
1223     return ERROR_SUCCESS;
1224 }
1225
1226 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1227 {
1228     MSIFEATURE *feature;
1229
1230     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1231     {
1232         if ( !lstrcmpW( feature->Feature, name ) )
1233             return feature;
1234     }
1235
1236     return NULL;
1237 }
1238
1239 static UINT load_feature(MSIRECORD * row, LPVOID param)
1240 {
1241     MSIPACKAGE* package = (MSIPACKAGE*)param;
1242     MSIFEATURE* feature;
1243     static const WCHAR Query1[] = 
1244         {'S','E','L','E','C','T',' ',
1245          '`','C','o','m','p','o','n','e','n','t','_','`',
1246          ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1247          'C','o','m','p','o','n','e','n','t','s','`',' ',
1248          'W','H','E','R','E',' ',
1249          '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1250     MSIQUERY * view;
1251     UINT    rc;
1252     _ilfs ilfs;
1253
1254     /* fill in the data */
1255
1256     feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1257     if (!feature)
1258         return ERROR_NOT_ENOUGH_MEMORY;
1259
1260     list_init( &feature->Children );
1261     list_init( &feature->Components );
1262     
1263     feature->Feature = msi_dup_record_field( row, 1 );
1264
1265     TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1266
1267     feature->Feature_Parent = msi_dup_record_field( row, 2 );
1268     feature->Title = msi_dup_record_field( row, 3 );
1269     feature->Description = msi_dup_record_field( row, 4 );
1270
1271     if (!MSI_RecordIsNull(row,5))
1272         feature->Display = MSI_RecordGetInteger(row,5);
1273   
1274     feature->Level= MSI_RecordGetInteger(row,6);
1275     feature->Directory = msi_dup_record_field( row, 7 );
1276     feature->Attributes = MSI_RecordGetInteger(row,8);
1277
1278     feature->Installed = INSTALLSTATE_UNKNOWN;
1279     msi_feature_set_state( feature, INSTALLSTATE_UNKNOWN );
1280
1281     list_add_tail( &package->features, &feature->entry );
1282
1283     /* load feature components */
1284
1285     rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1286     if (rc != ERROR_SUCCESS)
1287         return ERROR_SUCCESS;
1288
1289     ilfs.package = package;
1290     ilfs.feature = feature;
1291
1292     MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1293     msiobj_release(&view->hdr);
1294
1295     return ERROR_SUCCESS;
1296 }
1297
1298 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1299 {
1300     MSIPACKAGE* package = (MSIPACKAGE*)param;
1301     MSIFEATURE *parent, *child;
1302
1303     child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1304     if (!child)
1305         return ERROR_FUNCTION_FAILED;
1306
1307     if (!child->Feature_Parent)
1308         return ERROR_SUCCESS;
1309
1310     parent = find_feature_by_name( package, child->Feature_Parent );
1311     if (!parent)
1312         return ERROR_FUNCTION_FAILED;
1313
1314     add_feature_child( parent, child );
1315     return ERROR_SUCCESS;
1316 }
1317
1318 static UINT load_all_features( MSIPACKAGE *package )
1319 {
1320     static const WCHAR query[] = {
1321         'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1322         '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1323         ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1324     MSIQUERY *view;
1325     UINT r;
1326
1327     if (!list_empty(&package->features))
1328         return ERROR_SUCCESS;
1329  
1330     r = MSI_DatabaseOpenViewW( package->db, query, &view );
1331     if (r != ERROR_SUCCESS)
1332         return r;
1333
1334     r = MSI_IterateRecords( view, NULL, load_feature, package );
1335     if (r != ERROR_SUCCESS)
1336         return r;
1337
1338     r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1339     msiobj_release( &view->hdr );
1340
1341     return r;
1342 }
1343
1344 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1345 {
1346     if (!p)
1347         return p;
1348     p = strchrW(p, ch);
1349     if (!p)
1350         return p;
1351     *p = 0;
1352     return p+1;
1353 }
1354
1355 static UINT load_file(MSIRECORD *row, LPVOID param)
1356 {
1357     MSIPACKAGE* package = (MSIPACKAGE*)param;
1358     LPCWSTR component;
1359     MSIFILE *file;
1360
1361     /* fill in the data */
1362
1363     file = msi_alloc_zero( sizeof (MSIFILE) );
1364     if (!file)
1365         return ERROR_NOT_ENOUGH_MEMORY;
1366  
1367     file->File = msi_dup_record_field( row, 1 );
1368
1369     component = MSI_RecordGetString( row, 2 );
1370     file->Component = get_loaded_component( package, component );
1371
1372     if (!file->Component)
1373         ERR("Unfound Component %s\n",debugstr_w(component));
1374
1375     file->FileName = msi_dup_record_field( row, 3 );
1376     reduce_to_longfilename( file->FileName );
1377
1378     file->ShortName = msi_dup_record_field( row, 3 );
1379     file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1380     
1381     file->FileSize = MSI_RecordGetInteger( row, 4 );
1382     file->Version = msi_dup_record_field( row, 5 );
1383     file->Language = msi_dup_record_field( row, 6 );
1384     file->Attributes = MSI_RecordGetInteger( row, 7 );
1385     file->Sequence = MSI_RecordGetInteger( row, 8 );
1386
1387     file->state = msifs_invalid;
1388
1389     /* if the compressed bits are not set in the file attributes,
1390      * then read the information from the package word count property
1391      */
1392     if (file->Attributes & msidbFileAttributesCompressed)
1393     {
1394         file->IsCompressed = TRUE;
1395     }
1396     else if (file->Attributes & msidbFileAttributesNoncompressed)
1397     {
1398         file->IsCompressed = FALSE;
1399     }
1400     else
1401     {
1402         file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
1403     }
1404
1405     TRACE("File Loaded (%s)\n",debugstr_w(file->File));  
1406
1407     list_add_tail( &package->files, &file->entry );
1408  
1409     return ERROR_SUCCESS;
1410 }
1411
1412 static UINT load_all_files(MSIPACKAGE *package)
1413 {
1414     MSIQUERY * view;
1415     UINT rc;
1416     static const WCHAR Query[] =
1417         {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1418          '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1419          '`','S','e','q','u','e','n','c','e','`', 0};
1420
1421     if (!list_empty(&package->files))
1422         return ERROR_SUCCESS;
1423
1424     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1425     if (rc != ERROR_SUCCESS)
1426         return ERROR_SUCCESS;
1427
1428     rc = MSI_IterateRecords(view, NULL, load_file, package);
1429     msiobj_release(&view->hdr);
1430
1431     return ERROR_SUCCESS;
1432 }
1433
1434
1435 /*
1436  * I am not doing any of the costing functionality yet.
1437  * Mostly looking at doing the Component and Feature loading
1438  *
1439  * The native MSI does A LOT of modification to tables here. Mostly adding
1440  * a lot of temporary columns to the Feature and Component tables.
1441  *
1442  *    note: Native msi also tracks the short filename. But I am only going to
1443  *          track the long ones.  Also looking at this directory table
1444  *          it appears that the directory table does not get the parents
1445  *          resolved base on property only based on their entries in the
1446  *          directory table.
1447  */
1448 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1449 {
1450     static const WCHAR szCosting[] =
1451         {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1452     static const WCHAR szZero[] = { '0', 0 };
1453
1454     if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1455         return ERROR_SUCCESS;
1456
1457     MSI_SetPropertyW(package, szCosting, szZero);
1458     MSI_SetPropertyW(package, cszRootDrive, c_colon);
1459
1460     load_all_components( package );
1461     load_all_features( package );
1462     load_all_files( package );
1463
1464     return ERROR_SUCCESS;
1465 }
1466
1467 static UINT execute_script(MSIPACKAGE *package, UINT script )
1468 {
1469     int i;
1470     UINT rc = ERROR_SUCCESS;
1471
1472     TRACE("Executing Script %i\n",script);
1473
1474     if (!package->script)
1475     {
1476         ERR("no script!\n");
1477         return ERROR_FUNCTION_FAILED;
1478     }
1479
1480     for (i = 0; i < package->script->ActionCount[script]; i++)
1481     {
1482         LPWSTR action;
1483         action = package->script->Actions[script][i];
1484         ui_actionstart(package, action);
1485         TRACE("Executing Action (%s)\n",debugstr_w(action));
1486         rc = ACTION_PerformAction(package, action, TRUE);
1487         msi_free(package->script->Actions[script][i]);
1488         if (rc != ERROR_SUCCESS)
1489             break;
1490     }
1491     msi_free(package->script->Actions[script]);
1492
1493     package->script->ActionCount[script] = 0;
1494     package->script->Actions[script] = NULL;
1495     return rc;
1496 }
1497
1498 static UINT ACTION_FileCost(MSIPACKAGE *package)
1499 {
1500     return ERROR_SUCCESS;
1501 }
1502
1503 static MSIFOLDER *load_folder( MSIPACKAGE *package, LPCWSTR dir )
1504 {
1505     static const WCHAR Query[] =
1506         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1507          '`','D','i','r','e','c', 't','o','r','y','`',' ',
1508          'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
1509          ' ','=',' ','\'','%','s','\'',
1510          0};
1511     static const WCHAR szDot[] = { '.',0 };
1512     static WCHAR szEmpty[] = { 0 };
1513     LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1514     LPCWSTR parent;
1515     MSIRECORD *row;
1516     MSIFOLDER *folder;
1517
1518     TRACE("Looking for dir %s\n",debugstr_w(dir));
1519
1520     folder = get_loaded_folder( package, dir );
1521     if (folder)
1522         return folder;
1523
1524     TRACE("Working to load %s\n",debugstr_w(dir));
1525
1526     folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1527     if (!folder)
1528         return NULL;
1529
1530     folder->Directory = strdupW(dir);
1531
1532     row = MSI_QueryGetRecord(package->db, Query, dir);
1533     if (!row)
1534         return NULL;
1535
1536     p = msi_dup_record_field(row, 3);
1537
1538     /* split src and target dir */
1539     tgt_short = p;
1540     src_short = folder_split_path( p, ':' );
1541
1542     /* split the long and short paths */
1543     tgt_long = folder_split_path( tgt_short, '|' );
1544     src_long = folder_split_path( src_short, '|' );
1545
1546     /* check for no-op dirs */
1547     if (!lstrcmpW(szDot, tgt_short))
1548         tgt_short = szEmpty;
1549     if (!lstrcmpW(szDot, src_short))
1550         src_short = szEmpty;
1551
1552     if (!tgt_long)
1553         tgt_long = tgt_short;
1554         
1555     if (!src_short) {
1556         src_short = tgt_short;
1557         src_long = tgt_long;
1558     }
1559     
1560     if (!src_long)
1561         src_long = src_short;
1562
1563     /* FIXME: use the target short path too */
1564     folder->TargetDefault = strdupW(tgt_long);
1565     folder->SourceShortPath = strdupW(src_short);
1566     folder->SourceLongPath = strdupW(src_long);
1567     msi_free(p);
1568
1569     TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1570     TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1571     TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1572
1573     parent = MSI_RecordGetString(row, 2);
1574     if (parent) 
1575     {
1576         folder->Parent = load_folder( package, parent );
1577         if ( folder->Parent )
1578             TRACE("loaded parent %p %s\n", folder->Parent,
1579                   debugstr_w(folder->Parent->Directory));
1580         else
1581             ERR("failed to load parent folder %s\n", debugstr_w(parent));
1582     }
1583
1584     folder->Property = msi_dup_property( package, dir );
1585
1586     msiobj_release(&row->hdr);
1587
1588     list_add_tail( &package->folders, &folder->entry );
1589
1590     TRACE("%s returning %p\n",debugstr_w(dir),folder);
1591
1592     return folder;
1593 }
1594
1595 /* scan for and update current install states */
1596 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
1597 {
1598     MSICOMPONENT *comp;
1599     MSIFEATURE *feature;
1600
1601     /* FIXME: component's installed state should be determined
1602      * by the component's registration
1603      */
1604     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1605     {
1606         INSTALLSTATE res;
1607
1608         if (!comp->ComponentId)
1609             continue;
1610
1611         res = MsiGetComponentPathW( package->ProductCode, 
1612                                     comp->ComponentId, NULL, NULL);
1613         if (res < 0)
1614             res = INSTALLSTATE_ABSENT;
1615         comp->Installed = res;
1616     }
1617
1618     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1619     {
1620         ComponentList *cl;
1621         INSTALLSTATE res = INSTALLSTATE_ABSENT;
1622
1623         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1624         {
1625             comp= cl->component;
1626
1627             if (!comp->ComponentId)
1628             {
1629                 res = INSTALLSTATE_ABSENT;
1630                 break;
1631             }
1632
1633             if (res == INSTALLSTATE_ABSENT)
1634                 res = comp->Installed;
1635             else
1636             {
1637                 if (res == comp->Installed)
1638                     continue;
1639
1640                 if (res != INSTALLSTATE_DEFAULT || res != INSTALLSTATE_LOCAL ||
1641                     res != INSTALLSTATE_SOURCE)
1642                 {
1643                     res = INSTALLSTATE_INCOMPLETE;
1644                 }
1645             }
1646         }
1647         feature->Installed = res;
1648     }
1649 }
1650
1651 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property, 
1652                                     INSTALLSTATE state)
1653 {
1654     static const WCHAR all[]={'A','L','L',0};
1655     LPWSTR override;
1656     MSIFEATURE *feature;
1657
1658     override = msi_dup_property( package, property );
1659     if (!override)
1660         return FALSE;
1661
1662     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1663     {
1664         if (strcmpiW(override,all)==0)
1665             msi_feature_set_state( feature, state );
1666         else
1667         {
1668             LPWSTR ptr = override;
1669             LPWSTR ptr2 = strchrW(override,',');
1670
1671             while (ptr)
1672             {
1673                 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1674                     || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1675                 {
1676                     msi_feature_set_state( feature, state );
1677                     break;
1678                 }
1679                 if (ptr2)
1680                 {
1681                     ptr=ptr2+1;
1682                     ptr2 = strchrW(ptr,',');
1683                 }
1684                 else
1685                     break;
1686             }
1687         }
1688     }
1689     msi_free(override);
1690
1691     return TRUE;
1692 }
1693
1694 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1695 {
1696     int install_level;
1697     static const WCHAR szlevel[] =
1698         {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1699     static const WCHAR szAddLocal[] =
1700         {'A','D','D','L','O','C','A','L',0};
1701     static const WCHAR szRemove[] =
1702         {'R','E','M','O','V','E',0};
1703     static const WCHAR szReinstall[] =
1704         {'R','E','I','N','S','T','A','L','L',0};
1705     BOOL override = FALSE;
1706     MSICOMPONENT* component;
1707     MSIFEATURE *feature;
1708
1709
1710     /* I do not know if this is where it should happen.. but */
1711
1712     TRACE("Checking Install Level\n");
1713
1714     install_level = msi_get_property_int( package, szlevel, 1 );
1715
1716     /* ok here is the _real_ rub
1717      * all these activation/deactivation things happen in order and things
1718      * later on the list override things earlier on the list.
1719      * 1) INSTALLLEVEL processing
1720      * 2) ADDLOCAL
1721      * 3) REMOVE
1722      * 4) ADDSOURCE
1723      * 5) ADDDEFAULT
1724      * 6) REINSTALL
1725      * 7) COMPADDLOCAL
1726      * 8) COMPADDSOURCE
1727      * 9) FILEADDLOCAL
1728      * 10) FILEADDSOURCE
1729      * 11) FILEADDDEFAULT
1730      * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
1731      * ignored for all the features. seems strange, especially since it is not
1732      * documented anywhere, but it is how it works.
1733      *
1734      * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1735      * REMOVE are the big ones, since we don't handle administrative installs
1736      * yet anyway.
1737      */
1738     override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
1739     override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
1740     override |= process_state_property(package,szReinstall,INSTALLSTATE_LOCAL);
1741
1742     if (!override)
1743     {
1744         LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1745         {
1746             BOOL feature_state = ((feature->Level > 0) &&
1747                              (feature->Level <= install_level));
1748
1749             if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1750             {
1751                 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1752                     msi_feature_set_state( feature, INSTALLSTATE_SOURCE );
1753                 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1754                     msi_feature_set_state( feature, INSTALLSTATE_ADVERTISED );
1755                 else
1756                     msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1757             }
1758         }
1759
1760         /* disable child features of unselected parent features */
1761         LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1762         {
1763             FeatureList *fl;
1764
1765             if (feature->Level > 0 && feature->Level <= install_level)
1766                 continue;
1767
1768             LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1769                 msi_feature_set_state( fl->feature, INSTALLSTATE_UNKNOWN );
1770         }
1771     }
1772     else
1773     {
1774         /* set the Preselected Property */
1775         static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
1776         static const WCHAR szOne[] = { '1', 0 };
1777
1778         MSI_SetPropertyW(package,szPreselected,szOne);
1779     }
1780
1781     /*
1782      * now we want to enable or disable components base on feature
1783      */
1784
1785     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1786     {
1787         ComponentList *cl;
1788
1789         TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
1790             debugstr_w(feature->Feature), feature->Installed, feature->Action,
1791             feature->ActionRequest);
1792
1793         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1794         {
1795             component = cl->component;
1796
1797             switch (component->Attributes)
1798             {
1799             case msidbComponentAttributesLocalOnly:
1800                 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1801                 break;
1802             case msidbComponentAttributesSourceOnly:
1803                 msi_component_set_state( component, INSTALLSTATE_SOURCE );
1804                 break;
1805             case msidbComponentAttributesOptional:
1806                 msi_component_set_state( component, INSTALLSTATE_DEFAULT );
1807                 break;
1808             default:
1809                 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1810             }
1811
1812             if (component->ForceLocalState)
1813                 msi_component_set_state( component, INSTALLSTATE_LOCAL );
1814
1815             if (!component->Enabled)
1816                 msi_component_set_state( component, INSTALLSTATE_UNKNOWN );
1817             else if (feature->Attributes == msidbFeatureAttributesFavorLocal)
1818             {
1819                 if (!(component->Attributes & msidbComponentAttributesSourceOnly))
1820                     msi_component_set_state( component, INSTALLSTATE_LOCAL );
1821             }
1822             else if (feature->Attributes == msidbFeatureAttributesFavorSource)
1823             {
1824                 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1825                     (component->Action == INSTALLSTATE_ABSENT) ||
1826                     (component->Action == INSTALLSTATE_ADVERTISED) ||
1827                     (component->Action == INSTALLSTATE_DEFAULT))
1828                     msi_component_set_state( component, INSTALLSTATE_SOURCE );
1829             }
1830             else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
1831             {
1832                 if ((component->Action == INSTALLSTATE_UNKNOWN) ||
1833                     (component->Action == INSTALLSTATE_ABSENT))
1834                     msi_component_set_state( component, INSTALLSTATE_ADVERTISED );
1835             }
1836             else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
1837             {
1838                 if (component->Action == INSTALLSTATE_UNKNOWN)
1839                     msi_component_set_state( component, INSTALLSTATE_ABSENT );
1840             }
1841             else if (feature->ActionRequest == INSTALLSTATE_UNKNOWN)
1842                 msi_component_set_state( component, INSTALLSTATE_UNKNOWN );
1843
1844             if (component->ForceLocalState && feature->Action == INSTALLSTATE_SOURCE)
1845                 msi_feature_set_state( feature, INSTALLSTATE_LOCAL );
1846         }
1847     }
1848
1849     LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1850     {
1851         TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
1852             debugstr_w(component->Component), component->Installed,
1853             component->Action, component->ActionRequest);
1854     }
1855
1856
1857     return ERROR_SUCCESS;
1858 }
1859
1860 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1861 {
1862     MSIPACKAGE *package = (MSIPACKAGE*)param;
1863     LPCWSTR name;
1864     LPWSTR path;
1865
1866     name = MSI_RecordGetString(row,1);
1867
1868     /* This helper function now does ALL the work */
1869     TRACE("Dir %s ...\n",debugstr_w(name));
1870     load_folder(package,name);
1871     path = resolve_folder(package,name,FALSE,TRUE,NULL);
1872     TRACE("resolves to %s\n",debugstr_w(path));
1873     msi_free(path);
1874
1875     return ERROR_SUCCESS;
1876 }
1877
1878 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1879 {
1880     MSIPACKAGE *package = (MSIPACKAGE*)param;
1881     LPCWSTR name;
1882     MSIFEATURE *feature;
1883
1884     name = MSI_RecordGetString( row, 1 );
1885
1886     feature = get_loaded_feature( package, name );
1887     if (!feature)
1888         ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1889     else
1890     {
1891         LPCWSTR Condition;
1892         Condition = MSI_RecordGetString(row,3);
1893
1894         if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1895         {
1896             int level = MSI_RecordGetInteger(row,2);
1897             TRACE("Reseting feature %s to level %i\n", debugstr_w(name), level);
1898             feature->Level = level;
1899         }
1900     }
1901     return ERROR_SUCCESS;
1902 }
1903
1904 LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1905 {
1906     static const WCHAR name_fmt[] =
1907         {'%','u','.','%','u','.','%','u','.','%','u',0};
1908     static WCHAR name[] = {'\\',0};
1909     VS_FIXEDFILEINFO *lpVer;
1910     WCHAR filever[0x100];
1911     LPVOID version;
1912     DWORD versize;
1913     DWORD handle;
1914     UINT sz;
1915
1916     TRACE("%s\n", debugstr_w(filename));
1917
1918     versize = GetFileVersionInfoSizeW( filename, &handle );
1919     if (!versize)
1920         return NULL;
1921
1922     version = msi_alloc( versize );
1923     GetFileVersionInfoW( filename, 0, versize, version );
1924
1925     VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz );
1926     msi_free( version );
1927
1928     sprintfW( filever, name_fmt,
1929         HIWORD(lpVer->dwFileVersionMS),
1930         LOWORD(lpVer->dwFileVersionMS),
1931         HIWORD(lpVer->dwFileVersionLS),
1932         LOWORD(lpVer->dwFileVersionLS));
1933
1934     return strdupW( filever );
1935 }
1936
1937 /*
1938  * A lot is done in this function aside from just the costing.
1939  * The costing needs to be implemented at some point but for now I am going
1940  * to focus on the directory building
1941  *
1942  */
1943 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1944 {
1945     static const WCHAR ExecSeqQuery[] =
1946         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1947          '`','D','i','r','e','c','t','o','r','y','`',0};
1948     static const WCHAR ConditionQuery[] =
1949         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1950          '`','C','o','n','d','i','t','i','o','n','`',0};
1951     static const WCHAR szCosting[] =
1952         {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1953     static const WCHAR szlevel[] =
1954         {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1955     static const WCHAR szOne[] = { '1', 0 };
1956     MSICOMPONENT *comp;
1957     MSIFILE *file;
1958     UINT rc;
1959     MSIQUERY * view;
1960     LPWSTR level, file_version;
1961
1962     if ( 1 == msi_get_property_int( package, szCosting, 0 ) )
1963         return ERROR_SUCCESS;
1964
1965     TRACE("Building Directory properties\n");
1966
1967     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1968     if (rc == ERROR_SUCCESS)
1969     {
1970         rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1971                         package);
1972         msiobj_release(&view->hdr);
1973     }
1974
1975     TRACE("File calculations\n");
1976
1977     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1978     {
1979         MSICOMPONENT* comp = file->Component;
1980         LPWSTR p;
1981
1982         if (!comp)
1983             continue;
1984
1985         if (file->IsCompressed)
1986             comp->ForceLocalState = TRUE;
1987
1988         /* calculate target */
1989         p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
1990
1991         msi_free(file->TargetPath);
1992
1993         TRACE("file %s is named %s\n",
1994                debugstr_w(file->File), debugstr_w(file->FileName));
1995
1996         file->TargetPath = build_directory_name(2, p, file->FileName);
1997
1998         msi_free(p);
1999
2000         TRACE("file %s resolves to %s\n",
2001                debugstr_w(file->File), debugstr_w(file->TargetPath));
2002
2003         if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2004         {
2005             file->state = msifs_missing;
2006             comp->Cost += file->FileSize;
2007             continue;
2008         }
2009
2010         if (file->Version &&
2011             (file_version = msi_get_disk_file_version( file->TargetPath )))
2012         {
2013             TRACE("new %s old %s\n", debugstr_w(file->Version),
2014                   debugstr_w(file_version));
2015             /* FIXME: seems like a bad way to compare version numbers */
2016             if (lstrcmpiW(file_version, file->Version)<0)
2017             {
2018                 file->state = msifs_overwrite;
2019                 comp->Cost += file->FileSize;
2020             }
2021             else
2022                 file->state = msifs_present;
2023             msi_free( file_version );
2024         }
2025         else
2026             file->state = msifs_present;
2027     }
2028
2029     TRACE("Evaluating Condition Table\n");
2030
2031     rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2032     if (rc == ERROR_SUCCESS)
2033     {
2034         rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
2035                     package);
2036         msiobj_release(&view->hdr);
2037     }
2038
2039     TRACE("Enabling or Disabling Components\n");
2040     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2041     {
2042         if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2043         {
2044             TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2045             comp->Enabled = FALSE;
2046         }
2047     }
2048
2049     MSI_SetPropertyW(package,szCosting,szOne);
2050     /* set default run level if not set */
2051     level = msi_dup_property( package, szlevel );
2052     if (!level)
2053         MSI_SetPropertyW(package,szlevel, szOne);
2054     msi_free(level);
2055
2056     ACTION_UpdateInstallStates(package);
2057
2058     return MSI_SetFeatureStates(package);
2059 }
2060
2061 /* OK this value is "interpreted" and then formatted based on the 
2062    first few characters */
2063 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type, 
2064                          DWORD *size)
2065 {
2066     LPSTR data = NULL;
2067     if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2068     {
2069         if (value[1]=='x')
2070         {
2071             LPWSTR ptr;
2072             CHAR byte[5];
2073             LPWSTR deformated = NULL;
2074             int count;
2075
2076             deformat_string(package, &value[2], &deformated);
2077
2078             /* binary value type */
2079             ptr = deformated;
2080             *type = REG_BINARY;
2081             if (strlenW(ptr)%2)
2082                 *size = (strlenW(ptr)/2)+1;
2083             else
2084                 *size = strlenW(ptr)/2;
2085
2086             data = msi_alloc(*size);
2087
2088             byte[0] = '0'; 
2089             byte[1] = 'x'; 
2090             byte[4] = 0; 
2091             count = 0;
2092             /* if uneven pad with a zero in front */
2093             if (strlenW(ptr)%2)
2094             {
2095                 byte[2]= '0';
2096                 byte[3]= *ptr;
2097                 ptr++;
2098                 data[count] = (BYTE)strtol(byte,NULL,0);
2099                 count ++;
2100                 TRACE("Uneven byte count\n");
2101             }
2102             while (*ptr)
2103             {
2104                 byte[2]= *ptr;
2105                 ptr++;
2106                 byte[3]= *ptr;
2107                 ptr++;
2108                 data[count] = (BYTE)strtol(byte,NULL,0);
2109                 count ++;
2110             }
2111             msi_free(deformated);
2112
2113             TRACE("Data %i bytes(%i)\n",*size,count);
2114         }
2115         else
2116         {
2117             LPWSTR deformated;
2118             LPWSTR p;
2119             DWORD d = 0;
2120             deformat_string(package, &value[1], &deformated);
2121
2122             *type=REG_DWORD; 
2123             *size = sizeof(DWORD);
2124             data = msi_alloc(*size);
2125             p = deformated;
2126             if (*p == '-')
2127                 p++;
2128             while (*p)
2129             {
2130                 if ( (*p < '0') || (*p > '9') )
2131                     break;
2132                 d *= 10;
2133                 d += (*p - '0');
2134                 p++;
2135             }
2136             if (deformated[0] == '-')
2137                 d = -d;
2138             *(LPDWORD)data = d;
2139             TRACE("DWORD %i\n",*(LPDWORD)data);
2140
2141             msi_free(deformated);
2142         }
2143     }
2144     else
2145     {
2146         static const WCHAR szMulti[] = {'[','~',']',0};
2147         LPCWSTR ptr;
2148         *type=REG_SZ;
2149
2150         if (value[0]=='#')
2151         {
2152             if (value[1]=='%')
2153             {
2154                 ptr = &value[2];
2155                 *type=REG_EXPAND_SZ;
2156             }
2157             else
2158                 ptr = &value[1];
2159          }
2160          else
2161             ptr=value;
2162
2163         if (strstrW(value,szMulti))
2164             *type = REG_MULTI_SZ;
2165
2166         *size = deformat_string(package, ptr,(LPWSTR*)&data);
2167     }
2168     return data;
2169 }
2170
2171 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2172 {
2173     MSIPACKAGE *package = (MSIPACKAGE*)param;
2174     static const WCHAR szHCR[] = 
2175         {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2176          'R','O','O','T','\\',0};
2177     static const WCHAR szHCU[] =
2178         {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2179          'U','S','E','R','\\',0};
2180     static const WCHAR szHLM[] =
2181         {'H','K','E','Y','_','L','O','C','A','L','_',
2182          'M','A','C','H','I','N','E','\\',0};
2183     static const WCHAR szHU[] =
2184         {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2185
2186     LPSTR value_data = NULL;
2187     HKEY  root_key, hkey;
2188     DWORD type,size;
2189     LPWSTR  deformated;
2190     LPCWSTR szRoot, component, name, key, value;
2191     MSICOMPONENT *comp;
2192     MSIRECORD * uirow;
2193     LPWSTR uikey;
2194     INT   root;
2195     BOOL check_first = FALSE;
2196     UINT rc;
2197
2198     ui_progress(package,2,0,0,0);
2199
2200     value = NULL;
2201     key = NULL;
2202     uikey = NULL;
2203     name = NULL;
2204
2205     component = MSI_RecordGetString(row, 6);
2206     comp = get_loaded_component(package,component);
2207     if (!comp)
2208         return ERROR_SUCCESS;
2209
2210     if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2211     {
2212         TRACE("Skipping write due to disabled component %s\n",
2213                         debugstr_w(component));
2214
2215         comp->Action = comp->Installed;
2216
2217         return ERROR_SUCCESS;
2218     }
2219
2220     comp->Action = INSTALLSTATE_LOCAL;
2221
2222     name = MSI_RecordGetString(row, 4);
2223     if( MSI_RecordIsNull(row,5) && name )
2224     {
2225         /* null values can have special meanings */
2226         if (name[0]=='-' && name[1] == 0)
2227                 return ERROR_SUCCESS;
2228         else if ((name[0]=='+' && name[1] == 0) || 
2229                  (name[0] == '*' && name[1] == 0))
2230                 name = NULL;
2231         check_first = TRUE;
2232     }
2233
2234     root = MSI_RecordGetInteger(row,2);
2235     key = MSI_RecordGetString(row, 3);
2236
2237     /* get the root key */
2238     switch (root)
2239     {
2240         case -1: 
2241             {
2242                 static const WCHAR szALLUSER[] = {'A','L','L','U','S','E','R','S',0};
2243                 LPWSTR all_users = msi_dup_property( package, szALLUSER );
2244                 if (all_users && all_users[0] == '1')
2245                 {
2246                     root_key = HKEY_LOCAL_MACHINE;
2247                     szRoot = szHLM;
2248                 }
2249                 else
2250                 {
2251                     root_key = HKEY_CURRENT_USER;
2252                     szRoot = szHCU;
2253                 }
2254                 msi_free(all_users);
2255             }
2256                  break;
2257         case 0:  root_key = HKEY_CLASSES_ROOT; 
2258                  szRoot = szHCR;
2259                  break;
2260         case 1:  root_key = HKEY_CURRENT_USER;
2261                  szRoot = szHCU;
2262                  break;
2263         case 2:  root_key = HKEY_LOCAL_MACHINE;
2264                  szRoot = szHLM;
2265                  break;
2266         case 3:  root_key = HKEY_USERS; 
2267                  szRoot = szHU;
2268                  break;
2269         default:
2270                  ERR("Unknown root %i\n",root);
2271                  root_key=NULL;
2272                  szRoot = NULL;
2273                  break;
2274     }
2275     if (!root_key)
2276         return ERROR_SUCCESS;
2277
2278     deformat_string(package, key , &deformated);
2279     size = strlenW(deformated) + strlenW(szRoot) + 1;
2280     uikey = msi_alloc(size*sizeof(WCHAR));
2281     strcpyW(uikey,szRoot);
2282     strcatW(uikey,deformated);
2283
2284     if (RegCreateKeyW( root_key, deformated, &hkey))
2285     {
2286         ERR("Could not create key %s\n",debugstr_w(deformated));
2287         msi_free(deformated);
2288         msi_free(uikey);
2289         return ERROR_SUCCESS;
2290     }
2291     msi_free(deformated);
2292
2293     value = MSI_RecordGetString(row,5);
2294     if (value)
2295         value_data = parse_value(package, value, &type, &size); 
2296     else
2297     {
2298         static const WCHAR szEmpty[] = {0};
2299         value_data = (LPSTR)strdupW(szEmpty);
2300         size = 0;
2301         type = REG_SZ;
2302     }
2303
2304     deformat_string(package, name, &deformated);
2305
2306     /* get the double nulls to terminate SZ_MULTI */
2307     if (type == REG_MULTI_SZ)
2308         size +=sizeof(WCHAR);
2309
2310     if (!check_first)
2311     {
2312         TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2313                         debugstr_w(uikey));
2314         RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2315     }
2316     else
2317     {
2318         DWORD sz = 0;
2319         rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2320         if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2321         {
2322             TRACE("value %s of %s checked already exists\n",
2323                             debugstr_w(deformated), debugstr_w(uikey));
2324         }
2325         else
2326         {
2327             TRACE("Checked and setting value %s of %s\n",
2328                             debugstr_w(deformated), debugstr_w(uikey));
2329             if (deformated || size)
2330                 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2331         }
2332     }
2333     RegCloseKey(hkey);
2334
2335     uirow = MSI_CreateRecord(3);
2336     MSI_RecordSetStringW(uirow,2,deformated);
2337     MSI_RecordSetStringW(uirow,1,uikey);
2338
2339     if (type == REG_SZ)
2340         MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2341     else
2342         MSI_RecordSetStringW(uirow,3,value);
2343
2344     ui_actiondata(package,szWriteRegistryValues,uirow);
2345     msiobj_release( &uirow->hdr );
2346
2347     msi_free(value_data);
2348     msi_free(deformated);
2349     msi_free(uikey);
2350
2351     return ERROR_SUCCESS;
2352 }
2353
2354 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2355 {
2356     UINT rc;
2357     MSIQUERY * view;
2358     static const WCHAR ExecSeqQuery[] =
2359         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2360          '`','R','e','g','i','s','t','r','y','`',0 };
2361
2362     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2363     if (rc != ERROR_SUCCESS)
2364         return ERROR_SUCCESS;
2365
2366     /* increment progress bar each time action data is sent */
2367     ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2368
2369     rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2370
2371     msiobj_release(&view->hdr);
2372     return rc;
2373 }
2374
2375 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2376 {
2377     package->script->CurrentlyScripting = TRUE;
2378
2379     return ERROR_SUCCESS;
2380 }
2381
2382
2383 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2384 {
2385     MSICOMPONENT *comp;
2386     DWORD progress = 0;
2387     DWORD total = 0;
2388     static const WCHAR q1[]=
2389         {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2390          '`','R','e','g','i','s','t','r','y','`',0};
2391     UINT rc;
2392     MSIQUERY * view;
2393     MSIFEATURE *feature;
2394     MSIFILE *file;
2395
2396     TRACE("InstallValidate\n");
2397
2398     rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2399     if (rc == ERROR_SUCCESS)
2400     {
2401         MSI_IterateRecords( view, &progress, NULL, package );
2402         msiobj_release( &view->hdr );
2403         total += progress * REG_PROGRESS_VALUE;
2404     }
2405
2406     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2407         total += COMPONENT_PROGRESS_VALUE;
2408
2409     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2410         total += file->FileSize;
2411
2412     ui_progress(package,0,total,0,0);
2413
2414     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2415     {
2416         TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2417             debugstr_w(feature->Feature), feature->Installed, feature->Action,
2418             feature->ActionRequest);
2419     }
2420     
2421     return ERROR_SUCCESS;
2422 }
2423
2424 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2425 {
2426     MSIPACKAGE* package = (MSIPACKAGE*)param;
2427     LPCWSTR cond = NULL; 
2428     LPCWSTR message = NULL;
2429     static const WCHAR title[]=
2430         {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2431
2432     cond = MSI_RecordGetString(row,1);
2433
2434     if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
2435     {
2436         LPWSTR deformated;
2437         message = MSI_RecordGetString(row,2);
2438         deformat_string(package,message,&deformated); 
2439         MessageBoxW(NULL,deformated,title,MB_OK);
2440         msi_free(deformated);
2441         return ERROR_FUNCTION_FAILED;
2442     }
2443
2444     return ERROR_SUCCESS;
2445 }
2446
2447 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2448 {
2449     UINT rc;
2450     MSIQUERY * view = NULL;
2451     static const WCHAR ExecSeqQuery[] =
2452         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2453          '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2454
2455     TRACE("Checking launch conditions\n");
2456
2457     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2458     if (rc != ERROR_SUCCESS)
2459         return ERROR_SUCCESS;
2460
2461     rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2462     msiobj_release(&view->hdr);
2463
2464     return rc;
2465 }
2466
2467 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2468 {
2469
2470     if (!cmp->KeyPath)
2471         return resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
2472
2473     if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2474     {
2475         MSIRECORD * row = 0;
2476         UINT root,len;
2477         LPWSTR deformated,buffer,deformated_name;
2478         LPCWSTR key,name;
2479         static const WCHAR ExecSeqQuery[] =
2480             {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2481              '`','R','e','g','i','s','t','r','y','`',' ',
2482              'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2483              ' ','=',' ' ,'\'','%','s','\'',0 };
2484         static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
2485         static const WCHAR fmt2[]=
2486             {'%','0','2','i',':','\\','%','s','\\','%','s',0};
2487
2488         row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2489         if (!row)
2490             return NULL;
2491
2492         root = MSI_RecordGetInteger(row,2);
2493         key = MSI_RecordGetString(row, 3);
2494         name = MSI_RecordGetString(row, 4);
2495         deformat_string(package, key , &deformated);
2496         deformat_string(package, name, &deformated_name);
2497
2498         len = strlenW(deformated) + 6;
2499         if (deformated_name)
2500             len+=strlenW(deformated_name);
2501
2502         buffer = msi_alloc( len *sizeof(WCHAR));
2503
2504         if (deformated_name)
2505             sprintfW(buffer,fmt2,root,deformated,deformated_name);
2506         else
2507             sprintfW(buffer,fmt,root,deformated);
2508
2509         msi_free(deformated);
2510         msi_free(deformated_name);
2511         msiobj_release(&row->hdr);
2512
2513         return buffer;
2514     }
2515     else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2516     {
2517         FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2518         return NULL;
2519     }
2520     else
2521     {
2522         MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2523
2524         if (file)
2525             return strdupW( file->TargetPath );
2526     }
2527     return NULL;
2528 }
2529
2530 static HKEY openSharedDLLsKey(void)
2531 {
2532     HKEY hkey=0;
2533     static const WCHAR path[] =
2534         {'S','o','f','t','w','a','r','e','\\',
2535          'M','i','c','r','o','s','o','f','t','\\',
2536          'W','i','n','d','o','w','s','\\',
2537          'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2538          'S','h','a','r','e','d','D','L','L','s',0};
2539
2540     RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2541     return hkey;
2542 }
2543
2544 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2545 {
2546     HKEY hkey;
2547     DWORD count=0;
2548     DWORD type;
2549     DWORD sz = sizeof(count);
2550     DWORD rc;
2551     
2552     hkey = openSharedDLLsKey();
2553     rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2554     if (rc != ERROR_SUCCESS)
2555         count = 0;
2556     RegCloseKey(hkey);
2557     return count;
2558 }
2559
2560 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2561 {
2562     HKEY hkey;
2563
2564     hkey = openSharedDLLsKey();
2565     if (count > 0)
2566         msi_reg_set_val_dword( hkey, path, count );
2567     else
2568         RegDeleteValueW(hkey,path);
2569     RegCloseKey(hkey);
2570     return count;
2571 }
2572
2573 /*
2574  * Return TRUE if the count should be written out and FALSE if not
2575  */
2576 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2577 {
2578     MSIFEATURE *feature;
2579     INT count = 0;
2580     BOOL write = FALSE;
2581
2582     /* only refcount DLLs */
2583     if (comp->KeyPath == NULL || 
2584         comp->Attributes & msidbComponentAttributesRegistryKeyPath || 
2585         comp->Attributes & msidbComponentAttributesODBCDataSource)
2586         write = FALSE;
2587     else
2588     {
2589         count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2590         write = (count > 0);
2591
2592         if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2593             write = TRUE;
2594     }
2595
2596     /* increment counts */
2597     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2598     {
2599         ComponentList *cl;
2600
2601         if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2602             continue;
2603
2604         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2605         {
2606             if ( cl->component == comp )
2607                 count++;
2608         }
2609     }
2610
2611     /* decrement counts */
2612     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2613     {
2614         ComponentList *cl;
2615
2616         if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2617             continue;
2618
2619         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2620         {
2621             if ( cl->component == comp )
2622                 count--;
2623         }
2624     }
2625
2626     /* ref count all the files in the component */
2627     if (write)
2628     {
2629         MSIFILE *file;
2630
2631         LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2632         {
2633             if (file->Component == comp)
2634                 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2635         }
2636     }
2637     
2638     /* add a count for permenent */
2639     if (comp->Attributes & msidbComponentAttributesPermanent)
2640         count ++;
2641     
2642     comp->RefCount = count;
2643
2644     if (write)
2645         ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2646 }
2647
2648 /*
2649  * Ok further analysis makes me think that this work is
2650  * actually done in the PublishComponents and PublishFeatures
2651  * step, and not here.  It appears like the keypath and all that is
2652  * resolved in this step, however actually written in the Publish steps.
2653  * But we will leave it here for now because it is unclear
2654  */
2655 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2656 {
2657     WCHAR squished_pc[GUID_SIZE];
2658     WCHAR squished_cc[GUID_SIZE];
2659     UINT rc;
2660     MSICOMPONENT *comp;
2661     HKEY hkey=0,hkey2=0;
2662
2663     /* writes the Component and Features values to the registry */
2664
2665     rc = MSIREG_OpenComponents(&hkey);
2666     if (rc != ERROR_SUCCESS)
2667         return rc;
2668
2669     squash_guid(package->ProductCode,squished_pc);
2670     ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2671
2672     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2673     {
2674         MSIRECORD * uirow;
2675
2676         ui_progress(package,2,0,0,0);
2677         if (!comp->ComponentId)
2678             continue;
2679
2680         squash_guid(comp->ComponentId,squished_cc);
2681            
2682         msi_free(comp->FullKeypath);
2683         comp->FullKeypath = resolve_keypath( package, comp );
2684
2685         /* do the refcounting */
2686         ACTION_RefCountComponent( package, comp );
2687
2688         TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2689                             debugstr_w(comp->Component),
2690                             debugstr_w(squished_cc),
2691                             debugstr_w(comp->FullKeypath),
2692                             comp->RefCount);
2693         /*
2694          * Write the keypath out if the component is to be registered
2695          * and delete the key if the component is to be deregistered
2696          */
2697         if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2698         {
2699             rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
2700             if (rc != ERROR_SUCCESS)
2701                 continue;
2702
2703             if (!comp->FullKeypath)
2704                 continue;
2705
2706             msi_reg_set_val_str( hkey2, squished_pc, comp->FullKeypath );
2707
2708             if (comp->Attributes & msidbComponentAttributesPermanent)
2709             {
2710                 static const WCHAR szPermKey[] =
2711                     { '0','0','0','0','0','0','0','0','0','0','0','0',
2712                       '0','0','0','0','0','0','0','0','0','0','0','0',
2713                       '0','0','0','0','0','0','0','0',0 };
2714
2715                 msi_reg_set_val_str( hkey2, szPermKey, comp->FullKeypath );
2716             }
2717
2718             RegCloseKey(hkey2);
2719
2720             /* UI stuff */
2721             uirow = MSI_CreateRecord(3);
2722             MSI_RecordSetStringW(uirow,1,package->ProductCode);
2723             MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2724             MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2725             ui_actiondata(package,szProcessComponents,uirow);
2726             msiobj_release( &uirow->hdr );
2727         }
2728         else if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ABSENT))
2729         {
2730             DWORD res;
2731
2732             rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
2733             if (rc != ERROR_SUCCESS)
2734                 continue;
2735
2736             RegDeleteValueW(hkey2,squished_pc);
2737
2738             /* if the key is empty delete it */
2739             res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
2740             RegCloseKey(hkey2);
2741             if (res == ERROR_NO_MORE_ITEMS)
2742                 RegDeleteKeyW(hkey,squished_cc);
2743
2744             /* UI stuff */
2745             uirow = MSI_CreateRecord(2);
2746             MSI_RecordSetStringW(uirow,1,package->ProductCode);
2747             MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2748             ui_actiondata(package,szProcessComponents,uirow);
2749             msiobj_release( &uirow->hdr );
2750         }
2751     } 
2752     RegCloseKey(hkey);
2753     return rc;
2754 }
2755
2756 typedef struct {
2757     CLSID       clsid;
2758     LPWSTR      source;
2759
2760     LPWSTR      path;
2761     ITypeLib    *ptLib;
2762 } typelib_struct;
2763
2764 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType, 
2765                                        LPWSTR lpszName, LONG_PTR lParam)
2766 {
2767     TLIBATTR *attr;
2768     typelib_struct *tl_struct = (typelib_struct*) lParam;
2769     static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2770     int sz; 
2771     HRESULT res;
2772
2773     if (!IS_INTRESOURCE(lpszName))
2774     {
2775         ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2776         return TRUE;
2777     }
2778
2779     sz = strlenW(tl_struct->source)+4;
2780     sz *= sizeof(WCHAR);
2781
2782     if ((INT_PTR)lpszName == 1)
2783         tl_struct->path = strdupW(tl_struct->source);
2784     else
2785     {
2786         tl_struct->path = msi_alloc(sz);
2787         sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2788     }
2789
2790     TRACE("trying %s\n", debugstr_w(tl_struct->path));
2791     res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2792     if (!SUCCEEDED(res))
2793     {
2794         msi_free(tl_struct->path);
2795         tl_struct->path = NULL;
2796
2797         return TRUE;
2798     }
2799
2800     ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2801     if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2802     {
2803         ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2804         return FALSE;
2805     }
2806
2807     msi_free(tl_struct->path);
2808     tl_struct->path = NULL;
2809
2810     ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2811     ITypeLib_Release(tl_struct->ptLib);
2812
2813     return TRUE;
2814 }
2815
2816 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2817 {
2818     MSIPACKAGE* package = (MSIPACKAGE*)param;
2819     LPCWSTR component;
2820     MSICOMPONENT *comp;
2821     MSIFILE *file;
2822     typelib_struct tl_struct;
2823     HMODULE module;
2824     static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2825
2826     component = MSI_RecordGetString(row,3);
2827     comp = get_loaded_component(package,component);
2828     if (!comp)
2829         return ERROR_SUCCESS;
2830
2831     if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2832     {
2833         TRACE("Skipping typelib reg due to disabled component\n");
2834
2835         comp->Action = comp->Installed;
2836
2837         return ERROR_SUCCESS;
2838     }
2839
2840     comp->Action = INSTALLSTATE_LOCAL;
2841
2842     file = get_loaded_file( package, comp->KeyPath ); 
2843     if (!file)
2844         return ERROR_SUCCESS;
2845
2846     module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2847     if (module)
2848     {
2849         LPCWSTR guid;
2850         guid = MSI_RecordGetString(row,1);
2851         CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2852         tl_struct.source = strdupW( file->TargetPath );
2853         tl_struct.path = NULL;
2854
2855         EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2856                         (LONG_PTR)&tl_struct);
2857
2858         if (tl_struct.path)
2859         {
2860             LPWSTR help = NULL;
2861             LPCWSTR helpid;
2862             HRESULT res;
2863
2864             helpid = MSI_RecordGetString(row,6);
2865
2866             if (helpid)
2867                 help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
2868             res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2869             msi_free(help);
2870
2871             if (!SUCCEEDED(res))
2872                 ERR("Failed to register type library %s\n",
2873                         debugstr_w(tl_struct.path));
2874             else
2875             {
2876                 ui_actiondata(package,szRegisterTypeLibraries,row);
2877
2878                 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2879             }
2880
2881             ITypeLib_Release(tl_struct.ptLib);
2882             msi_free(tl_struct.path);
2883         }
2884         else
2885             ERR("Failed to load type library %s\n",
2886                     debugstr_w(tl_struct.source));
2887
2888         FreeLibrary(module);
2889         msi_free(tl_struct.source);
2890     }
2891     else
2892         ERR("Could not load file! %s\n", debugstr_w(file->TargetPath));
2893
2894     return ERROR_SUCCESS;
2895 }
2896
2897 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2898 {
2899     /* 
2900      * OK this is a bit confusing.. I am given a _Component key and I believe
2901      * that the file that is being registered as a type library is the "key file
2902      * of that component" which I interpret to mean "The file in the KeyPath of
2903      * that component".
2904      */
2905     UINT rc;
2906     MSIQUERY * view;
2907     static const WCHAR Query[] =
2908         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2909          '`','T','y','p','e','L','i','b','`',0};
2910
2911     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2912     if (rc != ERROR_SUCCESS)
2913         return ERROR_SUCCESS;
2914
2915     rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2916     msiobj_release(&view->hdr);
2917     return rc;
2918 }
2919
2920 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2921 {
2922     MSIPACKAGE *package = (MSIPACKAGE*)param;
2923     LPWSTR target_file, target_folder, filename;
2924     LPCWSTR buffer, extension;
2925     MSICOMPONENT *comp;
2926     static const WCHAR szlnk[]={'.','l','n','k',0};
2927     IShellLinkW *sl = NULL;
2928     IPersistFile *pf = NULL;
2929     HRESULT res;
2930
2931     buffer = MSI_RecordGetString(row,4);
2932     comp = get_loaded_component(package,buffer);
2933     if (!comp)
2934         return ERROR_SUCCESS;
2935
2936     if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2937     {
2938         TRACE("Skipping shortcut creation due to disabled component\n");
2939
2940         comp->Action = comp->Installed;
2941
2942         return ERROR_SUCCESS;
2943     }
2944
2945     comp->Action = INSTALLSTATE_LOCAL;
2946
2947     ui_actiondata(package,szCreateShortcuts,row);
2948
2949     res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2950                     &IID_IShellLinkW, (LPVOID *) &sl );
2951
2952     if (FAILED( res ))
2953     {
2954         ERR("CLSID_ShellLink not available\n");
2955         goto err;
2956     }
2957
2958     res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2959     if (FAILED( res ))
2960     {
2961         ERR("QueryInterface(IID_IPersistFile) failed\n");
2962         goto err;
2963     }
2964
2965     buffer = MSI_RecordGetString(row,2);
2966     target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
2967
2968     /* may be needed because of a bug somehwere else */
2969     create_full_pathW(target_folder);
2970
2971     filename = msi_dup_record_field( row, 3 );
2972     reduce_to_longfilename(filename);
2973
2974     extension = strchrW(filename,'.');
2975     if (!extension || strcmpiW(extension,szlnk))
2976     {
2977         int len = strlenW(filename);
2978         filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2979         memcpy(filename + len, szlnk, sizeof(szlnk));
2980     }
2981     target_file = build_directory_name(2, target_folder, filename);
2982     msi_free(target_folder);
2983     msi_free(filename);
2984
2985     buffer = MSI_RecordGetString(row,5);
2986     if (strchrW(buffer,'['))
2987     {
2988         LPWSTR deformated;
2989         deformat_string(package,buffer,&deformated);
2990         IShellLinkW_SetPath(sl,deformated);
2991         msi_free(deformated);
2992     }
2993     else
2994     {
2995         FIXME("poorly handled shortcut format, advertised shortcut\n");
2996         IShellLinkW_SetPath(sl,comp->FullKeypath);
2997     }
2998
2999     if (!MSI_RecordIsNull(row,6))
3000     {
3001         LPWSTR deformated;
3002         buffer = MSI_RecordGetString(row,6);
3003         deformat_string(package,buffer,&deformated);
3004         IShellLinkW_SetArguments(sl,deformated);
3005         msi_free(deformated);
3006     }
3007
3008     if (!MSI_RecordIsNull(row,7))
3009     {
3010         buffer = MSI_RecordGetString(row,7);
3011         IShellLinkW_SetDescription(sl,buffer);
3012     }
3013
3014     if (!MSI_RecordIsNull(row,8))
3015         IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3016
3017     if (!MSI_RecordIsNull(row,9))
3018     {
3019         LPWSTR Path;
3020         INT index; 
3021
3022         buffer = MSI_RecordGetString(row,9);
3023
3024         Path = build_icon_path(package,buffer);
3025         index = MSI_RecordGetInteger(row,10);
3026
3027         /* no value means 0 */
3028         if (index == MSI_NULL_INTEGER)
3029             index = 0;
3030
3031         IShellLinkW_SetIconLocation(sl,Path,index);
3032         msi_free(Path);
3033     }
3034
3035     if (!MSI_RecordIsNull(row,11))
3036         IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3037
3038     if (!MSI_RecordIsNull(row,12))
3039     {
3040         LPWSTR Path;
3041         buffer = MSI_RecordGetString(row,12);
3042         Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
3043         if (Path)
3044             IShellLinkW_SetWorkingDirectory(sl,Path);
3045         msi_free(Path);
3046     }
3047
3048     TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3049     IPersistFile_Save(pf,target_file,FALSE);
3050
3051     msi_free(target_file);    
3052
3053 err:
3054     if (pf)
3055         IPersistFile_Release( pf );
3056     if (sl)
3057         IShellLinkW_Release( sl );
3058
3059     return ERROR_SUCCESS;
3060 }
3061
3062 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3063 {
3064     UINT rc;
3065     HRESULT res;
3066     MSIQUERY * view;
3067     static const WCHAR Query[] =
3068         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3069          '`','S','h','o','r','t','c','u','t','`',0};
3070
3071     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3072     if (rc != ERROR_SUCCESS)
3073         return ERROR_SUCCESS;
3074
3075     res = CoInitialize( NULL );
3076     if (FAILED (res))
3077     {
3078         ERR("CoInitialize failed\n");
3079         return ERROR_FUNCTION_FAILED;
3080     }
3081
3082     rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3083     msiobj_release(&view->hdr);
3084
3085     CoUninitialize();
3086
3087     return rc;
3088 }
3089
3090 static UINT ITERATE_PublishProduct(MSIRECORD *row, LPVOID param)
3091 {
3092     MSIPACKAGE* package = (MSIPACKAGE*)param;
3093     HANDLE the_file;
3094     LPWSTR FilePath;
3095     LPCWSTR FileName;
3096     CHAR buffer[1024];
3097     DWORD sz;
3098     UINT rc;
3099     MSIRECORD *uirow;
3100
3101     FileName = MSI_RecordGetString(row,1);
3102     if (!FileName)
3103     {
3104         ERR("Unable to get FileName\n");
3105         return ERROR_SUCCESS;
3106     }
3107
3108     FilePath = build_icon_path(package,FileName);
3109
3110     TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3111
3112     the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3113                         FILE_ATTRIBUTE_NORMAL, NULL);
3114
3115     if (the_file == INVALID_HANDLE_VALUE)
3116     {
3117         ERR("Unable to create file %s\n",debugstr_w(FilePath));
3118         msi_free(FilePath);
3119         return ERROR_SUCCESS;
3120     }
3121
3122     do 
3123     {
3124         DWORD write;
3125         sz = 1024;
3126         rc = MSI_RecordReadStream(row,2,buffer,&sz);
3127         if (rc != ERROR_SUCCESS)
3128         {
3129             ERR("Failed to get stream\n");
3130             CloseHandle(the_file);  
3131             DeleteFileW(FilePath);
3132             break;
3133         }
3134         WriteFile(the_file,buffer,sz,&write,NULL);
3135     } while (sz == 1024);
3136
3137     msi_free(FilePath);
3138
3139     CloseHandle(the_file);
3140
3141     uirow = MSI_CreateRecord(1);
3142     MSI_RecordSetStringW(uirow,1,FileName);
3143     ui_actiondata(package,szPublishProduct,uirow);
3144     msiobj_release( &uirow->hdr );
3145
3146     return ERROR_SUCCESS;
3147 }
3148
3149 /*
3150  * 99% of the work done here is only done for 
3151  * advertised installs. However this is where the
3152  * Icon table is processed and written out
3153  * so that is what I am going to do here.
3154  */
3155 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3156 {
3157     UINT rc;
3158     MSIQUERY * view;
3159     static const WCHAR Query[]=
3160         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3161          '`','I','c','o','n','`',0};
3162     /* for registry stuff */
3163     HKEY hkey=0;
3164     HKEY hukey=0;
3165     static const WCHAR szProductLanguage[] =
3166         {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3167     static const WCHAR szARPProductIcon[] =
3168         {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3169     static const WCHAR szProductVersion[] =
3170         {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3171     DWORD langid;
3172     LPWSTR buffer;
3173     DWORD size;
3174     MSIHANDLE hDb, hSumInfo;
3175
3176     /* write out icon files */
3177
3178     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3179     if (rc == ERROR_SUCCESS)
3180     {
3181         MSI_IterateRecords(view, NULL, ITERATE_PublishProduct, package);
3182         msiobj_release(&view->hdr);
3183     }
3184
3185     /* ok there is a lot more done here but i need to figure out what */
3186
3187     rc = MSIREG_OpenProductsKey(package->ProductCode,&hkey,TRUE);
3188     if (rc != ERROR_SUCCESS)
3189         goto end;
3190
3191     rc = MSIREG_OpenUserProductsKey(package->ProductCode,&hukey,TRUE);
3192     if (rc != ERROR_SUCCESS)
3193         goto end;
3194
3195
3196     buffer = msi_dup_property( package, INSTALLPROPERTY_PRODUCTNAMEW );
3197     msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTNAMEW, buffer );
3198     msi_free(buffer);
3199
3200     langid = msi_get_property_int( package, szProductLanguage, 0 );
3201     msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3202
3203     buffer = msi_dup_property( package, szARPProductIcon );
3204     if (buffer)
3205     {
3206         LPWSTR path = build_icon_path(package,buffer);
3207         msi_reg_set_val_str( hukey, INSTALLPROPERTY_PRODUCTICONW, path );
3208         msi_free( path );
3209     }
3210     msi_free(buffer);
3211
3212     buffer = msi_dup_property( package, szProductVersion );
3213     if (buffer)
3214     {
3215         DWORD verdword = msi_version_str_to_dword(buffer);
3216         msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3217     }
3218     msi_free(buffer);
3219     
3220     /* FIXME: Need to write more keys to the user registry */
3221   
3222     hDb= alloc_msihandle( &package->db->hdr );
3223     if (!hDb) {
3224         rc = ERROR_NOT_ENOUGH_MEMORY;
3225         goto end;
3226     }
3227     rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo); 
3228     MsiCloseHandle(hDb);
3229     if (rc == ERROR_SUCCESS)
3230     {
3231         WCHAR guidbuffer[0x200];
3232         size = 0x200;
3233         rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
3234                                         guidbuffer, &size);
3235         if (rc == ERROR_SUCCESS)
3236         {
3237             WCHAR squashed[GUID_SIZE];
3238             /* for now we only care about the first guid */
3239             LPWSTR ptr = strchrW(guidbuffer,';');
3240             if (ptr) *ptr = 0;
3241             squash_guid(guidbuffer,squashed);
3242             msi_reg_set_val_str( hukey, INSTALLPROPERTY_PACKAGECODEW, squashed );
3243         }
3244         else
3245         {
3246             ERR("Unable to query Revision_Number...\n");
3247             rc = ERROR_SUCCESS;
3248         }
3249         MsiCloseHandle(hSumInfo);
3250     }
3251     else
3252     {
3253         ERR("Unable to open Summary Information\n");
3254         rc = ERROR_SUCCESS;
3255     }
3256
3257 end:
3258
3259     RegCloseKey(hkey);
3260     RegCloseKey(hukey);
3261
3262     return rc;
3263 }
3264
3265 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3266 {
3267     MSIPACKAGE *package = (MSIPACKAGE*)param;
3268     LPCWSTR component,section,key,value,identifier,filename,dirproperty;
3269     LPWSTR deformated_section, deformated_key, deformated_value;
3270     LPWSTR folder, fullname = NULL;
3271     MSIRECORD * uirow;
3272     INT action;
3273     MSICOMPONENT *comp;
3274     static const WCHAR szWindowsFolder[] =
3275           {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3276
3277     component = MSI_RecordGetString(row, 8);
3278     comp = get_loaded_component(package,component);
3279
3280     if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3281     {
3282         TRACE("Skipping ini file due to disabled component %s\n",
3283                         debugstr_w(component));
3284
3285         comp->Action = comp->Installed;
3286
3287         return ERROR_SUCCESS;
3288     }
3289
3290     comp->Action = INSTALLSTATE_LOCAL;
3291
3292     identifier = MSI_RecordGetString(row,1); 
3293     filename = MSI_RecordGetString(row,2);
3294     dirproperty = MSI_RecordGetString(row,3);
3295     section = MSI_RecordGetString(row,4);
3296     key = MSI_RecordGetString(row,5);
3297     value = MSI_RecordGetString(row,6);
3298     action = MSI_RecordGetInteger(row,7);
3299
3300     deformat_string(package,section,&deformated_section);
3301     deformat_string(package,key,&deformated_key);
3302     deformat_string(package,value,&deformated_value);
3303
3304     if (dirproperty)
3305     {
3306         folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
3307         if (!folder)
3308             folder = msi_dup_property( package, dirproperty );
3309     }
3310     else
3311         folder = msi_dup_property( package, szWindowsFolder );
3312
3313     if (!folder)
3314     {
3315         ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3316         goto cleanup;
3317     }
3318
3319     fullname = build_directory_name(2, folder, filename);
3320
3321     if (action == 0)
3322     {
3323         TRACE("Adding value %s to section %s in %s\n",
3324                 debugstr_w(deformated_key), debugstr_w(deformated_section),
3325                 debugstr_w(fullname));
3326         WritePrivateProfileStringW(deformated_section, deformated_key,
3327                                    deformated_value, fullname);
3328     }
3329     else if (action == 1)
3330     {
3331         WCHAR returned[10];
3332         GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3333                                  returned, 10, fullname);
3334         if (returned[0] == 0)
3335         {
3336             TRACE("Adding value %s to section %s in %s\n",
3337                     debugstr_w(deformated_key), debugstr_w(deformated_section),
3338                     debugstr_w(fullname));
3339
3340             WritePrivateProfileStringW(deformated_section, deformated_key,
3341                                        deformated_value, fullname);
3342         }
3343     }
3344     else if (action == 3)
3345         FIXME("Append to existing section not yet implemented\n");
3346
3347     uirow = MSI_CreateRecord(4);
3348     MSI_RecordSetStringW(uirow,1,identifier);
3349     MSI_RecordSetStringW(uirow,2,deformated_section);
3350     MSI_RecordSetStringW(uirow,3,deformated_key);
3351     MSI_RecordSetStringW(uirow,4,deformated_value);
3352     ui_actiondata(package,szWriteIniValues,uirow);
3353     msiobj_release( &uirow->hdr );
3354 cleanup:
3355     msi_free(fullname);
3356     msi_free(folder);
3357     msi_free(deformated_key);
3358     msi_free(deformated_value);
3359     msi_free(deformated_section);
3360     return ERROR_SUCCESS;
3361 }
3362
3363 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3364 {
3365     UINT rc;
3366     MSIQUERY * view;
3367     static const WCHAR ExecSeqQuery[] = 
3368         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3369          '`','I','n','i','F','i','l','e','`',0};
3370
3371     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3372     if (rc != ERROR_SUCCESS)
3373     {
3374         TRACE("no IniFile table\n");
3375         return ERROR_SUCCESS;
3376     }
3377
3378     rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3379     msiobj_release(&view->hdr);
3380     return rc;
3381 }
3382
3383 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3384 {
3385     MSIPACKAGE *package = (MSIPACKAGE*)param;
3386     LPCWSTR filename;
3387     LPWSTR FullName;
3388     MSIFILE *file;
3389     DWORD len;
3390     static const WCHAR ExeStr[] =
3391         {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3392     static const WCHAR close[] =  {'\"',0};
3393     STARTUPINFOW si;
3394     PROCESS_INFORMATION info;
3395     BOOL brc;
3396     MSIRECORD *uirow;
3397     LPWSTR uipath, p;
3398
3399     memset(&si,0,sizeof(STARTUPINFOW));
3400
3401     filename = MSI_RecordGetString(row,1);
3402     file = get_loaded_file( package, filename );
3403
3404     if (!file)
3405     {
3406         ERR("Unable to find file id %s\n",debugstr_w(filename));
3407         return ERROR_SUCCESS;
3408     }
3409
3410     len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3411
3412     FullName = msi_alloc(len*sizeof(WCHAR));
3413     strcpyW(FullName,ExeStr);
3414     strcatW( FullName, file->TargetPath );
3415     strcatW(FullName,close);
3416
3417     TRACE("Registering %s\n",debugstr_w(FullName));
3418     brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3419                     &si, &info);
3420
3421     if (brc)
3422         msi_dialog_check_messages(info.hProcess);
3423
3424     msi_free(FullName);
3425
3426     /* the UI chunk */
3427     uirow = MSI_CreateRecord( 2 );
3428     uipath = strdupW( file->TargetPath );
3429     p = strrchrW(uipath,'\\');
3430     if (p)
3431         p[1]=0;
3432     MSI_RecordSetStringW( uirow, 1, &p[2] );
3433     MSI_RecordSetStringW( uirow, 2, uipath);
3434     ui_actiondata( package, szSelfRegModules, uirow);
3435     msiobj_release( &uirow->hdr );
3436     msi_free( uipath );
3437     /* FIXME: call ui_progress? */
3438
3439     return ERROR_SUCCESS;
3440 }
3441
3442 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3443 {
3444     UINT rc;
3445     MSIQUERY * view;
3446     static const WCHAR ExecSeqQuery[] = 
3447         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3448          '`','S','e','l','f','R','e','g','`',0};
3449
3450     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3451     if (rc != ERROR_SUCCESS)
3452     {
3453         TRACE("no SelfReg table\n");
3454         return ERROR_SUCCESS;
3455     }
3456
3457     MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3458     msiobj_release(&view->hdr);
3459
3460     return ERROR_SUCCESS;
3461 }
3462
3463 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3464 {
3465     MSIFEATURE *feature;
3466     UINT rc;
3467     HKEY hkey=0;
3468     HKEY hukey=0;
3469     
3470     rc = MSIREG_OpenFeaturesKey(package->ProductCode,&hkey,TRUE);
3471     if (rc != ERROR_SUCCESS)
3472         goto end;
3473
3474     rc = MSIREG_OpenUserFeaturesKey(package->ProductCode,&hukey,TRUE);
3475     if (rc != ERROR_SUCCESS)
3476         goto end;
3477
3478     /* here the guids are base 85 encoded */
3479     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3480     {
3481         ComponentList *cl;
3482         LPWSTR data = NULL;
3483         GUID clsid;
3484         INT size;
3485         BOOL absent = FALSE;
3486         MSIRECORD *uirow;
3487
3488         if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3489             !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3490             !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3491             absent = TRUE;
3492
3493         size = 1;
3494         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3495         {
3496             size += 21;
3497         }
3498         if (feature->Feature_Parent)
3499             size += strlenW( feature->Feature_Parent )+2;
3500
3501         data = msi_alloc(size * sizeof(WCHAR));
3502
3503         data[0] = 0;
3504         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3505         {
3506             MSICOMPONENT* component = cl->component;
3507             WCHAR buf[21];
3508
3509             buf[0] = 0;
3510             if (component->ComponentId)
3511             {
3512                 TRACE("From %s\n",debugstr_w(component->ComponentId));
3513                 CLSIDFromString(component->ComponentId, &clsid);
3514                 encode_base85_guid(&clsid,buf);
3515                 TRACE("to %s\n",debugstr_w(buf));
3516                 strcatW(data,buf);
3517             }
3518         }
3519         if (feature->Feature_Parent)
3520         {
3521             static const WCHAR sep[] = {'\2',0};
3522             strcatW(data,sep);
3523             strcatW(data,feature->Feature_Parent);
3524         }
3525
3526         msi_reg_set_val_str( hkey, feature->Feature, data );
3527         msi_free(data);
3528
3529         size = 0;
3530         if (feature->Feature_Parent)
3531             size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3532         if (!absent)
3533         {
3534             RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3535                        (LPBYTE)feature->Feature_Parent,size);
3536         }
3537         else
3538         {
3539             size += 2*sizeof(WCHAR);
3540             data = msi_alloc(size);
3541             data[0] = 0x6;
3542             data[1] = 0;
3543             if (feature->Feature_Parent)
3544                 strcpyW( &data[1], feature->Feature_Parent );
3545             RegSetValueExW(hukey,feature->Feature,0,REG_SZ,
3546                        (LPBYTE)data,size);
3547             msi_free(data);
3548         }
3549
3550         /* the UI chunk */
3551         uirow = MSI_CreateRecord( 1 );
3552         MSI_RecordSetStringW( uirow, 1, feature->Feature );
3553         ui_actiondata( package, szPublishFeatures, uirow);
3554         msiobj_release( &uirow->hdr );
3555         /* FIXME: call ui_progress? */
3556     }
3557
3558 end:
3559     RegCloseKey(hkey);
3560     RegCloseKey(hukey);
3561     return rc;
3562 }
3563
3564 static UINT msi_get_local_package_name( LPWSTR path )
3565 {
3566     static const WCHAR szInstaller[] = {
3567         '\\','I','n','s','t','a','l','l','e','r','\\',0};
3568     static const WCHAR fmt[] = { '%','x','.','m','s','i',0};
3569     DWORD time, len, i;
3570     HANDLE handle;
3571
3572     time = GetTickCount();
3573     GetWindowsDirectoryW( path, MAX_PATH );
3574     lstrcatW( path, szInstaller );
3575     CreateDirectoryW( path, NULL );
3576
3577     len = lstrlenW(path);
3578     for (i=0; i<0x10000; i++)
3579     {
3580         snprintfW( &path[len], MAX_PATH - len, fmt, (time+i)&0xffff );
3581         handle = CreateFileW( path, GENERIC_WRITE, 0, NULL,
3582                               CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
3583         if (handle != INVALID_HANDLE_VALUE)
3584         {
3585             CloseHandle(handle);
3586             break;
3587         }
3588         if (GetLastError() != ERROR_FILE_EXISTS &&
3589             GetLastError() != ERROR_SHARING_VIOLATION)
3590             return ERROR_FUNCTION_FAILED;
3591     }
3592
3593     return ERROR_SUCCESS;
3594 }
3595
3596 static UINT msi_make_package_local( MSIPACKAGE *package, HKEY hkey )
3597 {
3598     static const WCHAR szOriginalDatabase[] =
3599         {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
3600     WCHAR packagefile[MAX_PATH];
3601     LPWSTR msiFilePath;
3602     UINT r;
3603
3604     r = msi_get_local_package_name( packagefile );
3605     if (r != ERROR_SUCCESS)
3606         return r;
3607
3608     TRACE("Copying to local package %s\n",debugstr_w(packagefile));
3609
3610     msiFilePath = msi_dup_property( package, szOriginalDatabase );
3611     r = CopyFileW( msiFilePath, packagefile, FALSE);
3612     msi_free( msiFilePath );
3613
3614     if (!r)
3615     {
3616         ERR("Unable to copy package (%s -> %s) (error %d)\n",
3617             debugstr_w(msiFilePath), debugstr_w(packagefile), GetLastError());
3618         return ERROR_FUNCTION_FAILED;
3619     }
3620
3621     /* FIXME: maybe set this key in ACTION_RegisterProduct instead */
3622     msi_reg_set_val_str( hkey, INSTALLPROPERTY_LOCALPACKAGEW, packagefile );
3623     return ERROR_SUCCESS;
3624 }
3625
3626 static UINT msi_write_uninstall_property_vals( MSIPACKAGE *package, HKEY hkey )
3627 {
3628     LPWSTR prop, val, key;
3629     static const LPCSTR propval[] = {
3630         "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3631         "ARPCONTACT",             "Contact",
3632         "ARPCOMMENTS",            "Comments",
3633         "ProductName",            "DisplayName",
3634         "ProductVersion",         "DisplayVersion",
3635         "ARPHELPLINK",            "HelpLink",
3636         "ARPHELPTELEPHONE",       "HelpTelephone",
3637         "ARPINSTALLLOCATION",     "InstallLocation",
3638         "SourceDir",              "InstallSource",
3639         "Manufacturer",           "Publisher",
3640         "ARPREADME",              "Readme",
3641         "ARPSIZE",                "Size",
3642         "ARPURLINFOABOUT",        "URLInfoAbout",
3643         "ARPURLUPDATEINFO",       "URLUpdateInfo",
3644         NULL,
3645     };
3646     const LPCSTR *p = propval;
3647
3648     while( *p )
3649     {
3650         prop = strdupAtoW( *p++ );
3651         key = strdupAtoW( *p++ );
3652         val = msi_dup_property( package, prop );
3653         msi_reg_set_val_str( hkey, key, val );
3654         msi_free(val);
3655         msi_free(key);
3656         msi_free(prop);
3657     }
3658     return ERROR_SUCCESS;
3659 }
3660
3661 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3662 {
3663     HKEY hkey=0;
3664     LPWSTR buffer = NULL;
3665     UINT rc;
3666     DWORD size, langid;
3667     static const WCHAR szWindowsInstaller[] = 
3668         {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3669     static const WCHAR szUpgradeCode[] = 
3670         {'U','p','g','r','a','d','e','C','o','d','e',0};
3671     static const WCHAR modpath_fmt[] = 
3672         {'M','s','i','E','x','e','c','.','e','x','e',' ',
3673          '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3674     static const WCHAR szModifyPath[] = 
3675         {'M','o','d','i','f','y','P','a','t','h',0};
3676     static const WCHAR szUninstallString[] = 
3677         {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3678     static const WCHAR szEstimatedSize[] = 
3679         {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3680     static const WCHAR szProductLanguage[] =
3681         {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3682     static const WCHAR szProductVersion[] =
3683         {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3684
3685     SYSTEMTIME systime;
3686     static const WCHAR date_fmt[] = {'%','i','%','i','%','i',0};
3687     LPWSTR upgrade_code;
3688     WCHAR szDate[9]; 
3689
3690     rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3691     if (rc != ERROR_SUCCESS)
3692         return rc;
3693
3694     /* dump all the info i can grab */
3695     /* FIXME: Flesh out more information */
3696
3697     msi_write_uninstall_property_vals( package, hkey );
3698
3699     msi_reg_set_val_dword( hkey, szWindowsInstaller, 1 );
3700     
3701     msi_make_package_local( package, hkey );
3702
3703     /* do ModifyPath and UninstallString */
3704     size = deformat_string(package,modpath_fmt,&buffer);
3705     RegSetValueExW(hkey,szModifyPath,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3706     RegSetValueExW(hkey,szUninstallString,0,REG_EXPAND_SZ,(LPBYTE)buffer,size);
3707     msi_free(buffer);
3708
3709     /* FIXME: Write real Estimated Size when we have it */
3710     msi_reg_set_val_dword( hkey, szEstimatedSize, 0 );
3711    
3712     GetLocalTime(&systime);
3713     sprintfW(szDate,date_fmt,systime.wYear,systime.wMonth,systime.wDay);
3714     msi_reg_set_val_str( hkey, INSTALLPROPERTY_INSTALLDATEW, szDate );
3715    
3716     langid = msi_get_property_int( package, szProductLanguage, 0 );
3717     msi_reg_set_val_dword( hkey, INSTALLPROPERTY_LANGUAGEW, langid );
3718
3719     buffer = msi_dup_property( package, szProductVersion );
3720     if (buffer)
3721     {
3722         DWORD verdword = msi_version_str_to_dword(buffer);
3723
3724         msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONW, verdword );
3725         msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword>>24 );
3726         msi_reg_set_val_dword( hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword>>16)&0x00FF );
3727     }
3728     msi_free(buffer);
3729     
3730     /* Handle Upgrade Codes */
3731     upgrade_code = msi_dup_property( package, szUpgradeCode );
3732     if (upgrade_code)
3733     {
3734         HKEY hkey2;
3735         WCHAR squashed[33];
3736         MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3737         squash_guid(package->ProductCode,squashed);
3738         msi_reg_set_val_str( hkey2, squashed, NULL );
3739         RegCloseKey(hkey2);
3740         MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
3741         squash_guid(package->ProductCode,squashed);
3742         msi_reg_set_val_str( hkey2, squashed, NULL );
3743         RegCloseKey(hkey2);
3744
3745         msi_free(upgrade_code);
3746     }
3747     
3748     RegCloseKey(hkey);
3749
3750     /* FIXME: call ui_actiondata */
3751
3752     return ERROR_SUCCESS;
3753 }
3754
3755 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3756 {
3757     return execute_script(package,INSTALL_SCRIPT);
3758 }
3759
3760 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
3761 {
3762     UINT rc;
3763
3764     /* turn off scheduleing */
3765     package->script->CurrentlyScripting= FALSE;
3766
3767     /* first do the same as an InstallExecute */
3768     rc = ACTION_InstallExecute(package);
3769     if (rc != ERROR_SUCCESS)
3770         return rc;
3771
3772     /* then handle Commit Actions */
3773     rc = execute_script(package,COMMIT_SCRIPT);
3774
3775     return rc;
3776 }
3777
3778 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
3779 {
3780     static const WCHAR RunOnce[] = {
3781     'S','o','f','t','w','a','r','e','\\',
3782     'M','i','c','r','o','s','o','f','t','\\',
3783     'W','i','n','d','o','w','s','\\',
3784     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3785     'R','u','n','O','n','c','e',0};
3786     static const WCHAR InstallRunOnce[] = {
3787     'S','o','f','t','w','a','r','e','\\',
3788     'M','i','c','r','o','s','o','f','t','\\',
3789     'W','i','n','d','o','w','s','\\',
3790     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3791     'I','n','s','t','a','l','l','e','r','\\',
3792     'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
3793
3794     static const WCHAR msiexec_fmt[] = {
3795     '%','s',
3796     '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
3797     '\"','%','s','\"',0};
3798     static const WCHAR install_fmt[] = {
3799     '/','I',' ','\"','%','s','\"',' ',
3800     'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
3801     'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
3802     WCHAR buffer[256], sysdir[MAX_PATH];
3803     HKEY hkey;
3804     WCHAR squished_pc[100];
3805
3806     squash_guid(package->ProductCode,squished_pc);
3807
3808     GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
3809     RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
3810     snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
3811      squished_pc);
3812
3813     msi_reg_set_val_str( hkey, squished_pc, buffer );
3814     RegCloseKey(hkey);
3815
3816     TRACE("Reboot command %s\n",debugstr_w(buffer));
3817
3818     RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
3819     sprintfW(buffer,install_fmt,package->ProductCode,squished_pc);
3820
3821     msi_reg_set_val_str( hkey, squished_pc, buffer );
3822     RegCloseKey(hkey);
3823
3824     return ERROR_INSTALL_SUSPEND;
3825 }
3826
3827 static UINT ACTION_ResolveSource(MSIPACKAGE* package)
3828 {
3829     DWORD attrib, len;
3830     LPWSTR ptr, source;
3831     UINT rc;
3832     
3833     /*
3834      * we are currently doing what should be done here in the top level Install
3835      * however for Adminastrative and uninstalls this step will be needed
3836      */
3837     if (!package->PackagePath)
3838         return ERROR_SUCCESS;
3839
3840     ptr = strrchrW(package->PackagePath, '\\');
3841     if (!ptr)
3842         return ERROR_SUCCESS;
3843
3844     len = ptr - package->PackagePath + 2;
3845     source = msi_alloc(len * sizeof(WCHAR));
3846     lstrcpynW(source,  package->PackagePath, len);
3847
3848     MSI_SetPropertyW(package, cszSourceDir, source);
3849     MSI_SetPropertyW(package, cszSOURCEDIR, source);
3850
3851     msi_free(source);
3852
3853     attrib = GetFileAttributesW(package->PackagePath);
3854     if (attrib == INVALID_FILE_ATTRIBUTES)
3855     {
3856         LPWSTR prompt;
3857         LPWSTR msg;
3858         DWORD size = 0;
3859
3860         rc = MsiSourceListGetInfoW(package->ProductCode, NULL, 
3861                 MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3862                 INSTALLPROPERTY_DISKPROMPTW,NULL,&size);
3863         if (rc == ERROR_MORE_DATA)
3864         {
3865             prompt = msi_alloc(size * sizeof(WCHAR));
3866             MsiSourceListGetInfoW(package->ProductCode, NULL, 
3867                     MSIINSTALLCONTEXT_USERMANAGED, MSICODE_PRODUCT,
3868                     INSTALLPROPERTY_DISKPROMPTW,prompt,&size);
3869         }
3870         else
3871             prompt = strdupW(package->PackagePath);
3872
3873         msg = generate_error_string(package,1302,1,prompt);
3874         while(attrib == INVALID_FILE_ATTRIBUTES)
3875         {
3876             rc = MessageBoxW(NULL,msg,NULL,MB_OKCANCEL);
3877             if (rc == IDCANCEL)
3878             {
3879                 rc = ERROR_INSTALL_USEREXIT;
3880                 break;
3881             }
3882             attrib = GetFileAttributesW(package->PackagePath);
3883         }
3884         msi_free(prompt);
3885         rc = ERROR_SUCCESS;
3886     }
3887     else
3888         return ERROR_SUCCESS;
3889
3890     return rc;
3891 }
3892
3893 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
3894 {
3895     HKEY hkey=0;
3896     LPWSTR buffer;
3897     LPWSTR productid;
3898     UINT rc,i;
3899
3900     static const WCHAR szPropKeys[][80] = 
3901     {
3902         {'P','r','o','d','u','c','t','I','D',0},
3903         {'U','S','E','R','N','A','M','E',0},
3904         {'C','O','M','P','A','N','Y','N','A','M','E',0},
3905         {0},
3906     };
3907
3908     static const WCHAR szRegKeys[][80] = 
3909     {
3910         {'P','r','o','d','u','c','t','I','D',0},
3911         {'R','e','g','O','w','n','e','r',0},
3912         {'R','e','g','C','o','m','p','a','n','y',0},
3913         {0},
3914     };
3915
3916     productid = msi_dup_property( package, INSTALLPROPERTY_PRODUCTIDW );
3917     if (!productid)
3918         return ERROR_SUCCESS;
3919
3920     rc = MSIREG_OpenUninstallKey(package->ProductCode,&hkey,TRUE);
3921     if (rc != ERROR_SUCCESS)
3922         goto end;
3923
3924     for( i = 0; szPropKeys[i][0]; i++ )
3925     {
3926         buffer = msi_dup_property( package, szPropKeys[i] );
3927         msi_reg_set_val_str( hkey, szRegKeys[i], buffer );
3928         msi_free( buffer );
3929     }
3930
3931 end:
3932     msi_free(productid);
3933     RegCloseKey(hkey);
3934
3935     /* FIXME: call ui_actiondata */
3936
3937     return ERROR_SUCCESS;
3938 }
3939
3940
3941 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
3942 {
3943     UINT rc;
3944
3945     package->script->InWhatSequence |= SEQUENCE_EXEC;
3946     rc = ACTION_ProcessExecSequence(package,FALSE);
3947     return rc;
3948 }
3949
3950
3951 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
3952 {
3953     MSIPACKAGE *package = (MSIPACKAGE*)param;
3954     LPCWSTR compgroupid=NULL;
3955     LPCWSTR feature=NULL;
3956     LPCWSTR text = NULL;
3957     LPCWSTR qualifier = NULL;
3958     LPCWSTR component = NULL;
3959     LPWSTR advertise = NULL;
3960     LPWSTR output = NULL;
3961     HKEY hkey;
3962     UINT rc = ERROR_SUCCESS;
3963     MSICOMPONENT *comp;
3964     DWORD sz = 0;
3965     MSIRECORD *uirow;
3966
3967     component = MSI_RecordGetString(rec,3);
3968     comp = get_loaded_component(package,component);
3969
3970     if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ) && 
3971        !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE ) &&
3972        !ACTION_VerifyComponentForAction( comp, INSTALLSTATE_ADVERTISED ))
3973     {
3974         TRACE("Skipping: Component %s not scheduled for install\n",
3975                         debugstr_w(component));
3976
3977         return ERROR_SUCCESS;
3978     }
3979
3980     compgroupid = MSI_RecordGetString(rec,1);
3981     qualifier = MSI_RecordGetString(rec,2);
3982
3983     rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
3984     if (rc != ERROR_SUCCESS)
3985         goto end;
3986     
3987     text = MSI_RecordGetString(rec,4);
3988     feature = MSI_RecordGetString(rec,5);
3989   
3990     advertise = create_component_advertise_string(package, comp, feature);
3991
3992     sz = strlenW(advertise);
3993
3994     if (text)
3995         sz += lstrlenW(text);
3996
3997     sz+=3;
3998     sz *= sizeof(WCHAR);
3999            
4000     output = msi_alloc_zero(sz);
4001     strcpyW(output,advertise);
4002     msi_free(advertise);
4003
4004     if (text)
4005         strcatW(output,text);
4006
4007     msi_reg_set_val_multi_str( hkey, qualifier, output );
4008     
4009 end:
4010     RegCloseKey(hkey);
4011     msi_free(output);
4012
4013     /* the UI chunk */
4014     uirow = MSI_CreateRecord( 2 );
4015     MSI_RecordSetStringW( uirow, 1, compgroupid );
4016     MSI_RecordSetStringW( uirow, 2, qualifier);
4017     ui_actiondata( package, szPublishComponents, uirow);
4018     msiobj_release( &uirow->hdr );
4019     /* FIXME: call ui_progress? */
4020
4021     return rc;
4022 }
4023
4024 /*
4025  * At present I am ignorning the advertised components part of this and only
4026  * focusing on the qualified component sets
4027  */
4028 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
4029 {
4030     UINT rc;
4031     MSIQUERY * view;
4032     static const WCHAR ExecSeqQuery[] =
4033         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4034          '`','P','u','b','l','i','s','h',
4035          'C','o','m','p','o','n','e','n','t','`',0};
4036     
4037     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4038     if (rc != ERROR_SUCCESS)
4039         return ERROR_SUCCESS;
4040
4041     rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
4042     msiobj_release(&view->hdr);
4043
4044     return rc;
4045 }
4046
4047 static UINT ITERATE_InstallService(MSIRECORD *rec, LPVOID param)
4048 {
4049     MSIPACKAGE *package = (MSIPACKAGE*)param;
4050     MSIRECORD *row;
4051     MSIFILE *file;
4052     SC_HANDLE hscm, service = NULL;
4053     LPCWSTR name, disp, comp, depends, pass;
4054     LPCWSTR load_order, serv_name, key;
4055     DWORD serv_type, start_type;
4056     DWORD err_control;
4057
4058     static const WCHAR query[] =
4059         {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
4060          '`','C','o','m','p','o','n','e','n','t','`',' ',
4061          'W','H','E','R','E',' ',
4062          '`','C','o','m','p','o','n','e','n','t','`',' ',
4063          '=','\'','%','s','\'',0};
4064
4065     hscm = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASEW, GENERIC_WRITE);
4066     if (!hscm)
4067     {
4068         ERR("Failed to open the SC Manager!\n");
4069         goto done;
4070     }
4071
4072     start_type = MSI_RecordGetInteger(rec, 5);
4073     if (start_type == SERVICE_BOOT_START || start_type == SERVICE_SYSTEM_START)
4074         goto done;
4075
4076     depends = MSI_RecordGetString(rec, 8);
4077     if (depends && *depends)
4078         FIXME("Dependency list unhandled!\n");
4079
4080     name = MSI_RecordGetString(rec, 2);
4081     disp = MSI_RecordGetString(rec, 3);
4082     serv_type = MSI_RecordGetInteger(rec, 4);
4083     err_control = MSI_RecordGetInteger(rec, 6);
4084     load_order = MSI_RecordGetString(rec, 7);
4085     serv_name = MSI_RecordGetString(rec, 9);
4086     pass = MSI_RecordGetString(rec, 10);
4087     comp = MSI_RecordGetString(rec, 12);
4088
4089     /* fetch the service path */
4090     row = MSI_QueryGetRecord(package->db, query, comp);
4091     if (!row)
4092     {
4093         ERR("Control query failed!\n");
4094         goto done;
4095     }
4096
4097     key = MSI_RecordGetString(row, 6);
4098     msiobj_release(&row->hdr);
4099
4100     file = get_loaded_file(package, key);
4101     if (!file)
4102     {
4103         ERR("Failed to load the service file\n");
4104         goto done;
4105     }
4106
4107     service = CreateServiceW(hscm, name, disp, GENERIC_ALL, serv_type,
4108                              start_type, err_control, file->TargetPath,
4109                              load_order, NULL, NULL, serv_name, pass);
4110     if (!service)
4111     {
4112         if (GetLastError() != ERROR_SERVICE_EXISTS)
4113             ERR("Failed to create service %s: %d\n", debugstr_w(name), GetLastError());
4114     }
4115
4116 done:
4117     CloseServiceHandle(service);
4118     CloseServiceHandle(hscm);
4119
4120     return ERROR_SUCCESS;
4121 }
4122
4123 static UINT ACTION_InstallServices( MSIPACKAGE *package )
4124 {
4125     UINT rc;
4126     MSIQUERY * view;
4127     static const WCHAR ExecSeqQuery[] =
4128         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4129          'S','e','r','v','i','c','e','I','n','s','t','a','l','l',0};
4130     
4131     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4132     if (rc != ERROR_SUCCESS)
4133         return ERROR_SUCCESS;
4134
4135     rc = MSI_IterateRecords(view, NULL, ITERATE_InstallService, package);
4136     msiobj_release(&view->hdr);
4137
4138     return rc;
4139 }
4140
4141 static UINT msi_unimplemented_action_stub( MSIPACKAGE *package,
4142                                            LPCSTR action, LPCWSTR table )
4143 {
4144     static const WCHAR query[] = {
4145         'S','E','L','E','C','T',' ','*',' ',
4146         'F','R','O','M',' ','`','%','s','`',0 };
4147     MSIQUERY *view = NULL;
4148     DWORD count = 0;
4149     UINT r;
4150     
4151     r = MSI_OpenQuery( package->db, &view, query, table );
4152     if (r == ERROR_SUCCESS)
4153     {
4154         r = MSI_IterateRecords(view, &count, NULL, package);
4155         msiobj_release(&view->hdr);
4156     }
4157
4158     if (count)
4159         FIXME("%s -> %u ignored %s table values\n",
4160               action, count, debugstr_w(table));
4161
4162     return ERROR_SUCCESS;
4163 }
4164
4165 static UINT ACTION_AllocateRegistrySpace( MSIPACKAGE *package )
4166 {
4167     TRACE("%p\n", package);
4168     return ERROR_SUCCESS;
4169 }
4170
4171 static UINT ACTION_RemoveIniValues( MSIPACKAGE *package )
4172 {
4173     static const WCHAR table[] =
4174          {'R','e','m','o','v','e','I','n','i','F','i','l','e',0 };
4175     return msi_unimplemented_action_stub( package, "RemoveIniValues", table );
4176 }
4177
4178 static UINT ACTION_MoveFiles( MSIPACKAGE *package )
4179 {
4180     static const WCHAR table[] = { 'M','o','v','e','F','i','l','e',0 };
4181     return msi_unimplemented_action_stub( package, "MoveFiles", table );
4182 }
4183
4184 static UINT ACTION_PatchFiles( MSIPACKAGE *package )
4185 {
4186     static const WCHAR table[] = { 'P','a','t','c','h',0 };
4187     return msi_unimplemented_action_stub( package, "PatchFiles", table );
4188 }
4189
4190 static UINT ACTION_BindImage( MSIPACKAGE *package )
4191 {
4192     static const WCHAR table[] = { 'B','i','n','d','I','m','a','g','e',0 };
4193     return msi_unimplemented_action_stub( package, "BindImage", table );
4194 }
4195
4196 static UINT ACTION_IsolateComponents( MSIPACKAGE *package )
4197 {
4198     static const WCHAR table[] = {
4199         'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t',0 };
4200     return msi_unimplemented_action_stub( package, "IsolateComponents", table );
4201 }
4202
4203 static UINT ACTION_MigrateFeatureStates( MSIPACKAGE *package )
4204 {
4205     static const WCHAR table[] = { 'U','p','g','r','a','d','e',0 };
4206     return msi_unimplemented_action_stub( package, "MigrateFeatureStates", table );
4207 }
4208
4209 static UINT ACTION_SelfUnregModules( MSIPACKAGE *package )
4210 {
4211     static const WCHAR table[] = { 'S','e','l','f','R','e','g',0 };
4212     return msi_unimplemented_action_stub( package, "SelfUnregModules", table );
4213 }
4214
4215 static UINT ACTION_StartServices( MSIPACKAGE *package )
4216 {
4217     static const WCHAR table[] = {
4218         'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4219     return msi_unimplemented_action_stub( package, "StartServices", table );
4220 }
4221
4222 static UINT ACTION_StopServices( MSIPACKAGE *package )
4223 {
4224     static const WCHAR table[] = {
4225         'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4226     return msi_unimplemented_action_stub( package, "StopServices", table );
4227 }
4228
4229 static UINT ACTION_DeleteServices( MSIPACKAGE *package )
4230 {
4231     static const WCHAR table[] = {
4232         'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 };
4233     return msi_unimplemented_action_stub( package, "DeleteServices", table );
4234 }
4235
4236 static UINT ACTION_WriteEnvironmentStrings( MSIPACKAGE *package )
4237 {
4238     static const WCHAR table[] = {
4239         'E','n','v','i','r','o','n','m','e','n','t',0 };
4240     return msi_unimplemented_action_stub( package, "WriteEnvironmentStrings", table );
4241 }
4242
4243 static UINT ACTION_RemoveEnvironmentStrings( MSIPACKAGE *package )
4244 {
4245     static const WCHAR table[] = {
4246         'E','n','v','i','r','o','n','m','e','n','t',0 };
4247     return msi_unimplemented_action_stub( package, "RemoveEnvironmentStrings", table );
4248 }
4249
4250 static UINT ACTION_MsiPublishAssemblies( MSIPACKAGE *package )
4251 {
4252     static const WCHAR table[] = {
4253         'M','s','i','A','s','s','e','m','b','l','y',0 };
4254     return msi_unimplemented_action_stub( package, "MsiPublishAssemblies", table );
4255 }
4256
4257 static UINT ACTION_MsiUnpublishAssemblies( MSIPACKAGE *package )
4258 {
4259     static const WCHAR table[] = {
4260         'M','s','i','A','s','s','e','m','b','l','y',0 };
4261     return msi_unimplemented_action_stub( package, "MsiUnpublishAssemblies", table );
4262 }
4263
4264 static UINT ACTION_UnregisterFonts( MSIPACKAGE *package )
4265 {
4266     static const WCHAR table[] = { 'F','o','n','t',0 };
4267     return msi_unimplemented_action_stub( package, "UnregisterFonts", table );
4268 }
4269
4270 static UINT ACTION_CCPSearch( MSIPACKAGE *package )
4271 {
4272     static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4273     return msi_unimplemented_action_stub( package, "CCPSearch", table );
4274 }
4275
4276 static UINT ACTION_RMCCPSearch( MSIPACKAGE *package )
4277 {
4278     static const WCHAR table[] = { 'C','C','P','S','e','a','r','c','h',0 };
4279     return msi_unimplemented_action_stub( package, "RMCCPSearch", table );
4280 }
4281
4282 static UINT ACTION_RegisterComPlus( MSIPACKAGE *package )
4283 {
4284     static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4285     return msi_unimplemented_action_stub( package, "RegisterComPlus", table );
4286 }
4287
4288 static UINT ACTION_UnregisterComPlus( MSIPACKAGE *package )
4289 {
4290     static const WCHAR table[] = { 'C','o','m','p','l','u','s',0 };
4291     return msi_unimplemented_action_stub( package, "UnregisterComPlus", table );
4292 }
4293
4294 static struct _actions StandardActions[] = {
4295     { szAllocateRegistrySpace, ACTION_AllocateRegistrySpace },
4296     { szAppSearch, ACTION_AppSearch },
4297     { szBindImage, ACTION_BindImage },
4298     { szCCPSearch, ACTION_CCPSearch},
4299     { szCostFinalize, ACTION_CostFinalize },
4300     { szCostInitialize, ACTION_CostInitialize },
4301     { szCreateFolders, ACTION_CreateFolders },
4302     { szCreateShortcuts, ACTION_CreateShortcuts },
4303     { szDeleteServices, ACTION_DeleteServices },
4304     { szDisableRollback, NULL},
4305     { szDuplicateFiles, ACTION_DuplicateFiles },
4306     { szExecuteAction, ACTION_ExecuteAction },
4307     { szFileCost, ACTION_FileCost },
4308     { szFindRelatedProducts, ACTION_FindRelatedProducts },
4309     { szForceReboot, ACTION_ForceReboot },
4310     { szInstallAdminPackage, NULL},
4311     { szInstallExecute, ACTION_InstallExecute },
4312     { szInstallExecuteAgain, ACTION_InstallExecute },
4313     { szInstallFiles, ACTION_InstallFiles},
4314     { szInstallFinalize, ACTION_InstallFinalize },
4315     { szInstallInitialize, ACTION_InstallInitialize },
4316     { szInstallSFPCatalogFile, NULL},
4317     { szInstallValidate, ACTION_InstallValidate },
4318     { szIsolateComponents, ACTION_IsolateComponents },
4319     { szLaunchConditions, ACTION_LaunchConditions },
4320     { szMigrateFeatureStates, ACTION_MigrateFeatureStates },
4321     { szMoveFiles, ACTION_MoveFiles },
4322     { szMsiPublishAssemblies, ACTION_MsiPublishAssemblies },
4323     { szMsiUnpublishAssemblies, ACTION_MsiUnpublishAssemblies },
4324     { szInstallODBC, NULL},
4325     { szInstallServices, ACTION_InstallServices },
4326     { szPatchFiles, ACTION_PatchFiles },
4327     { szProcessComponents, ACTION_ProcessComponents },
4328     { szPublishComponents, ACTION_PublishComponents },
4329     { szPublishFeatures, ACTION_PublishFeatures },
4330     { szPublishProduct, ACTION_PublishProduct },
4331     { szRegisterClassInfo, ACTION_RegisterClassInfo },
4332     { szRegisterComPlus, ACTION_RegisterComPlus},
4333     { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
4334     { szRegisterFonts, ACTION_RegisterFonts },
4335     { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
4336     { szRegisterProduct, ACTION_RegisterProduct },
4337     { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
4338     { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
4339     { szRegisterUser, ACTION_RegisterUser},
4340     { szRemoveDuplicateFiles, NULL},
4341     { szRemoveEnvironmentStrings, ACTION_RemoveEnvironmentStrings },
4342     { szRemoveExistingProducts, NULL},
4343     { szRemoveFiles, ACTION_RemoveFiles},
4344     { szRemoveFolders, NULL},
4345     { szRemoveIniValues, ACTION_RemoveIniValues },
4346     { szRemoveODBC, NULL},
4347     { szRemoveRegistryValues, NULL},
4348     { szRemoveShortcuts, NULL},
4349     { szResolveSource, ACTION_ResolveSource},
4350     { szRMCCPSearch, ACTION_RMCCPSearch},
4351     { szScheduleReboot, NULL},
4352     { szSelfRegModules, ACTION_SelfRegModules },
4353     { szSelfUnregModules, ACTION_SelfUnregModules },
4354     { szSetODBCFolders, NULL},
4355     { szStartServices, ACTION_StartServices },
4356     { szStopServices, ACTION_StopServices },
4357     { szUnpublishComponents, NULL},
4358     { szUnpublishFeatures, NULL},
4359     { szUnregisterClassInfo, NULL},
4360     { szUnregisterComPlus, ACTION_UnregisterComPlus},
4361     { szUnregisterExtensionInfo, NULL},
4362     { szUnregisterFonts, ACTION_UnregisterFonts },
4363     { szUnregisterMIMEInfo, NULL},
4364     { szUnregisterProgIdInfo, NULL},
4365     { szUnregisterTypeLibraries, NULL},
4366     { szValidateProductID, NULL},
4367     { szWriteEnvironmentStrings, ACTION_WriteEnvironmentStrings },
4368     { szWriteIniValues, ACTION_WriteIniValues },
4369     { szWriteRegistryValues, ACTION_WriteRegistryValues},
4370     { NULL, NULL},
4371 };