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