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