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