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