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