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