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