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