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