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