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