Use a better location than HKCU\Wine for saving the temporary
[wine] / dlls / msi / action.c
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2004 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 #include <stdio.h>
31
32 #define COBJMACROS
33
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "winreg.h"
38 #include "wine/debug.h"
39 #include "fdi.h"
40 #include "msi.h"
41 #include "msiquery.h"
42 #include "msidefs.h"
43 #include "msvcrt/fcntl.h"
44 #include "objbase.h"
45 #include "objidl.h"
46 #include "msipriv.h"
47 #include "winnls.h"
48 #include "winuser.h"
49 #include "shlobj.h"
50 #include "wine/unicode.h"
51 #include "winver.h"
52 #include "action.h"
53
54 #define REG_PROGRESS_VALUE 13200
55 #define COMPONENT_PROGRESS_VALUE 24000
56
57 WINE_DEFAULT_DEBUG_CHANNEL(msi);
58
59 /*
60  * Prototypes
61  */
62 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran);
63 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
64 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI);
65 static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, 
66                             LPWSTR *FilePath);
67
68 /* 
69  * action handlers
70  */
71 typedef UINT (*STANDARDACTIONHANDLER)(MSIPACKAGE*);
72
73 static UINT ACTION_LaunchConditions(MSIPACKAGE *package);
74 static UINT ACTION_CostInitialize(MSIPACKAGE *package);
75 static UINT ACTION_CreateFolders(MSIPACKAGE *package);
76 static UINT ACTION_CostFinalize(MSIPACKAGE *package);
77 static UINT ACTION_FileCost(MSIPACKAGE *package);
78 static UINT ACTION_InstallFiles(MSIPACKAGE *package);
79 static UINT ACTION_DuplicateFiles(MSIPACKAGE *package);
80 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package);
81 static UINT ACTION_InstallInitialize(MSIPACKAGE *package);
82 static UINT ACTION_InstallValidate(MSIPACKAGE *package);
83 static UINT ACTION_ProcessComponents(MSIPACKAGE *package);
84 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package);
85 static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package);
86 static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package);
87 static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package);
88 static UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package);
89 static UINT ACTION_RegisterUser(MSIPACKAGE *package);
90 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package);
91 static UINT ACTION_PublishProduct(MSIPACKAGE *package);
92 static UINT ACTION_WriteIniValues(MSIPACKAGE *package);
93 static UINT ACTION_SelfRegModules(MSIPACKAGE *package);
94 static UINT ACTION_PublishFeatures(MSIPACKAGE *package);
95 static UINT ACTION_RegisterProduct(MSIPACKAGE *package);
96 static UINT ACTION_InstallExecute(MSIPACKAGE *package);
97 static UINT ACTION_InstallFinalize(MSIPACKAGE *package);
98 static UINT ACTION_ForceReboot(MSIPACKAGE *package);
99 static UINT ACTION_ResolveSource(MSIPACKAGE *package);
100 static UINT ACTION_ExecuteAction(MSIPACKAGE *package);
101 static UINT ACTION_RegisterFonts(MSIPACKAGE *package);
102 static UINT ACTION_PublishComponents(MSIPACKAGE *package);
103
104  
105 /*
106  * consts and values used
107  */
108 static const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0};
109 static const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0};
110 static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0};
111 static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
112 static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0};
113 static const WCHAR c_colon[] = {'C',':','\\',0};
114 static const WCHAR szProductCode[]=
115     {'P','r','o','d','u','c','t','C','o','d','e',0};
116 static const WCHAR cszbs[]={'\\',0};
117 const static WCHAR szCreateFolders[] =
118     {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
119 const static WCHAR szCostFinalize[] =
120     {'C','o','s','t','F','i','n','a','l','i','z','e',0};
121 const static WCHAR szInstallFiles[] =
122     {'I','n','s','t','a','l','l','F','i','l','e','s',0};
123 const static WCHAR szDuplicateFiles[] =
124     {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
125 const static WCHAR szWriteRegistryValues[] =
126     {'W','r','i','t','e','R','e','g','i','s','t','r','y',
127             'V','a','l','u','e','s',0};
128 const static WCHAR szCostInitialize[] =
129     {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
130 const static WCHAR szFileCost[] = 
131     {'F','i','l','e','C','o','s','t',0};
132 const static WCHAR szInstallInitialize[] = 
133     {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
134 const static WCHAR szInstallValidate[] = 
135     {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
136 const static WCHAR szLaunchConditions[] = 
137     {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
138 const static WCHAR szProcessComponents[] = 
139     {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
140 const static WCHAR szRegisterTypeLibraries[] = 
141     {'R','e','g','i','s','t','e','r','T','y','p','e',
142             'L','i','b','r','a','r','i','e','s',0};
143 const static WCHAR szRegisterClassInfo[] = 
144     {'R','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
145 const static WCHAR szRegisterProgIdInfo[] = 
146     {'R','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
147 const static WCHAR szCreateShortcuts[] = 
148     {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
149 const static WCHAR szPublishProduct[] = 
150     {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
151 const static WCHAR szWriteIniValues[] = 
152     {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
153 const static WCHAR szSelfRegModules[] = 
154     {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
155 const static WCHAR szPublishFeatures[] = 
156     {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
157 const static WCHAR szRegisterProduct[] = 
158     {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
159 const static WCHAR szInstallExecute[] = 
160     {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
161 const static WCHAR szInstallExecuteAgain[] = 
162     {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',
163             'A','g','a','i','n',0};
164 const static WCHAR szInstallFinalize[] = 
165     {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
166 const static WCHAR szForceReboot[] = 
167     {'F','o','r','c','e','R','e','b','o','o','t',0};
168 const static WCHAR szResolveSource[] =
169     {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
170 const static WCHAR szAppSearch[] = 
171     {'A','p','p','S','e','a','r','c','h',0};
172 const static WCHAR szAllocateRegistrySpace[] = 
173     {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y',
174             'S','p','a','c','e',0};
175 const static WCHAR szBindImage[] = 
176     {'B','i','n','d','I','m','a','g','e',0};
177 const static WCHAR szCCPSearch[] = 
178     {'C','C','P','S','e','a','r','c','h',0};
179 const static WCHAR szDeleteServices[] = 
180     {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
181 const static WCHAR szDisableRollback[] = 
182     {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
183 const static WCHAR szExecuteAction[] = 
184     {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
185 const static WCHAR szFindRelatedProducts[] = 
186     {'F','i','n','d','R','e','l','a','t','e','d',
187             'P','r','o','d','u','c','t','s',0};
188 const static WCHAR szInstallAdminPackage[] = 
189     {'I','n','s','t','a','l','l','A','d','m','i','n',
190             'P','a','c','k','a','g','e',0};
191 const static WCHAR szInstallSFPCatalogFile[] = 
192     {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g',
193             'F','i','l','e',0};
194 const static WCHAR szIsolateComponents[] = 
195     {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
196 const static WCHAR szMigrateFeatureStates[] = 
197     {'M','i','g','r','a','t','e','F','e','a','t','u','r','e',
198             'S','t','a','t','e','s',0};
199 const static WCHAR szMoveFiles[] = 
200     {'M','o','v','e','F','i','l','e','s',0};
201 const static WCHAR szMsiPublishAssemblies[] = 
202     {'M','s','i','P','u','b','l','i','s','h',
203             'A','s','s','e','m','b','l','i','e','s',0};
204 const static WCHAR szMsiUnpublishAssemblies[] = 
205     {'M','s','i','U','n','p','u','b','l','i','s','h',
206             'A','s','s','e','m','b','l','i','e','s',0};
207 const static WCHAR szInstallODBC[] = 
208     {'I','n','s','t','a','l','l','O','D','B','C',0};
209 const static WCHAR szInstallServices[] = 
210     {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
211 const static WCHAR szPatchFiles[] = 
212     {'P','a','t','c','h','F','i','l','e','s',0};
213 const static WCHAR szPublishComponents[] = 
214     {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
215 const static WCHAR szRegisterComPlus[] =
216     {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
217 const static WCHAR szRegisterExtensionInfo[] =
218     {'R','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n',
219             'I','n','f','o',0};
220 const static WCHAR szRegisterFonts[] =
221     {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
222 const static WCHAR szRegisterMIMEInfo[] =
223     {'R','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
224 const static WCHAR szRegisterUser[] =
225     {'R','e','g','i','s','t','e','r','U','s','e','r',0};
226 const static WCHAR szRemoveDuplicateFiles[] =
227     {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e',
228             'F','i','l','e','s',0};
229 const static WCHAR szRemoveEnvironmentStrings[] =
230     {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t',
231             'S','t','r','i','n','g','s',0};
232 const static WCHAR szRemoveExistingProducts[] =
233     {'R','e','m','o','v','e','E','x','i','s','t','i','n','g',
234             'P','r','o','d','u','c','t','s',0};
235 const static WCHAR szRemoveFiles[] =
236     {'R','e','m','o','v','e','F','i','l','e','s',0};
237 const static WCHAR szRemoveFolders[] =
238     {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
239 const static WCHAR szRemoveIniValues[] =
240     {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
241 const static WCHAR szRemoveODBC[] =
242     {'R','e','m','o','v','e','O','D','B','C',0};
243 const static WCHAR szRemoveRegistryValues[] =
244     {'R','e','m','o','v','e','R','e','g','i','s','t','r','y',
245             'V','a','l','u','e','s',0};
246 const static WCHAR szRemoveShortcuts[] =
247     {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
248 const static WCHAR szRMCCPSearch[] =
249     {'R','M','C','C','P','S','e','a','r','c','h',0};
250 const static WCHAR szScheduleReboot[] =
251     {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
252 const static WCHAR szSelfUnregModules[] =
253     {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
254 const static WCHAR szSetODBCFolders[] =
255     {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
256 const static WCHAR szStartServices[] =
257     {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
258 const static WCHAR szStopServices[] =
259     {'S','t','o','p','S','e','r','v','i','c','e','s',0};
260 const static WCHAR szUnpublishComponents[] =
261     {'U','n','p','u','b','l','i','s','h',
262             'C','o','m','p','o','n','e','n','t','s',0};
263 const static WCHAR szUnpublishFeatures[] =
264     {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
265 const static WCHAR szUnregisterClassInfo[] =
266     {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s',
267             'I','n','f','o',0};
268 const static WCHAR szUnregisterComPlus[] =
269     {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
270 const static WCHAR szUnregisterExtensionInfo[] =
271     {'U','n','r','e','g','i','s','t','e','r',
272             'E','x','t','e','n','s','i','o','n','I','n','f','o',0};
273 const static WCHAR szUnregisterFonts[] =
274     {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
275 const static WCHAR szUnregisterMIMEInfo[] =
276     {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
277 const static WCHAR szUnregisterProgIdInfo[] =
278     {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d',
279             'I','n','f','o',0};
280 const static WCHAR szUnregisterTypeLibraries[] =
281     {'U','n','r','e','g','i','s','t','e','r','T','y','p','e',
282             'L','i','b','r','a','r','i','e','s',0};
283 const static WCHAR szValidateProductID[] =
284     {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
285 const static WCHAR szWriteEnvironmentStrings[] =
286     {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t',
287             'S','t','r','i','n','g','s',0};
288
289 struct _actions {
290     LPCWSTR action;
291     STANDARDACTIONHANDLER handler;
292 };
293
294 static struct _actions StandardActions[] = {
295     { szAllocateRegistrySpace, NULL},
296     { szAppSearch, ACTION_AppSearch },
297     { szBindImage, NULL},
298     { szCCPSearch, NULL},
299     { szCostFinalize, ACTION_CostFinalize },
300     { szCostInitialize, ACTION_CostInitialize },
301     { szCreateFolders, ACTION_CreateFolders },
302     { szCreateShortcuts, ACTION_CreateShortcuts },
303     { szDeleteServices, NULL},
304     { szDisableRollback, NULL},
305     { szDuplicateFiles, ACTION_DuplicateFiles },
306     { szExecuteAction, ACTION_ExecuteAction },
307     { szFileCost, ACTION_FileCost },
308     { szFindRelatedProducts, ACTION_FindRelatedProducts },
309     { szForceReboot, ACTION_ForceReboot },
310     { szInstallAdminPackage, NULL},
311     { szInstallExecute, ACTION_InstallExecute },
312     { szInstallExecuteAgain, ACTION_InstallExecute },
313     { szInstallFiles, ACTION_InstallFiles},
314     { szInstallFinalize, ACTION_InstallFinalize },
315     { szInstallInitialize, ACTION_InstallInitialize },
316     { szInstallSFPCatalogFile, NULL},
317     { szInstallValidate, ACTION_InstallValidate },
318     { szIsolateComponents, NULL},
319     { szLaunchConditions, ACTION_LaunchConditions },
320     { szMigrateFeatureStates, NULL},
321     { szMoveFiles, NULL},
322     { szMsiPublishAssemblies, NULL},
323     { szMsiUnpublishAssemblies, NULL},
324     { szInstallODBC, NULL},
325     { szInstallServices, NULL},
326     { szPatchFiles, NULL},
327     { szProcessComponents, ACTION_ProcessComponents },
328     { szPublishComponents, ACTION_PublishComponents },
329     { szPublishFeatures, ACTION_PublishFeatures },
330     { szPublishProduct, ACTION_PublishProduct },
331     { szRegisterClassInfo, ACTION_RegisterClassInfo },
332     { szRegisterComPlus, NULL},
333     { szRegisterExtensionInfo, ACTION_RegisterExtensionInfo },
334     { szRegisterFonts, ACTION_RegisterFonts },
335     { szRegisterMIMEInfo, ACTION_RegisterMIMEInfo },
336     { szRegisterProduct, ACTION_RegisterProduct },
337     { szRegisterProgIdInfo, ACTION_RegisterProgIdInfo },
338     { szRegisterTypeLibraries, ACTION_RegisterTypeLibraries },
339     { szRegisterUser, ACTION_RegisterUser},
340     { szRemoveDuplicateFiles, NULL},
341     { szRemoveEnvironmentStrings, NULL},
342     { szRemoveExistingProducts, NULL},
343     { szRemoveFiles, NULL},
344     { szRemoveFolders, NULL},
345     { szRemoveIniValues, NULL},
346     { szRemoveODBC, NULL},
347     { szRemoveRegistryValues, NULL},
348     { szRemoveShortcuts, NULL},
349     { szResolveSource, ACTION_ResolveSource},
350     { szRMCCPSearch, NULL},
351     { szScheduleReboot, NULL},
352     { szSelfRegModules, ACTION_SelfRegModules },
353     { szSelfUnregModules, NULL},
354     { szSetODBCFolders, NULL},
355     { szStartServices, NULL},
356     { szStopServices, NULL},
357     { szUnpublishComponents, NULL},
358     { szUnpublishFeatures, NULL},
359     { szUnregisterClassInfo, NULL},
360     { szUnregisterComPlus, NULL},
361     { szUnregisterExtensionInfo, NULL},
362     { szUnregisterFonts, NULL},
363     { szUnregisterMIMEInfo, NULL},
364     { szUnregisterProgIdInfo, NULL},
365     { szUnregisterTypeLibraries, NULL},
366     { szValidateProductID, NULL},
367     { szWriteEnvironmentStrings, NULL},
368     { szWriteIniValues, ACTION_WriteIniValues },
369     { szWriteRegistryValues, ACTION_WriteRegistryValues},
370     { NULL, NULL},
371 };
372
373
374 /******************************************************** 
375  * helper functions to get around current HACKS and such
376  ********************************************************/
377 inline static void reduce_to_longfilename(WCHAR* filename)
378 {
379     LPWSTR p = strchrW(filename,'|');
380     if (p)
381         memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR));
382 }
383
384 inline static void reduce_to_shortfilename(WCHAR* filename)
385 {
386     LPWSTR p = strchrW(filename,'|');
387     if (p)
388         *p = 0;
389 }
390
391 WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index)
392 {
393     UINT rc;
394     DWORD sz;
395     LPWSTR ret;
396    
397     sz = 0; 
398     if (MSI_RecordIsNull(row,index))
399         return NULL;
400
401     rc = MSI_RecordGetStringW(row,index,NULL,&sz);
402
403     /* having an empty string is different than NULL */
404     if (sz == 0)
405     {
406         ret = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR));
407         ret[0] = 0;
408         return ret;
409     }
410
411     sz ++;
412     ret = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR));
413     rc = MSI_RecordGetStringW(row,index,ret,&sz);
414     if (rc!=ERROR_SUCCESS)
415     {
416         ERR("Unable to load dynamic string\n");
417         HeapFree(GetProcessHeap(), 0, ret);
418         ret = NULL;
419     }
420     return ret;
421 }
422
423 LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, UINT* rc)
424 {
425     DWORD sz = 0;
426     LPWSTR str;
427     UINT r;
428
429     r = MSI_GetPropertyW(package, prop, NULL, &sz);
430     if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
431     {
432         if (rc)
433             *rc = r;
434         return NULL;
435     }
436     sz++;
437     str = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
438     r = MSI_GetPropertyW(package, prop, str, &sz);
439     if (r != ERROR_SUCCESS)
440     {
441         HeapFree(GetProcessHeap(),0,str);
442         str = NULL;
443     }
444     if (rc)
445         *rc = r;
446     return str;
447 }
448
449 int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component )
450 {
451     int rc = -1;
452     DWORD i;
453
454     for (i = 0; i < package->loaded_components; i++)
455     {
456         if (strcmpW(Component,package->components[i].Component)==0)
457         {
458             rc = i;
459             break;
460         }
461     }
462     return rc;
463 }
464
465 int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature )
466 {
467     int rc = -1;
468     DWORD i;
469
470     for (i = 0; i < package->loaded_features; i++)
471     {
472         if (strcmpW(Feature,package->features[i].Feature)==0)
473         {
474             rc = i;
475             break;
476         }
477     }
478     return rc;
479 }
480
481 int get_loaded_file(MSIPACKAGE* package, LPCWSTR file)
482 {
483     int rc = -1;
484     DWORD i;
485
486     for (i = 0; i < package->loaded_files; i++)
487     {
488         if (strcmpW(file,package->files[i].File)==0)
489         {
490             rc = i;
491             break;
492         }
493     }
494     return rc;
495 }
496
497 int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path)
498 {
499     DWORD i;
500     DWORD index;
501
502     if (!package)
503         return -2;
504
505     for (i=0; i < package->loaded_files; i++)
506         if (strcmpW(package->files[i].File,name)==0)
507             return -1;
508
509     index = package->loaded_files;
510     package->loaded_files++;
511     if (package->loaded_files== 1)
512         package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
513     else
514         package->files = HeapReAlloc(GetProcessHeap(),0,
515             package->files , package->loaded_files * sizeof(MSIFILE));
516
517     memset(&package->files[index],0,sizeof(MSIFILE));
518
519     package->files[index].File = strdupW(name);
520     package->files[index].TargetPath = strdupW(path);
521     package->files[index].Temporary = TRUE;
522
523     TRACE("Tracking tempfile (%s)\n",debugstr_w(package->files[index].File));  
524
525     return 0;
526 }
527
528 static void remove_tracked_tempfiles(MSIPACKAGE* package)
529 {
530     DWORD i;
531
532     if (!package)
533         return;
534
535     for (i = 0; i < package->loaded_files; i++)
536     {
537         if (package->files[i].Temporary)
538         {
539             TRACE("Cleaning up %s\n",debugstr_w(package->files[i].TargetPath));
540             DeleteFileW(package->files[i].TargetPath);
541         }
542
543     }
544 }
545
546 /* wrapper to resist a need for a full rewrite right now */
547 DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data )
548 {
549     if (ptr)
550     {
551         MSIRECORD *rec = MSI_CreateRecord(1);
552         DWORD size = 0;
553
554         MSI_RecordSetStringW(rec,0,ptr);
555         MSI_FormatRecordW(package,rec,NULL,&size);
556         if (size >= 0)
557         {
558             size++;
559             *data = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
560             if (size > 1)
561                 MSI_FormatRecordW(package,rec,*data,&size);
562             else
563                 *data[0] = 0;
564             msiobj_release( &rec->hdr );
565             return sizeof(WCHAR)*size;
566         }
567         msiobj_release( &rec->hdr );
568     }
569
570     *data = NULL;
571     return 0;
572 }
573
574 DWORD build_version_dword(LPCWSTR version_string)
575 {
576     SHORT major,minor;
577     WORD build;
578     DWORD rc = 0x00000000;
579     LPCWSTR ptr1;
580
581     ptr1 = version_string;
582
583     if (!ptr1)
584         return rc;
585     else
586         major = atoiW(ptr1);
587
588
589     if(ptr1)
590         ptr1 = strchrW(ptr1,'.');
591     if (ptr1)
592     {
593         ptr1++;
594         minor = atoiW(ptr1);
595     }
596     else
597         minor = 0;
598
599     if (ptr1)
600         ptr1 = strchrW(ptr1,'.');
601
602     if (ptr1)
603     {
604         ptr1++;
605         build = atoiW(ptr1);
606     }
607     else
608         build = 0;
609
610     rc = MAKELONG(build,MAKEWORD(minor,major));
611     TRACE("%s -> 0x%lx\n",debugstr_w(version_string),rc);
612     return rc;
613 }
614
615 /* Called when the package is being closed */
616 void ACTION_free_package_structures( MSIPACKAGE* package)
617 {
618     INT i;
619     
620     TRACE("Freeing package action data\n");
621
622     remove_tracked_tempfiles(package);
623
624     /* No dynamic buffers in features */
625     if (package->features && package->loaded_features > 0)
626         HeapFree(GetProcessHeap(),0,package->features);
627
628     for (i = 0; i < package->loaded_folders; i++)
629     {
630         HeapFree(GetProcessHeap(),0,package->folders[i].Directory);
631         HeapFree(GetProcessHeap(),0,package->folders[i].TargetDefault);
632         HeapFree(GetProcessHeap(),0,package->folders[i].SourceDefault);
633         HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
634         HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedSource);
635         HeapFree(GetProcessHeap(),0,package->folders[i].Property);
636     }
637     if (package->folders && package->loaded_folders > 0)
638         HeapFree(GetProcessHeap(),0,package->folders);
639
640     for (i = 0; i < package->loaded_components; i++)
641         HeapFree(GetProcessHeap(),0,package->components[i].FullKeypath);
642
643     if (package->components && package->loaded_components > 0)
644         HeapFree(GetProcessHeap(),0,package->components);
645
646     for (i = 0; i < package->loaded_files; i++)
647     {
648         HeapFree(GetProcessHeap(),0,package->files[i].File);
649         HeapFree(GetProcessHeap(),0,package->files[i].FileName);
650         HeapFree(GetProcessHeap(),0,package->files[i].ShortName);
651         HeapFree(GetProcessHeap(),0,package->files[i].Version);
652         HeapFree(GetProcessHeap(),0,package->files[i].Language);
653         HeapFree(GetProcessHeap(),0,package->files[i].SourcePath);
654         HeapFree(GetProcessHeap(),0,package->files[i].TargetPath);
655     }
656
657     if (package->files && package->loaded_files > 0)
658         HeapFree(GetProcessHeap(),0,package->files);
659
660     /* clean up extension, progid, class and verb structures */
661     for (i = 0; i < package->loaded_classes; i++)
662     {
663         HeapFree(GetProcessHeap(),0,package->classes[i].Description);
664         HeapFree(GetProcessHeap(),0,package->classes[i].FileTypeMask);
665         HeapFree(GetProcessHeap(),0,package->classes[i].IconPath);
666         HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler);
667         HeapFree(GetProcessHeap(),0,package->classes[i].DefInprocHandler32);
668         HeapFree(GetProcessHeap(),0,package->classes[i].Argument);
669         HeapFree(GetProcessHeap(),0,package->classes[i].ProgIDText);
670     }
671
672     if (package->classes && package->loaded_classes > 0)
673         HeapFree(GetProcessHeap(),0,package->classes);
674
675     for (i = 0; i < package->loaded_extensions; i++)
676     {
677         HeapFree(GetProcessHeap(),0,package->extensions[i].ProgIDText);
678     }
679
680     if (package->extensions && package->loaded_extensions > 0)
681         HeapFree(GetProcessHeap(),0,package->extensions);
682
683     for (i = 0; i < package->loaded_progids; i++)
684     {
685         HeapFree(GetProcessHeap(),0,package->progids[i].ProgID);
686         HeapFree(GetProcessHeap(),0,package->progids[i].Description);
687         HeapFree(GetProcessHeap(),0,package->progids[i].IconPath);
688     }
689
690     if (package->progids && package->loaded_progids > 0)
691         HeapFree(GetProcessHeap(),0,package->progids);
692
693     for (i = 0; i < package->loaded_verbs; i++)
694     {
695         HeapFree(GetProcessHeap(),0,package->verbs[i].Verb);
696         HeapFree(GetProcessHeap(),0,package->verbs[i].Command);
697         HeapFree(GetProcessHeap(),0,package->verbs[i].Argument);
698     }
699
700     if (package->verbs && package->loaded_verbs > 0)
701         HeapFree(GetProcessHeap(),0,package->verbs);
702
703     for (i = 0; i < package->loaded_mimes; i++)
704         HeapFree(GetProcessHeap(),0,package->mimes[i].ContentType);
705
706     if (package->mimes && package->loaded_mimes > 0)
707         HeapFree(GetProcessHeap(),0,package->mimes);
708
709     for (i = 0; i < package->loaded_appids; i++)
710     {
711         HeapFree(GetProcessHeap(),0,package->appids[i].RemoteServerName);
712         HeapFree(GetProcessHeap(),0,package->appids[i].LocalServer);
713         HeapFree(GetProcessHeap(),0,package->appids[i].ServiceParameters);
714         HeapFree(GetProcessHeap(),0,package->appids[i].DllSurrogate);
715     }
716
717     if (package->appids && package->loaded_appids > 0)
718         HeapFree(GetProcessHeap(),0,package->appids);
719
720     if (package->script)
721     {
722         for (i = 0; i < TOTAL_SCRIPTS; i++)
723         {
724             int j;
725             for (j = 0; j < package->script->ActionCount[i]; j++)
726                 HeapFree(GetProcessHeap(),0,package->script->Actions[i][j]);
727         
728             HeapFree(GetProcessHeap(),0,package->script->Actions[i]);
729         }
730         HeapFree(GetProcessHeap(),0,package->script);
731     }
732
733     HeapFree(GetProcessHeap(),0,package->PackagePath);
734
735     /* cleanup control event subscriptions */
736     ControlEvent_CleanupSubscriptions(package);
737 }
738
739 static void ce_actiontext(MSIPACKAGE* package, LPCWSTR action)
740 {
741     static const WCHAR szActionText[] = 
742         {'A','c','t','i','o','n','T','e','x','t',0};
743     MSIRECORD *row;
744
745     row = MSI_CreateRecord(1);
746     MSI_RecordSetStringW(row,1,action);
747     ControlEvent_FireSubscribedEvent(package,szActionText, row);
748     msiobj_release(&row->hdr);
749 }
750
751 static void ui_progress(MSIPACKAGE *package, int a, int b, int c, int d )
752 {
753     MSIRECORD * row;
754
755     row = MSI_CreateRecord(4);
756     MSI_RecordSetInteger(row,1,a);
757     MSI_RecordSetInteger(row,2,b);
758     MSI_RecordSetInteger(row,3,c);
759     MSI_RecordSetInteger(row,4,d);
760     MSI_ProcessMessage(package, INSTALLMESSAGE_PROGRESS, row);
761     msiobj_release(&row->hdr);
762
763     msi_dialog_check_messages(NULL);
764 }
765
766 static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * record)
767 {
768     static const WCHAR Query_t[] = 
769         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
770          '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
771          'W','H','E','R','E',' ', '`','A','c','t','i','o','n','`',' ','=', 
772          ' ','\'','%','s','\'',0};
773     WCHAR message[1024];
774     MSIRECORD * row = 0;
775     DWORD size;
776     static const WCHAR szActionData[] = 
777         {'A','c','t','i','o','n','D','a','t','a',0};
778
779     if (!package->LastAction || strcmpW(package->LastAction,action))
780     {
781         row = MSI_QueryGetRecord(package->db, Query_t, action);
782         if (!row)
783             return;
784
785         if (MSI_RecordIsNull(row,3))
786         {
787             msiobj_release(&row->hdr);
788             return;
789         }
790
791         /* update the cached actionformat */
792         HeapFree(GetProcessHeap(),0,package->ActionFormat);
793         package->ActionFormat = load_dynamic_stringW(row,3);
794
795         HeapFree(GetProcessHeap(),0,package->LastAction);
796         package->LastAction = strdupW(action);
797
798         msiobj_release(&row->hdr);
799     }
800
801     MSI_RecordSetStringW(record,0,package->ActionFormat);
802     size = 1024;
803     MSI_FormatRecordW(package,record,message,&size);
804
805     row = MSI_CreateRecord(1);
806     MSI_RecordSetStringW(row,1,message);
807  
808     MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONDATA, row);
809
810     ControlEvent_FireSubscribedEvent(package,szActionData, row);
811
812     msiobj_release(&row->hdr);
813 }
814
815
816 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
817 {
818     static const WCHAR template_s[]=
819         {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ', '%','s',
820          '.',0};
821     static const WCHAR format[] = 
822         {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
823     static const WCHAR Query_t[] = 
824         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
825          '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
826          'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=', 
827          ' ','\'','%','s','\'',0};
828     WCHAR message[1024];
829     WCHAR timet[0x100];
830     MSIRECORD * row = 0;
831     LPCWSTR ActionText;
832
833     GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
834
835     row = MSI_QueryGetRecord( package->db, Query_t, action );
836     if (!row)
837         return;
838
839     ActionText = MSI_RecordGetString(row,2);
840
841     sprintfW(message,template_s,timet,action,ActionText);
842     msiobj_release(&row->hdr);
843
844     row = MSI_CreateRecord(1);
845     MSI_RecordSetStringW(row,1,message);
846  
847     MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
848     msiobj_release(&row->hdr);
849 }
850
851 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start, 
852                           UINT rc)
853 {
854     MSIRECORD * row;
855     static const WCHAR template_s[]=
856         {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
857          '%','s', '.',0};
858     static const WCHAR template_e[]=
859         {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
860          '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
861          '%','i','.',0};
862     static const WCHAR format[] = 
863         {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
864     WCHAR message[1024];
865     WCHAR timet[0x100];
866
867     GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
868     if (start)
869         sprintfW(message,template_s,timet,action);
870     else
871         sprintfW(message,template_e,timet,action,rc);
872     
873     row = MSI_CreateRecord(1);
874     MSI_RecordSetStringW(row,1,message);
875  
876     MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
877     msiobj_release(&row->hdr);
878 }
879
880 /*
881  *  build_directory_name()
882  *
883  *  This function is to save messing round with directory names
884  *  It handles adding backslashes between path segments, 
885  *   and can add \ at the end of the directory name if told to.
886  *
887  *  It takes a variable number of arguments.
888  *  It always allocates a new string for the result, so make sure
889  *   to free the return value when finished with it.
890  *
891  *  The first arg is the number of path segments that follow.
892  *  The arguments following count are a list of path segments.
893  *  A path segment may be NULL.
894  *
895  *  Path segments will be added with a \ separating them.
896  *  A \ will not be added after the last segment, however if the
897  *    last segment is NULL, then the last character will be a \
898  * 
899  */
900 static LPWSTR build_directory_name(DWORD count, ...)
901 {
902     DWORD sz = 1, i;
903     LPWSTR dir;
904     va_list va;
905
906     va_start(va,count);
907     for(i=0; i<count; i++)
908     {
909         LPCWSTR str = va_arg(va,LPCWSTR);
910         if (str)
911             sz += strlenW(str) + 1;
912     }
913     va_end(va);
914
915     dir = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR));
916     dir[0]=0;
917
918     va_start(va,count);
919     for(i=0; i<count; i++)
920     {
921         LPCWSTR str = va_arg(va,LPCWSTR);
922         if (!str)
923             continue;
924         strcatW(dir, str);
925         if( ((i+1)!=count) && dir[strlenW(dir)-1]!='\\')
926             strcatW(dir, cszbs);
927     }
928     return dir;
929 }
930
931 static BOOL ACTION_VerifyComponentForAction(MSIPACKAGE* package, INT index, 
932                                             INSTALLSTATE check )
933 {
934     if (package->components[index].Installed == check)
935         return FALSE;
936
937     if (package->components[index].ActionRequest == check)
938         return TRUE;
939     else
940         return FALSE;
941 }
942
943 static BOOL ACTION_VerifyFeatureForAction(MSIPACKAGE* package, INT index, 
944                                             INSTALLSTATE check )
945 {
946     if (package->features[index].Installed == check)
947         return FALSE;
948
949     if (package->features[index].ActionRequest == check)
950         return TRUE;
951     else
952         return FALSE;
953 }
954
955
956 /****************************************************
957  * TOP level entry points 
958  *****************************************************/
959
960 UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath,
961                               LPCWSTR szCommandLine)
962 {
963     DWORD sz;
964     WCHAR buffer[10];
965     UINT rc;
966     BOOL ui = FALSE;
967     static const WCHAR szUILevel[] = {'U','I','L','e','v','e','l',0};
968     static const WCHAR szAction[] = {'A','C','T','I','O','N',0};
969     static const WCHAR szInstall[] = {'I','N','S','T','A','L','L',0};
970
971     MSI_SetPropertyW(package, szAction, szInstall);
972
973     package->script = HeapAlloc(GetProcessHeap(),0,sizeof(MSISCRIPT));
974     memset(package->script,0,sizeof(MSISCRIPT));
975
976     if (szPackagePath)   
977     {
978         LPWSTR p, check, path;
979  
980         package->PackagePath = strdupW(szPackagePath);
981         path = strdupW(szPackagePath);
982         p = strrchrW(path,'\\');    
983         if (p)
984         {
985             p++;
986             *p=0;
987         }
988         else
989         {
990             HeapFree(GetProcessHeap(),0,path);
991             path = HeapAlloc(GetProcessHeap(),0,MAX_PATH*sizeof(WCHAR));
992             GetCurrentDirectoryW(MAX_PATH,path);
993             strcatW(path,cszbs);
994         }
995
996         check = load_dynamic_property(package, cszSourceDir,NULL);
997         if (!check)
998             MSI_SetPropertyW(package, cszSourceDir, path);
999         else
1000             HeapFree(GetProcessHeap(), 0, check);
1001
1002         HeapFree(GetProcessHeap(), 0, path);
1003     }
1004
1005     if (szCommandLine)
1006     {
1007         LPWSTR ptr,ptr2;
1008         ptr = (LPWSTR)szCommandLine;
1009        
1010         while (*ptr)
1011         {
1012             WCHAR *prop = NULL;
1013             WCHAR *val = NULL;
1014
1015             TRACE("Looking at %s\n",debugstr_w(ptr));
1016
1017             ptr2 = strchrW(ptr,'=');
1018             if (ptr2)
1019             {
1020                 BOOL quote=FALSE;
1021                 DWORD len = 0;
1022
1023                 while (*ptr == ' ') ptr++;
1024                 len = ptr2-ptr;
1025                 prop = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
1026                 memcpy(prop,ptr,len*sizeof(WCHAR));
1027                 prop[len]=0;
1028                 ptr2++;
1029            
1030                 len = 0; 
1031                 ptr = ptr2; 
1032                 while (*ptr && (quote || (!quote && *ptr!=' ')))
1033                 {
1034                     if (*ptr == '"')
1035                         quote = !quote;
1036                     ptr++;
1037                     len++;
1038                 }
1039                
1040                 if (*ptr2=='"')
1041                 {
1042                     ptr2++;
1043                     len -= 2;
1044                 }
1045                 val = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR));
1046                 memcpy(val,ptr2,len*sizeof(WCHAR));
1047                 val[len] = 0;
1048
1049                 if (strlenW(prop) > 0)
1050                 {
1051                     TRACE("Found commandline property (%s) = (%s)\n", 
1052                                        debugstr_w(prop), debugstr_w(val));
1053                     MSI_SetPropertyW(package,prop,val);
1054                 }
1055                 HeapFree(GetProcessHeap(),0,val);
1056                 HeapFree(GetProcessHeap(),0,prop);
1057             }
1058             ptr++;
1059         }
1060     }
1061   
1062     sz = 10; 
1063     if (MSI_GetPropertyW(package,szUILevel,buffer,&sz) == ERROR_SUCCESS)
1064     {
1065         if (atoiW(buffer) >= INSTALLUILEVEL_REDUCED)
1066         {
1067             rc = ACTION_ProcessUISequence(package);
1068             ui = TRUE;
1069             if (rc == ERROR_SUCCESS)
1070                 rc = ACTION_ProcessExecSequence(package,TRUE);
1071         }
1072         else
1073             rc = ACTION_ProcessExecSequence(package,FALSE);
1074     }
1075     else
1076         rc = ACTION_ProcessExecSequence(package,FALSE);
1077     
1078     if (rc == -1)
1079     {
1080         /* install was halted but should be considered a success */
1081         rc = ERROR_SUCCESS;
1082     }
1083
1084     package->script->CurrentlyScripting= FALSE;
1085
1086     /* process the ending type action */
1087     if (rc == ERROR_SUCCESS)
1088         ACTION_PerformActionSequence(package,-1,ui);
1089     else if (rc == ERROR_INSTALL_USEREXIT) 
1090         ACTION_PerformActionSequence(package,-2,ui);
1091     else if (rc == ERROR_INSTALL_SUSPEND) 
1092         ACTION_PerformActionSequence(package,-4,ui);
1093     else  /* failed */
1094         ACTION_PerformActionSequence(package,-3,ui);
1095
1096     /* finish up running custom actions */
1097     ACTION_FinishCustomActions(package);
1098     
1099     return rc;
1100 }
1101
1102 static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq, BOOL UI)
1103 {
1104     UINT rc = ERROR_SUCCESS;
1105     MSIRECORD * row = 0;
1106     static const WCHAR ExecSeqQuery[] =
1107         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1108          '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
1109          'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
1110          '`','S','e','q','u','e','n','c','e','`',' ', '=',' ','%','i',0};
1111
1112     static const WCHAR UISeqQuery[] =
1113         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1114      '`','I','n','s','t','a','l','l','U','I','S','e','q','u','e','n','c','e',
1115      '`', ' ', 'W','H','E','R','E',' ','`','S','e','q','u','e','n','c','e','`',
1116          ' ', '=',' ','%','i',0};
1117
1118     if (UI)
1119         row = MSI_QueryGetRecord(package->db, UISeqQuery, seq);
1120     else
1121         row = MSI_QueryGetRecord(package->db, ExecSeqQuery, seq);
1122
1123     if (row)
1124     {
1125         LPCWSTR action, cond;
1126
1127         TRACE("Running the actions\n"); 
1128
1129         /* check conditions */
1130         cond = MSI_RecordGetString(row,2);
1131         if (cond)
1132         {
1133             /* this is a hack to skip errors in the condition code */
1134             if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
1135                 goto end;
1136         }
1137
1138         action = MSI_RecordGetString(row,1);
1139         if (!action)
1140         {
1141             ERR("failed to fetch action\n");
1142             rc = ERROR_FUNCTION_FAILED;
1143             goto end;
1144         }
1145
1146         if (UI)
1147             rc = ACTION_PerformUIAction(package,action);
1148         else
1149             rc = ACTION_PerformAction(package,action,FALSE);
1150 end:
1151         msiobj_release(&row->hdr);
1152     }
1153     else
1154         rc = ERROR_SUCCESS;
1155
1156     return rc;
1157 }
1158
1159 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
1160 {
1161     MSIQUERY * view;
1162     UINT rc;
1163     static const WCHAR ExecSeqQuery[] =
1164         {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1165          '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
1166          'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
1167          '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
1168          'O','R','D','E','R',' ', 'B','Y',' ',
1169          '`','S','e','q','u','e','n','c','e','`',0 };
1170     MSIRECORD * row = 0;
1171     static const WCHAR IVQuery[] =
1172         {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
1173          ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
1174          'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
1175          'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
1176          ' ','\'', 'I','n','s','t','a','l','l',
1177          'V','a','l','i','d','a','t','e','\'', 0};
1178     INT seq = 0;
1179
1180
1181     if (package->script->ExecuteSequenceRun)
1182     {
1183         TRACE("Execute Sequence already Run\n");
1184         return ERROR_SUCCESS;
1185     }
1186
1187     package->script->ExecuteSequenceRun = TRUE;
1188     
1189     /* get the sequence number */
1190     if (UIran)
1191     {
1192         row = MSI_QueryGetRecord(package->db, IVQuery);
1193         if( !row )
1194             return ERROR_FUNCTION_FAILED;
1195         seq = MSI_RecordGetInteger(row,1);
1196         msiobj_release(&row->hdr);
1197     }
1198
1199     rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
1200     if (rc == ERROR_SUCCESS)
1201     {
1202         rc = MSI_ViewExecute(view, 0);
1203
1204         if (rc != ERROR_SUCCESS)
1205         {
1206             MSI_ViewClose(view);
1207             msiobj_release(&view->hdr);
1208             goto end;
1209         }
1210        
1211         TRACE("Running the actions\n"); 
1212
1213         while (1)
1214         {
1215             LPCWSTR cond, action;
1216
1217             rc = MSI_ViewFetch(view,&row);
1218             if (rc != ERROR_SUCCESS)
1219             {
1220                 rc = ERROR_SUCCESS;
1221                 break;
1222             }
1223
1224             action = MSI_RecordGetString(row,1);
1225             if (!action)
1226             {
1227                 ERR("Error in retrieving action name\n");
1228                 rc = ERROR_FUNCTION_FAILED;
1229                 msiobj_release(&row->hdr);
1230                 break;
1231             }
1232
1233             /* check conditions */
1234             cond = MSI_RecordGetString(row,2);
1235             if (cond)
1236             {
1237                 /* this is a hack to skip errors in the condition code */
1238                 if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
1239                 {
1240                     TRACE("Skipping action: %s (condition is false)\n",
1241                                     debugstr_w(action));
1242                     msiobj_release(&row->hdr);
1243                     continue; 
1244                 }
1245             }
1246
1247             rc = ACTION_PerformAction(package,action,FALSE);
1248
1249             if (rc == ERROR_FUNCTION_NOT_CALLED)
1250                 rc = ERROR_SUCCESS;
1251
1252             if (rc != ERROR_SUCCESS)
1253             {
1254                 ERR("Execution halted due to error (%i)\n",rc);
1255                 msiobj_release(&row->hdr);
1256                 break;
1257             }
1258
1259             msiobj_release(&row->hdr);
1260         }
1261
1262         MSI_ViewClose(view);
1263         msiobj_release(&view->hdr);
1264     }
1265
1266 end:
1267     return rc;
1268 }
1269
1270
1271 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
1272 {
1273     MSIQUERY * view;
1274     UINT rc;
1275     static const WCHAR ExecSeqQuery [] =
1276         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1277          '`','I','n','s','t','a','l','l',
1278          'U','I','S','e','q','u','e','n','c','e','`',
1279          ' ','W','H','E','R','E',' ', 
1280          '`','S','e','q','u','e','n','c','e','`',' ',
1281          '>',' ','0',' ','O','R','D','E','R',' ','B','Y',' ',
1282          '`','S','e','q','u','e','n','c','e','`',0};
1283     
1284     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1285     
1286     if (rc == ERROR_SUCCESS)
1287     {
1288         rc = MSI_ViewExecute(view, 0);
1289
1290         if (rc != ERROR_SUCCESS)
1291         {
1292             MSI_ViewClose(view);
1293             msiobj_release(&view->hdr);
1294             goto end;
1295         }
1296        
1297         TRACE("Running the actions \n"); 
1298
1299         while (1)
1300         {
1301             LPCWSTR action, cond;
1302             MSIRECORD * row = 0;
1303
1304             rc = MSI_ViewFetch(view,&row);
1305             if (rc != ERROR_SUCCESS)
1306             {
1307                 rc = ERROR_SUCCESS;
1308                 break;
1309             }
1310
1311             action = MSI_RecordGetString(row,1);
1312             if (!action)
1313             {
1314                 ERR("failed to fetch action\n");
1315                 rc = ERROR_FUNCTION_FAILED;
1316                 msiobj_release(&row->hdr);
1317                 break;
1318             }
1319
1320             /* check conditions */
1321             cond = MSI_RecordGetString(row,2);
1322             if (cond)
1323             {
1324                 /* this is a hack to skip errors in the condition code */
1325                 if (MSI_EvaluateConditionW(package,cond) == MSICONDITION_FALSE)
1326                 {
1327                     TRACE("Skipping action: %s (condition is false)\n",
1328                                     debugstr_w(action));
1329                     msiobj_release(&row->hdr);
1330                     continue; 
1331                 }
1332             }
1333
1334             rc = ACTION_PerformUIAction(package,action);
1335
1336             if (rc == ERROR_FUNCTION_NOT_CALLED)
1337                 rc = ERROR_SUCCESS;
1338
1339             if (rc != ERROR_SUCCESS)
1340             {
1341                 ERR("Execution halted due to error (%i)\n",rc);
1342                 msiobj_release(&row->hdr);
1343                 break;
1344             }
1345
1346             msiobj_release(&row->hdr);
1347         }
1348
1349         MSI_ViewClose(view);
1350         msiobj_release(&view->hdr);
1351     }
1352
1353 end:
1354     return rc;
1355 }
1356
1357 /********************************************************
1358  * ACTION helper functions and functions that perform the actions
1359  *******************************************************/
1360 static BOOL ACTION_HandleStandardAction(MSIPACKAGE *package, LPCWSTR action, 
1361                                         UINT* rc, BOOL force )
1362 {
1363     BOOL ret = FALSE; 
1364     BOOL run = force;
1365     int i;
1366
1367     if (!run && !package->script->CurrentlyScripting)
1368         run = TRUE;
1369    
1370     if (!run)
1371     {
1372         if (strcmpW(action,szInstallFinalize) == 0 ||
1373             strcmpW(action,szInstallExecute) == 0 ||
1374             strcmpW(action,szInstallExecuteAgain) == 0) 
1375                 run = TRUE;
1376     }
1377     
1378     i = 0;
1379     while (StandardActions[i].action != NULL)
1380     {
1381         if (strcmpW(StandardActions[i].action, action)==0)
1382         {
1383             ce_actiontext(package, action);
1384             if (!run)
1385             {
1386                 ui_actioninfo(package, action, TRUE, 0);
1387                 *rc = schedule_action(package,INSTALL_SCRIPT,action);
1388                 ui_actioninfo(package, action, FALSE, *rc);
1389             }
1390             else
1391             {
1392                 ui_actionstart(package, action);
1393                 if (StandardActions[i].handler)
1394                 {
1395                     *rc = StandardActions[i].handler(package);
1396                 }
1397                 else
1398                 {
1399                     FIXME("UNHANDLED Standard Action %s\n",debugstr_w(action));
1400                     *rc = ERROR_SUCCESS;
1401                 }
1402             }
1403             ret = TRUE;
1404             break;
1405         }
1406         i++;
1407     }
1408     return ret;
1409 }
1410
1411 static BOOL ACTION_HandleDialogBox( MSIPACKAGE *package, LPCWSTR dialog, UINT* rc )
1412 {
1413     BOOL ret = FALSE;
1414
1415     if (ACTION_DialogBox(package,dialog) == ERROR_SUCCESS)
1416     {
1417         *rc = package->CurrentInstallState;
1418         ret = TRUE;
1419     }
1420     return ret;
1421 }
1422
1423 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
1424                                        UINT* rc, BOOL force )
1425 {
1426     BOOL ret=FALSE;
1427     UINT arc;
1428
1429     arc = ACTION_CustomAction(package,action, force);
1430
1431     if (arc != ERROR_CALL_NOT_IMPLEMENTED)
1432     {
1433         *rc = arc;
1434         ret = TRUE;
1435     }
1436     return ret;
1437 }
1438
1439 /* 
1440  * A lot of actions are really important even if they don't do anything
1441  * explicit... Lots of properties are set at the beginning of the installation
1442  * CostFinalize does a bunch of work to translate the directories and such
1443  * 
1444  * But until I get write access to the database that is hard, so I am going to
1445  * hack it to see if I can get something to run.
1446  */
1447 UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action, BOOL force)
1448 {
1449     UINT rc = ERROR_SUCCESS; 
1450     BOOL handled;
1451
1452     TRACE("Performing action (%s)\n",debugstr_w(action));
1453
1454     handled = ACTION_HandleStandardAction(package, action, &rc, force);
1455
1456     if (!handled)
1457         handled = ACTION_HandleCustomAction(package, action, &rc, force);
1458
1459     if (!handled)
1460     {
1461         FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action));
1462         rc = ERROR_FUNCTION_NOT_CALLED;
1463     }
1464
1465     package->CurrentInstallState = rc;
1466     return rc;
1467 }
1468
1469 UINT ACTION_PerformUIAction(MSIPACKAGE *package, const WCHAR *action)
1470 {
1471     UINT rc = ERROR_SUCCESS;
1472     BOOL handled = FALSE;
1473
1474     TRACE("Performing action (%s)\n",debugstr_w(action));
1475
1476     handled = ACTION_HandleStandardAction(package, action, &rc,TRUE);
1477
1478     if (!handled)
1479         handled = ACTION_HandleCustomAction(package, action, &rc, FALSE);
1480
1481     if (!handled)
1482         handled = ACTION_HandleDialogBox(package, action, &rc);
1483
1484     msi_dialog_check_messages( NULL );
1485
1486     if (!handled)
1487     {
1488         FIXME("UNHANDLED MSI ACTION %s\n",debugstr_w(action));
1489         rc = ERROR_FUNCTION_NOT_CALLED;
1490     }
1491
1492     package->CurrentInstallState = rc;
1493     return rc;
1494 }
1495
1496 /***********************************************************************
1497  *            create_full_pathW
1498  *
1499  * Recursively create all directories in the path.
1500  *
1501  * shamelessly stolen from setupapi/queue.c
1502  */
1503 static BOOL create_full_pathW(const WCHAR *path)
1504 {
1505     BOOL ret = TRUE;
1506     int len;
1507     WCHAR *new_path;
1508
1509     new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) *
1510                                               sizeof(WCHAR));
1511
1512     strcpyW(new_path, path);
1513
1514     while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
1515     new_path[len - 1] = 0;
1516
1517     while(!CreateDirectoryW(new_path, NULL))
1518     {
1519         WCHAR *slash;
1520         DWORD last_error = GetLastError();
1521         if(last_error == ERROR_ALREADY_EXISTS)
1522             break;
1523
1524         if(last_error != ERROR_PATH_NOT_FOUND)
1525         {
1526             ret = FALSE;
1527             break;
1528         }
1529
1530         if(!(slash = strrchrW(new_path, '\\')))
1531         {
1532             ret = FALSE;
1533             break;
1534         }
1535
1536         len = slash - new_path;
1537         new_path[len] = 0;
1538         if(!create_full_pathW(new_path))
1539         {
1540             ret = FALSE;
1541             break;
1542         }
1543         new_path[len] = '\\';
1544     }
1545
1546     HeapFree(GetProcessHeap(), 0, new_path);
1547     return ret;
1548 }
1549
1550 /*
1551  * Also we cannot enable/disable components either, so for now I am just going 
1552  * to do all the directories for all the components.
1553  */
1554 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
1555 {
1556     static const WCHAR ExecSeqQuery[] =
1557         {'S','E','L','E','C','T',' ',
1558          '`','D','i','r','e','c','t','o','r','y','_','`',
1559          ' ','F','R','O','M',' ',
1560          '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
1561     UINT rc;
1562     MSIQUERY *view;
1563     MSIFOLDER *folder;
1564
1565     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
1566     if (rc != ERROR_SUCCESS)
1567         return ERROR_SUCCESS;
1568
1569     rc = MSI_ViewExecute(view, 0);
1570     if (rc != ERROR_SUCCESS)
1571     {
1572         MSI_ViewClose(view);
1573         msiobj_release(&view->hdr);
1574         return rc;
1575     }
1576     
1577     while (1)
1578     {
1579         LPCWSTR dir;
1580         LPWSTR full_path;
1581         MSIRECORD *row = NULL, *uirow;
1582
1583         rc = MSI_ViewFetch(view,&row);
1584         if (rc != ERROR_SUCCESS)
1585         {
1586             rc = ERROR_SUCCESS;
1587             break;
1588         }
1589
1590         dir = MSI_RecordGetString(row,1);
1591         if (!dir)
1592         {
1593             ERR("Unable to get folder id \n");
1594             msiobj_release(&row->hdr);
1595             continue;
1596         }
1597
1598         full_path = resolve_folder(package,dir,FALSE,FALSE,&folder);
1599         if (!full_path)
1600         {
1601             ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
1602             msiobj_release(&row->hdr);
1603             continue;
1604         }
1605
1606         TRACE("Folder is %s\n",debugstr_w(full_path));
1607
1608         /* UI stuff */
1609         uirow = MSI_CreateRecord(1);
1610         MSI_RecordSetStringW(uirow,1,full_path);
1611         ui_actiondata(package,szCreateFolders,uirow);
1612         msiobj_release( &uirow->hdr );
1613
1614         if (folder->State == 0)
1615             create_full_pathW(full_path);
1616
1617         folder->State = 3;
1618
1619         msiobj_release(&row->hdr);
1620         HeapFree(GetProcessHeap(),0,full_path);
1621     }
1622     MSI_ViewClose(view);
1623     msiobj_release(&view->hdr);
1624    
1625     return rc;
1626 }
1627
1628 static int load_component(MSIPACKAGE* package, MSIRECORD * row)
1629 {
1630     int index = package->loaded_components;
1631     DWORD sz;
1632
1633     /* fill in the data */
1634
1635     package->loaded_components++;
1636     if (package->loaded_components == 1)
1637         package->components = HeapAlloc(GetProcessHeap(),0,
1638                                         sizeof(MSICOMPONENT));
1639     else
1640         package->components = HeapReAlloc(GetProcessHeap(),0,
1641             package->components, package->loaded_components * 
1642             sizeof(MSICOMPONENT));
1643
1644     memset(&package->components[index],0,sizeof(MSICOMPONENT));
1645
1646     sz = IDENTIFIER_SIZE;       
1647     MSI_RecordGetStringW(row,1,package->components[index].Component,&sz);
1648
1649     TRACE("Loading Component %s\n",
1650            debugstr_w(package->components[index].Component));
1651
1652     sz = 0x100;
1653     if (!MSI_RecordIsNull(row,2))
1654         MSI_RecordGetStringW(row,2,package->components[index].ComponentId,&sz);
1655             
1656     sz = IDENTIFIER_SIZE;       
1657     MSI_RecordGetStringW(row,3,package->components[index].Directory,&sz);
1658
1659     package->components[index].Attributes = MSI_RecordGetInteger(row,4);
1660
1661     sz = 0x100;       
1662     MSI_RecordGetStringW(row,5,package->components[index].Condition,&sz);
1663
1664     sz = IDENTIFIER_SIZE;       
1665     MSI_RecordGetStringW(row,6,package->components[index].KeyPath,&sz);
1666
1667     package->components[index].Installed = INSTALLSTATE_ABSENT;
1668     package->components[index].Action = INSTALLSTATE_UNKNOWN;
1669     package->components[index].ActionRequest = INSTALLSTATE_UNKNOWN;
1670
1671     package->components[index].Enabled = TRUE;
1672
1673     return index;
1674 }
1675
1676 static void load_feature(MSIPACKAGE* package, MSIRECORD * row)
1677 {
1678     int index = package->loaded_features;
1679     DWORD sz;
1680     static const WCHAR Query1[] = 
1681         {'S','E','L','E','C','T',' ',
1682          '`','C','o','m','p','o','n','e','n','t','_','`',
1683          ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1684          'C','o','m','p','o','n','e','n','t','s','`',' ',
1685          'W','H','E','R','E',' ',
1686          '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1687     static const WCHAR Query2[] = 
1688         {'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ', 
1689          '`','C','o','m','p','o','n','e','n','t','`',' ',
1690          'W','H','E','R','E',' ', 
1691          '`','C','o','m','p','o','n','e','n','t','`',' ',
1692          '=','\'','%','s','\'',0};
1693     MSIQUERY * view;
1694     MSIQUERY * view2;
1695     MSIRECORD * row2;
1696     MSIRECORD * row3;
1697     UINT    rc;
1698
1699     /* fill in the data */
1700
1701     package->loaded_features ++;
1702     if (package->loaded_features == 1)
1703         package->features = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFEATURE));
1704     else
1705         package->features = HeapReAlloc(GetProcessHeap(),0,package->features,
1706                                 package->loaded_features * sizeof(MSIFEATURE));
1707
1708     memset(&package->features[index],0,sizeof(MSIFEATURE));
1709     
1710     sz = IDENTIFIER_SIZE;       
1711     MSI_RecordGetStringW(row,1,package->features[index].Feature,&sz);
1712
1713     TRACE("Loading feature %s\n",debugstr_w(package->features[index].Feature));
1714
1715     sz = IDENTIFIER_SIZE;
1716     if (!MSI_RecordIsNull(row,2))
1717         MSI_RecordGetStringW(row,2,package->features[index].Feature_Parent,&sz);
1718
1719     sz = 0x100;
1720      if (!MSI_RecordIsNull(row,3))
1721         MSI_RecordGetStringW(row,3,package->features[index].Title,&sz);
1722
1723      sz = 0x100;
1724      if (!MSI_RecordIsNull(row,4))
1725         MSI_RecordGetStringW(row,4,package->features[index].Description,&sz);
1726
1727     if (!MSI_RecordIsNull(row,5))
1728         package->features[index].Display = MSI_RecordGetInteger(row,5);
1729   
1730     package->features[index].Level= MSI_RecordGetInteger(row,6);
1731
1732      sz = IDENTIFIER_SIZE;
1733      if (!MSI_RecordIsNull(row,7))
1734         MSI_RecordGetStringW(row,7,package->features[index].Directory,&sz);
1735
1736     package->features[index].Attributes= MSI_RecordGetInteger(row,8);
1737
1738     package->features[index].Installed = INSTALLSTATE_ABSENT;
1739     package->features[index].Action = INSTALLSTATE_UNKNOWN;
1740     package->features[index].ActionRequest = INSTALLSTATE_UNKNOWN;
1741
1742     /* load feature components */
1743
1744     rc = MSI_OpenQuery(package->db, &view, Query1, package->features[index].Feature);
1745     if (rc != ERROR_SUCCESS)
1746         return;
1747     rc = MSI_ViewExecute(view,0);
1748     if (rc != ERROR_SUCCESS)
1749     {
1750         MSI_ViewClose(view);
1751         msiobj_release(&view->hdr);
1752         return;
1753     }
1754     while (1)
1755     {
1756         LPCWSTR component;
1757         DWORD rc;
1758         INT c_indx;
1759         INT cnt = package->features[index].ComponentCount;
1760
1761         rc = MSI_ViewFetch(view,&row2);
1762         if (rc != ERROR_SUCCESS)
1763             break;
1764
1765         component = MSI_RecordGetString(row2,1);
1766
1767         /* check to see if the component is already loaded */
1768         c_indx = get_loaded_component(package,component);
1769         if (c_indx != -1)
1770         {
1771             TRACE("Component %s already loaded at %i\n", debugstr_w(component),
1772                   c_indx);
1773             package->features[index].Components[cnt] = c_indx;
1774             package->features[index].ComponentCount ++;
1775             msiobj_release( &row2->hdr );
1776             continue;
1777         }
1778
1779         rc = MSI_OpenQuery(package->db, &view2, Query2, component);
1780         if (rc != ERROR_SUCCESS)
1781         {
1782             msiobj_release( &row2->hdr );
1783             continue;
1784         }
1785         rc = MSI_ViewExecute(view2,0);
1786         if (rc != ERROR_SUCCESS)
1787         {
1788             msiobj_release( &row2->hdr );
1789             MSI_ViewClose(view2);
1790             msiobj_release( &view2->hdr );  
1791             continue;
1792         }
1793         while (1)
1794         {
1795             DWORD rc;
1796
1797             rc = MSI_ViewFetch(view2,&row3);
1798             if (rc != ERROR_SUCCESS)
1799                 break;
1800             c_indx = load_component(package,row3);
1801             msiobj_release( &row3->hdr );
1802
1803             package->features[index].Components[cnt] = c_indx;
1804             package->features[index].ComponentCount ++;
1805             TRACE("Loaded new component to index %i\n",c_indx);
1806         }
1807         MSI_ViewClose(view2);
1808         msiobj_release( &view2->hdr );
1809         msiobj_release( &row2->hdr );
1810     }
1811     MSI_ViewClose(view);
1812     msiobj_release(&view->hdr);
1813 }
1814
1815 static UINT load_file(MSIPACKAGE* package, MSIRECORD * row)
1816 {
1817     DWORD index = package->loaded_files;
1818     LPCWSTR component;
1819
1820     /* fill in the data */
1821
1822     package->loaded_files++;
1823     if (package->loaded_files== 1)
1824         package->files = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFILE));
1825     else
1826         package->files = HeapReAlloc(GetProcessHeap(),0,
1827             package->files , package->loaded_files * sizeof(MSIFILE));
1828
1829     memset(&package->files[index],0,sizeof(MSIFILE));
1830  
1831     package->files[index].File = load_dynamic_stringW(row, 1);
1832
1833     component = MSI_RecordGetString(row, 2);
1834     package->files[index].ComponentIndex = get_loaded_component(package,
1835                     component);
1836
1837     if (package->files[index].ComponentIndex == -1)
1838         ERR("Unfound Component %s\n",debugstr_w(component));
1839
1840     package->files[index].FileName = load_dynamic_stringW(row,3);
1841     reduce_to_longfilename(package->files[index].FileName);
1842
1843     package->files[index].ShortName = load_dynamic_stringW(row,3);
1844     reduce_to_shortfilename(package->files[index].ShortName);
1845     
1846     package->files[index].FileSize = MSI_RecordGetInteger(row,4);
1847     package->files[index].Version = load_dynamic_stringW(row, 5);
1848     package->files[index].Language = load_dynamic_stringW(row, 6);
1849     package->files[index].Attributes= MSI_RecordGetInteger(row,7);
1850     package->files[index].Sequence= MSI_RecordGetInteger(row,8);
1851
1852     package->files[index].Temporary = FALSE;
1853     package->files[index].State = 0;
1854
1855     TRACE("File Loaded (%s)\n",debugstr_w(package->files[index].File));  
1856  
1857     return ERROR_SUCCESS;
1858 }
1859
1860 static UINT load_all_files(MSIPACKAGE *package)
1861 {
1862     MSIQUERY * view;
1863     MSIRECORD * row;
1864     UINT rc;
1865     static const WCHAR Query[] =
1866         {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1867          '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1868          '`','S','e','q','u','e','n','c','e','`', 0};
1869
1870     if (!package)
1871         return ERROR_INVALID_HANDLE;
1872
1873     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1874     if (rc != ERROR_SUCCESS)
1875         return ERROR_SUCCESS;
1876    
1877     rc = MSI_ViewExecute(view, 0);
1878     if (rc != ERROR_SUCCESS)
1879     {
1880         MSI_ViewClose(view);
1881         msiobj_release(&view->hdr);
1882         return ERROR_SUCCESS;
1883     }
1884
1885     while (1)
1886     {
1887         rc = MSI_ViewFetch(view,&row);
1888         if (rc != ERROR_SUCCESS)
1889         {
1890             rc = ERROR_SUCCESS;
1891             break;
1892         }
1893         load_file(package,row);
1894         msiobj_release(&row->hdr);
1895     }
1896     MSI_ViewClose(view);
1897     msiobj_release(&view->hdr);
1898
1899     return ERROR_SUCCESS;
1900 }
1901
1902
1903 /*
1904  * I am not doing any of the costing functionality yet. 
1905  * Mostly looking at doing the Component and Feature loading
1906  *
1907  * The native MSI does A LOT of modification to tables here. Mostly adding
1908  * a lot of temporary columns to the Feature and Component tables. 
1909  *
1910  *    note: Native msi also tracks the short filename. But I am only going to
1911  *          track the long ones.  Also looking at this directory table
1912  *          it appears that the directory table does not get the parents
1913  *          resolved base on property only based on their entries in the 
1914  *          directory table.
1915  */
1916 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1917 {
1918     MSIQUERY * view;
1919     MSIRECORD * row;
1920     UINT rc;
1921     static const WCHAR Query_all[] =
1922         {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1923          '`','F','e','a','t','u','r','e','`',0};
1924     static const WCHAR szCosting[] =
1925         {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1926     static const WCHAR szZero[] = { '0', 0 };
1927     WCHAR buffer[3];
1928     DWORD sz = 3;
1929
1930     MSI_GetPropertyW(package, szCosting, buffer, &sz);
1931     if (buffer[0]=='1')
1932         return ERROR_SUCCESS;
1933     
1934     MSI_SetPropertyW(package, szCosting, szZero);
1935     MSI_SetPropertyW(package, cszRootDrive , c_colon);
1936
1937     rc = MSI_DatabaseOpenViewW(package->db,Query_all,&view);
1938     if (rc != ERROR_SUCCESS)
1939         return rc;
1940     rc = MSI_ViewExecute(view,0);
1941     if (rc != ERROR_SUCCESS)
1942     {
1943         MSI_ViewClose(view);
1944         msiobj_release(&view->hdr);
1945         return rc;
1946     }
1947     while (1)
1948     {
1949         DWORD rc;
1950
1951         rc = MSI_ViewFetch(view,&row);
1952         if (rc != ERROR_SUCCESS)
1953             break;
1954        
1955         load_feature(package,row); 
1956         msiobj_release(&row->hdr);
1957     }
1958     MSI_ViewClose(view);
1959     msiobj_release(&view->hdr);
1960
1961     load_all_files(package);
1962
1963     return ERROR_SUCCESS;
1964 }
1965
1966 UINT schedule_action(MSIPACKAGE *package, UINT script, LPCWSTR action)
1967 {
1968     UINT count;
1969     LPWSTR *newbuf = NULL;
1970     if (script >= TOTAL_SCRIPTS)
1971     {
1972         FIXME("Unknown script requested %i\n",script);
1973         return ERROR_FUNCTION_FAILED;
1974     }
1975     TRACE("Scheduling Action %s in script %i\n",debugstr_w(action), script);
1976     
1977     count = package->script->ActionCount[script];
1978     package->script->ActionCount[script]++;
1979     if (count != 0)
1980         newbuf = HeapReAlloc(GetProcessHeap(),0,
1981                         package->script->Actions[script],
1982                         package->script->ActionCount[script]* sizeof(LPWSTR));
1983     else
1984         newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR));
1985
1986     newbuf[count] = strdupW(action);
1987     package->script->Actions[script] = newbuf;
1988
1989    return ERROR_SUCCESS;
1990 }
1991
1992 static UINT execute_script(MSIPACKAGE *package, UINT script )
1993 {
1994     int i;
1995     UINT rc = ERROR_SUCCESS;
1996
1997     TRACE("Executing Script %i\n",script);
1998
1999     for (i = 0; i < package->script->ActionCount[script]; i++)
2000     {
2001         LPWSTR action;
2002         action = package->script->Actions[script][i];
2003         ui_actionstart(package, action);
2004         TRACE("Executing Action (%s)\n",debugstr_w(action));
2005         rc = ACTION_PerformAction(package, action, TRUE);
2006         HeapFree(GetProcessHeap(),0,package->script->Actions[script][i]);
2007         if (rc != ERROR_SUCCESS)
2008             break;
2009     }
2010     HeapFree(GetProcessHeap(),0,package->script->Actions[script]);
2011
2012     package->script->ActionCount[script] = 0;
2013     package->script->Actions[script] = NULL;
2014     return rc;
2015 }
2016
2017 static UINT ACTION_FileCost(MSIPACKAGE *package)
2018 {
2019     return ERROR_SUCCESS;
2020 }
2021
2022
2023 static INT load_folder(MSIPACKAGE *package, const WCHAR* dir)
2024 {
2025     static const WCHAR Query[] =
2026         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2027          '`','D','i','r','e','c', 't','o','r','y','`',' ',
2028          'W','H','E','R','E',' ', '`', 'D','i','r','e','c','t', 'o','r','y','`',
2029          ' ','=',' ','\'','%','s','\'',
2030          0};
2031     LPWSTR ptargetdir, targetdir, srcdir;
2032     LPCWSTR parent;
2033     LPWSTR shortname = NULL;
2034     MSIRECORD * row = 0;
2035     INT index = -1;
2036     DWORD i;
2037
2038     TRACE("Looking for dir %s\n",debugstr_w(dir));
2039
2040     for (i = 0; i < package->loaded_folders; i++)
2041     {
2042         if (strcmpW(package->folders[i].Directory,dir)==0)
2043         {
2044             TRACE(" %s retuning on index %lu\n",debugstr_w(dir),i);
2045             return i;
2046         }
2047     }
2048
2049     TRACE("Working to load %s\n",debugstr_w(dir));
2050
2051     index = package->loaded_folders++;
2052     if (package->loaded_folders==1)
2053         package->folders = HeapAlloc(GetProcessHeap(),0,
2054                                         sizeof(MSIFOLDER));
2055     else
2056         package->folders= HeapReAlloc(GetProcessHeap(),0,
2057             package->folders, package->loaded_folders* 
2058             sizeof(MSIFOLDER));
2059
2060     memset(&package->folders[index],0,sizeof(MSIFOLDER));
2061
2062     package->folders[index].Directory = strdupW(dir);
2063
2064     row = MSI_QueryGetRecord(package->db, Query, dir);
2065     if (!row)
2066         return -1;
2067
2068     ptargetdir = targetdir = load_dynamic_stringW(row,3);
2069
2070     /* split src and target dir */
2071     if (strchrW(targetdir,':'))
2072     {
2073         srcdir=strchrW(targetdir,':');
2074         *srcdir=0;
2075         srcdir ++;
2076     }
2077     else
2078         srcdir=NULL;
2079
2080     /* for now only pick long filename versions */
2081     if (strchrW(targetdir,'|'))
2082     {
2083         shortname = targetdir;
2084         targetdir = strchrW(targetdir,'|'); 
2085         *targetdir = 0;
2086         targetdir ++;
2087     }
2088     /* for the sourcedir pick the short filename */
2089     if (srcdir && strchrW(srcdir,'|'))
2090     {
2091         LPWSTR p = strchrW(srcdir,'|'); 
2092         *p = 0;
2093     }
2094
2095     /* now check for root dirs */
2096     if (targetdir[0] == '.' && targetdir[1] == 0)
2097         targetdir = NULL;
2098         
2099     if (srcdir && srcdir[0] == '.' && srcdir[1] == 0)
2100         srcdir = NULL;
2101
2102     if (targetdir)
2103     {
2104         TRACE("   TargetDefault = %s\n",debugstr_w(targetdir));
2105         HeapFree(GetProcessHeap(),0, package->folders[index].TargetDefault);
2106         package->folders[index].TargetDefault = strdupW(targetdir);
2107     }
2108
2109     if (srcdir)
2110         package->folders[index].SourceDefault = strdupW(srcdir);
2111     else if (shortname)
2112         package->folders[index].SourceDefault = strdupW(shortname);
2113     else if (targetdir)
2114         package->folders[index].SourceDefault = strdupW(targetdir);
2115     HeapFree(GetProcessHeap(), 0, ptargetdir);
2116         TRACE("   SourceDefault = %s\n",debugstr_w(package->folders[index].SourceDefault));
2117
2118     parent = MSI_RecordGetString(row,2);
2119     if (parent) 
2120     {
2121         i = load_folder(package,parent);
2122         package->folders[index].ParentIndex = i;
2123         TRACE("Parent is index %i... %s %s\n",
2124                     package->folders[index].ParentIndex,
2125         debugstr_w(package->folders[package->folders[index].ParentIndex].Directory),
2126                     debugstr_w(parent));
2127     }
2128     else
2129         package->folders[index].ParentIndex = -2;
2130
2131     package->folders[index].Property = load_dynamic_property(package, dir,NULL);
2132
2133     msiobj_release(&row->hdr);
2134     TRACE(" %s retuning on index %i\n",debugstr_w(dir),index);
2135     return index;
2136 }
2137
2138
2139 LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, 
2140                       BOOL set_prop, MSIFOLDER **folder)
2141 {
2142     DWORD i;
2143     LPWSTR p, path = NULL;
2144
2145     TRACE("Working to resolve %s\n",debugstr_w(name));
2146
2147     if (!name)
2148         return NULL;
2149
2150     /* special resolving for Target and Source root dir */
2151     if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0)
2152     {
2153         if (!source)
2154         {
2155             path = load_dynamic_property(package,cszTargetDir,NULL);
2156             if (!path)
2157             {
2158                 path = load_dynamic_property(package,cszRootDrive,NULL);
2159                 if (set_prop)
2160                     MSI_SetPropertyW(package,cszTargetDir,path);
2161             }
2162             if (folder)
2163             {
2164                 for (i = 0; i < package->loaded_folders; i++)
2165                 {
2166                     if (strcmpW(package->folders[i].Directory,name)==0)
2167                         break;
2168                 }
2169                 *folder = &(package->folders[i]);
2170             }
2171             return path;
2172         }
2173         else
2174         {
2175             path = load_dynamic_property(package,cszSourceDir,NULL);
2176             if (!path)
2177             {
2178                 path = load_dynamic_property(package,cszDatabase,NULL);
2179                 if (path)
2180                 {
2181                     p = strrchrW(path,'\\');
2182                     if (p)
2183                         *(p+1) = 0;
2184                 }
2185             }
2186             if (folder)
2187             {
2188                 for (i = 0; i < package->loaded_folders; i++)
2189                 {
2190                     if (strcmpW(package->folders[i].Directory,name)==0)
2191                         break;
2192                 }
2193                 *folder = &(package->folders[i]);
2194             }
2195             return path;
2196         }
2197     }
2198
2199     for (i = 0; i < package->loaded_folders; i++)
2200     {
2201         if (strcmpW(package->folders[i].Directory,name)==0)
2202             break;
2203     }
2204
2205     if (i >= package->loaded_folders)
2206         return NULL;
2207
2208     if (folder)
2209         *folder = &(package->folders[i]);
2210
2211     if (!source && package->folders[i].ResolvedTarget)
2212     {
2213         path = strdupW(package->folders[i].ResolvedTarget);
2214         TRACE("   already resolved to %s\n",debugstr_w(path));
2215         return path;
2216     }
2217     else if (source && package->folders[i].ResolvedSource)
2218     {
2219         path = strdupW(package->folders[i].ResolvedSource);
2220         TRACE("   (source)already resolved to %s\n",debugstr_w(path));
2221         return path;
2222     }
2223     else if (!source && package->folders[i].Property)
2224     {
2225         path = build_directory_name(2, package->folders[i].Property, NULL);
2226                     
2227         TRACE("   internally set to %s\n",debugstr_w(path));
2228         if (set_prop)
2229             MSI_SetPropertyW(package,name,path);
2230         return path;
2231     }
2232
2233     if (package->folders[i].ParentIndex >= 0)
2234     {
2235         LPWSTR parent = package->folders[package->folders[i].ParentIndex].Directory;
2236
2237         TRACE(" ! Parent is %s\n", debugstr_w(parent));
2238
2239         p = resolve_folder(package, parent, source, set_prop, NULL);
2240         if (!source)
2241         {
2242             TRACE("   TargetDefault = %s\n",debugstr_w(package->folders[i].TargetDefault));
2243             path = build_directory_name(3, p, package->folders[i].TargetDefault, NULL);
2244             package->folders[i].ResolvedTarget = strdupW(path);
2245             TRACE("   resolved into %s\n",debugstr_w(path));
2246             if (set_prop)
2247                 MSI_SetPropertyW(package,name,path);
2248         }
2249         else 
2250         {
2251             path = build_directory_name(3, p, package->folders[i].SourceDefault, NULL);
2252             TRACE("   (source)resolved into %s\n",debugstr_w(path));
2253             package->folders[i].ResolvedSource = strdupW(path);
2254         }
2255         HeapFree(GetProcessHeap(),0,p);
2256     }
2257     return path;
2258 }
2259
2260 /* scan for and update current install states */
2261 static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
2262 {
2263     int i;
2264     LPWSTR productcode;
2265
2266     productcode = load_dynamic_property(package,szProductCode,NULL);
2267
2268     for (i = 0; i < package->loaded_components; i++)
2269     {
2270         INSTALLSTATE res;
2271         res = MsiGetComponentPathW(productcode, 
2272                         package->components[i].ComponentId , NULL, NULL);
2273         if (res < 0)
2274             res = INSTALLSTATE_ABSENT;
2275         package->components[i].Installed = res;
2276     }
2277
2278     for (i = 0; i < package->loaded_features; i++)
2279     {
2280         INSTALLSTATE res = -10;
2281         int j;
2282         for (j = 0; j < package->features[i].ComponentCount; j++)
2283         {
2284             MSICOMPONENT* component = &package->components[package->features[i].
2285                                                            Components[j]];
2286             if (res == -10)
2287                 res = component->Installed;
2288             else
2289             {
2290                 if (res == component->Installed)
2291                     continue;
2292
2293                 if (res != component->Installed)
2294                         res = INSTALLSTATE_INCOMPLETE;
2295             }
2296         }
2297     }
2298 }
2299
2300 /* update compoennt state based on a feature change */
2301 void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
2302 {
2303     int i;
2304     INSTALLSTATE newstate;
2305     MSIFEATURE *feature;
2306
2307     i = get_loaded_feature(package,szFeature);
2308     if (i < 0)
2309         return;
2310
2311     feature = &package->features[i];
2312     newstate = feature->ActionRequest;
2313
2314     for( i = 0; i < feature->ComponentCount; i++)
2315     {
2316         MSICOMPONENT* component = &package->components[feature->Components[i]];
2317
2318         TRACE("MODIFYING(%i): Component %s (Installed %i, Action %i, Request %i)\n",
2319             newstate, debugstr_w(component->Component), component->Installed, 
2320             component->Action, component->ActionRequest);
2321         
2322         if (!component->Enabled)
2323             continue;
2324         else
2325         {
2326             if (newstate == INSTALLSTATE_LOCAL)
2327             {
2328                 component->ActionRequest = INSTALLSTATE_LOCAL;
2329                 component->Action = INSTALLSTATE_LOCAL;
2330             }
2331             else 
2332             {
2333                 int j,k;
2334
2335                 component->ActionRequest = newstate;
2336                 component->Action = newstate;
2337
2338                 /*if any other feature wants is local we need to set it local*/
2339                 for (j = 0; 
2340                      j < package->loaded_features &&
2341                      component->ActionRequest != INSTALLSTATE_LOCAL; 
2342                      j++)
2343                 {
2344                     for (k = 0; k < package->features[j].ComponentCount; k++)
2345                         if ( package->features[j].Components[k] ==
2346                              feature->Components[i] )
2347                         {
2348                             if (package->features[j].ActionRequest == 
2349                                 INSTALLSTATE_LOCAL)
2350                             {
2351                                 TRACE("Saved by %s\n", debugstr_w(package->features[j].Feature));
2352                                 component->ActionRequest = INSTALLSTATE_LOCAL;
2353                                 component->Action = INSTALLSTATE_LOCAL;
2354                             }
2355                             break;
2356                         }
2357                 }
2358             }
2359         }
2360         TRACE("Result (%i): Component %s (Installed %i, Action %i, Request %i)\n",
2361             newstate, debugstr_w(component->Component), component->Installed, 
2362             component->Action, component->ActionRequest);
2363     } 
2364 }
2365
2366 static BOOL process_state_property (MSIPACKAGE* package, LPCWSTR property, 
2367                                     INSTALLSTATE state)
2368 {
2369     static const WCHAR all[]={'A','L','L',0};
2370     LPWSTR override = NULL;
2371     INT i;
2372     BOOL rc = FALSE;
2373
2374     override = load_dynamic_property(package, property, NULL);
2375     if (override)
2376     {
2377         rc = TRUE;
2378         for(i = 0; i < package->loaded_features; i++)
2379         {
2380             if (strcmpiW(override,all)==0)
2381             {
2382                 package->features[i].ActionRequest= state;
2383                 package->features[i].Action = state;
2384             }
2385             else
2386             {
2387                 LPWSTR ptr = override;
2388                 LPWSTR ptr2 = strchrW(override,',');
2389
2390                 while (ptr)
2391                 {
2392                     if ((ptr2 && 
2393                         strncmpW(ptr,package->features[i].Feature, ptr2-ptr)==0)
2394                         || (!ptr2 &&
2395                         strcmpW(ptr,package->features[i].Feature)==0))
2396                     {
2397                         package->features[i].ActionRequest= state;
2398                         package->features[i].Action = state;
2399                         break;
2400                     }
2401                     if (ptr2)
2402                     {
2403                         ptr=ptr2+1;
2404                         ptr2 = strchrW(ptr,',');
2405                     }
2406                     else
2407                         break;
2408                 }
2409             }
2410         }
2411         HeapFree(GetProcessHeap(),0,override);
2412     } 
2413
2414     return rc;
2415 }
2416
2417 static UINT SetFeatureStates(MSIPACKAGE *package)
2418 {
2419     LPWSTR level;
2420     INT install_level;
2421     DWORD i;
2422     INT j;
2423     static const WCHAR szlevel[] =
2424         {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2425     static const WCHAR szAddLocal[] =
2426         {'A','D','D','L','O','C','A','L',0};
2427     static const WCHAR szRemove[] =
2428         {'R','E','M','O','V','E',0};
2429     BOOL override = FALSE;
2430
2431     /* I do not know if this is where it should happen.. but */
2432
2433     TRACE("Checking Install Level\n");
2434
2435     level = load_dynamic_property(package,szlevel,NULL);
2436     if (level)
2437     {
2438         install_level = atoiW(level);
2439         HeapFree(GetProcessHeap(), 0, level);
2440     }
2441     else
2442         install_level = 1;
2443
2444     /* ok hereis the _real_ rub
2445      * all these activation/deactivation things happen in order and things
2446      * later on the list override things earlier on the list.
2447      * 1) INSTALLLEVEL processing
2448      * 2) ADDLOCAL
2449      * 3) REMOVE
2450      * 4) ADDSOURCE
2451      * 5) ADDDEFAULT
2452      * 6) REINSTALL
2453      * 7) COMPADDLOCAL
2454      * 8) COMPADDSOURCE
2455      * 9) FILEADDLOCAL
2456      * 10) FILEADDSOURCE
2457      * 11) FILEADDDEFAULT
2458      * I have confirmed that if ADDLOCAL is stated then the INSTALLLEVEL is
2459      * ignored for all the features. seems strange, especially since it is not
2460      * documented anywhere, but it is how it works. 
2461      *
2462      * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
2463      * REMOVE are the big ones, since we don't handle administrative installs
2464      * yet anyway.
2465      */
2466     override |= process_state_property(package,szAddLocal,INSTALLSTATE_LOCAL);
2467     override |= process_state_property(package,szRemove,INSTALLSTATE_ABSENT);
2468
2469     if (!override)
2470     {
2471         for(i = 0; i < package->loaded_features; i++)
2472         {
2473             BOOL feature_state = ((package->features[i].Level > 0) &&
2474                              (package->features[i].Level <= install_level));
2475
2476             if ((feature_state) && 
2477                (package->features[i].Action == INSTALLSTATE_UNKNOWN))
2478             {
2479                 if (package->features[i].Attributes & 
2480                                 msidbFeatureAttributesFavorSource)
2481                 {
2482                     package->features[i].ActionRequest = INSTALLSTATE_SOURCE;
2483                     package->features[i].Action = INSTALLSTATE_SOURCE;
2484                 }
2485                 else if (package->features[i].Attributes &
2486                                 msidbFeatureAttributesFavorAdvertise)
2487                 {
2488                     package->features[i].ActionRequest =INSTALLSTATE_ADVERTISED;
2489                     package->features[i].Action =INSTALLSTATE_ADVERTISED;
2490                 }
2491                 else
2492                 {
2493                     package->features[i].ActionRequest = INSTALLSTATE_LOCAL;
2494                     package->features[i].Action = INSTALLSTATE_LOCAL;
2495                 }
2496             }
2497         }
2498     }
2499     else
2500     {
2501         /* set the Preselected Property */
2502         static const WCHAR szPreselected[] = {'P','r','e','s','e','l','e','c','t','e','d',0};
2503         static const WCHAR szOne[] = { '1', 0 };
2504
2505         MSI_SetPropertyW(package,szPreselected,szOne);
2506     }
2507
2508     /*
2509      * now we want to enable or disable components base on feature 
2510     */
2511
2512     for(i = 0; i < package->loaded_features; i++)
2513     {
2514         MSIFEATURE* feature = &package->features[i];
2515         TRACE("Examining Feature %s (Installed %i, Action %i, Request %i)\n",
2516             debugstr_w(feature->Feature), feature->Installed, feature->Action,
2517             feature->ActionRequest);
2518
2519         for( j = 0; j < feature->ComponentCount; j++)
2520         {
2521             MSICOMPONENT* component = &package->components[
2522                                                     feature->Components[j]];
2523
2524             if (!component->Enabled)
2525             {
2526                 component->Action = INSTALLSTATE_UNKNOWN;
2527                 component->ActionRequest = INSTALLSTATE_UNKNOWN;
2528             }
2529             else
2530             {
2531                 if (feature->Action == INSTALLSTATE_LOCAL)
2532                 {
2533                     component->Action = INSTALLSTATE_LOCAL;
2534                     component->ActionRequest = INSTALLSTATE_LOCAL;
2535                 }
2536                 else if (feature->ActionRequest == INSTALLSTATE_SOURCE)
2537                 {
2538                     if ((component->Action == INSTALLSTATE_UNKNOWN) ||
2539                         (component->Action == INSTALLSTATE_ABSENT) ||
2540                         (component->Action == INSTALLSTATE_ADVERTISED))
2541                            
2542                     {
2543                         component->Action = INSTALLSTATE_SOURCE;
2544                         component->ActionRequest = INSTALLSTATE_SOURCE;
2545                     }
2546                 }
2547                 else if (feature->ActionRequest == INSTALLSTATE_ADVERTISED)
2548                 {
2549                     if ((component->Action == INSTALLSTATE_UNKNOWN) ||
2550                         (component->Action == INSTALLSTATE_ABSENT))
2551                            
2552                     {
2553                         component->Action = INSTALLSTATE_ADVERTISED;
2554                         component->ActionRequest = INSTALLSTATE_ADVERTISED;
2555                     }
2556                 }
2557                 else if (feature->ActionRequest == INSTALLSTATE_ABSENT)
2558                 {
2559                     if (component->Action == INSTALLSTATE_UNKNOWN)
2560                     {
2561                         component->Action = INSTALLSTATE_ABSENT;
2562                         component->ActionRequest = INSTALLSTATE_ABSENT;
2563                     }
2564                 }
2565             }
2566         }
2567     } 
2568
2569     for(i = 0; i < package->loaded_components; i++)
2570     {
2571         MSICOMPONENT* component= &package->components[i];
2572
2573         TRACE("Result: Component %s (Installed %i, Action %i, Request %i)\n",
2574             debugstr_w(component->Component), component->Installed, 
2575             component->Action, component->ActionRequest);
2576     }
2577
2578
2579     return ERROR_SUCCESS;
2580 }
2581
2582 /* 
2583  * A lot is done in this function aside from just the costing.
2584  * The costing needs to be implemented at some point but for now I am going
2585  * to focus on the directory building
2586  *
2587  */
2588 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
2589 {
2590     static const WCHAR ExecSeqQuery[] =
2591         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2592          '`','D','i','r','e','c','t','o','r','y','`',0};
2593     static const WCHAR ConditionQuery[] =
2594         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2595          '`','C','o','n','d','i','t','i','o','n','`',0};
2596     static const WCHAR szCosting[] =
2597         {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
2598     static const WCHAR szlevel[] =
2599         {'I','N','S','T','A','L','L','L','E','V','E','L',0};
2600     static const WCHAR szOne[] = { '1', 0 };
2601     UINT rc;
2602     MSIQUERY * view;
2603     DWORD i;
2604     LPWSTR level;
2605     DWORD sz = 3;
2606     WCHAR buffer[3];
2607
2608     MSI_GetPropertyW(package, szCosting, buffer, &sz);
2609     if (buffer[0]=='1')
2610         return ERROR_SUCCESS;
2611
2612     TRACE("Building Directory properties\n");
2613
2614     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2615     if (rc == ERROR_SUCCESS)
2616     {
2617         rc = MSI_ViewExecute(view, 0);
2618         if (rc != ERROR_SUCCESS)
2619         {
2620             MSI_ViewClose(view);
2621             msiobj_release(&view->hdr);
2622             return rc;
2623         }
2624
2625         while (1)
2626         {
2627             LPCWSTR name;
2628             LPWSTR path;
2629             MSIRECORD * row = 0;
2630
2631             rc = MSI_ViewFetch(view,&row);
2632             if (rc != ERROR_SUCCESS)
2633             {
2634                 rc = ERROR_SUCCESS;
2635                 break;
2636             }
2637
2638             name = MSI_RecordGetString(row,1);
2639
2640             /* This helper function now does ALL the work */
2641             TRACE("Dir %s ...\n",debugstr_w(name));
2642             load_folder(package,name);
2643             path = resolve_folder(package,name,FALSE,TRUE,NULL);
2644             TRACE("resolves to %s\n",debugstr_w(path));
2645             HeapFree( GetProcessHeap(), 0, path);
2646
2647             msiobj_release(&row->hdr);
2648         }
2649         MSI_ViewClose(view);
2650         msiobj_release(&view->hdr);
2651     }
2652
2653     TRACE("File calculations %i files\n",package->loaded_files);
2654
2655     for (i = 0; i < package->loaded_files; i++)
2656     {
2657         MSICOMPONENT* comp = NULL;
2658         MSIFILE* file= NULL;
2659
2660         file = &package->files[i];
2661         if (file->ComponentIndex >= 0)
2662             comp = &package->components[file->ComponentIndex];
2663
2664         if (file->Temporary == TRUE)
2665             continue;
2666
2667         if (comp)
2668         {
2669             LPWSTR p;
2670
2671             /* calculate target */
2672             p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
2673
2674             HeapFree(GetProcessHeap(),0,file->TargetPath);
2675
2676             TRACE("file %s is named %s\n",
2677                    debugstr_w(file->File),debugstr_w(file->FileName));       
2678
2679             file->TargetPath = build_directory_name(2, p, file->FileName);
2680
2681             HeapFree(GetProcessHeap(),0,p);
2682
2683             TRACE("file %s resolves to %s\n",
2684                    debugstr_w(file->File),debugstr_w(file->TargetPath));       
2685
2686             if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
2687             {
2688                 file->State = 1;
2689                 comp->Cost += file->FileSize;
2690             }
2691             else
2692             {
2693                 if (file->Version)
2694                 {
2695                     DWORD handle;
2696                     DWORD versize;
2697                     UINT sz;
2698                     LPVOID version;
2699                     static const WCHAR name[] = 
2700                         {'\\',0};
2701                     static const WCHAR name_fmt[] = 
2702                         {'%','u','.','%','u','.','%','u','.','%','u',0};
2703                     WCHAR filever[0x100];
2704                     VS_FIXEDFILEINFO *lpVer;
2705
2706                     TRACE("Version comparison.. \n");
2707                     versize = GetFileVersionInfoSizeW(file->TargetPath,&handle);
2708                     version = HeapAlloc(GetProcessHeap(),0,versize);
2709                     GetFileVersionInfoW(file->TargetPath, 0, versize, version);
2710
2711                     VerQueryValueW(version, name, (LPVOID*)&lpVer, &sz);
2712
2713                     sprintfW(filever,name_fmt,
2714                         HIWORD(lpVer->dwFileVersionMS),
2715                         LOWORD(lpVer->dwFileVersionMS),
2716                         HIWORD(lpVer->dwFileVersionLS),
2717                         LOWORD(lpVer->dwFileVersionLS));
2718
2719                     TRACE("new %s old %s\n", debugstr_w(file->Version),
2720                           debugstr_w(filever));
2721                     if (strcmpiW(filever,file->Version)<0)
2722                     {
2723                         file->State = 2;
2724                         FIXME("cost should be diff in size\n");
2725                         comp->Cost += file->FileSize;
2726                     }
2727                     else
2728                         file->State = 3;
2729                     HeapFree(GetProcessHeap(),0,version);
2730                 }
2731                 else
2732                     file->State = 3;
2733             }
2734         } 
2735     }
2736
2737     TRACE("Evaluating Condition Table\n");
2738
2739     rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
2740     if (rc == ERROR_SUCCESS)
2741     {
2742         rc = MSI_ViewExecute(view, 0);
2743         if (rc != ERROR_SUCCESS)
2744         {
2745             MSI_ViewClose(view);
2746             msiobj_release(&view->hdr);
2747             return rc;
2748         }
2749     
2750         while (1)
2751         {
2752             LPCWSTR Feature;
2753             MSIRECORD * row = 0;
2754             int feature_index;
2755
2756             rc = MSI_ViewFetch(view,&row);
2757
2758             if (rc != ERROR_SUCCESS)
2759             {
2760                 rc = ERROR_SUCCESS;
2761                 break;
2762             }
2763
2764             Feature = MSI_RecordGetString(row,1);
2765
2766             feature_index = get_loaded_feature(package,Feature);
2767             if (feature_index < 0)
2768                 ERR("FAILED to find loaded feature %s\n",debugstr_w(Feature));
2769             else
2770             {
2771                 LPCWSTR Condition;
2772                 Condition = MSI_RecordGetString(row,3);
2773
2774                 if (MSI_EvaluateConditionW(package,Condition) == 
2775                     MSICONDITION_TRUE)
2776                 {
2777                     int level = MSI_RecordGetInteger(row,2);
2778                     TRACE("Reseting feature %s to level %i\n",
2779                            debugstr_w(Feature), level);
2780                     package->features[feature_index].Level = level;
2781                 }
2782             }
2783
2784             msiobj_release(&row->hdr);
2785         }
2786         MSI_ViewClose(view);
2787         msiobj_release(&view->hdr);
2788     }
2789
2790     TRACE("Enabling or Disabling Components\n");
2791     for (i = 0; i < package->loaded_components; i++)
2792     {
2793         if (package->components[i].Condition[0])
2794         {
2795             if (MSI_EvaluateConditionW(package,
2796                 package->components[i].Condition) == MSICONDITION_FALSE)
2797             {
2798                 TRACE("Disabling component %s\n",
2799                       debugstr_w(package->components[i].Component));
2800                 package->components[i].Enabled = FALSE;
2801             }
2802         }
2803     }
2804
2805     MSI_SetPropertyW(package,szCosting,szOne);
2806     /* set default run level if not set */
2807     level = load_dynamic_property(package,szlevel,NULL);
2808     if (!level)
2809         MSI_SetPropertyW(package,szlevel, szOne);
2810     else
2811         HeapFree(GetProcessHeap(),0,level);
2812
2813     ACTION_UpdateInstallStates(package);
2814
2815     return SetFeatureStates(package);
2816 }
2817
2818 /*
2819  * This is a helper function for handling embedded cabinet media
2820  */
2821 static UINT writeout_cabinet_stream(MSIPACKAGE *package, LPCWSTR stream_name,
2822                                     WCHAR* source)
2823 {
2824     UINT rc;
2825     USHORT* data;
2826     UINT    size;
2827     DWORD   write;
2828     HANDLE  the_file;
2829     WCHAR tmp[MAX_PATH];
2830
2831     rc = read_raw_stream_data(package->db,stream_name,&data,&size); 
2832     if (rc != ERROR_SUCCESS)
2833         return rc;
2834
2835     write = MAX_PATH;
2836     if (MSI_GetPropertyW(package, cszTempFolder, tmp, &write))
2837         GetTempPathW(MAX_PATH,tmp);
2838
2839     GetTempFileNameW(tmp,stream_name,0,source);
2840
2841     track_tempfile(package,strrchrW(source,'\\'), source);
2842     the_file = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
2843                            FILE_ATTRIBUTE_NORMAL, NULL);
2844
2845     if (the_file == INVALID_HANDLE_VALUE)
2846     {
2847         ERR("Unable to create file %s\n",debugstr_w(source));
2848         rc = ERROR_FUNCTION_FAILED;
2849         goto end;
2850     }
2851
2852     WriteFile(the_file,data,size,&write,NULL);
2853     CloseHandle(the_file);
2854     TRACE("wrote %li bytes to %s\n",write,debugstr_w(source));
2855 end:
2856     HeapFree(GetProcessHeap(),0,data);
2857     return rc;
2858 }
2859
2860
2861 /* Support functions for FDI functions */
2862 typedef struct
2863 {
2864     MSIPACKAGE* package;
2865     LPCSTR cab_path;
2866     LPCSTR file_name;
2867 } CabData;
2868
2869 static void * cabinet_alloc(ULONG cb)
2870 {
2871     return HeapAlloc(GetProcessHeap(), 0, cb);
2872 }
2873
2874 static void cabinet_free(void *pv)
2875 {
2876     HeapFree(GetProcessHeap(), 0, pv);
2877 }
2878
2879 static INT_PTR cabinet_open(char *pszFile, int oflag, int pmode)
2880 {
2881     DWORD dwAccess = 0;
2882     DWORD dwShareMode = 0;
2883     DWORD dwCreateDisposition = OPEN_EXISTING;
2884     switch (oflag & _O_ACCMODE)
2885     {
2886     case _O_RDONLY:
2887         dwAccess = GENERIC_READ;
2888         dwShareMode = FILE_SHARE_READ | FILE_SHARE_DELETE;
2889         break;
2890     case _O_WRONLY:
2891         dwAccess = GENERIC_WRITE;
2892         dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2893         break;
2894     case _O_RDWR:
2895         dwAccess = GENERIC_READ | GENERIC_WRITE;
2896         dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2897         break;
2898     }
2899     if ((oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))
2900         dwCreateDisposition = CREATE_NEW;
2901     else if (oflag & _O_CREAT)
2902         dwCreateDisposition = CREATE_ALWAYS;
2903     return (INT_PTR)CreateFileA(pszFile, dwAccess, dwShareMode, NULL, 
2904                                 dwCreateDisposition, 0, NULL);
2905 }
2906
2907 static UINT cabinet_read(INT_PTR hf, void *pv, UINT cb)
2908 {
2909     DWORD dwRead;
2910     if (ReadFile((HANDLE)hf, pv, cb, &dwRead, NULL))
2911         return dwRead;
2912     return 0;
2913 }
2914
2915 static UINT cabinet_write(INT_PTR hf, void *pv, UINT cb)
2916 {
2917     DWORD dwWritten;
2918     if (WriteFile((HANDLE)hf, pv, cb, &dwWritten, NULL))
2919         return dwWritten;
2920     return 0;
2921 }
2922
2923 static int cabinet_close(INT_PTR hf)
2924 {
2925     return CloseHandle((HANDLE)hf) ? 0 : -1;
2926 }
2927
2928 static long cabinet_seek(INT_PTR hf, long dist, int seektype)
2929 {
2930     /* flags are compatible and so are passed straight through */
2931     return SetFilePointer((HANDLE)hf, dist, NULL, seektype);
2932 }
2933
2934 static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
2935 {
2936     /* FIXME: try to do more processing in this function */
2937     switch (fdint)
2938     {
2939     case fdintCOPY_FILE:
2940     {
2941         CabData *data = (CabData*) pfdin->pv;
2942         ULONG len = strlen(data->cab_path) + strlen(pfdin->psz1);
2943         char *file;
2944
2945         LPWSTR trackname;
2946         LPWSTR trackpath;
2947         LPWSTR tracknametmp;
2948         static const WCHAR tmpprefix[] = {'C','A','B','T','M','P','_',0};
2949        
2950         if (data->file_name && lstrcmpiA(data->file_name,pfdin->psz1))
2951                 return 0;
2952         
2953         file = cabinet_alloc((len+1)*sizeof(char));
2954         strcpy(file, data->cab_path);
2955         strcat(file, pfdin->psz1);
2956
2957         TRACE("file: %s\n", debugstr_a(file));
2958
2959         /* track this file so it can be deleted if not installed */
2960         trackpath=strdupAtoW(file);
2961         tracknametmp=strdupAtoW(strrchr(file,'\\')+1);
2962         trackname = HeapAlloc(GetProcessHeap(),0,(strlenW(tracknametmp) + 
2963                                   strlenW(tmpprefix)+1) * sizeof(WCHAR));
2964
2965         strcpyW(trackname,tmpprefix);
2966         strcatW(trackname,tracknametmp);
2967
2968         track_tempfile(data->package, trackname, trackpath);
2969
2970         HeapFree(GetProcessHeap(),0,trackpath);
2971         HeapFree(GetProcessHeap(),0,trackname);
2972         HeapFree(GetProcessHeap(),0,tracknametmp);
2973
2974         return cabinet_open(file, _O_WRONLY | _O_CREAT, 0);
2975     }
2976     case fdintCLOSE_FILE_INFO:
2977     {
2978         FILETIME ft;
2979             FILETIME ftLocal;
2980         if (!DosDateTimeToFileTime(pfdin->date, pfdin->time, &ft))
2981             return -1;
2982         if (!LocalFileTimeToFileTime(&ft, &ftLocal))
2983             return -1;
2984         if (!SetFileTime((HANDLE)pfdin->hf, &ftLocal, 0, &ftLocal))
2985             return -1;
2986
2987         cabinet_close(pfdin->hf);
2988         return 1;
2989     }
2990     default:
2991         return 0;
2992     }
2993 }
2994
2995 /***********************************************************************
2996  *            extract_cabinet_file
2997  *
2998  * Extract files from a cab file.
2999  */
3000 static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source, 
3001                                  const WCHAR* path, const WCHAR* file)
3002 {
3003     HFDI hfdi;
3004     ERF erf;
3005     BOOL ret;
3006     char *cabinet;
3007     char *cab_path;
3008     char *file_name;
3009     CabData data;
3010
3011     TRACE("Extracting %s (%s) to %s\n",debugstr_w(source), 
3012                     debugstr_w(file), debugstr_w(path));
3013
3014     hfdi = FDICreate(cabinet_alloc,
3015                      cabinet_free,
3016                      cabinet_open,
3017                      cabinet_read,
3018                      cabinet_write,
3019                      cabinet_close,
3020                      cabinet_seek,
3021                      0,
3022                      &erf);
3023     if (!hfdi)
3024     {
3025         ERR("FDICreate failed\n");
3026         return FALSE;
3027     }
3028
3029     if (!(cabinet = strdupWtoA( source )))
3030     {
3031         FDIDestroy(hfdi);
3032         return FALSE;
3033     }
3034     if (!(cab_path = strdupWtoA( path )))
3035     {
3036         FDIDestroy(hfdi);
3037         HeapFree(GetProcessHeap(), 0, cabinet);
3038         return FALSE;
3039     }
3040
3041     data.package = package;
3042     data.cab_path = cab_path;
3043     if (file)
3044         file_name = strdupWtoA(file);
3045     else
3046         file_name = NULL;
3047     data.file_name = file_name;
3048
3049     ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);
3050
3051     if (!ret)
3052         ERR("FDICopy failed\n");
3053
3054     FDIDestroy(hfdi);
3055
3056     HeapFree(GetProcessHeap(), 0, cabinet);
3057     HeapFree(GetProcessHeap(), 0, cab_path);
3058     HeapFree(GetProcessHeap(), 0, file_name);
3059
3060     return ret;
3061 }
3062
3063 static UINT ready_media_for_file(MSIPACKAGE *package, WCHAR* path, 
3064                                  MSIFILE* file)
3065 {
3066     UINT rc = ERROR_SUCCESS;
3067     MSIRECORD * row = 0;
3068     static WCHAR source[MAX_PATH];
3069     static const WCHAR ExecSeqQuery[] =
3070         {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3071          '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
3072          '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ','>','=',
3073          ' ','%', 'i',' ','O','R','D','E','R',' ','B','Y',' ',
3074          '`','L','a','s','t','S','e','q','u','e','n','c','e','`',0};
3075     LPCWSTR cab;
3076     DWORD sz;
3077     INT seq;
3078     static UINT last_sequence = 0; 
3079
3080     if (file->Attributes & msidbFileAttributesNoncompressed)
3081     {
3082         TRACE("Uncompressed File, no media to ready.\n");
3083         return ERROR_SUCCESS;
3084     }
3085
3086     if (file->Sequence <= last_sequence)
3087     {
3088         TRACE("Media already ready (%u, %u)\n",file->Sequence,last_sequence);
3089         /*extract_a_cabinet_file(package, source,path,file->File); */
3090         return ERROR_SUCCESS;
3091     }
3092
3093     row = MSI_QueryGetRecord(package->db, ExecSeqQuery, file->Sequence);
3094     if (!row)
3095         return ERROR_FUNCTION_FAILED;
3096
3097     seq = MSI_RecordGetInteger(row,2);
3098     last_sequence = seq;
3099
3100     cab = MSI_RecordGetString(row,4);
3101     if (cab)
3102     {
3103         TRACE("Source is CAB %s\n",debugstr_w(cab));
3104         /* the stream does not contain the # character */
3105         if (cab[0]=='#')
3106         {
3107             writeout_cabinet_stream(package,&cab[1],source);
3108             strcpyW(path,source);
3109             *(strrchrW(path,'\\')+1)=0;
3110         }
3111         else
3112         {
3113             sz = MAX_PATH;
3114             if (MSI_GetPropertyW(package, cszSourceDir, source, &sz))
3115             {
3116                 ERR("No Source dir defined \n");
3117                 rc = ERROR_FUNCTION_FAILED;
3118             }
3119             else
3120             {
3121                 strcpyW(path,source);
3122                 strcatW(source,cab);
3123                 /* extract the cab file into a folder in the temp folder */
3124                 sz = MAX_PATH;
3125                 if (MSI_GetPropertyW(package, cszTempFolder,path, &sz) 
3126                                     != ERROR_SUCCESS)
3127                     GetTempPathW(MAX_PATH,path);
3128             }
3129         }
3130         rc = !extract_a_cabinet_file(package, source,path,NULL);
3131     }
3132     else
3133     {
3134         sz = MAX_PATH;
3135         MSI_GetPropertyW(package,cszSourceDir,source,&sz);
3136         strcpyW(path,source);
3137     }
3138     msiobj_release(&row->hdr);
3139     return rc;
3140 }
3141
3142 inline static UINT create_component_directory ( MSIPACKAGE* package, INT component)
3143 {
3144     UINT rc = ERROR_SUCCESS;
3145     MSIFOLDER *folder;
3146     LPWSTR install_path;
3147
3148     install_path = resolve_folder(package, package->components[component].Directory,
3149                         FALSE, FALSE, &folder);
3150     if (!install_path)
3151         return ERROR_FUNCTION_FAILED; 
3152
3153     /* create the path */
3154     if (folder->State == 0)
3155     {
3156         create_full_pathW(install_path);
3157         folder->State = 2;
3158     }
3159     HeapFree(GetProcessHeap(), 0, install_path);
3160
3161     return rc;
3162 }
3163
3164 static UINT ACTION_InstallFiles(MSIPACKAGE *package)
3165 {
3166     UINT rc = ERROR_SUCCESS;
3167     DWORD index;
3168     MSIRECORD * uirow;
3169     WCHAR uipath[MAX_PATH];
3170
3171     if (!package)
3172         return ERROR_INVALID_HANDLE;
3173
3174     /* increment progress bar each time action data is sent */
3175     ui_progress(package,1,1,0,0);
3176
3177     for (index = 0; index < package->loaded_files; index++)
3178     {
3179         WCHAR path_to_source[MAX_PATH];
3180         MSIFILE *file;
3181         
3182         file = &package->files[index];
3183
3184         if (file->Temporary)
3185             continue;
3186
3187
3188         if (!ACTION_VerifyComponentForAction(package, file->ComponentIndex, 
3189                                        INSTALLSTATE_LOCAL))
3190         {
3191             ui_progress(package,2,file->FileSize,0,0);
3192             TRACE("File %s is not scheduled for install\n",
3193                    debugstr_w(file->File));
3194
3195             continue;
3196         }
3197
3198         if ((file->State == 1) || (file->State == 2))
3199         {
3200             LPWSTR p;
3201             MSICOMPONENT* comp = NULL;
3202
3203             TRACE("Installing %s\n",debugstr_w(file->File));
3204             rc = ready_media_for_file(package, path_to_source, file);
3205             /* 
3206              * WARNING!
3207              * our file table could change here because a new temp file
3208              * may have been created
3209              */
3210             file = &package->files[index];
3211             if (rc != ERROR_SUCCESS)
3212             {
3213                 ERR("Unable to ready media\n");
3214                 rc = ERROR_FUNCTION_FAILED;
3215                 break;
3216             }
3217
3218             create_component_directory( package, file->ComponentIndex);
3219
3220             /* recalculate file paths because things may have changed */
3221
3222             if (file->ComponentIndex >= 0)
3223                 comp = &package->components[file->ComponentIndex];
3224
3225             p = resolve_folder(package, comp->Directory, FALSE, FALSE, NULL);
3226             HeapFree(GetProcessHeap(),0,file->TargetPath);
3227
3228             file->TargetPath = build_directory_name(2, p, file->FileName);
3229             HeapFree(GetProcessHeap(),0,p);
3230
3231             if (file->Attributes & msidbFileAttributesNoncompressed)
3232             {
3233                 p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
3234                 file->SourcePath = build_directory_name(2, p, file->ShortName);
3235                 HeapFree(GetProcessHeap(),0,p);
3236             }
3237             else
3238                 file->SourcePath = build_directory_name(2, path_to_source, 
3239                             file->File);
3240
3241
3242             TRACE("file paths %s to %s\n",debugstr_w(file->SourcePath),
3243                   debugstr_w(file->TargetPath));
3244
3245             /* the UI chunk */
3246             uirow=MSI_CreateRecord(9);
3247             MSI_RecordSetStringW(uirow,1,file->File);
3248             strcpyW(uipath,file->TargetPath);
3249             *(strrchrW(uipath,'\\')+1)=0;
3250             MSI_RecordSetStringW(uirow,9,uipath);
3251             MSI_RecordSetInteger(uirow,6,file->FileSize);
3252             ui_actiondata(package,szInstallFiles,uirow);
3253             msiobj_release( &uirow->hdr );
3254             ui_progress(package,2,file->FileSize,0,0);
3255
3256             
3257             if (file->Attributes & msidbFileAttributesNoncompressed)
3258                 rc = CopyFileW(file->SourcePath,file->TargetPath,FALSE);
3259             else
3260                 rc = MoveFileW(file->SourcePath, file->TargetPath);
3261
3262             if (!rc)
3263             {
3264                 rc = GetLastError();
3265                 ERR("Unable to move/copy file (%s -> %s) (error %d)\n",
3266                      debugstr_w(file->SourcePath), debugstr_w(file->TargetPath),
3267                       rc);
3268                 if (rc == ERROR_ALREADY_EXISTS && file->State == 2)
3269                 {
3270                     if (!CopyFileW(file->SourcePath,file->TargetPath,FALSE))
3271                         ERR("Unable to copy file (%s -> %s) (error %ld)\n",
3272                             debugstr_w(file->SourcePath), 
3273                             debugstr_w(file->TargetPath), GetLastError());
3274                     if (!(file->Attributes & msidbFileAttributesNoncompressed))
3275                         DeleteFileW(file->SourcePath);
3276                     rc = 0;
3277                 }
3278                 else if (rc == ERROR_FILE_NOT_FOUND)
3279                 {
3280                     ERR("Source File Not Found!  Continuing\n");
3281                     rc = 0;
3282                 }
3283                 else if (file->Attributes & msidbFileAttributesVital)
3284                 {
3285                     ERR("Ignoring Error and continuing (nonvital file)...\n");
3286                     rc = 0;
3287                 }
3288             }
3289             else
3290             {
3291                 file->State = 4;
3292                 rc = ERROR_SUCCESS;
3293             }
3294         }
3295     }
3296
3297     return rc;
3298 }
3299
3300 inline static UINT get_file_target(MSIPACKAGE *package, LPCWSTR file_key, 
3301                                    LPWSTR* file_source)
3302 {
3303     DWORD index;
3304
3305     if (!package)
3306         return ERROR_INVALID_HANDLE;
3307
3308     for (index = 0; index < package->loaded_files; index ++)
3309     {
3310         if (strcmpW(file_key,package->files[index].File)==0)
3311         {
3312             if (package->files[index].State >= 2)
3313             {
3314                 *file_source = strdupW(package->files[index].TargetPath);
3315                 return ERROR_SUCCESS;
3316             }
3317             else
3318                 return ERROR_FILE_NOT_FOUND;
3319         }
3320     }
3321
3322     return ERROR_FUNCTION_FAILED;
3323 }
3324
3325 static UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
3326 {
3327     UINT rc;
3328     MSIQUERY * view;
3329     MSIRECORD * row = 0;
3330     static const WCHAR ExecSeqQuery[] =
3331         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3332          '`','D','u','p','l','i','c','a','t','e','F','i','l','e','`',0};
3333
3334     if (!package)
3335         return ERROR_INVALID_HANDLE;
3336
3337     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3338     if (rc != ERROR_SUCCESS)
3339         return ERROR_SUCCESS;
3340
3341     rc = MSI_ViewExecute(view, 0);
3342     if (rc != ERROR_SUCCESS)
3343     {
3344         MSI_ViewClose(view);
3345         msiobj_release(&view->hdr);
3346         return rc;
3347     }
3348
3349     while (1)
3350     {
3351         WCHAR *file_source = NULL;
3352         WCHAR dest_name[0x100];
3353         LPWSTR dest_path, dest;
3354         LPCWSTR file_key, component;
3355         INT component_index;
3356
3357         DWORD sz;
3358
3359         rc = MSI_ViewFetch(view,&row);
3360         if (rc != ERROR_SUCCESS)
3361         {
3362             rc = ERROR_SUCCESS;
3363             break;
3364         }
3365
3366         component = MSI_RecordGetString(row,2);
3367         component_index = get_loaded_component(package,component);
3368
3369         if (!ACTION_VerifyComponentForAction(package, component_index, 
3370                                        INSTALLSTATE_LOCAL))
3371         {
3372             TRACE("Skipping copy due to disabled component %s\n",
3373                             debugstr_w(component));
3374
3375             /* the action taken was the same as the current install state */        
3376             package->components[component_index].Action =
3377                 package->components[component_index].Installed;
3378
3379             msiobj_release(&row->hdr);
3380             continue;
3381         }
3382
3383         package->components[component_index].Action = INSTALLSTATE_LOCAL;
3384
3385         file_key = MSI_RecordGetString(row,3);
3386         if (!file_key)
3387         {
3388             ERR("Unable to get file key\n");
3389             msiobj_release(&row->hdr);
3390             break;
3391         }
3392
3393         rc = get_file_target(package,file_key,&file_source);
3394
3395         if (rc != ERROR_SUCCESS)
3396         {
3397             ERR("Original file unknown %s\n",debugstr_w(file_key));
3398             msiobj_release(&row->hdr);
3399             HeapFree(GetProcessHeap(),0,file_source);
3400             continue;
3401         }
3402
3403         if (MSI_RecordIsNull(row,4))
3404         {
3405             strcpyW(dest_name,strrchrW(file_source,'\\')+1);
3406         }
3407         else
3408         {
3409             sz=0x100;
3410             MSI_RecordGetStringW(row,4,dest_name,&sz);
3411             reduce_to_longfilename(dest_name);
3412          }
3413
3414         if (MSI_RecordIsNull(row,5))
3415         {
3416             LPWSTR p;
3417             dest_path = strdupW(file_source);
3418             p = strrchrW(dest_path,'\\');
3419             if (p)
3420                 *p=0;
3421         }
3422         else
3423         {
3424             LPCWSTR destkey;
3425             destkey = MSI_RecordGetString(row,5);
3426             dest_path = resolve_folder(package, destkey, FALSE,FALSE,NULL);
3427             if (!dest_path)
3428             {
3429                 ERR("Unable to get destination folder\n");
3430                 msiobj_release(&row->hdr);
3431                 HeapFree(GetProcessHeap(),0,file_source);
3432                 break;
3433             }
3434         }
3435
3436         dest = build_directory_name(2, dest_path, dest_name);
3437            
3438         TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),
3439               debugstr_w(dest)); 
3440         
3441         if (strcmpW(file_source,dest))
3442             rc = !CopyFileW(file_source,dest,TRUE);
3443         else
3444             rc = ERROR_SUCCESS;
3445         
3446         if (rc != ERROR_SUCCESS)
3447             ERR("Failed to copy file %s -> %s, last error %ld\n", debugstr_w(file_source), debugstr_w(dest_path), GetLastError());
3448
3449         FIXME("We should track these duplicate files as well\n");   
3450  
3451         msiobj_release(&row->hdr);
3452         HeapFree(GetProcessHeap(),0,dest_path);
3453         HeapFree(GetProcessHeap(),0,dest);
3454         HeapFree(GetProcessHeap(),0,file_source);
3455     }
3456     MSI_ViewClose(view);
3457     msiobj_release(&view->hdr);
3458     return rc;
3459 }
3460
3461
3462 /* OK this value is "interpreted" and then formatted based on the 
3463    first few characters */
3464 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type, 
3465                          DWORD *size)
3466 {
3467     LPSTR data = NULL;
3468     if (value[0]=='#' && value[1]!='#' && value[1]!='%')
3469     {
3470         if (value[1]=='x')
3471         {
3472             LPWSTR ptr;
3473             CHAR byte[5];
3474             LPWSTR deformated = NULL;
3475             int count;
3476
3477             deformat_string(package, &value[2], &deformated);
3478
3479             /* binary value type */
3480             ptr = deformated;
3481             *type = REG_BINARY;
3482             if (strlenW(ptr)%2)
3483                 *size = (strlenW(ptr)/2)+1;
3484             else
3485                 *size = strlenW(ptr)/2;
3486
3487             data = HeapAlloc(GetProcessHeap(),0,*size);
3488
3489             byte[0] = '0'; 
3490             byte[1] = 'x'; 
3491             byte[4] = 0; 
3492             count = 0;
3493             /* if uneven pad with a zero in front */
3494             if (strlenW(ptr)%2)
3495             {
3496                 byte[2]= '0';
3497                 byte[3]= *ptr;
3498                 ptr++;
3499                 data[count] = (BYTE)strtol(byte,NULL,0);
3500                 count ++;
3501                 TRACE("Uneven byte count\n");
3502             }
3503             while (*ptr)
3504             {
3505                 byte[2]= *ptr;
3506                 ptr++;
3507                 byte[3]= *ptr;
3508                 ptr++;
3509                 data[count] = (BYTE)strtol(byte,NULL,0);
3510                 count ++;
3511             }
3512             HeapFree(GetProcessHeap(),0,deformated);
3513
3514             TRACE("Data %li bytes(%i)\n",*size,count);
3515         }
3516         else
3517         {
3518             LPWSTR deformated;
3519             LPWSTR p;
3520             DWORD d = 0;
3521             deformat_string(package, &value[1], &deformated);
3522
3523             *type=REG_DWORD; 
3524             *size = sizeof(DWORD);
3525             data = HeapAlloc(GetProcessHeap(),0,*size);
3526             p = deformated;
3527             if (*p == '-')
3528                 p++;
3529             while (*p)
3530             {
3531                 if ( (*p < '0') || (*p > '9') )
3532                     break;
3533                 d *= 10;
3534                 d += (*p - '0');
3535                 p++;
3536             }
3537             if (deformated[0] == '-')
3538                 d = -d;
3539             *(LPDWORD)data = d;
3540             TRACE("DWORD %li\n",*(LPDWORD)data);
3541
3542             HeapFree(GetProcessHeap(),0,deformated);
3543         }
3544     }
3545     else
3546     {
3547         static const WCHAR szMulti[] = {'[','~',']',0};
3548         LPCWSTR ptr;
3549         *type=REG_SZ;
3550
3551         if (value[0]=='#')
3552         {
3553             if (value[1]=='%')
3554             {
3555                 ptr = &value[2];
3556                 *type=REG_EXPAND_SZ;
3557             }
3558             else
3559                 ptr = &value[1];
3560          }
3561          else
3562             ptr=value;
3563
3564         if (strstrW(value,szMulti))
3565             *type = REG_MULTI_SZ;
3566
3567         *size = deformat_string(package, ptr,(LPWSTR*)&data);
3568     }
3569     return data;
3570 }
3571
3572 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
3573 {
3574     UINT rc;
3575     MSIQUERY * view;
3576     MSIRECORD * row = 0;
3577     static const WCHAR ExecSeqQuery[] =
3578         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3579          '`','R','e','g','i','s','t','r','y','`',0 };
3580
3581     if (!package)
3582         return ERROR_INVALID_HANDLE;
3583
3584     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3585     if (rc != ERROR_SUCCESS)
3586         return ERROR_SUCCESS;
3587
3588     rc = MSI_ViewExecute(view, 0);
3589     if (rc != ERROR_SUCCESS)
3590     {
3591         MSI_ViewClose(view);
3592         msiobj_release(&view->hdr);
3593         return rc;
3594     }
3595
3596     /* increment progress bar each time action data is sent */
3597     ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
3598
3599     while (1)
3600     {
3601         static const WCHAR szHCR[] = 
3602             {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
3603              'R','O','O','T','\\',0};
3604         static const WCHAR szHCU[] =
3605             {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
3606              'U','S','E','R','\\',0};
3607         static const WCHAR szHLM[] =
3608             {'H','K','E','Y','_','L','O','C','A','L','_',
3609              'M','A','C','H','I','N','E','\\',0};
3610         static const WCHAR szHU[] =
3611             {'H','K','E','Y','_','U','S','E','R','S','\\',0};
3612
3613         LPSTR value_data = NULL;
3614         HKEY  root_key, hkey;
3615         DWORD type,size;
3616         LPWSTR  deformated;
3617         LPCWSTR szRoot, component, name, key, value;
3618         INT component_index;
3619         MSIRECORD * uirow;
3620         LPWSTR uikey;
3621         INT   root;
3622         BOOL check_first = FALSE;
3623
3624         rc = MSI_ViewFetch(view,&row);
3625         if (rc != ERROR_SUCCESS)
3626         {
3627             rc = ERROR_SUCCESS;
3628             break;
3629         }
3630         ui_progress(package,2,0,0,0);
3631
3632         value = NULL;
3633         key = NULL;
3634         uikey = NULL;
3635         name = NULL;
3636
3637         component = MSI_RecordGetString(row, 6);
3638         component_index = get_loaded_component(package,component);
3639
3640         if (!ACTION_VerifyComponentForAction(package, component_index, 
3641                                        INSTALLSTATE_LOCAL))
3642         {
3643             TRACE("Skipping write due to disabled component %s\n", 
3644                             debugstr_w(component));
3645             msiobj_release(&row->hdr);
3646
3647             package->components[component_index].Action =
3648                 package->components[component_index].Installed;
3649
3650             goto next;
3651         }
3652
3653         package->components[component_index].Action = INSTALLSTATE_LOCAL;
3654
3655         name = MSI_RecordGetString(row, 4);
3656         if( MSI_RecordIsNull(row,5) && name )
3657         {
3658             /* null values can have special meanings */
3659             if (name[0]=='-' && name[1] == 0)
3660             {
3661                 msiobj_release(&row->hdr);
3662                 goto next;
3663             }
3664             else if ((name[0]=='+' && name[1] == 0) || 
3665                      (name[0] == '*' && name[1] == 0))
3666                 name = NULL;
3667                 check_first = TRUE;
3668         }
3669
3670         root = MSI_RecordGetInteger(row,2);
3671         key = MSI_RecordGetString(row, 3);
3672    
3673         /* get the root key */
3674         switch (root)
3675         {
3676             case 0:  root_key = HKEY_CLASSES_ROOT; 
3677                      szRoot = szHCR;
3678                      break;
3679             case 1:  root_key = HKEY_CURRENT_USER;
3680                      szRoot = szHCU;
3681                      break;
3682             case 2:  root_key = HKEY_LOCAL_MACHINE;
3683                      szRoot = szHLM;
3684                      break;
3685             case 3:  root_key = HKEY_USERS; 
3686                      szRoot = szHU;
3687                      break;
3688             default:
3689                  ERR("Unknown root %i\n",root);
3690                  root_key=NULL;
3691                  szRoot = NULL;
3692                  break;
3693         }
3694         if (!root_key)
3695         {
3696             msiobj_release(&row->hdr);
3697             goto next;
3698         }
3699
3700         deformat_string(package, key , &deformated);
3701         size = strlenW(deformated) + strlenW(szRoot) + 1;
3702         uikey = HeapAlloc(GetProcessHeap(), 0, size*sizeof(WCHAR));
3703         strcpyW(uikey,szRoot);
3704         strcatW(uikey,deformated);
3705
3706         if (RegCreateKeyW( root_key, deformated, &hkey))
3707         {
3708             ERR("Could not create key %s\n",debugstr_w(deformated));
3709             msiobj_release(&row->hdr);
3710             HeapFree(GetProcessHeap(),0,deformated);
3711             goto next;
3712         }
3713         HeapFree(GetProcessHeap(),0,deformated);
3714
3715         value = MSI_RecordGetString(row,5);
3716         if (value)
3717             value_data = parse_value(package, value, &type, &size); 
3718         else
3719         {
3720             static const WCHAR szEmpty[] = {0};
3721             value_data = (LPSTR)strdupW(szEmpty);
3722             size = 0;
3723             type = REG_SZ;
3724         }
3725
3726         deformat_string(package, name, &deformated);
3727
3728         /* get the double nulls to terminate SZ_MULTI */
3729         if (type == REG_MULTI_SZ)
3730             size +=sizeof(WCHAR);
3731
3732         if (!check_first)
3733         {
3734             TRACE("Setting value %s of %s\n",debugstr_w(deformated),
3735                             debugstr_w(uikey));
3736             RegSetValueExW(hkey, deformated, 0, type, value_data, size);
3737         }
3738         else
3739         {
3740             DWORD sz = 0;
3741             rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
3742             if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
3743             {
3744                 TRACE("value %s of %s checked already exists\n",
3745                                 debugstr_w(deformated), debugstr_w(uikey));
3746             }
3747             else
3748             {
3749                 TRACE("Checked and setting value %s of %s\n",
3750                                 debugstr_w(deformated), debugstr_w(uikey));
3751                 if (deformated || size)
3752                     RegSetValueExW(hkey, deformated, 0, type, value_data, size);
3753             }
3754         }
3755
3756         uirow = MSI_CreateRecord(3);
3757         MSI_RecordSetStringW(uirow,2,deformated);
3758         MSI_RecordSetStringW(uirow,1,uikey);
3759
3760         if (type == REG_SZ)
3761             MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
3762         else
3763             MSI_RecordSetStringW(uirow,3,value);
3764
3765         ui_actiondata(package,szWriteRegistryValues,uirow);
3766         msiobj_release( &uirow->hdr );
3767
3768         HeapFree(GetProcessHeap(),0,value_data);
3769         HeapFree(GetProcessHeap(),0,deformated);
3770
3771         msiobj_release(&row->hdr);
3772         RegCloseKey(hkey);
3773 next:
3774         HeapFree(GetProcessHeap(),0,uikey);
3775     }
3776     MSI_ViewClose(view);
3777     msiobj_release(&view->hdr);
3778     return rc;
3779 }
3780
3781 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
3782 {
3783     package->script->CurrentlyScripting = TRUE;
3784
3785     return ERROR_SUCCESS;
3786 }
3787
3788
3789 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
3790 {
3791     DWORD progress = 0;
3792     DWORD total = 0;
3793     static const WCHAR q1[]=
3794         {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
3795          '`','R','e','g','i','s','t','r','y','`',0};
3796     UINT rc;
3797     MSIQUERY * view;
3798     MSIRECORD * row = 0;
3799     int i;
3800
3801     TRACE(" InstallValidate \n");
3802
3803     rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
3804     if (rc != ERROR_SUCCESS)
3805         return ERROR_SUCCESS;
3806
3807     rc = MSI_ViewExecute(view, 0);
3808     if (rc != ERROR_SUCCESS)
3809     {
3810         MSI_ViewClose(view);
3811         msiobj_release(&view->hdr);
3812         return rc;
3813     }
3814     while (1)
3815     {
3816         rc = MSI_ViewFetch(view,&row);
3817         if (rc != ERROR_SUCCESS)
3818         {
3819             rc = ERROR_SUCCESS;
3820             break;
3821         }
3822         progress +=1;
3823
3824         msiobj_release(&row->hdr);
3825     }
3826     MSI_ViewClose(view);
3827     msiobj_release(&view->hdr);
3828
3829     total = total + progress * REG_PROGRESS_VALUE;
3830     total = total + package->loaded_components * COMPONENT_PROGRESS_VALUE;
3831     for (i=0; i < package->loaded_files; i++)
3832         total += package->files[i].FileSize;
3833     ui_progress(package,0,total,0,0);
3834
3835     for(i = 0; i < package->loaded_features; i++)
3836     {
3837         MSIFEATURE* feature = &package->features[i];
3838         TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
3839             debugstr_w(feature->Feature), feature->Installed, feature->Action,
3840             feature->ActionRequest);
3841     }
3842     
3843     return ERROR_SUCCESS;
3844 }
3845
3846 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
3847 {
3848     UINT rc;
3849     MSIQUERY * view = NULL;
3850     MSIRECORD * row = 0;
3851     static const WCHAR ExecSeqQuery[] =
3852         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3853          '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
3854     static const WCHAR title[]=
3855         {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
3856
3857     TRACE("Checking launch conditions\n");
3858
3859     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3860     if (rc != ERROR_SUCCESS)
3861         return ERROR_SUCCESS;
3862
3863     rc = MSI_ViewExecute(view, 0);
3864     if (rc != ERROR_SUCCESS)
3865     {
3866         MSI_ViewClose(view);
3867         msiobj_release(&view->hdr);
3868         return rc;
3869     }
3870
3871     rc = ERROR_SUCCESS;
3872     while (rc == ERROR_SUCCESS)
3873     {
3874         LPCWSTR cond = NULL; 
3875         LPCWSTR message = NULL;
3876
3877         rc = MSI_ViewFetch(view,&row);
3878         if (rc != ERROR_SUCCESS)
3879         {
3880             rc = ERROR_SUCCESS;
3881             break;
3882         }
3883
3884         cond = MSI_RecordGetString(row,1);
3885
3886         if (MSI_EvaluateConditionW(package,cond) != MSICONDITION_TRUE)
3887         {
3888             LPWSTR deformated;
3889             message = MSI_RecordGetString(row,2);
3890             deformat_string(package,message,&deformated); 
3891             MessageBoxW(NULL,deformated,title,MB_OK);
3892             HeapFree(GetProcessHeap(),0,deformated);
3893             rc = ERROR_FUNCTION_FAILED;
3894         }
3895         msiobj_release(&row->hdr);
3896     }
3897     MSI_ViewClose(view);
3898     msiobj_release(&view->hdr);
3899     return rc;
3900 }
3901
3902 static LPWSTR resolve_keypath( MSIPACKAGE* package, INT
3903                             component_index)
3904 {
3905     MSICOMPONENT* cmp = &package->components[component_index];
3906
3907     if (cmp->KeyPath[0]==0)
3908     {
3909         LPWSTR p = resolve_folder(package,cmp->Directory,FALSE,FALSE,NULL);
3910         return p;
3911     }
3912     if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
3913     {
3914         MSIRECORD * row = 0;
3915         UINT root,len;
3916         LPWSTR deformated,buffer,deformated_name;
3917         LPCWSTR key,name;
3918         static const WCHAR ExecSeqQuery[] =
3919             {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3920              '`','R','e','g','i','s','t','r','y','`',' ',
3921              'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
3922              ' ','=',' ' ,'\'','%','s','\'',0 };
3923         static const WCHAR fmt[]={'%','0','2','i',':','\\','%','s','\\',0};
3924         static const WCHAR fmt2[]=
3925             {'%','0','2','i',':','\\','%','s','\\','%','s',0};
3926
3927         row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
3928         if (!row)
3929             return NULL;
3930
3931         root = MSI_RecordGetInteger(row,2);
3932         key = MSI_RecordGetString(row, 3);
3933         name = MSI_RecordGetString(row, 4);
3934         deformat_string(package, key , &deformated);
3935         deformat_string(package, name, &deformated_name);
3936
3937         len = strlenW(deformated) + 6;
3938         if (deformated_name)
3939             len+=strlenW(deformated_name);
3940
3941         buffer = HeapAlloc(GetProcessHeap(),0, len *sizeof(WCHAR));
3942
3943         if (deformated_name)
3944             sprintfW(buffer,fmt2,root,deformated,deformated_name);
3945         else
3946             sprintfW(buffer,fmt,root,deformated);
3947
3948         HeapFree(GetProcessHeap(),0,deformated);
3949         HeapFree(GetProcessHeap(),0,deformated_name);
3950         msiobj_release(&row->hdr);
3951
3952         return buffer;
3953     }
3954     else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
3955     {
3956         FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
3957         return NULL;
3958     }
3959     else
3960     {
3961         int j;
3962         j = get_loaded_file(package,cmp->KeyPath);
3963
3964         if (j>=0)
3965         {
3966             LPWSTR p = strdupW(package->files[j].TargetPath);
3967             return p;
3968         }
3969     }
3970     return NULL;
3971 }
3972
3973 static HKEY openSharedDLLsKey()
3974 {
3975     HKEY hkey=0;
3976     static const WCHAR path[] =
3977         {'S','o','f','t','w','a','r','e','\\',
3978          'M','i','c','r','o','s','o','f','t','\\',
3979          'W','i','n','d','o','w','s','\\',
3980          'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3981          'S','h','a','r','e','d','D','L','L','s',0};
3982
3983     RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
3984     return hkey;
3985 }
3986
3987 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
3988 {
3989     HKEY hkey;
3990     DWORD count=0;
3991     DWORD type;
3992     DWORD sz = sizeof(count);
3993     DWORD rc;
3994     
3995     hkey = openSharedDLLsKey();
3996     rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
3997     if (rc != ERROR_SUCCESS)
3998         count = 0;
3999     RegCloseKey(hkey);
4000     return count;
4001 }
4002
4003 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
4004 {
4005     HKEY hkey;
4006
4007     hkey = openSharedDLLsKey();
4008     if (count > 0)
4009         RegSetValueExW(hkey,path,0,REG_DWORD,
4010                     (LPBYTE)&count,sizeof(count));
4011     else
4012         RegDeleteValueW(hkey,path);
4013     RegCloseKey(hkey);
4014     return count;
4015 }
4016
4017 /*
4018  * Return TRUE if the count should be written out and FALSE if not
4019  */
4020 static void ACTION_RefCountComponent( MSIPACKAGE* package, UINT index)
4021 {
4022     INT count = 0;
4023     BOOL write = FALSE;
4024     INT j;
4025
4026     /* only refcount DLLs */
4027     if (package->components[index].KeyPath[0]==0 || 
4028         package->components[index].Attributes & 
4029             msidbComponentAttributesRegistryKeyPath || 
4030         package->components[index].Attributes & 
4031             msidbComponentAttributesODBCDataSource)
4032         write = FALSE;
4033     else
4034     {
4035         count = ACTION_GetSharedDLLsCount(package->components[index].
4036                         FullKeypath);
4037         write = (count > 0);
4038
4039         if (package->components[index].Attributes & 
4040                     msidbComponentAttributesSharedDllRefCount)
4041             write = TRUE;
4042     }
4043
4044     /* increment counts */
4045     for (j = 0; j < package->loaded_features; j++)
4046     {
4047         int i;
4048
4049         if (!ACTION_VerifyFeatureForAction(package,j,INSTALLSTATE_LOCAL))
4050             continue;
4051
4052         for (i = 0; i < package->features[j].ComponentCount; i++)
4053         {
4054             if (package->features[j].Components[i] == index)
4055                 count++;
4056         }
4057     }
4058     /* decrement counts */
4059     for (j = 0; j < package->loaded_features; j++)
4060     {
4061         int i;
4062         if (!ACTION_VerifyFeatureForAction(package,j,INSTALLSTATE_ABSENT))
4063             continue;
4064
4065         for (i = 0; i < package->features[j].ComponentCount; i++)
4066         {
4067             if (package->features[j].Components[i] == index)
4068                 count--;
4069         }
4070     }
4071
4072     /* ref count all the files in the component */
4073     if (write)
4074         for (j = 0; j < package->loaded_files; j++)
4075         {
4076             if (package->files[j].Temporary)
4077                 continue;
4078             if (package->files[j].ComponentIndex == index)
4079                 ACTION_WriteSharedDLLsCount(package->files[j].TargetPath,count);
4080         }
4081     
4082     /* add a count for permenent */
4083     if (package->components[index].Attributes &
4084                                 msidbComponentAttributesPermanent)
4085         count ++;
4086     
4087     package->components[index].RefCount = count;
4088
4089     if (write)
4090         ACTION_WriteSharedDLLsCount(package->components[index].FullKeypath,
4091             package->components[index].RefCount);
4092 }
4093
4094 /*
4095  * Ok further analysis makes me think that this work is
4096  * actually done in the PublishComponents and PublishFeatures
4097  * step, and not here.  It appears like the keypath and all that is
4098  * resolved in this step, however actually written in the Publish steps.
4099  * But we will leave it here for now because it is unclear
4100  */
4101 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
4102 {
4103     LPWSTR productcode;
4104     WCHAR squished_pc[GUID_SIZE];
4105     WCHAR squished_cc[GUID_SIZE];
4106     UINT rc;
4107     DWORD i;
4108     HKEY hkey=0,hkey2=0;
4109
4110     if (!package)
4111         return ERROR_INVALID_HANDLE;
4112
4113     /* writes the Component and Features values to the registry */
4114     productcode = load_dynamic_property(package,szProductCode,&rc);
4115     if (!productcode)
4116         return rc;
4117
4118     rc = MSIREG_OpenComponents(&hkey);
4119     if (rc != ERROR_SUCCESS)
4120         goto end;
4121       
4122     squash_guid(productcode,squished_pc);
4123     ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
4124     for (i = 0; i < package->loaded_components; i++)
4125     {
4126         ui_progress(package,2,0,0,0);
4127         if (package->components[i].ComponentId[0]!=0)
4128         {
4129             WCHAR *keypath = NULL;
4130             MSIRECORD * uirow;
4131
4132             squash_guid(package->components[i].ComponentId,squished_cc);
4133            
4134             keypath = resolve_keypath(package,i);
4135             package->components[i].FullKeypath = keypath;
4136
4137             /* do the refcounting */
4138             ACTION_RefCountComponent( package, i);
4139
4140             TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n", 
4141                             debugstr_w(package->components[i].Component),
4142                             debugstr_w(squished_cc),
4143                             debugstr_w(package->components[i].FullKeypath), 
4144                             package->components[i].RefCount);
4145             /*
4146             * Write the keypath out if the component is to be registered
4147             * and delete the key if the component is to be deregistered
4148             */
4149             if (ACTION_VerifyComponentForAction(package, i,
4150                                     INSTALLSTATE_LOCAL))
4151             {
4152                 rc = RegCreateKeyW(hkey,squished_cc,&hkey2);
4153                 if (rc != ERROR_SUCCESS)
4154                     continue;
4155
4156                 if (keypath)
4157                 {
4158                     RegSetValueExW(hkey2,squished_pc,0,REG_SZ,(LPVOID)keypath,
4159                                 (strlenW(keypath)+1)*sizeof(WCHAR));
4160
4161                     if (package->components[i].Attributes & 
4162                                 msidbComponentAttributesPermanent)
4163                     {
4164                         static const WCHAR szPermKey[] =
4165                             { '0','0','0','0','0','0','0','0','0','0','0','0',
4166                               '0','0','0','0','0','0','0', '0','0','0','0','0',
4167                               '0','0','0','0','0','0','0','0',0};
4168
4169                         RegSetValueExW(hkey2,szPermKey,0,REG_SZ,
4170                                         (LPVOID)keypath,
4171                                         (strlenW(keypath)+1)*sizeof(WCHAR));
4172                     }
4173                     
4174                     RegCloseKey(hkey2);
4175         
4176                     /* UI stuff */
4177                     uirow = MSI_CreateRecord(3);
4178                     MSI_RecordSetStringW(uirow,1,productcode);
4179                     MSI_RecordSetStringW(uirow,2,package->components[i].
4180                                                             ComponentId);
4181                     MSI_RecordSetStringW(uirow,3,keypath);
4182                     ui_actiondata(package,szProcessComponents,uirow);
4183                     msiobj_release( &uirow->hdr );
4184                }
4185             }
4186             else if (ACTION_VerifyComponentForAction(package, i,
4187                                     INSTALLSTATE_ABSENT))
4188             {
4189                 DWORD res;
4190
4191                 rc = RegOpenKeyW(hkey,squished_cc,&hkey2);
4192                 if (rc != ERROR_SUCCESS)
4193                     continue;
4194
4195                 RegDeleteValueW(hkey2,squished_pc);
4196
4197                 /* if the key is empty delete it */
4198                 res = RegEnumKeyExW(hkey2,0,NULL,0,0,NULL,0,NULL);
4199                 RegCloseKey(hkey2);
4200                 if (res == ERROR_NO_MORE_ITEMS)
4201                     RegDeleteKeyW(hkey,squished_cc);
4202         
4203                 /* UI stuff */
4204                 uirow = MSI_CreateRecord(2);
4205                 MSI_RecordSetStringW(uirow,1,productcode);
4206                 MSI_RecordSetStringW(uirow,2,package->components[i].
4207                                 ComponentId);
4208                 ui_actiondata(package,szProcessComponents,uirow);
4209                 msiobj_release( &uirow->hdr );
4210             }
4211         }
4212     } 
4213 end:
4214     HeapFree(GetProcessHeap(), 0, productcode);
4215     RegCloseKey(hkey);
4216     return rc;
4217 }
4218
4219 typedef struct {
4220     CLSID       clsid;
4221     LPWSTR      source;
4222
4223     LPWSTR      path;
4224     ITypeLib    *ptLib;
4225 } typelib_struct;
4226
4227 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType, 
4228                                        LPWSTR lpszName, LONG_PTR lParam)
4229 {
4230     TLIBATTR *attr;
4231     typelib_struct *tl_struct = (typelib_struct*) lParam;
4232     static const WCHAR fmt[] = {'%','s','\\','%','i',0};
4233     int sz; 
4234     HRESULT res;
4235
4236     if (!IS_INTRESOURCE(lpszName))
4237     {
4238         ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
4239         return TRUE;
4240     }
4241
4242     sz = strlenW(tl_struct->source)+4;
4243     sz *= sizeof(WCHAR);
4244
4245     if ((INT)lpszName == 1)
4246         tl_struct->path = strdupW(tl_struct->source);
4247     else
4248     {
4249         tl_struct->path = HeapAlloc(GetProcessHeap(),0,sz);
4250         sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
4251     }
4252
4253     TRACE("trying %s\n", debugstr_w(tl_struct->path));
4254     res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
4255     if (!SUCCEEDED(res))
4256     {
4257         HeapFree(GetProcessHeap(),0,tl_struct->path);
4258         tl_struct->path = NULL;
4259
4260         return TRUE;
4261     }
4262
4263     ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
4264     if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
4265     {
4266         ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
4267         return FALSE;
4268     }
4269
4270     HeapFree(GetProcessHeap(),0,tl_struct->path);
4271     tl_struct->path = NULL;
4272
4273     ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
4274     ITypeLib_Release(tl_struct->ptLib);
4275
4276     return TRUE;
4277 }
4278
4279 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
4280 {
4281     /* 
4282      * OK this is a bit confusing.. I am given a _Component key and I believe
4283      * that the file that is being registered as a type library is the "key file
4284      * of that component" which I interpret to mean "The file in the KeyPath of
4285      * that component".
4286      */
4287     UINT rc;
4288     MSIQUERY * view;
4289     MSIRECORD * row = 0;
4290     static const WCHAR Query[] =
4291         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4292          '`','T','y','p','e','L','i','b','`',0};
4293
4294     if (!package)
4295         return ERROR_INVALID_HANDLE;
4296
4297     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
4298     if (rc != ERROR_SUCCESS)
4299         return ERROR_SUCCESS;
4300
4301     rc = MSI_ViewExecute(view, 0);
4302     if (rc != ERROR_SUCCESS)
4303     {
4304         MSI_ViewClose(view);
4305         msiobj_release(&view->hdr);
4306         return rc;
4307     }
4308
4309     while (1)
4310     {   
4311         LPCWSTR component;
4312         INT index;
4313         typelib_struct tl_struct;
4314         HMODULE module;
4315         static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
4316
4317         rc = MSI_ViewFetch(view,&row);
4318         if (rc != ERROR_SUCCESS)
4319         {
4320             rc = ERROR_SUCCESS;
4321             break;
4322         }
4323
4324         component = MSI_RecordGetString(row,3);
4325         index = get_loaded_component(package,component);
4326         if (index < 0)
4327         {
4328             msiobj_release(&row->hdr);
4329             continue;
4330         }
4331
4332         if (!ACTION_VerifyComponentForAction(package, index,
4333                                 INSTALLSTATE_LOCAL))
4334         {
4335             TRACE("Skipping typelib reg due to disabled component\n");
4336             msiobj_release(&row->hdr);
4337
4338             package->components[index].Action =
4339                 package->components[index].Installed;
4340
4341             continue;
4342         }
4343
4344         package->components[index].Action = INSTALLSTATE_LOCAL;
4345
4346         index = get_loaded_file(package,package->components[index].KeyPath); 
4347    
4348         if (index < 0)
4349         {
4350             msiobj_release(&row->hdr);
4351             continue;
4352         }
4353
4354         module = LoadLibraryExW(package->files[index].TargetPath, NULL,
4355                         LOAD_LIBRARY_AS_DATAFILE);
4356         if (module != NULL)
4357         {
4358             LPWSTR guid;
4359             guid = load_dynamic_stringW(row,1);
4360             CLSIDFromString(guid, &tl_struct.clsid);
4361             HeapFree(GetProcessHeap(),0,guid);
4362             tl_struct.source = strdupW(package->files[index].TargetPath);
4363             tl_struct.path = NULL;
4364
4365             EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc, 
4366                                (LONG_PTR)&tl_struct);
4367
4368             if (tl_struct.path != NULL)
4369             {
4370                 LPWSTR help = NULL;
4371                 LPCWSTR helpid;
4372                 HRESULT res;
4373
4374                 helpid = MSI_RecordGetString(row,6);
4375     
4376                 if (helpid)
4377                     help = resolve_folder(package,helpid,FALSE,FALSE,NULL);
4378                 res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
4379                 HeapFree(GetProcessHeap(),0,help);
4380
4381                 if (!SUCCEEDED(res))
4382                     ERR("Failed to register type library %s\n", 
4383                             debugstr_w(tl_struct.path));
4384                 else
4385                 {
4386                     ui_actiondata(package,szRegisterTypeLibraries,row);
4387                 
4388                     TRACE("Registered %s\n", debugstr_w(tl_struct.path));
4389                 }
4390
4391                 ITypeLib_Release(tl_struct.ptLib);
4392                 HeapFree(GetProcessHeap(),0,tl_struct.path);
4393             }
4394             else
4395                 ERR("Failed to load type library %s\n", 
4396                     debugstr_w(tl_struct.source));
4397        
4398             FreeLibrary(module);
4399             HeapFree(GetProcessHeap(),0,tl_struct.source);
4400         }
4401         else
4402             ERR("Could not load file! %s\n",
4403                     debugstr_w(package->files[index].TargetPath));
4404         msiobj_release(&row->hdr);
4405     }
4406     MSI_ViewClose(view);
4407     msiobj_release(&view->hdr);
4408     return rc;
4409 }
4410
4411 static INT load_appid(MSIPACKAGE* package, MSIRECORD *row)
4412 {
4413     DWORD index = package->loaded_appids;
4414     DWORD sz;
4415     LPCWSTR buffer;
4416
4417     /* fill in the data */
4418
4419     package->loaded_appids++;
4420     if (package->loaded_appids == 1)
4421         package->appids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIAPPID));
4422     else
4423         package->appids = HeapReAlloc(GetProcessHeap(),0,
4424             package->appids, package->loaded_appids * sizeof(MSIAPPID));
4425
4426     memset(&package->appids[index],0,sizeof(MSIAPPID));
4427     
4428     sz = IDENTIFIER_SIZE;
4429     MSI_RecordGetStringW(row, 1, package->appids[index].AppID, &sz);
4430     TRACE("loading appid %s\n",debugstr_w(package->appids[index].AppID));
4431
4432     buffer = MSI_RecordGetString(row,2);
4433     deformat_string(package,buffer,&package->appids[index].RemoteServerName);
4434
4435     package->appids[index].LocalServer = load_dynamic_stringW(row,3);
4436     package->appids[index].ServiceParameters = load_dynamic_stringW(row,4);
4437     package->appids[index].DllSurrogate = load_dynamic_stringW(row,5);
4438
4439     package->appids[index].ActivateAtStorage = !MSI_RecordIsNull(row,6);
4440     package->appids[index].RunAsInteractiveUser = !MSI_RecordIsNull(row,7);
4441     
4442     return index;
4443 }
4444
4445 static INT load_given_appid(MSIPACKAGE *package, LPCWSTR appid)
4446 {
4447     INT rc;
4448     MSIRECORD *row;
4449     INT i;
4450     static const WCHAR ExecSeqQuery[] =
4451         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4452          '`','A','p','p','I','d','`',' ','W','H','E','R','E',' ',
4453          '`','A','p','p','I','d','`',' ','=',' ','\'','%','s','\'',0};
4454
4455     if (!appid)
4456         return -1;
4457
4458     /* check for appids already loaded */
4459     for (i = 0; i < package->loaded_appids; i++)
4460         if (strcmpiW(package->appids[i].AppID,appid)==0)
4461         {
4462             TRACE("found appid %s at index %i\n",debugstr_w(appid),i);
4463             return i;
4464         }
4465     
4466     row = MSI_QueryGetRecord(package->db, ExecSeqQuery, appid);
4467     if (!row)
4468         return -1;
4469
4470     rc = load_appid(package, row);
4471     msiobj_release(&row->hdr);
4472
4473     return rc;
4474 }
4475
4476 static INT load_given_progid(MSIPACKAGE *package, LPCWSTR progid);
4477 static INT load_given_class(MSIPACKAGE *package, LPCWSTR classid);
4478
4479 static INT load_progid(MSIPACKAGE* package, MSIRECORD *row)
4480 {
4481     DWORD index = package->loaded_progids;
4482     LPCWSTR buffer;
4483
4484     /* fill in the data */
4485
4486     package->loaded_progids++;
4487     if (package->loaded_progids == 1)
4488         package->progids = HeapAlloc(GetProcessHeap(),0,sizeof(MSIPROGID));
4489     else
4490         package->progids = HeapReAlloc(GetProcessHeap(),0,
4491             package->progids , package->loaded_progids * sizeof(MSIPROGID));
4492
4493     memset(&package->progids[index],0,sizeof(MSIPROGID));
4494
4495     package->progids[index].ProgID = load_dynamic_stringW(row,1);
4496     TRACE("loading progid %s\n",debugstr_w(package->progids[index].ProgID));
4497
4498     buffer = MSI_RecordGetString(row,2);
4499     package->progids[index].ParentIndex = load_given_progid(package,buffer);
4500     if (package->progids[index].ParentIndex < 0 && buffer)
4501         FIXME("Unknown parent ProgID %s\n",debugstr_w(buffer));
4502
4503     buffer = MSI_RecordGetString(row,3);
4504     package->progids[index].ClassIndex = load_given_class(package,buffer);
4505     if (package->progids[index].ClassIndex< 0 && buffer)
4506         FIXME("Unknown class %s\n",debugstr_w(buffer));
4507
4508     package->progids[index].Description = load_dynamic_stringW(row,4);
4509
4510     if (!MSI_RecordIsNull(row,6))
4511     {
4512         INT icon_index = MSI_RecordGetInteger(row,6); 
4513         LPWSTR FileName = load_dynamic_stringW(row,5);
4514         LPWSTR FilePath;
4515         static const WCHAR fmt[] = {'%','s',',','%','i',0};
4516
4517         build_icon_path(package,FileName,&FilePath);
4518        
4519         package->progids[index].IconPath = 
4520                 HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+10)*
4521                                 sizeof(WCHAR));
4522
4523         sprintfW(package->progids[index].IconPath,fmt,FilePath,icon_index);
4524
4525         HeapFree(GetProcessHeap(),0,FilePath);
4526         HeapFree(GetProcessHeap(),0,FileName);
4527     }
4528     else
4529     {
4530         buffer = MSI_RecordGetString(row,5);
4531         if (buffer)
4532             build_icon_path(package,buffer,&(package->progids[index].IconPath));
4533     }
4534
4535     package->progids[index].CurVerIndex = -1;
4536     package->progids[index].VersionIndIndex = -1;
4537
4538     /* if we have a parent then we may be that parents CurVer */
4539     if (package->progids[index].ParentIndex >= 0 && 
4540         package->progids[index].ParentIndex != index)
4541     {
4542         int pindex = package->progids[index].ParentIndex;
4543         while (package->progids[pindex].ParentIndex>= 0)
4544             pindex = package->progids[pindex].ParentIndex;
4545
4546         FIXME("BAD BAD need to determing if we are really the CurVer\n");
4547
4548         package->progids[index].CurVerIndex = pindex;
4549         package->progids[pindex].VersionIndIndex = index;
4550     }
4551     
4552     return index;
4553 }
4554
4555 static INT load_given_progid(MSIPACKAGE *package, LPCWSTR progid)
4556 {
4557     INT rc;
4558     MSIRECORD *row;
4559     INT i;
4560     static const WCHAR ExecSeqQuery[] =
4561         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4562          '`','P','r','o','g','I','d','`',' ','W','H','E','R','E',' ',
4563          '`','P','r','o','g','I','d','`',' ','=',' ','\'','%','s','\'',0};
4564
4565     if (!progid)
4566         return -1;
4567
4568     /* check for progids already loaded */
4569     for (i = 0; i < package->loaded_progids; i++)
4570         if (strcmpiW(package->progids[i].ProgID,progid)==0)
4571         {
4572             TRACE("found progid %s at index %i\n",debugstr_w(progid), i);
4573             return i;
4574         }
4575     
4576     row = MSI_QueryGetRecord(package->db, ExecSeqQuery, progid);
4577     if(!row)
4578         return -1;
4579
4580     rc = load_progid(package, row);
4581     msiobj_release(&row->hdr);
4582
4583     return rc;
4584 }
4585
4586 static INT load_class(MSIPACKAGE* package, MSIRECORD *row)
4587 {
4588     DWORD index = package->loaded_classes;
4589     DWORD sz,i;
4590     LPCWSTR buffer;
4591
4592     /* fill in the data */
4593
4594     package->loaded_classes++;
4595     if (package->loaded_classes== 1)
4596         package->classes = HeapAlloc(GetProcessHeap(),0,sizeof(MSICLASS));
4597     else
4598         package->classes = HeapReAlloc(GetProcessHeap(),0,
4599             package->classes, package->loaded_classes * sizeof(MSICLASS));
4600
4601     memset(&package->classes[index],0,sizeof(MSICLASS));
4602
4603     sz = IDENTIFIER_SIZE;
4604     MSI_RecordGetStringW(row, 1, package->classes[index].CLSID, &sz);
4605     TRACE("loading class %s\n",debugstr_w(package->classes[index].CLSID));
4606     sz = IDENTIFIER_SIZE;
4607     MSI_RecordGetStringW(row, 2, package->classes[index].Context, &sz);
4608     buffer = MSI_RecordGetString(row,3);
4609     package->classes[index].ComponentIndex = get_loaded_component(package, 
4610                     buffer);
4611
4612     package->classes[index].ProgIDText = load_dynamic_stringW(row,4);
4613     package->classes[index].ProgIDIndex = 
4614                 load_given_progid(package, package->classes[index].ProgIDText);
4615
4616     package->classes[index].Description = load_dynamic_stringW(row,5);
4617
4618     buffer = MSI_RecordGetString(row,6);
4619     if (buffer)
4620         package->classes[index].AppIDIndex = 
4621                 load_given_appid(package, buffer);
4622     else
4623         package->classes[index].AppIDIndex = -1;
4624
4625     package->classes[index].FileTypeMask = load_dynamic_stringW(row,7);
4626
4627     if (!MSI_RecordIsNull(row,9))
4628     {
4629
4630         INT icon_index = MSI_RecordGetInteger(row,9); 
4631         LPWSTR FileName = load_dynamic_stringW(row,8);
4632         LPWSTR FilePath;
4633         static const WCHAR fmt[] = {'%','s',',','%','i',0};
4634
4635         build_icon_path(package,FileName,&FilePath);
4636        
4637         package->classes[index].IconPath = 
4638                 HeapAlloc(GetProcessHeap(),0,(strlenW(FilePath)+5)*
4639                                 sizeof(WCHAR));
4640
4641         sprintfW(package->classes[index].IconPath,fmt,FilePath,icon_index);
4642
4643         HeapFree(GetProcessHeap(),0,FilePath);
4644         HeapFree(GetProcessHeap(),0,FileName);
4645     }
4646     else
4647     {
4648         buffer = MSI_RecordGetString(row,8);
4649         if (buffer)
4650             build_icon_path(package,buffer,&(package->classes[index].IconPath));
4651     }
4652
4653     if (!MSI_RecordIsNull(row,10))
4654     {
4655         i = MSI_RecordGetInteger(row,10);
4656         if (i != MSI_NULL_INTEGER && i > 0 &&  i < 4)
4657         {
4658             static const WCHAR ole2[] = {'o','l','e','2','.','d','l','l',0};
4659             static const WCHAR ole32[] = {'o','l','e','3','2','.','d','l','l',0};
4660
4661             switch(i)
4662             {
4663                 case 1:
4664                     package->classes[index].DefInprocHandler = strdupW(ole2);
4665                     break;
4666                 case 2:
4667                     package->classes[index].DefInprocHandler32 = strdupW(ole32);
4668                     break;
4669                 case 3:
4670                     package->classes[index].DefInprocHandler = strdupW(ole2);
4671                     package->classes[index].DefInprocHandler32 = strdupW(ole32);
4672                     break;
4673             }
4674         }
4675         else
4676         {
4677             package->classes[index].DefInprocHandler32 = load_dynamic_stringW(
4678                             row, 10);
4679             reduce_to_longfilename(package->classes[index].DefInprocHandler32);
4680         }
4681     }
4682     buffer = MSI_RecordGetString(row,11);
4683     deformat_string(package,buffer,&package->classes[index].Argument);
4684
4685     buffer = MSI_RecordGetString(row,12);
4686     package->classes[index].FeatureIndex = get_loaded_feature(package,buffer);
4687
4688     package->classes[index].Attributes = MSI_RecordGetInteger(row,13);
4689     
4690     return index;
4691 }
4692
4693 /*
4694  * the Class table has 3 primary keys. Generally it is only 
4695  * referenced through the first CLSID key. However when loading
4696  * all of the classes we need to make sure we do not ignore rows
4697  * with other Context and ComponentIndexs 
4698  */
4699 static INT load_given_class(MSIPACKAGE *package, LPCWSTR classid)
4700 {
4701     INT rc;
4702     MSIRECORD *row;
4703     INT i;
4704     static const WCHAR ExecSeqQuery[] =
4705         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4706          '`','C','l','a','s','s','`',' ','W','H','E','R','E',' ',
4707          '`','C','L','S','I','D','`',' ','=',' ','\'','%','s','\'',0};
4708
4709
4710     if (!classid)
4711         return -1;
4712     
4713     /* check for classes already loaded */
4714     for (i = 0; i < package->loaded_classes; i++)
4715         if (strcmpiW(package->classes[i].CLSID,classid)==0)
4716         {
4717             TRACE("found class %s at index %i\n",debugstr_w(classid), i);
4718             return i;
4719         }
4720     
4721     row = MSI_QueryGetRecord(package->db, ExecSeqQuery, classid);
4722     if (!row)
4723         return -1;
4724
4725     rc = load_class(package, row);
4726     msiobj_release(&row->hdr);
4727
4728     return rc;
4729 }
4730
4731 static INT load_given_extension(MSIPACKAGE *package, LPCWSTR extension);
4732
4733 static INT load_mime(MSIPACKAGE* package, MSIRECORD *row)
4734 {
4735     DWORD index = package->loaded_mimes;
4736     DWORD sz;
4737     LPCWSTR buffer;
4738
4739     /* fill in the data */
4740
4741     package->loaded_mimes++;
4742     if (package->loaded_mimes== 1)
4743         package->mimes= HeapAlloc(GetProcessHeap(),0,sizeof(MSIMIME));
4744     else
4745         package->mimes= HeapReAlloc(GetProcessHeap(),0,
4746             package->mimes, package->loaded_mimes* 
4747             sizeof(MSIMIME));
4748
4749     memset(&package->mimes[index],0,sizeof(MSIMIME));
4750
4751     package->mimes[index].ContentType = load_dynamic_stringW(row,1); 
4752     TRACE("loading mime %s\n",debugstr_w(package->mimes[index].ContentType));
4753
4754     buffer = MSI_RecordGetString(row,2);
4755     package->mimes[index].ExtensionIndex = load_given_extension(package,
4756                     buffer);
4757
4758     sz = IDENTIFIER_SIZE;
4759     MSI_RecordGetStringW(row,3,package->mimes[index].CLSID,&sz);
4760     package->mimes[index].ClassIndex= load_given_class(package,
4761                     package->mimes[index].CLSID);
4762     
4763     return index;
4764 }
4765
4766 static INT load_given_mime(MSIPACKAGE *package, LPCWSTR mime)
4767 {
4768     INT rc;
4769     MSIRECORD *row;
4770     INT i;
4771     static const WCHAR ExecSeqQuery[] =
4772         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4773          '`','M','I','M','E','`',' ','W','H','E','R','E',' ',
4774          '`','C','o','n','t','e','n','t','T','y','p','e','`',' ','=',' ',
4775          '\'','%','s','\'',0};
4776
4777     if (!mime)
4778         return -1;
4779     
4780     /* check for mime already loaded */
4781     for (i = 0; i < package->loaded_mimes; i++)
4782         if (strcmpiW(package->mimes[i].ContentType,mime)==0)
4783         {
4784             TRACE("found mime %s at index %i\n",debugstr_w(mime), i);
4785             return i;
4786         }
4787     
4788     row = MSI_QueryGetRecord(package->db, ExecSeqQuery, mime);
4789     if (!row)
4790         return -1;
4791
4792     rc = load_mime(package, row);
4793     msiobj_release(&row->hdr);
4794
4795     return rc;
4796 }
4797
4798 static INT load_extension(MSIPACKAGE* package, MSIRECORD *row)
4799 {
4800     DWORD index = package->loaded_extensions;
4801     DWORD sz;
4802     LPCWSTR buffer;
4803
4804     /* fill in the data */
4805
4806     package->loaded_extensions++;
4807     if (package->loaded_extensions == 1)
4808         package->extensions = HeapAlloc(GetProcessHeap(),0,sizeof(MSIEXTENSION));
4809     else
4810         package->extensions = HeapReAlloc(GetProcessHeap(),0,
4811             package->extensions, package->loaded_extensions* 
4812             sizeof(MSIEXTENSION));
4813
4814     memset(&package->extensions[index],0,sizeof(MSIEXTENSION));
4815
4816     sz = 256;
4817     MSI_RecordGetStringW(row,1,package->extensions[index].Extension,&sz);
4818     TRACE("loading extension %s\n",
4819                     debugstr_w(package->extensions[index].Extension));
4820
4821     buffer = MSI_RecordGetString(row,2);
4822     package->extensions[index].ComponentIndex = 
4823             get_loaded_component(package,buffer);
4824
4825     package->extensions[index].ProgIDText = load_dynamic_stringW(row,3);
4826     package->extensions[index].ProgIDIndex = load_given_progid(package,
4827                     package->extensions[index].ProgIDText);
4828
4829     buffer = MSI_RecordGetString(row,4);
4830     package->extensions[index].MIMEIndex = load_given_mime(package,buffer);
4831
4832     buffer = MSI_RecordGetString(row,5);
4833     package->extensions[index].FeatureIndex = 
4834             get_loaded_feature(package,buffer);
4835
4836     return index;
4837 }
4838
4839 /*
4840  * While the extension table has 2 primary keys, this function is only looking
4841  * at the Extension key which is what is referenced as a forign key 
4842  */
4843 static INT load_given_extension(MSIPACKAGE *package, LPCWSTR extension)
4844 {
4845     INT rc;
4846     MSIRECORD *row;
4847     INT i;
4848     static const WCHAR ExecSeqQuery[] =
4849         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
4850          '`','E','x','t','e','n','s','i','o','n','`',' ',
4851          'W','H','E','R','E',' ',
4852          '`','E','x','t','e','n','s','i','o','n','`',' ','=',' ',
4853          '\'','%','s','\'',0};
4854
4855     if (!extension)
4856         return -1;
4857
4858     /* check for extensions already loaded */
4859     for (i = 0; i < package->loaded_extensions; i++)
4860         if (strcmpiW(package->extensions[i].Extension,extension)==0)
4861         {
4862             TRACE("extension %s already loaded at %i\n",debugstr_w(extension),
4863                             i);
4864             return i;
4865         }
4866     
4867     row = MSI_QueryGetRecord(package->db, ExecSeqQuery, extension);
4868     if (!row)
4869         return -1;
4870
4871     rc = load_extension(package, row);
4872     msiobj_release(&row->hdr);
4873
4874     return rc;
4875 }
4876
4877 static UINT iterate_load_verb(MSIRECORD *row, LPVOID param)
4878 {
4879     MSIPACKAGE* package = (MSIPACKAGE*)param;
4880     DWORD index = package->loaded_verbs;
4881     LPCWSTR buffer;
4882
4883     /* fill in the data */
4884
4885     package->loaded_verbs++;
4886     if (package->loaded_verbs == 1)
4887         package->verbs = HeapAlloc(GetProcessHeap(),0,sizeof(MSIVERB));
4888     else
4889         package->verbs = HeapReAlloc(GetProcessHeap(),0,
4890             package->verbs , package->loaded_verbs * sizeof(MSIVERB));
4891
4892     memset(&package->verbs[index],0,sizeof(MSIVERB));
4893
4894     buffer = MSI_RecordGetString(row,1);
4895     package->verbs[index].ExtensionIndex = load_given_extension(package,buffer);
4896     if (package->verbs[index].ExtensionIndex < 0 && buffer)
4897         ERR("Verb unable to find loaded extension %s\n", debugstr_w(buffer));
4898
4899     package->verbs[index].Verb = load_dynamic_stringW(row,2);
4900     TRACE("loading verb %s\n",debugstr_w(package->verbs[index].Verb));
4901     package->verbs[index].Sequence = MSI_RecordGetInteger(row,3);
4902
4903     buffer = MSI_RecordGetString(row,4);
4904     deformat_string(package,buffer,&package->verbs[index].Command);
4905
4906     buffer = MSI_RecordGetString(row,5);
4907     deformat_string(package,buffer,&package->verbs[index].Argument);
4908
4909     /* assosiate the verb with the correct extension */
4910     if (package->verbs[index].ExtensionIndex >= 0)
4911     {
4912         MSIEXTENSION* extension = &package->extensions[package->verbs[index].
4913                 ExtensionIndex];
4914         int count = extension->VerbCount;
4915
4916         if (count >= 99)
4917             FIXME("Exceeding max verb count! Increase that limit!!!\n");
4918         else
4919         {
4920             extension->VerbCount++;
4921             extension->Verbs[count] = index;
4922         }
4923     }
4924     
4925     return ERROR_SUCCESS;
4926 }
4927
4928 static UINT iterate_all_classes(MSIRECORD *rec, LPVOID param)
4929 {
4930     LPCWSTR clsid;
4931     LPCWSTR context;
4932     LPCWSTR buffer;
4933     INT    component_index;
4934     MSIPACKAGE* package =(MSIPACKAGE*)param;
4935     INT i;
4936     BOOL match = FALSE;
4937
4938     clsid = MSI_RecordGetString(rec,1);
4939     context = MSI_RecordGetString(rec,2);
4940     buffer = MSI_RecordGetString(rec,3);
4941     component_index = get_loaded_component(package,buffer);
4942
4943     for (i = 0; i < package->loaded_classes; i++)
4944     {
4945         if (strcmpiW(clsid,package->classes[i].CLSID))
4946             continue;
4947         if (strcmpW(context,package->classes[i].Context))
4948             continue;
4949         if (component_index == package->classes[i].ComponentIndex)
4950         {
4951             match = TRUE;
4952             break;
4953         }
4954     }
4955     
4956     if (!match)
4957         load_class(package, rec);
4958
4959     return ERROR_SUCCESS;
4960 }
4961
4962 static VOID load_all_classes(MSIPACKAGE *package)
4963 {
4964     UINT rc = ERROR_SUCCESS;
4965     MSIQUERY *view;
4966
4967     static const WCHAR ExecSeqQuery[] =
4968         {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
4969          '`','C','l','a','s','s','`',0};
4970
4971     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
4972     if (rc != ERROR_SUCCESS)
4973         return;
4974
4975     rc = MSI_IterateRecords(view, NULL, iterate_all_classes, package);
4976     msiobj_release(&view->hdr);
4977 }
4978
4979 static UINT iterate_all_extensions(MSIRECORD *rec, LPVOID param)
4980 {
4981     LPCWSTR buffer;
4982     LPCWSTR extension;
4983     INT    component_index;
4984     MSIPACKAGE* package =(MSIPACKAGE*)param;
4985     BOOL match = FALSE;
4986     INT i;
4987
4988     extension = MSI_RecordGetString(rec,1);
4989     buffer = MSI_RecordGetString(rec,2);
4990     component_index = get_loaded_component(package,buffer);
4991
4992     for (i = 0; i < package->loaded_extensions; i++)
4993     {
4994         if (strcmpiW(extension,package->extensions[i].Extension))
4995             continue;
4996         if (component_index == package->extensions[i].ComponentIndex)
4997         {
4998             match = TRUE;
4999             break;
5000         }
5001     }
5002
5003     if (!match)
5004         load_extension(package, rec);
5005
5006     return ERROR_SUCCESS;
5007 }
5008
5009 static VOID load_all_extensions(MSIPACKAGE *package)
5010 {
5011     UINT rc = ERROR_SUCCESS;
5012     MSIQUERY *view;
5013
5014     static const WCHAR ExecSeqQuery[] =
5015         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5016          '`','E','x','t','e','n','s','i','o','n','`',0};
5017
5018     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5019     if (rc != ERROR_SUCCESS)
5020         return;
5021
5022     rc = MSI_IterateRecords(view, NULL, iterate_all_extensions, package);
5023     msiobj_release(&view->hdr);
5024 }
5025
5026 static UINT iterate_all_progids(MSIRECORD *rec, LPVOID param)
5027 {
5028     LPCWSTR buffer;
5029     MSIPACKAGE* package =(MSIPACKAGE*)param;
5030
5031     buffer = MSI_RecordGetString(rec,1);
5032     load_given_progid(package,buffer);
5033     return ERROR_SUCCESS;
5034 }
5035
5036 static VOID load_all_progids(MSIPACKAGE *package)
5037 {
5038     UINT rc = ERROR_SUCCESS;
5039     MSIQUERY *view;
5040
5041     static const WCHAR ExecSeqQuery[] =
5042         {'S','E','L','E','C','T',' ','`','P','r','o','g','I','d','`',' ',
5043          'F','R','O','M',' ', '`','P','r','o','g','I','d','`',0};
5044
5045     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5046     if (rc != ERROR_SUCCESS)
5047         return;
5048
5049     rc = MSI_IterateRecords(view, NULL, iterate_all_progids, package);
5050     msiobj_release(&view->hdr);
5051 }
5052
5053 static VOID load_all_verbs(MSIPACKAGE *package)
5054 {
5055     UINT rc = ERROR_SUCCESS;
5056     MSIQUERY *view;
5057
5058     static const WCHAR ExecSeqQuery[] =
5059         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5060          '`','V','e','r','b','`',0};
5061
5062     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5063     if (rc != ERROR_SUCCESS)
5064         return;
5065
5066     rc = MSI_IterateRecords(view, NULL, iterate_load_verb, package);
5067     msiobj_release(&view->hdr);
5068 }
5069
5070 static UINT iterate_all_mimes(MSIRECORD *rec, LPVOID param)
5071 {
5072     LPCWSTR buffer;
5073     MSIPACKAGE* package =(MSIPACKAGE*)param;
5074
5075     buffer = MSI_RecordGetString(rec,1);
5076     load_given_mime(package,buffer);
5077     return ERROR_SUCCESS;
5078 }
5079
5080 static VOID load_all_mimes(MSIPACKAGE *package)
5081 {
5082     UINT rc = ERROR_SUCCESS;
5083     MSIQUERY *view;
5084
5085     static const WCHAR ExecSeqQuery[] =
5086         {'S','E','L','E','C','T',' ',
5087          '`','C','o','n','t','e','n','t','T','y','p','e','`',
5088          ' ','F','R','O','M',' ',
5089          '`','M','I','M','E','`',0};
5090
5091     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
5092     if (rc != ERROR_SUCCESS)
5093         return;
5094
5095     rc = MSI_IterateRecords(view, NULL, iterate_all_mimes, package);
5096     msiobj_release(&view->hdr);
5097 }
5098
5099 static void load_classes_and_such(MSIPACKAGE *package)
5100 {
5101     TRACE("Loading all the class info and related tables\n");
5102
5103     /* check if already loaded */
5104     if (package->classes || package->extensions || package->progids || 
5105         package->verbs || package->mimes)
5106         return;
5107
5108     load_all_classes(package);
5109     load_all_extensions(package);
5110     load_all_progids(package);
5111     /* these loads must come after the other loads */
5112     load_all_verbs(package);
5113     load_all_mimes(package);
5114 }
5115
5116 static void mark_progid_for_install(MSIPACKAGE* package, INT index)
5117 {
5118     MSIPROGID* progid;
5119     int i;
5120
5121     if (index < 0 || index >= package->loaded_progids)
5122         return;
5123
5124     progid = &package->progids[index];
5125
5126     if (progid->InstallMe == TRUE)
5127         return;
5128
5129     progid->InstallMe = TRUE;
5130
5131     /* all children if this is a parent also install */
5132    for (i = 0; i < package->loaded_progids; i++)
5133         if (package->progids[i].ParentIndex == index)
5134             mark_progid_for_install(package,i);
5135 }
5136
5137 static void mark_mime_for_install(MSIPACKAGE* package, INT index)
5138 {
5139     MSIMIME* mime;
5140
5141     if (index < 0 || index >= package->loaded_mimes)
5142         return;
5143
5144     mime = &package->mimes[index];
5145
5146     if (mime->InstallMe == TRUE)
5147         return;
5148
5149     mime->InstallMe = TRUE;
5150 }
5151
5152 static UINT register_appid(MSIPACKAGE *package, int appidIndex, LPCWSTR app )
5153 {
5154     static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
5155     HKEY hkey2,hkey3;
5156
5157     if (!package)
5158         return ERROR_INVALID_HANDLE;
5159
5160     RegCreateKeyW(HKEY_CLASSES_ROOT,szAppID,&hkey2);
5161     RegCreateKeyW(hkey2,package->appids[appidIndex].AppID,&hkey3);
5162     RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)app,
5163                    (strlenW(app)+1)*sizeof(WCHAR));
5164
5165     if (package->appids[appidIndex].RemoteServerName)
5166     {
5167         UINT size; 
5168         static const WCHAR szRemoteServerName[] =
5169              {'R','e','m','o','t','e','S','e','r','v','e','r','N','a','m','e',
5170               0};
5171
5172         size = (strlenW(package->appids[appidIndex].RemoteServerName)+1) * 
5173                 sizeof(WCHAR);
5174
5175         RegSetValueExW(hkey3,szRemoteServerName,0,REG_SZ,
5176                         (LPVOID)package->appids[appidIndex].RemoteServerName,
5177                         size);
5178     }
5179
5180     if (package->appids[appidIndex].LocalServer)
5181     {
5182         static const WCHAR szLocalService[] =
5183              {'L','o','c','a','l','S','e','r','v','i','c','e',0};
5184         UINT size;
5185         size = (strlenW(package->appids[appidIndex].LocalServer)+1) * 
5186                 sizeof(WCHAR);
5187
5188         RegSetValueExW(hkey3,szLocalService,0,REG_SZ,
5189                         (LPVOID)package->appids[appidIndex].LocalServer,size);
5190     }
5191
5192     if (package->appids[appidIndex].ServiceParameters)
5193     {
5194         static const WCHAR szService[] =
5195              {'S','e','r','v','i','c','e',
5196               'P','a','r','a','m','e','t','e','r','s',0};
5197         UINT size;
5198         size = (strlenW(package->appids[appidIndex].ServiceParameters)+1) * 
5199                 sizeof(WCHAR);
5200         RegSetValueExW(hkey3,szService,0,REG_SZ,
5201                         (LPVOID)package->appids[appidIndex].ServiceParameters,
5202                         size);
5203     }
5204
5205     if (package->appids[appidIndex].DllSurrogate)
5206     {
5207         static const WCHAR szDLL[] =
5208              {'D','l','l','S','u','r','r','o','g','a','t','e',0};
5209         UINT size;
5210         size = (strlenW(package->appids[appidIndex].DllSurrogate)+1) * 
5211                 sizeof(WCHAR);
5212         RegSetValueExW(hkey3,szDLL,0,REG_SZ,
5213                         (LPVOID)package->appids[appidIndex].DllSurrogate,size);
5214     }
5215
5216     if (package->appids[appidIndex].ActivateAtStorage)
5217     {
5218         static const WCHAR szActivate[] =
5219              {'A','c','t','i','v','a','t','e','A','s',
5220               'S','t','o','r','a','g','e',0};
5221         static const WCHAR szY[] = {'Y',0};
5222
5223         RegSetValueExW(hkey3,szActivate,0,REG_SZ,(LPVOID)szY,4);
5224     }
5225
5226     if (package->appids[appidIndex].RunAsInteractiveUser)
5227     {
5228         static const WCHAR szRunAs[] = {'R','u','n','A','s',0};
5229         static const WCHAR szUser[] = 
5230              {'I','n','t','e','r','a','c','t','i','v','e',' ',
5231               'U','s','e','r',0};
5232
5233         RegSetValueExW(hkey3,szRunAs,0,REG_SZ,(LPVOID)szUser,sizeof(szUser));
5234     }
5235
5236     RegCloseKey(hkey3);
5237     RegCloseKey(hkey2);
5238     return ERROR_SUCCESS;
5239 }
5240
5241 static UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
5242 {
5243     /* 
5244      * Again I am assuming the words, "Whose key file represents" when referring
5245      * to a Component as to meaning that Components KeyPath file
5246      */
5247     
5248     UINT rc;
5249     MSIRECORD *uirow;
5250     static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
5251     static const WCHAR szProgID[] = { 'P','r','o','g','I','D',0 };
5252     static const WCHAR szVIProgID[] = { 'V','e','r','s','i','o','n','I','n','d','e','p','e','n','d','e','n','t','P','r','o','g','I','D',0 };
5253     static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
5254     static const WCHAR szSpace[] = {' ',0};
5255     static const WCHAR szInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
5256     static const WCHAR szFileType_fmt[] = {'F','i','l','e','T','y','p','e','\\','%','s','\\','%','i',0};
5257     HKEY hkey,hkey2,hkey3;
5258     BOOL install_on_demand = FALSE;
5259     int i;
5260
5261     if (!package)
5262         return ERROR_INVALID_HANDLE;
5263
5264     load_classes_and_such(package);
5265     rc = RegCreateKeyW(HKEY_CLASSES_ROOT,szCLSID,&hkey);
5266     if (rc != ERROR_SUCCESS)
5267         return ERROR_FUNCTION_FAILED;
5268
5269     /* install_on_demand should be set if OLE supports install on demand OLE
5270      * servers. For now i am defaulting to FALSE because i do not know how to
5271      * check, and i am told our builtin OLE does not support it
5272      */
5273     
5274     for (i = 0; i < package->loaded_classes; i++)
5275     {
5276         INT index,f_index;
5277         DWORD size, sz;
5278         LPWSTR argument;
5279
5280         if (package->classes[i].ComponentIndex < 0)
5281         {
5282             continue;
5283         }
5284
5285         index = package->classes[i].ComponentIndex;
5286         f_index = package->classes[i].FeatureIndex;
5287
5288         /* 
5289          * yes. MSDN says that these are based on _Feature_ not on
5290          * Component.  So verify the feature is to be installed
5291          */
5292         if ((!ACTION_VerifyFeatureForAction(package, f_index,
5293                                 INSTALLSTATE_LOCAL)) &&
5294              !(install_on_demand && ACTION_VerifyFeatureForAction(package,
5295                              f_index, INSTALLSTATE_ADVERTISED)))
5296         {
5297             TRACE("Skipping class %s reg due to disabled feature %s\n", 
5298                             debugstr_w(package->classes[i].CLSID), 
5299                             debugstr_w(package->features[f_index].Feature));
5300
5301             continue;
5302         }
5303
5304         TRACE("Registering index %i  class %s\n",i,
5305                         debugstr_w(package->classes[i].CLSID));
5306
5307         package->classes[i].Installed = TRUE;
5308         if (package->classes[i].ProgIDIndex >= 0)
5309             mark_progid_for_install(package, package->classes[i].ProgIDIndex);
5310
5311         RegCreateKeyW(hkey,package->classes[i].CLSID,&hkey2);
5312
5313         if (package->classes[i].Description)
5314             RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)package->classes[i].
5315                             Description, (strlenW(package->classes[i].
5316                                      Description)+1)*sizeof(WCHAR));
5317
5318         RegCreateKeyW(hkey2,package->classes[i].Context,&hkey3);
5319         index = get_loaded_file(package,package->components[index].KeyPath);
5320
5321
5322         /* the context server is a short path name 
5323          * except for if it is InprocServer32... 
5324          */
5325         if (strcmpiW(package->classes[i].Context,szInprocServer32)!=0)
5326         {
5327             sz = 0;
5328             sz = GetShortPathNameW(package->files[index].TargetPath, NULL, 0);
5329             if (sz == 0)
5330             {
5331                 ERR("Unable to find short path for CLSID COM Server\n");
5332                 argument = NULL;
5333             }
5334             else
5335             {
5336                 size = sz * sizeof(WCHAR);
5337
5338                 if (package->classes[i].Argument)
5339                 {
5340                     size += strlenW(package->classes[i].Argument) * 
5341                             sizeof(WCHAR);
5342                     size += sizeof(WCHAR);
5343                 }
5344
5345                 argument = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR));
5346                 GetShortPathNameW(package->files[index].TargetPath, argument, 
5347                                 sz);
5348
5349                 if (package->classes[i].Argument)
5350                 {
5351                     strcatW(argument,szSpace);
5352                     strcatW(argument,package->classes[i].Argument);
5353                 }
5354             }
5355         }
5356         else
5357         {
5358             size = lstrlenW(package->files[index].TargetPath) * sizeof(WCHAR);
5359
5360             if (package->classes[i].Argument)
5361             {
5362                 size += strlenW(package->classes[i].Argument) * sizeof(WCHAR);
5363                 size += sizeof(WCHAR);
5364             }
5365
5366             argument = HeapAlloc(GetProcessHeap(), 0, size + sizeof(WCHAR));
5367             strcpyW(argument, package->files[index].TargetPath);
5368
5369             if (package->classes[i].Argument)
5370             {
5371                 strcatW(argument,szSpace);
5372                 strcatW(argument,package->classes[i].Argument);
5373             }
5374         }
5375
5376         if (argument)
5377         {
5378             RegSetValueExW(hkey3,NULL,0,REG_SZ, (LPVOID)argument, size);
5379             HeapFree(GetProcessHeap(),0,argument);
5380         }
5381
5382         RegCloseKey(hkey3);
5383
5384         if (package->classes[i].ProgIDIndex >= 0 || 
5385             package->classes[i].ProgIDText)
5386         {
5387             LPCWSTR progid;
5388
5389             if (package->classes[i].ProgIDIndex >= 0)
5390                 progid = package->progids[
5391                         package->classes[i].ProgIDIndex].ProgID;
5392             else
5393                 progid = package->classes[i].ProgIDText;
5394
5395             RegCreateKeyW(hkey2,szProgID,&hkey3);
5396             RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)progid,
5397                             (strlenW(progid)+1) *sizeof(WCHAR));
5398             RegCloseKey(hkey3);
5399
5400             if (package->classes[i].ProgIDIndex >= 0 &&
5401                 package->progids[package->classes[i].ProgIDIndex].
5402                                 VersionIndIndex >= 0)
5403             {
5404                 LPWSTR viprogid = strdupW(package->progids[package->progids[
5405                         package->classes[i].ProgIDIndex].VersionIndIndex].
5406                         ProgID);
5407                 RegCreateKeyW(hkey2,szVIProgID,&hkey3);
5408                 RegSetValueExW(hkey3,NULL,0,REG_SZ,(LPVOID)viprogid,
5409                             (strlenW(viprogid)+1) *sizeof(WCHAR));
5410                 RegCloseKey(hkey3);
5411                 HeapFree(GetProcessHeap(), 0, viprogid);
5412             }
5413         }
5414
5415         if (package->classes[i].AppIDIndex >= 0)
5416         { 
5417             RegSetValueExW(hkey2,szAppID,0,REG_SZ,
5418              (LPVOID)package->appids[package->classes[i].AppIDIndex].AppID,
5419              (strlenW(package->appids[package->classes[i].AppIDIndex].AppID)+1)
5420              *sizeof(WCHAR));
5421
5422             register_appid(package,package->classes[i].AppIDIndex,
5423                             package->classes[i].Description);
5424         }
5425
5426         if (package->classes[i].IconPath)
5427         {
5428             static const WCHAR szDefaultIcon[] = 
5429                 {'D','e','f','a','u','l','t','I','c','o','n',0};
5430
5431             RegCreateKeyW(hkey2,szDefaultIcon,&hkey3);
5432
5433             RegSetValueExW(hkey3,NULL,0,REG_SZ,
5434                            (LPVOID)package->classes[i].IconPath,
5435                            (strlenW(package->classes[i].IconPath)+1) * 
5436                            sizeof(WCHAR));
5437
5438             RegCloseKey(hkey3);
5439         }
5440
5441         if (package->classes[i].DefInprocHandler)
5442         {
5443             static const WCHAR szInproc[] =
5444                 {'I','n','p','r','o','c','H','a','n','d','l','e','r',0};
5445
5446             size = (strlenW(package->classes[i].DefInprocHandler) + 1) * 
5447                     sizeof(WCHAR);
5448             RegCreateKeyW(hkey2,szInproc,&hkey3);
5449             RegSetValueExW(hkey3,NULL,0,REG_SZ, 
5450                             (LPVOID)package->classes[i].DefInprocHandler, size);
5451             RegCloseKey(hkey3);
5452         }
5453
5454         if (package->classes[i].DefInprocHandler32)
5455         {
5456             static const WCHAR szInproc32[] =
5457                 {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',
5458                  0};
5459             size = (strlenW(package->classes[i].DefInprocHandler32) + 1) * 
5460                     sizeof(WCHAR);
5461
5462             RegCreateKeyW(hkey2,szInproc32,&hkey3);
5463             RegSetValueExW(hkey3,NULL,0,REG_SZ, 
5464                            (LPVOID)package->classes[i].DefInprocHandler32,size);
5465             RegCloseKey(hkey3);
5466         }
5467         
5468         RegCloseKey(hkey2);
5469
5470         /* if there is a FileTypeMask, register the FileType */
5471         if (package->classes[i].FileTypeMask)
5472         {
5473             LPWSTR ptr, ptr2;
5474             LPWSTR keyname;
5475             INT index = 0;
5476             ptr = package->classes[i].FileTypeMask;
5477             while (ptr && *ptr)
5478             {
5479                 ptr2 = strchrW(ptr,';');
5480                 if (ptr2)
5481                     *ptr2 = 0;
5482                 keyname = HeapAlloc(GetProcessHeap(),0,(strlenW(szFileType_fmt)+
5483                                         strlenW(package->classes[i].CLSID) + 4)
5484                                 * sizeof(WCHAR));
5485                 sprintfW(keyname,szFileType_fmt, package->classes[i].CLSID, 
5486                         index);
5487
5488                 RegCreateKeyW(HKEY_CLASSES_ROOT,keyname,&hkey2);
5489                 RegSetValueExW(hkey2,NULL,0,REG_SZ, (LPVOID)ptr,
5490                         strlenW(ptr)*sizeof(WCHAR));
5491                 RegCloseKey(hkey2);
5492                 HeapFree(GetProcessHeap(), 0, keyname);
5493
5494                 if (ptr2)
5495                     ptr = ptr2+1;
5496                 else
5497                     ptr = NULL;
5498
5499                 index ++;
5500             }
5501         }
5502         
5503         uirow = MSI_CreateRecord(1);
5504
5505         MSI_RecordSetStringW(uirow,1,package->classes[i].CLSID);
5506         ui_actiondata(package,szRegisterClassInfo,uirow);
5507         msiobj_release(&uirow->hdr);
5508     }
5509
5510     RegCloseKey(hkey);
5511     return rc;
5512 }
5513
5514 static UINT register_progid_base(MSIPACKAGE* package, MSIPROGID* progid,
5515                                  LPWSTR clsid)
5516 {
5517     static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
5518     static const WCHAR szDefaultIcon[] =
5519         {'D','e','f','a','u','l','t','I','c','o','n',0};
5520     HKEY hkey,hkey2;
5521
5522     RegCreateKeyW(HKEY_CLASSES_ROOT,progid->ProgID,&hkey);
5523
5524     if (progid->Description)
5525     {
5526         RegSetValueExW(hkey,NULL,0,REG_SZ,
5527                         (LPVOID)progid->Description, 
5528                         (strlenW(progid->Description)+1) *
5529                        sizeof(WCHAR));
5530     }
5531
5532     if (progid->ClassIndex >= 0)
5533     {   
5534         RegCreateKeyW(hkey,szCLSID,&hkey2);
5535         RegSetValueExW(hkey2,NULL,0,REG_SZ,
5536                         (LPVOID)package->classes[progid->ClassIndex].CLSID, 
5537                         (strlenW(package->classes[progid->ClassIndex].CLSID)+1)
5538                         * sizeof(WCHAR));
5539
5540         if (clsid)
5541             strcpyW(clsid,package->classes[progid->ClassIndex].CLSID);
5542
5543         RegCloseKey(hkey2);
5544     }
5545     else
5546     {
5547         FIXME("UNHANDLED case, Parent progid but classid is NULL\n");
5548     }
5549
5550     if (progid->IconPath)
5551     {
5552         RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
5553
5554         RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath,
5555                            (strlenW(progid->IconPath)+1) * sizeof(WCHAR));
5556         RegCloseKey(hkey2);
5557     }
5558     return ERROR_SUCCESS;
5559 }
5560
5561 static UINT register_progid(MSIPACKAGE *package, MSIPROGID* progid, 
5562                 LPWSTR clsid)
5563 {
5564     UINT rc = ERROR_SUCCESS; 
5565
5566     if (progid->ParentIndex < 0)
5567         rc = register_progid_base(package, progid, clsid);
5568     else
5569     {
5570         DWORD disp;
5571         HKEY hkey,hkey2;
5572         static const WCHAR szCLSID[] = { 'C','L','S','I','D',0 };
5573         static const WCHAR szDefaultIcon[] =
5574             {'D','e','f','a','u','l','t','I','c','o','n',0};
5575         static const WCHAR szCurVer[] =
5576             {'C','u','r','V','e','r',0};
5577
5578         /* check if already registered */
5579         RegCreateKeyExW(HKEY_CLASSES_ROOT, progid->ProgID, 0, NULL, 0,
5580                         KEY_ALL_ACCESS, NULL, &hkey, &disp );
5581         if (disp == REG_OPENED_EXISTING_KEY)
5582         {
5583             TRACE("Key already registered\n");
5584             RegCloseKey(hkey);
5585             return rc;
5586         }
5587
5588         TRACE("Registering Parent %s index %i\n",
5589                     debugstr_w(package->progids[progid->ParentIndex].ProgID), 
5590                     progid->ParentIndex);
5591         rc = register_progid(package,&package->progids[progid->ParentIndex],
5592                         clsid);
5593
5594         /* clsid is same as parent */
5595         RegCreateKeyW(hkey,szCLSID,&hkey2);
5596         RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)clsid, (strlenW(clsid)+1) *
5597                        sizeof(WCHAR));
5598
5599         RegCloseKey(hkey2);
5600
5601
5602         if (progid->Description)
5603         {
5604             RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid->Description,
5605                            (strlenW(progid->Description)+1) * sizeof(WCHAR));
5606         }
5607
5608         if (progid->IconPath)
5609         {
5610             RegCreateKeyW(hkey,szDefaultIcon,&hkey2);
5611             RegSetValueExW(hkey2,NULL,0,REG_SZ,(LPVOID)progid->IconPath,
5612                            (strlenW(progid->IconPath)+1) * sizeof(WCHAR));
5613             RegCloseKey(hkey2);
5614         }
5615
5616         /* write out the current version */
5617         if (progid->CurVerIndex >= 0)
5618         {
5619             RegCreateKeyW(hkey,szCurVer,&hkey2);
5620             RegSetValueExW(hkey2,NULL,0,REG_SZ,
5621                 (LPVOID)package->progids[progid->CurVerIndex].ProgID,
5622                 (strlenW(package->progids[progid->CurVerIndex].ProgID)+1) * 
5623                 sizeof(WCHAR));
5624             RegCloseKey(hkey2);
5625         }
5626
5627         RegCloseKey(hkey);
5628     }
5629     return rc;
5630 }
5631
5632 static UINT ACTION_RegisterProgIdInfo(MSIPACKAGE *package)
5633 {
5634     INT i;
5635     MSIRECORD *uirow;
5636
5637     if (!package)
5638         return ERROR_INVALID_HANDLE;
5639
5640     load_classes_and_such(package);
5641
5642     for (i = 0; i < package->loaded_progids; i++)
5643     {
5644         WCHAR clsid[0x1000];
5645
5646         /* check if this progid is to be installed */
5647         package->progids[i].InstallMe =  ((package->progids[i].InstallMe) ||
5648               (package->progids[i].ClassIndex >= 0 &&
5649               package->classes[package->progids[i].ClassIndex].Installed));
5650
5651         if (!package->progids[i].InstallMe)
5652         {
5653             TRACE("progid %s not scheduled to be installed\n",
5654                              debugstr_w(package->progids[i].ProgID));
5655             continue;
5656         }
5657        
5658         TRACE("Registering progid %s index %i\n",
5659                         debugstr_w(package->progids[i].ProgID), i);
5660
5661         register_progid(package,&package->progids[i],clsid);
5662
5663         uirow = MSI_CreateRecord(1);
5664         MSI_RecordSetStringW(uirow,1,package->progids[i].ProgID);
5665         ui_actiondata(package,szRegisterProgIdInfo,uirow);
5666         msiobj_release(&uirow->hdr);
5667     }
5668
5669     return ERROR_SUCCESS;
5670 }
5671
5672 static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, 
5673                             LPWSTR *FilePath)
5674 {
5675     LPWSTR ProductCode;
5676     LPWSTR SystemFolder;
5677     LPWSTR dest;
5678     UINT rc;
5679
5680     static const WCHAR szInstaller[] = 
5681         {'M','i','c','r','o','s','o','f','t','\\',
5682          'I','n','s','t','a','l','l','e','r','\\',0};
5683     static const WCHAR szFolder[] =
5684         {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
5685
5686     ProductCode = load_dynamic_property(package,szProductCode,&rc);
5687     if (!ProductCode)
5688         return rc;
5689
5690     SystemFolder = load_dynamic_property(package,szFolder,NULL);
5691
5692     dest = build_directory_name(3, SystemFolder, szInstaller, ProductCode);
5693
5694     create_full_pathW(dest);
5695
5696     *FilePath = build_directory_name(2, dest, icon_name);
5697
5698     HeapFree(GetProcessHeap(),0,SystemFolder);
5699     HeapFree(GetProcessHeap(),0,ProductCode);
5700     HeapFree(GetProcessHeap(),0,dest);
5701     return ERROR_SUCCESS;
5702 }
5703
5704 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
5705 {
5706     UINT rc;
5707     MSIQUERY * view;
5708     MSIRECORD * row = 0;
5709     static const WCHAR Query[] =
5710         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5711          '`','S','h','o','r','t','c','u','t','`',0};
5712     IShellLinkW *sl;
5713     IPersistFile *pf;
5714     HRESULT res;
5715
5716     if (!package)
5717         return ERROR_INVALID_HANDLE;
5718
5719     res = CoInitialize( NULL );
5720     if (FAILED (res))
5721     {
5722         ERR("CoInitialize failed\n");
5723         return ERROR_FUNCTION_FAILED;
5724     }
5725
5726     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
5727     if (rc != ERROR_SUCCESS)
5728         return ERROR_SUCCESS;
5729
5730     rc = MSI_ViewExecute(view, 0);
5731     if (rc != ERROR_SUCCESS)
5732     {
5733         MSI_ViewClose(view);
5734         msiobj_release(&view->hdr);
5735         return rc;
5736     }
5737
5738     while (1)
5739     {
5740         LPWSTR target_file, target_folder;
5741         LPCWSTR buffer;
5742         WCHAR filename[0x100];
5743         DWORD sz;
5744         DWORD index;
5745         static const WCHAR szlnk[]={'.','l','n','k',0};
5746
5747         rc = MSI_ViewFetch(view,&row);
5748         if (rc != ERROR_SUCCESS)
5749         {
5750             rc = ERROR_SUCCESS;
5751             break;
5752         }
5753         
5754         buffer = MSI_RecordGetString(row,4);
5755         index = get_loaded_component(package,buffer);
5756
5757         if (index < 0)
5758         {
5759             msiobj_release(&row->hdr);
5760             continue;
5761         }
5762
5763         if (!ACTION_VerifyComponentForAction(package, index,
5764                                 INSTALLSTATE_LOCAL))
5765         {
5766             TRACE("Skipping shortcut creation due to disabled component\n");
5767             msiobj_release(&row->hdr);
5768
5769             package->components[index].Action =
5770                 package->components[index].Installed;
5771
5772             continue;
5773         }
5774
5775         package->components[index].Action = INSTALLSTATE_LOCAL;
5776
5777         ui_actiondata(package,szCreateShortcuts,row);
5778
5779         res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
5780                               &IID_IShellLinkW, (LPVOID *) &sl );
5781
5782         if (FAILED(res))
5783         {
5784             ERR("Is IID_IShellLink\n");
5785             msiobj_release(&row->hdr);
5786             continue;
5787         }
5788
5789         res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
5790         if( FAILED( res ) )
5791         {
5792             ERR("Is IID_IPersistFile\n");
5793             msiobj_release(&row->hdr);
5794             continue;
5795         }
5796
5797         buffer = MSI_RecordGetString(row,2);
5798         target_folder = resolve_folder(package, buffer,FALSE,FALSE,NULL);
5799
5800         /* may be needed because of a bug somehwere else */
5801         create_full_pathW(target_folder);
5802
5803         sz = 0x100;
5804         MSI_RecordGetStringW(row,3,filename,&sz);
5805         reduce_to_longfilename(filename);
5806         if (!strchrW(filename,'.') || strcmpiW(strchrW(filename,'.'),szlnk))
5807             strcatW(filename,szlnk);
5808         target_file = build_directory_name(2, target_folder, filename);
5809         HeapFree(GetProcessHeap(),0,target_folder);
5810
5811         buffer = MSI_RecordGetString(row,5);
5812         if (strchrW(buffer,'['))
5813         {
5814             LPWSTR deformated;
5815             deformat_string(package,buffer,&deformated);
5816             IShellLinkW_SetPath(sl,deformated);
5817             HeapFree(GetProcessHeap(),0,deformated);
5818         }
5819         else
5820         {
5821             LPWSTR keypath;
5822             FIXME("poorly handled shortcut format, advertised shortcut\n");
5823             keypath = strdupW(package->components[index].FullKeypath);
5824             IShellLinkW_SetPath(sl,keypath);
5825             HeapFree(GetProcessHeap(),0,keypath);
5826         }
5827
5828         if (!MSI_RecordIsNull(row,6))
5829         {
5830             LPWSTR deformated;
5831             buffer = MSI_RecordGetString(row,6);
5832             deformat_string(package,buffer,&deformated);
5833             IShellLinkW_SetArguments(sl,deformated);
5834             HeapFree(GetProcessHeap(),0,deformated);
5835         }
5836
5837         if (!MSI_RecordIsNull(row,7))
5838         {
5839             buffer = MSI_RecordGetString(row,7);
5840             IShellLinkW_SetDescription(sl,buffer);
5841         }
5842
5843         if (!MSI_RecordIsNull(row,8))
5844             IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
5845
5846         if (!MSI_RecordIsNull(row,9))
5847         {
5848             WCHAR *Path = NULL;
5849             INT index; 
5850
5851             buffer = MSI_RecordGetString(row,9);
5852
5853             build_icon_path(package,buffer,&Path);
5854             index = MSI_RecordGetInteger(row,10);
5855
5856             IShellLinkW_SetIconLocation(sl,Path,index);
5857             HeapFree(GetProcessHeap(),0,Path);
5858         }
5859
5860         if (!MSI_RecordIsNull(row,11))
5861             IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
5862
5863         if (!MSI_RecordIsNull(row,12))
5864         {
5865             LPWSTR Path;
5866             buffer = MSI_RecordGetString(row,12);
5867             Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
5868             IShellLinkW_SetWorkingDirectory(sl,Path);
5869             HeapFree(GetProcessHeap(), 0, Path);
5870         }
5871
5872         TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
5873         IPersistFile_Save(pf,target_file,FALSE);
5874     
5875         HeapFree(GetProcessHeap(),0,target_file);    
5876
5877         IPersistFile_Release( pf );
5878         IShellLinkW_Release( sl );
5879
5880         msiobj_release(&row->hdr);
5881     }
5882     MSI_ViewClose(view);
5883     msiobj_release(&view->hdr);
5884
5885
5886     CoUninitialize();
5887
5888     return rc;
5889 }
5890
5891
5892 /*
5893  * 99% of the work done here is only done for 
5894  * advertised installs. However this is where the
5895  * Icon table is processed and written out
5896  * so that is what I am going to do here.
5897  */
5898 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
5899 {
5900     UINT rc;
5901     MSIQUERY * view;
5902     MSIRECORD * row = 0;
5903     static const WCHAR Query[]=
5904         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
5905          '`','I','c','o','n','`',0};
5906     DWORD sz;
5907     /* for registry stuff */
5908     LPWSTR productcode;
5909     HKEY hkey=0;
5910     HKEY hukey=0;
5911     static const WCHAR szProductName[] =
5912         {'P','r','o','d','u','c','t','N','a','m','e',0};
5913     static const WCHAR szPackageCode[] =
5914         {'P','a','c','k','a','g','e','C','o','d','e',0};
5915     static const WCHAR szLanguage[] =
5916         {'L','a','n','g','u','a','g','e',0};
5917     static const WCHAR szProductLanguage[] =
5918         {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
5919     static const WCHAR szProductIcon[] =
5920         {'P','r','o','d','u','c','t','I','c','o','n',0};
5921     static const WCHAR szARPProductIcon[] =
5922         {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
5923     static const WCHAR szProductVersion[] =
5924         {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
5925     static const WCHAR szVersion[] =
5926         {'V','e','r','s','i','o','n',0};
5927     DWORD langid;
5928     LPWSTR buffer;
5929     DWORD size;
5930     MSIHANDLE hDb, hSumInfo;
5931
5932     if (!package)
5933         return ERROR_INVALID_HANDLE;
5934
5935     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
5936     if (rc != ERROR_SUCCESS)
5937         goto next;
5938
5939     rc = MSI_ViewExecute(view, 0);
5940     if (rc != ERROR_SUCCESS)
5941     {
5942         MSI_ViewClose(view);
5943         msiobj_release(&view->hdr);
5944         goto next;
5945     }
5946
5947     while (1)
5948     {
5949         HANDLE the_file;
5950         LPWSTR FilePath=NULL;
5951         LPCWSTR FileName=NULL;
5952         CHAR buffer[1024];
5953
5954         rc = MSI_ViewFetch(view,&row);
5955         if (rc != ERROR_SUCCESS)
5956         {
5957             rc = ERROR_SUCCESS;
5958             break;
5959         }
5960     
5961         FileName = MSI_RecordGetString(row,1);
5962         if (!FileName)
5963         {
5964             ERR("Unable to get FileName\n");
5965             msiobj_release(&row->hdr);
5966             continue;
5967         }
5968
5969         build_icon_path(package,FileName,&FilePath);
5970
5971         TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
5972         
5973         the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
5974                            FILE_ATTRIBUTE_NORMAL, NULL);
5975
5976         if (the_file == INVALID_HANDLE_VALUE)
5977         {
5978             ERR("Unable to create file %s\n",debugstr_w(FilePath));
5979             msiobj_release(&row->hdr);
5980             HeapFree(GetProcessHeap(),0,FilePath);
5981             continue;
5982         }
5983
5984         do 
5985         {
5986             DWORD write;
5987             sz = 1024;
5988             rc = MSI_RecordReadStream(row,2,buffer,&sz);
5989             if (rc != ERROR_SUCCESS)
5990             {
5991                 ERR("Failed to get stream\n");
5992                 CloseHandle(the_file);  
5993                 DeleteFileW(FilePath);
5994                 break;
5995             }
5996             WriteFile(the_file,buffer,sz,&write,NULL);
5997         } while (sz == 1024);
5998
5999         HeapFree(GetProcessHeap(),0,FilePath);
6000
6001         CloseHandle(the_file);
6002         msiobj_release(&row->hdr);
6003     }
6004     MSI_ViewClose(view);
6005     msiobj_release(&view->hdr);
6006
6007 next:
6008     /* ok there is a lot more done here but i need to figure out what */
6009     productcode = load_dynamic_property(package,szProductCode,&rc);
6010     if (!productcode)
6011         return rc;
6012
6013     rc = MSIREG_OpenProductsKey(productcode,&hkey,TRUE);
6014     if (rc != ERROR_SUCCESS)
6015         goto end;
6016
6017     rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE);
6018     if (rc != ERROR_SUCCESS)
6019         goto end;
6020
6021
6022     buffer = load_dynamic_property(package,szProductName,NULL);
6023     size = strlenW(buffer)*sizeof(WCHAR);
6024     RegSetValueExW(hukey,szProductName,0,REG_SZ, (BYTE *)buffer,size);
6025     HeapFree(GetProcessHeap(),0,buffer);
6026
6027     buffer = load_dynamic_property(package,szProductLanguage,NULL);
6028     size = sizeof(DWORD);
6029     langid = atoiW(buffer);
6030     RegSetValueExW(hukey,szLanguage,0,REG_DWORD, (BYTE *)&langid,size);
6031     HeapFree(GetProcessHeap(),0,buffer);
6032
6033     buffer = load_dynamic_property(package,szARPProductIcon,NULL);
6034     if (buffer)
6035     {
6036         LPWSTR path;
6037         build_icon_path(package,buffer,&path);
6038         size = strlenW(path) * sizeof(WCHAR);
6039         RegSetValueExW(hukey,szProductIcon,0,REG_SZ, (BYTE *)path,size);
6040     }
6041     HeapFree(GetProcessHeap(),0,buffer);
6042
6043     buffer = load_dynamic_property(package,szProductVersion,NULL);
6044     if (buffer)
6045     {
6046         DWORD verdword = build_version_dword(buffer);
6047         size = sizeof(DWORD);
6048         RegSetValueExW(hukey,szVersion,0,REG_DWORD, (BYTE *)&verdword,size);
6049     }
6050     HeapFree(GetProcessHeap(),0,buffer);
6051     
6052     FIXME("Need to write more keys to the user registry\n");
6053   
6054     hDb= alloc_msihandle( &package->db->hdr );
6055     rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo); 
6056     MsiCloseHandle(hDb);
6057     if (rc == ERROR_SUCCESS)
6058     {
6059         WCHAR guidbuffer[0x200];
6060         size = 0x200;
6061         rc = MsiSummaryInfoGetPropertyW(hSumInfo, 9, NULL, NULL, NULL,
6062                                         guidbuffer, &size);
6063         if (rc == ERROR_SUCCESS)
6064         {
6065             WCHAR squashed[GUID_SIZE];
6066             /* for now we only care about the first guid */
6067             LPWSTR ptr = strchrW(guidbuffer,';');
6068             if (ptr) *ptr = 0;
6069             squash_guid(guidbuffer,squashed);
6070             size = strlenW(squashed)*sizeof(WCHAR);
6071             RegSetValueExW(hukey,szPackageCode,0,REG_SZ, (LPSTR)squashed,
6072                            size);
6073         }
6074         else
6075         {
6076             ERR("Unable to query Revision_Number... \n");
6077             rc = ERROR_SUCCESS;
6078         }
6079         MsiCloseHandle(hSumInfo);
6080     }
6081     else
6082     {
6083         ERR("Unable to open Summary Information\n");
6084         rc = ERROR_SUCCESS;
6085     }
6086
6087 end:
6088
6089     HeapFree(GetProcessHeap(),0,productcode);    
6090     RegCloseKey(hkey);
6091     RegCloseKey(hukey);
6092
6093     return rc;
6094 }
6095
6096 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
6097 {
6098     UINT rc;
6099     MSIQUERY * view;
6100     MSIRECORD * row = 0;
6101     static const WCHAR ExecSeqQuery[] = 
6102         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6103          '`','I','n','i','F','i','l','e','`',0};
6104     static const WCHAR szWindowsFolder[] =
6105           {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
6106
6107     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6108     if (rc != ERROR_SUCCESS)
6109     {
6110         TRACE("no IniFile table\n");
6111         return ERROR_SUCCESS;
6112     }
6113
6114     rc = MSI_ViewExecute(view, 0);
6115     if (rc != ERROR_SUCCESS)
6116     {
6117         MSI_ViewClose(view);
6118         msiobj_release(&view->hdr);
6119         return rc;
6120     }
6121
6122     while (1)
6123     {
6124         LPCWSTR component,section,key,value,identifier,filename,dirproperty;
6125         LPWSTR deformated_section, deformated_key, deformated_value;
6126         LPWSTR folder, fullname = NULL;
6127         MSIRECORD * uirow;
6128         INT component_index,action;
6129
6130         rc = MSI_ViewFetch(view,&row);
6131         if (rc != ERROR_SUCCESS)
6132         {
6133             rc = ERROR_SUCCESS;
6134             break;
6135         }
6136
6137         component = MSI_RecordGetString(row, 8);
6138         component_index = get_loaded_component(package,component);
6139
6140         if (!ACTION_VerifyComponentForAction(package, component_index,
6141                                 INSTALLSTATE_LOCAL))
6142         {
6143             TRACE("Skipping ini file due to disabled component %s\n",
6144                             debugstr_w(component));
6145             msiobj_release(&row->hdr);
6146
6147             package->components[component_index].Action =
6148                 package->components[component_index].Installed;
6149
6150             continue;
6151         }
6152
6153         package->components[component_index].Action = INSTALLSTATE_LOCAL;
6154    
6155         identifier = MSI_RecordGetString(row,1); 
6156         filename = MSI_RecordGetString(row,2);
6157         dirproperty = MSI_RecordGetString(row,3);
6158         section = MSI_RecordGetString(row,4);
6159         key = MSI_RecordGetString(row,5);
6160         value = MSI_RecordGetString(row,6);
6161         action = MSI_RecordGetInteger(row,7);
6162
6163         deformat_string(package,section,&deformated_section);
6164         deformat_string(package,key,&deformated_key);
6165         deformat_string(package,value,&deformated_value);
6166
6167         if (dirproperty)
6168         {
6169             folder = resolve_folder(package, dirproperty, FALSE, FALSE, NULL);
6170             if (!folder)
6171                 folder = load_dynamic_property(package,dirproperty,NULL);
6172         }
6173         else
6174             folder = load_dynamic_property(package, szWindowsFolder, NULL);
6175
6176         if (!folder)
6177         {
6178             ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
6179             goto cleanup;
6180         }
6181
6182         fullname = build_directory_name(3, folder, filename, NULL);
6183
6184         if (action == 0)
6185         {
6186             TRACE("Adding value %s to section %s in %s\n",
6187                 debugstr_w(deformated_key), debugstr_w(deformated_section),
6188                 debugstr_w(fullname));
6189             WritePrivateProfileStringW(deformated_section, deformated_key,
6190                                        deformated_value, fullname);
6191         }
6192         else if (action == 1)
6193         {
6194             WCHAR returned[10];
6195             GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
6196                                      returned, 10, fullname);
6197             if (returned[0] == 0)
6198             {
6199                 TRACE("Adding value %s to section %s in %s\n",
6200                     debugstr_w(deformated_key), debugstr_w(deformated_section),
6201                     debugstr_w(fullname));
6202
6203                 WritePrivateProfileStringW(deformated_section, deformated_key,
6204                                        deformated_value, fullname);
6205             }
6206         }
6207         else if (action == 3)
6208         {
6209             FIXME("Append to existing section not yet implemented\n");
6210         }
6211         
6212         uirow = MSI_CreateRecord(4);
6213         MSI_RecordSetStringW(uirow,1,identifier);
6214         MSI_RecordSetStringW(uirow,2,deformated_section);
6215         MSI_RecordSetStringW(uirow,3,deformated_key);
6216         MSI_RecordSetStringW(uirow,4,deformated_value);
6217         ui_actiondata(package,szWriteIniValues,uirow);
6218         msiobj_release( &uirow->hdr );
6219 cleanup:
6220         HeapFree(GetProcessHeap(),0,fullname);
6221         HeapFree(GetProcessHeap(),0,folder);
6222         HeapFree(GetProcessHeap(),0,deformated_key);
6223         HeapFree(GetProcessHeap(),0,deformated_value);
6224         HeapFree(GetProcessHeap(),0,deformated_section);
6225         msiobj_release(&row->hdr);
6226     }
6227     MSI_ViewClose(view);
6228     msiobj_release(&view->hdr);
6229     return rc;
6230 }
6231
6232 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
6233 {
6234     UINT rc;
6235     MSIQUERY * view;
6236     MSIRECORD * row = 0;
6237     static const WCHAR ExecSeqQuery[] = 
6238         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
6239          '`','S','e','l','f','R','e','g','`',0};
6240
6241     static const WCHAR ExeStr[] =
6242         {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
6243     static const WCHAR close[] =  {'\"',0};
6244     STARTUPINFOW si;
6245     PROCESS_INFORMATION info;
6246     BOOL brc;
6247
6248     memset(&si,0,sizeof(STARTUPINFOW));
6249
6250     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
6251     if (rc != ERROR_SUCCESS)
6252     {
6253         TRACE("no SelfReg table\n");
6254         return ERROR_SUCCESS;
6255     }
6256
6257     rc = MSI_ViewExecute(view, 0);
6258     if (rc != ERROR_SUCCESS)
6259     {
6260         MSI_ViewClose(view);
6261         msiobj_release(&view->hdr);
6262         return rc;
6263     }
6264
6265     while (1)
6266     {
6267         LPCWSTR filename;
6268         LPWSTR FullName;
6269         INT index;
6270         DWORD len;
6271
6272         rc = MSI_ViewFetch(view,&row);
6273         if (rc != ERROR_SUCCESS)
6274         {
6275             rc = ERROR_SUCCESS;
6276             break;
6277         }
6278
6279         filename = MSI_RecordGetString(row,1);
6280         index = get_loaded_file(package,filename);
6281
6282         if (index < 0)
6283         {
6284             ERR("Unable to find file id %s\n",debugstr_w(filename));
6285             msiobj_release(&row->hdr);
6286             continue;
6287         }
6288
6289         len = strlenW(ExeStr);
6290         len += strlenW(package->files[index].TargetPath);
6291         len +=2;
6292
6293         FullName = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
6294         strcpyW(FullName,ExeStr);
6295         strcatW(FullName,package->files[index].TargetPath);
6296         strcatW(FullName,close);
6297
6298         TRACE("Registering %s\n",debugstr_w(FullName));
6299         brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL,
6300                   c_colon, &si, &info);
6301
6302         if (brc)
6303             msi_dialog_check_messages(info.hProcess);
6304  
6305         HeapFree(GetProcessHeap(),0,FullName);
6306         msiobj_release(&row->hdr);
6307     }
6308     MSI_ViewClose(view);
6309     msiobj_release(&view->hdr);
6310     return rc;
6311 }
6312
6313 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
6314 {
6315     LPWSTR productcode;
6316     UINT rc;
6317     DWORD i;
6318     HKEY hkey=0;
6319     HKEY hukey=0;
6320     
6321     if (!package)
6322         return ERROR_INVALID_HANDLE;
6323
6324     productcode = load_dynamic_property(package,szProductCode,&rc);
6325     if (!productcode)
6326         return rc;
6327
6328     rc = MSIREG_OpenFeaturesKey(productcode,&hkey,TRUE);
6329     if (rc != ERROR_SUCCESS)
6330         goto end;
6331
6332     rc = MSIREG_OpenUserFeaturesKey(productcode,&hukey,TRUE);
6333     if (rc != ERROR_SUCCESS)
6334         goto end;
6335
6336     /* here the guids are base 85 encoded */
6337     for (i = 0; i < package->loaded_features; i++)
6338     {
6339         LPWSTR data = NULL;
6340         GUID clsid;
6341         int j;
6342         INT size;
6343         BOOL absent = FALSE;
6344
6345         if (!ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_LOCAL) &&
6346             !ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_SOURCE) &&
6347             !ACTION_VerifyFeatureForAction(package,i,INSTALLSTATE_ADVERTISED))
6348             absent = TRUE;
6349
6350         size = package->features[i].ComponentCount*21;
6351         size +=1;
6352         if (package->features[i].Feature_Parent[0])
6353             size += strlenW(package->features[i].Feature_Parent)+2;
6354
6355         data = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
6356
6357         data[0] = 0;
6358         for (j = 0; j < package->features[i].ComponentCount; j++)
6359         {
6360             WCHAR buf[21];
6361             memset(buf,0,sizeof(buf));
6362             if (package->components
6363                 [package->features[i].Components[j]].ComponentId[0]!=0)
6364             {
6365                 TRACE("From %s\n",debugstr_w(package->components
6366                             [package->features[i].Components[j]].ComponentId));
6367                 CLSIDFromString(package->components
6368                             [package->features[i].Components[j]].ComponentId,
6369                             &clsid);
6370                 encode_base85_guid(&clsid,buf);
6371                 TRACE("to %s\n",debugstr_w(buf));
6372                 strcatW(data,buf);
6373             }
6374         }
6375         if (package->features[i].Feature_Parent[0])
6376         {
6377             static const WCHAR sep[] = {'\2',0};
6378             strcatW(data,sep);
6379             strcatW(data,package->features[i].Feature_Parent);
6380         }
6381
6382         size = (strlenW(data)+1)*sizeof(WCHAR);
6383         RegSetValueExW(hkey,package->features[i].Feature,0,REG_SZ,
6384                        (LPSTR)data,size);
6385         HeapFree(GetProcessHeap(),0,data);
6386
6387         if (!absent)
6388         {
6389             size = strlenW(package->features[i].Feature_Parent)*sizeof(WCHAR);
6390             RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ,
6391                        (LPSTR)package->features[i].Feature_Parent,size);
6392         }
6393         else
6394         {
6395             size = (strlenW(package->features[i].Feature_Parent)+2)*
6396                     sizeof(WCHAR);
6397             data = HeapAlloc(GetProcessHeap(),0,size);
6398             data[0] = 0x6;
6399             strcpyW(&data[1],package->features[i].Feature_Parent);
6400             RegSetValueExW(hukey,package->features[i].Feature,0,REG_SZ,
6401                        (LPSTR)data,size);
6402             HeapFree(GetProcessHeap(),0,data);
6403         }
6404     }
6405
6406 end:
6407     RegCloseKey(hkey);
6408     RegCloseKey(hukey);
6409     HeapFree(GetProcessHeap(), 0, productcode);
6410     return rc;
6411 }
6412
6413 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
6414 {
6415     HKEY hkey=0;
6416     LPWSTR buffer;
6417     LPWSTR productcode;
6418     UINT rc,i;
6419     DWORD size;
6420     static WCHAR szNONE[] = {0};
6421     static const WCHAR szWindowsInstaler[] = 
6422     {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
6423     static const WCHAR szPropKeys[][80] = 
6424     {
6425 {'A','R','P','A','U','T','H','O','R','I','Z','E','D','C','D','F','P','R','E','F','I','X',0},
6426 {'A','R','P','C','O','N','T','A','C','T',0},
6427 {'A','R','P','C','O','M','M','E','N','T','S',0},
6428 {'P','r','o','d','u','c','t','N','a','m','e',0},
6429 {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0},
6430 {'A','R','P','H','E','L','P','L','I','N','K',0},
6431 {'A','R','P','H','E','L','P','T','E','L','E','P','H','O','N','E',0},
6432 {'A','R','P','I','N','S','T','A','L','L','L','O','C','A','T','I','O','N',0},
6433 {'S','o','u','r','c','e','D','i','r',0},
6434 {'M','a','n','u','f','a','c','t','u','r','e','r',0},
6435 {'A','R','P','R','E','A','D','M','E',0},
6436 {'A','R','P','S','I','Z','E',0},
6437 {'A','R','P','U','R','L','I','N','F','O','A','B','O','U','T',0},
6438 {'A','R','P','U','R','L','U','P','D','A','T','E','I','N','F','O',0},
6439 {0},
6440     };
6441
6442     static const WCHAR szRegKeys[][80] = 
6443     {
6444 {'A','u','t','h','o','r','i','z','e','d','C','D','F','P','r','e','f','i','x',0},
6445 {'C','o','n','t','a','c','t',0},
6446 {'C','o','m','m','e','n','t','s',0},
6447 {'D','i','s','p','l','a','y','N','a','m','e',0},
6448 {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0},
6449 {'H','e','l','p','L','i','n','k',0},
6450 {'H','e','l','p','T','e','l','e','p','h','o','n','e',0},
6451 {'I','n','s','t','a','l','l','L','o','c','a','t','i','o','n',0},
6452 {'I','n','s','t','a','l','l','S','o','u','r','c','e',0},
6453 {'P','u','b','l','i','s','h','e','r',0},
6454 {'R','e','a','d','m','e',0},
6455 {'S','i','z','e',0},
6456 {'U','R','L','I','n','f','o','A','b','o','u','t',0},
6457 {'U','R','L','U','p','d','a','t','e','I','n','f','o',0},
6458 {0},
6459     };
6460
6461     static const WCHAR installerPathFmt[] = {
6462     '%','s','\\',
6463     'I','n','s','t','a','l','l','e','r','\\',0};
6464     static const WCHAR fmt[] = {
6465     '%','s','\\',
6466     'I','n','s','t','a','l','l','e','r','\\',
6467     '%','x','.','m','s','i',0};
6468     static const WCHAR szLocalPackage[]=
6469          {'L','o','c','a','l','P','a','c','k','a','g','e',0};
6470     static const WCHAR szUpgradeCode[] = 
6471         {'U','p','g','r','a','d','e','C','o','d','e',0};
6472     LPWSTR upgrade_code;
6473     WCHAR windir[MAX_PATH], path[MAX_PATH], packagefile[MAX_PATH];
6474     INT num,start;
6475
6476     if (!package)
6477         return ERROR_INVALID_HANDLE;
6478
6479     productcode = load_dynamic_property(package,szProductCode,&rc);
6480     if (!productcode)
6481         return rc;
6482
6483     rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE);
6484     if (rc != ERROR_SUCCESS)
6485         goto end;
6486
6487     /* dump all the info i can grab */
6488     FIXME("Flesh out more information \n");
6489
6490     i = 0;
6491     while (szPropKeys[i][0]!=0)
6492     {
6493         buffer = load_dynamic_property(package,szPropKeys[i],&rc);
6494         if (rc != ERROR_SUCCESS)
6495             buffer = szNONE;
6496         size = strlenW(buffer)*sizeof(WCHAR);
6497         RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size);
6498         i++;
6499     }
6500
6501     rc = 0x1;
6502     size = sizeof(rc);
6503     RegSetValueExW(hkey,szWindowsInstaler,0,REG_DWORD,(LPSTR)&rc,size);
6504     
6505     /* copy the package locally */
6506     num = GetTickCount() & 0xffff;
6507     if (!num) 
6508         num = 1;
6509     start = num;
6510     GetWindowsDirectoryW(windir, sizeof(windir) / sizeof(windir[0]));
6511     snprintfW(packagefile,sizeof(packagefile)/sizeof(packagefile[0]),fmt,
6512      windir,num);
6513     do 
6514     {
6515         HANDLE handle = CreateFileW(packagefile,GENERIC_WRITE, 0, NULL,
6516                                   CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
6517         if (handle != INVALID_HANDLE_VALUE)
6518         {
6519             CloseHandle(handle);
6520             break;
6521         }
6522         if (GetLastError() != ERROR_FILE_EXISTS &&
6523             GetLastError() != ERROR_SHARING_VIOLATION)
6524             break;
6525         if (!(++num & 0xffff)) num = 1;
6526         sprintfW(packagefile,fmt,num);
6527     } while (num != start);
6528
6529     snprintfW(path,sizeof(path)/sizeof(path[0]),installerPathFmt,windir);
6530     create_full_pathW(path);
6531     TRACE("Copying to local package %s\n",debugstr_w(packagefile));
6532     if (!CopyFileW(package->PackagePath,packagefile,FALSE))
6533         ERR("Unable to copy package (%s -> %s) (error %ld)\n",
6534             debugstr_w(package->PackagePath), debugstr_w(packagefile),
6535             GetLastError());
6536     size = strlenW(packagefile)*sizeof(WCHAR);
6537     RegSetValueExW(hkey,szLocalPackage,0,REG_SZ,(LPSTR)packagefile,size);
6538
6539     /* Handle Upgrade Codes */
6540     upgrade_code = load_dynamic_property(package,szUpgradeCode, NULL);
6541     if (upgrade_code)
6542     {
6543         HKEY hkey2;
6544         WCHAR squashed[33];
6545         MSIREG_OpenUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
6546         squash_guid(productcode,squashed);
6547         RegSetValueExW(hkey2, squashed, 0,REG_SZ,NULL,0);
6548         RegCloseKey(hkey2);
6549         MSIREG_OpenUserUpgradeCodesKey(upgrade_code, &hkey2, TRUE);
6550         squash_guid(productcode,squashed);
6551         RegSetValueExW(hkey2, squashed, 0,REG_SZ,NULL,0);
6552         RegCloseKey(hkey2);
6553
6554         HeapFree(GetProcessHeap(),0,upgrade_code);
6555     }
6556     
6557 end:
6558     HeapFree(GetProcessHeap(),0,productcode);
6559     RegCloseKey(hkey);
6560
6561     return ERROR_SUCCESS;
6562 }
6563
6564 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
6565 {
6566     UINT rc;
6567
6568     if (!package)
6569         return ERROR_INVALID_HANDLE;
6570
6571     rc = execute_script(package,INSTALL_SCRIPT);
6572
6573     return rc;
6574 }
6575
6576 static UINT ACTION_InstallFinalize(MSIPACKAGE *package)
6577 {
6578     UINT rc;
6579
6580     if (!package)
6581         return ERROR_INVALID_HANDLE;
6582
6583     /* turn off scheduleing */
6584     package->script->CurrentlyScripting= FALSE;
6585
6586     /* first do the same as an InstallExecute */
6587     rc = ACTION_InstallExecute(package);
6588     if (rc != ERROR_SUCCESS)
6589         return rc;
6590
6591     /* then handle Commit Actions */
6592     rc = execute_script(package,COMMIT_SCRIPT);
6593
6594     return rc;
6595 }
6596
6597 static UINT ACTION_ForceReboot(MSIPACKAGE *package)
6598 {
6599     static const WCHAR RunOnce[] = {
6600     'S','o','f','t','w','a','r','e','\\',
6601     'M','i','c','r','o','s','o','f','t','\\',
6602     'W','i','n','d','o','w','s','\\',
6603     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
6604     'R','u','n','O','n','c','e',0};
6605     static const WCHAR InstallRunOnce[] = {
6606     'S','o','f','t','w','a','r','e','\\',
6607     'M','i','c','r','o','s','o','f','t','\\',
6608     'W','i','n','d','o','w','s','\\',
6609     'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
6610     'I','n','s','t','a','l','l','e','r','\\',
6611     'R','u','n','O','n','c','e','E','n','t','r','i','e','s',0};
6612
6613     static const WCHAR msiexec_fmt[] = {
6614     '%','s',
6615     '\\','M','s','i','E','x','e','c','.','e','x','e',' ','/','@',' ',
6616     '\"','%','s','\"',0};
6617     static const WCHAR install_fmt[] = {
6618     '/','I',' ','\"','%','s','\"',' ',
6619     'A','F','T','E','R','R','E','B','O','O','T','=','1',' ',
6620     'R','U','N','O','N','C','E','E','N','T','R','Y','=','\"','%','s','\"',0};
6621     WCHAR buffer[256], sysdir[MAX_PATH];
6622     HKEY hkey,hukey;
6623     LPWSTR productcode;
6624     WCHAR  squished_pc[100];
6625     INT rc;
6626     DWORD size;
6627     static const WCHAR szLUS[] = {
6628          'L','a','s','t','U','s','e','d','S','o','u','r','c','e',0};
6629     static const WCHAR szSourceList[] = {
6630          'S','o','u','r','c','e','L','i','s','t',0};
6631     static const WCHAR szPackageName[] = { 
6632         'P','a','c','k','a','g','e','N','a','m','e',0};
6633
6634     if (!package)
6635         return ERROR_INVALID_HANDLE;
6636
6637     productcode = load_dynamic_property(package,szProductCode,&rc);
6638     if (!productcode)
6639         return rc;
6640
6641     squash_guid(productcode,squished_pc);
6642
6643     GetSystemDirectoryW(sysdir, sizeof(sysdir)/sizeof(sysdir[0]));
6644     RegCreateKeyW(HKEY_LOCAL_MACHINE,RunOnce,&hkey);
6645     snprintfW(buffer,sizeof(buffer)/sizeof(buffer[0]),msiexec_fmt,sysdir,
6646      squished_pc);
6647
6648     size = strlenW(buffer)*sizeof(WCHAR);
6649     RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size);
6650     RegCloseKey(hkey);
6651
6652     TRACE("Reboot command %s\n",debugstr_w(buffer));
6653
6654     RegCreateKeyW(HKEY_LOCAL_MACHINE,InstallRunOnce,&hkey);
6655     sprintfW(buffer,install_fmt,productcode,squished_pc);
6656
6657     size = strlenW(buffer)*sizeof(WCHAR);
6658     RegSetValueExW(hkey,squished_pc,0,REG_SZ,(LPSTR)buffer,size);
6659     RegCloseKey(hkey);
6660
6661     rc = MSIREG_OpenUserProductsKey(productcode,&hukey,TRUE);
6662     if (rc == ERROR_SUCCESS)
6663     {
6664         HKEY hukey2;
6665         LPWSTR buf;
6666         RegCreateKeyW(hukey, szSourceList, &hukey2);
6667         buf = load_dynamic_property(package,cszSourceDir,NULL);
6668         size = strlenW(buf)*sizeof(WCHAR);
6669         RegSetValueExW(hukey2,szLUS,0,REG_SZ,(LPSTR)buf,size);
6670         HeapFree(GetProcessHeap(),0,buf); 
6671
6672         buf = strrchrW(package->PackagePath,'\\');
6673         if (buf)
6674         {
6675             buf++;
6676             size = strlenW(buf)*sizeof(WCHAR);
6677             RegSetValueExW(hukey2,szPackageName,0,REG_SZ,(LPSTR)buf,size);
6678         }
6679
6680         RegCloseKey(hukey2);
6681     }
6682     HeapFree(GetProcessHeap(),0,productcode);
6683
6684     return ERROR_INSTALL_SUSPEND;
6685 }
6686
6687 UINT ACTION_ResolveSource(MSIPACKAGE* package)
6688 {
6689     /*
6690      * we are currently doing what should be done here in the top level Install
6691      * however for Adminastrative and uninstalls this step will be needed
6692      */
6693     return ERROR_SUCCESS;
6694 }
6695
6696 static LPWSTR create_component_advertise_string(MSIPACKAGE* package, 
6697                 MSICOMPONENT* component, LPCWSTR feature)
6698 {
6699     LPWSTR productid=NULL;
6700     GUID clsid;
6701     WCHAR productid_85[21];
6702     WCHAR component_85[21];
6703     /*
6704      * I have a fair bit of confusion as to when a < is used and when a > is
6705      * used. I do not think i have it right...
6706      *
6707      * Ok it appears that the > is used if there is a guid for the compoenent
6708      * and the < is used if not.
6709      */
6710     static WCHAR fmt1[] = {'%','s','%','s','<',0,0};
6711     static WCHAR fmt2[] = {'%','s','%','s','>','%','s',0,0};
6712     LPWSTR output = NULL;
6713     DWORD sz = 0;
6714
6715     memset(productid_85,0,sizeof(productid_85));
6716     memset(component_85,0,sizeof(component_85));
6717
6718     productid = load_dynamic_property(package,szProductCode,NULL);
6719     CLSIDFromString(productid, &clsid);
6720     
6721     encode_base85_guid(&clsid,productid_85);
6722
6723     CLSIDFromString(component->ComponentId, &clsid);
6724     encode_base85_guid(&clsid,component_85);
6725
6726     TRACE("Doing something with this... %s %s %s\n", 
6727             debugstr_w(productid_85), debugstr_w(feature),
6728             debugstr_w(component_85));
6729  
6730     sz = lstrlenW(productid_85) + lstrlenW(feature);
6731     if (component)
6732         sz += lstrlenW(component_85);
6733
6734     sz+=3;
6735     sz *= sizeof(WCHAR);
6736            
6737     output = HeapAlloc(GetProcessHeap(),0,sz);
6738     memset(output,0,sz);
6739
6740     if (component)
6741         sprintfW(output,fmt2,productid_85,feature,component_85);
6742     else
6743         sprintfW(output,fmt1,productid_85,feature);
6744
6745     HeapFree(GetProcessHeap(),0,productid);
6746     
6747     return output;
6748 }
6749
6750 static UINT register_verb(MSIPACKAGE *package, LPCWSTR progid, 
6751                 MSICOMPONENT* component, MSIEXTENSION* extension,
6752                 MSIVERB* verb, INT* Sequence )
6753 {
6754     LPWSTR keyname;
6755     HKEY key;
6756     static const WCHAR szShell[] = {'s','h','e','l','l',0};
6757     static const WCHAR szCommand[] = {'c','o','m','m','a','n','d',0};
6758     static const WCHAR fmt[] = {'\"','%','s','\"',' ','%','s',0};
6759     static const WCHAR fmt2[] = {'\"','%','s','\"',0};
6760     LPWSTR command;
6761     DWORD size;
6762     LPWSTR advertise;
6763
6764     keyname = build_directory_name(4, progid, szShell, verb->Verb, szCommand);
6765
6766     TRACE("Making Key %s\n",debugstr_w(keyname));
6767     RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
6768     size = strlenW(component->FullKeypath);
6769     if (verb->Argument)
6770         size += strlenW(verb->Argument);
6771      size += 4;
6772
6773      command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR));
6774      if (verb->Argument)
6775         sprintfW(command, fmt, component->FullKeypath, verb->Argument);
6776      else
6777         sprintfW(command, fmt2, component->FullKeypath);
6778
6779      RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)command, (strlenW(command)+1)*
6780                      sizeof(WCHAR));
6781      HeapFree(GetProcessHeap(),0,command);
6782
6783      advertise = create_component_advertise_string(package, component, 
6784                         package->features[extension->FeatureIndex].Feature);
6785
6786      size = strlenW(advertise);
6787
6788      if (verb->Argument)
6789         size += strlenW(verb->Argument);
6790      size += 4;
6791
6792      command = HeapAlloc(GetProcessHeap(),0, size * sizeof (WCHAR));
6793      memset(command,0,size*sizeof(WCHAR));
6794
6795      strcpyW(command,advertise);
6796      if (verb->Argument)
6797      {
6798         static const WCHAR szSpace[] = {' ',0};
6799          strcatW(command,szSpace);
6800          strcatW(command,verb->Argument);
6801      }
6802
6803      RegSetValueExW(key, szCommand, 0, REG_MULTI_SZ, (LPBYTE)command,
6804                         (strlenW(command)+2)*sizeof(WCHAR));
6805      
6806      RegCloseKey(key);
6807      HeapFree(GetProcessHeap(),0,keyname);
6808      HeapFree(GetProcessHeap(),0,advertise);
6809      HeapFree(GetProcessHeap(),0,command);
6810
6811      if (verb->Command)
6812      {
6813         keyname = build_directory_name(3, progid, szShell, verb->Verb);
6814         RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
6815         RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Command,
6816                                     (strlenW(verb->Command)+1) *sizeof(WCHAR));
6817         RegCloseKey(key);
6818         HeapFree(GetProcessHeap(),0,keyname);
6819      }
6820
6821      if (verb->Sequence != MSI_NULL_INTEGER)
6822      {
6823         if (*Sequence == MSI_NULL_INTEGER || verb->Sequence < *Sequence)
6824         {
6825             *Sequence = verb->Sequence;
6826             keyname = build_directory_name(2, progid, szShell);
6827             RegCreateKeyW(HKEY_CLASSES_ROOT, keyname, &key);
6828             RegSetValueExW(key,NULL,0,REG_SZ, (LPVOID)verb->Verb,
6829                             (strlenW(verb->Verb)+1) *sizeof(WCHAR));
6830             RegCloseKey(key);
6831             HeapFree(GetProcessHeap(),0,keyname);
6832         }
6833     }
6834     return ERROR_SUCCESS;
6835 }
6836
6837 static UINT ACTION_RegisterExtensionInfo(MSIPACKAGE *package)
6838 {
6839     static const WCHAR szContentType[] = 
6840         {'C','o','n','t','e','n','t',' ','T','y','p','e',0 };
6841     HKEY hkey;
6842     INT i;
6843     MSIRECORD *uirow;
6844     BOOL install_on_demand = TRUE;
6845
6846     if (!package)
6847         return ERROR_INVALID_HANDLE;
6848
6849     load_classes_and_such(package);
6850
6851     /* We need to set install_on_demand based on if the shell handles advertised
6852      * shortcuts and the like. Because Mike McCormack is working on this i am
6853      * going to default to TRUE
6854      */
6855     
6856     for (i = 0; i < package->loaded_extensions; i++)
6857     {
6858         WCHAR extension[257];
6859         INT index,f_index;
6860      
6861         index = package->extensions[i].ComponentIndex;
6862         f_index = package->extensions[i].FeatureIndex;
6863
6864         if (index < 0)
6865             continue;
6866
6867         /* 
6868          * yes. MSDN says that these are based on _Feature_ not on
6869          * Component.  So verify the feature is to be installed
6870          */
6871         if ((!ACTION_VerifyFeatureForAction(package, f_index,
6872                                 INSTALLSTATE_LOCAL)) &&
6873              !(install_on_demand && ACTION_VerifyFeatureForAction(package,
6874                              f_index, INSTALLSTATE_ADVERTISED)))
6875         {
6876             TRACE("Skipping extension  %s reg due to disabled feature %s\n",
6877                             debugstr_w(package->extensions[i].Extension),
6878                             debugstr_w(package->features[f_index].Feature));
6879
6880             continue;
6881         }
6882
6883         TRACE("Registering extension %s index %i\n",
6884                         debugstr_w(package->extensions[i].Extension), i);
6885
6886         package->extensions[i].Installed = TRUE;
6887
6888         /* this is only registered if the extension has at least 1 verb
6889          * according to MSDN
6890          */
6891         if (package->extensions[i].ProgIDIndex >= 0 &&
6892                 package->extensions[i].VerbCount > 0)
6893            mark_progid_for_install(package, package->extensions[i].ProgIDIndex);
6894
6895         if (package->extensions[i].MIMEIndex >= 0)
6896            mark_mime_for_install(package, package->extensions[i].MIMEIndex);
6897
6898         extension[0] = '.';
6899         extension[1] = 0;
6900         strcatW(extension,package->extensions[i].Extension);
6901
6902         RegCreateKeyW(HKEY_CLASSES_ROOT,extension,&hkey);
6903
6904         if (package->extensions[i].MIMEIndex >= 0)
6905         {
6906             RegSetValueExW(hkey,szContentType,0,REG_SZ,
6907                             (LPVOID)package->mimes[package->extensions[i].
6908                                 MIMEIndex].ContentType,
6909                            (strlenW(package->mimes[package->extensions[i].
6910                                     MIMEIndex].ContentType)+1)*sizeof(WCHAR));
6911         }
6912
6913         if (package->extensions[i].ProgIDIndex >= 0 || 
6914             package->extensions[i].ProgIDText)
6915         {
6916             static const WCHAR szSN[] = 
6917                 {'\\','S','h','e','l','l','N','e','w',0};
6918             HKEY hkey2;
6919             LPWSTR newkey;
6920             LPCWSTR progid;
6921             INT v;
6922             INT Sequence = MSI_NULL_INTEGER;
6923             
6924             if (package->extensions[i].ProgIDIndex >= 0)
6925                 progid = package->progids[package->extensions[i].
6926                     ProgIDIndex].ProgID;
6927             else
6928                 progid = package->extensions[i].ProgIDText;
6929
6930             RegSetValueExW(hkey,NULL,0,REG_SZ,(LPVOID)progid,
6931                            (strlenW(progid)+1)*sizeof(WCHAR));
6932
6933             newkey = HeapAlloc(GetProcessHeap(),0,
6934                            (strlenW(progid)+strlenW(szSN)+1) * sizeof(WCHAR)); 
6935
6936             strcpyW(newkey,progid);
6937             strcatW(newkey,szSN);
6938             RegCreateKeyW(hkey,newkey,&hkey2);
6939             RegCloseKey(hkey2);
6940
6941             HeapFree(GetProcessHeap(),0,newkey);
6942
6943             /* do all the verbs */
6944             for (v = 0; v < package->extensions[i].VerbCount; v++)
6945                 register_verb(package, progid, 
6946                               &package->components[index],
6947                               &package->extensions[i],
6948                               &package->verbs[package->extensions[i].Verbs[v]], 
6949                               &Sequence);
6950         }
6951         
6952         RegCloseKey(hkey);
6953
6954         uirow = MSI_CreateRecord(1);
6955         MSI_RecordSetStringW(uirow,1,package->extensions[i].Extension);
6956         ui_actiondata(package,szRegisterExtensionInfo,uirow);
6957         msiobj_release(&uirow->hdr);
6958     }
6959
6960     return ERROR_SUCCESS;
6961 }
6962
6963 static UINT ACTION_RegisterMIMEInfo(MSIPACKAGE *package)
6964 {
6965     static const WCHAR szExten[] = 
6966         {'E','x','t','e','n','s','i','o','n',0 };
6967     HKEY hkey;
6968     INT i;
6969     MSIRECORD *uirow;
6970
6971     if (!package)
6972         return ERROR_INVALID_HANDLE;
6973
6974     load_classes_and_such(package);
6975
6976     for (i = 0; i < package->loaded_mimes; i++)
6977     {
6978         WCHAR extension[257];
6979         LPCWSTR exten;
6980         LPCWSTR mime;
6981         static const WCHAR fmt[] = 
6982             {'M','I','M','E','\\','D','a','t','a','b','a','s','e','\\',
6983              'C','o','n','t','e','n','t',' ','T','y','p','e','\\', '%','s',0};
6984         LPWSTR key;
6985
6986         /* 
6987          * check if the MIME is to be installed. Either as requesed by an
6988          * extension or Class
6989          */
6990         package->mimes[i].InstallMe =  ((package->mimes[i].InstallMe) ||
6991               (package->mimes[i].ClassIndex >= 0 &&
6992               package->classes[package->mimes[i].ClassIndex].Installed) ||
6993               (package->mimes[i].ExtensionIndex >=0 &&
6994               package->extensions[package->mimes[i].ExtensionIndex].Installed));
6995
6996         if (!package->mimes[i].InstallMe)
6997         {
6998             TRACE("MIME %s not scheduled to be installed\n",
6999                              debugstr_w(package->mimes[i].ContentType));
7000             continue;
7001         }
7002         
7003         mime = package->mimes[i].ContentType;
7004         exten = package->extensions[package->mimes[i].ExtensionIndex].Extension;
7005         extension[0] = '.';
7006         extension[1] = 0;
7007         strcatW(extension,exten);
7008
7009         key = HeapAlloc(GetProcessHeap(),0,(strlenW(mime)+strlenW(fmt)+1) *
7010                                             sizeof(WCHAR));
7011         sprintfW(key,fmt,mime);
7012         RegCreateKeyW(HKEY_CLASSES_ROOT,key,&hkey);
7013         RegSetValueExW(hkey,szExten,0,REG_SZ,(LPVOID)extension,
7014                            (strlenW(extension)+1)*sizeof(WCHAR));
7015
7016         HeapFree(GetProcessHeap(),0,key);
7017
7018         if (package->mimes[i].CLSID[0])
7019         {
7020             FIXME("Handle non null for field 3\n");
7021         }
7022
7023         RegCloseKey(hkey);
7024
7025         uirow = MSI_CreateRecord(2);
7026         MSI_RecordSetStringW(uirow,1,package->mimes[i].ContentType);
7027         MSI_RecordSetStringW(uirow,2,exten);
7028         ui_actiondata(package,szRegisterMIMEInfo,uirow);
7029         msiobj_release(&uirow->hdr);
7030     }
7031
7032     return ERROR_SUCCESS;
7033 }
7034
7035 static UINT ACTION_RegisterUser(MSIPACKAGE *package)
7036 {
7037     static const WCHAR szProductID[]=
7038          {'P','r','o','d','u','c','t','I','D',0};
7039     HKEY hkey=0;
7040     LPWSTR buffer;
7041     LPWSTR productcode;
7042     LPWSTR productid;
7043     UINT rc,i;
7044     DWORD size;
7045
7046     static const WCHAR szPropKeys[][80] = 
7047     {
7048         {'P','r','o','d','u','c','t','I','D',0},
7049         {'U','S','E','R','N','A','M','E',0},
7050         {'C','O','M','P','A','N','Y','N','A','M','E',0},
7051         {0},
7052     };
7053
7054     static const WCHAR szRegKeys[][80] = 
7055     {
7056         {'P','r','o','d','u','c','t','I','D',0},
7057         {'R','e','g','O','w','n','e','r',0},
7058         {'R','e','g','C','o','m','p','a','n','y',0},
7059         {0},
7060     };
7061
7062     if (!package)
7063         return ERROR_INVALID_HANDLE;
7064
7065     productid = load_dynamic_property(package,szProductID,&rc);
7066     if (!productid)
7067         return ERROR_SUCCESS;
7068
7069     productcode = load_dynamic_property(package,szProductCode,&rc);
7070     if (!productcode)
7071         return rc;
7072
7073     rc = MSIREG_OpenUninstallKey(productcode,&hkey,TRUE);
7074     if (rc != ERROR_SUCCESS)
7075         goto end;
7076
7077     i = 0;
7078     while (szPropKeys[i][0]!=0)
7079     {
7080         buffer = load_dynamic_property(package,szPropKeys[i],&rc);
7081         if (rc == ERROR_SUCCESS)
7082         {
7083             size = strlenW(buffer)*sizeof(WCHAR);
7084             RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,(LPSTR)buffer,size);
7085         }
7086         else
7087             RegSetValueExW(hkey,szRegKeys[i],0,REG_SZ,NULL,0);
7088         i++;
7089     }
7090
7091 end:
7092     HeapFree(GetProcessHeap(),0,productcode);
7093     HeapFree(GetProcessHeap(),0,productid);
7094     RegCloseKey(hkey);
7095
7096     return ERROR_SUCCESS;
7097 }
7098
7099
7100 static UINT ACTION_ExecuteAction(MSIPACKAGE *package)
7101 {
7102     UINT rc;
7103     rc = ACTION_ProcessExecSequence(package,FALSE);
7104     return rc;
7105 }
7106
7107
7108 /*
7109  * Code based off of code located here
7110  * http://www.codeproject.com/gdi/fontnamefromfile.asp
7111  *
7112  * Using string index 4 (full font name) instead of 1 (family name)
7113  */
7114 static LPWSTR load_ttfname_from(LPCWSTR filename)
7115 {
7116     HANDLE handle;
7117     LPWSTR ret = NULL;
7118     int i;
7119
7120     typedef struct _tagTT_OFFSET_TABLE{
7121         USHORT uMajorVersion;
7122         USHORT uMinorVersion;
7123         USHORT uNumOfTables;
7124         USHORT uSearchRange;
7125         USHORT uEntrySelector;
7126         USHORT uRangeShift;
7127     }TT_OFFSET_TABLE;
7128
7129     typedef struct _tagTT_TABLE_DIRECTORY{
7130         char szTag[4]; /* table name */
7131         ULONG uCheckSum; /* Check sum */
7132         ULONG uOffset; /* Offset from beginning of file */
7133         ULONG uLength; /* length of the table in bytes */
7134     }TT_TABLE_DIRECTORY;
7135
7136     typedef struct _tagTT_NAME_TABLE_HEADER{
7137     USHORT uFSelector; /* format selector. Always 0 */
7138     USHORT uNRCount; /* Name Records count */
7139     USHORT uStorageOffset; /* Offset for strings storage, 
7140                             * from start of the table */
7141     }TT_NAME_TABLE_HEADER;
7142    
7143     typedef struct _tagTT_NAME_RECORD{
7144         USHORT uPlatformID;
7145         USHORT uEncodingID;
7146         USHORT uLanguageID;
7147         USHORT uNameID;
7148         USHORT uStringLength;
7149         USHORT uStringOffset; /* from start of storage area */
7150     }TT_NAME_RECORD;
7151
7152 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
7153 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
7154
7155     handle = CreateFileW(filename ,GENERIC_READ, 0, NULL, OPEN_EXISTING,
7156                     FILE_ATTRIBUTE_NORMAL, 0 );
7157     if (handle != INVALID_HANDLE_VALUE)
7158     {
7159         TT_TABLE_DIRECTORY tblDir;
7160         BOOL bFound = FALSE;
7161         TT_OFFSET_TABLE ttOffsetTable;
7162
7163         ReadFile(handle,&ttOffsetTable, sizeof(TT_OFFSET_TABLE),NULL,NULL);
7164         ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables);
7165         ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion);
7166         ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion);
7167         
7168         if (ttOffsetTable.uMajorVersion != 1 || 
7169                         ttOffsetTable.uMinorVersion != 0)
7170             return NULL;
7171
7172         for (i=0; i< ttOffsetTable.uNumOfTables; i++)
7173         {
7174             ReadFile(handle,&tblDir, sizeof(TT_TABLE_DIRECTORY),NULL,NULL);
7175             if (strncmp(tblDir.szTag,"name",4)==0)
7176             {
7177                 bFound = TRUE;
7178                 tblDir.uLength = SWAPLONG(tblDir.uLength);
7179                 tblDir.uOffset = SWAPLONG(tblDir.uOffset);
7180                 break;
7181             }
7182         }
7183
7184         if (bFound)
7185         {
7186             TT_NAME_TABLE_HEADER ttNTHeader;
7187             TT_NAME_RECORD ttRecord;
7188
7189             SetFilePointer(handle, tblDir.uOffset, NULL, FILE_BEGIN);
7190             ReadFile(handle,&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER),
7191                             NULL,NULL);
7192
7193             ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount);
7194             ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset);
7195             bFound = FALSE;
7196             for(i=0; i<ttNTHeader.uNRCount; i++)
7197             {
7198                 ReadFile(handle,&ttRecord, sizeof(TT_NAME_RECORD),NULL,NULL);
7199                 ttRecord.uNameID = SWAPWORD(ttRecord.uNameID);
7200                 /* 4 is the Full Font Name */
7201                 if(ttRecord.uNameID == 4)
7202                 {
7203                     int nPos;
7204                     LPSTR buf;
7205                     static LPCSTR tt = " (TrueType)";
7206
7207                     ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength);
7208                     ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset);
7209                     nPos = SetFilePointer(handle, 0, NULL, FILE_CURRENT);
7210                     SetFilePointer(handle, tblDir.uOffset + 
7211                                     ttRecord.uStringOffset + 
7212                                     ttNTHeader.uStorageOffset,
7213                                     NULL, FILE_BEGIN);
7214                     buf = HeapAlloc(GetProcessHeap(), 0, 
7215                                     ttRecord.uStringLength + 1 + strlen(tt));
7216                     memset(buf, 0, ttRecord.uStringLength + 1 + strlen(tt));
7217                     ReadFile(handle, buf, ttRecord.uStringLength, NULL, NULL);
7218                     if (strlen(buf) > 0)
7219                     {
7220                         strcat(buf,tt);
7221                         ret = strdupAtoW(buf);
7222                         HeapFree(GetProcessHeap(),0,buf);
7223                         break;
7224                     }
7225
7226                     HeapFree(GetProcessHeap(),0,buf);
7227                     SetFilePointer(handle,nPos, NULL, FILE_BEGIN);
7228                 }
7229             }
7230         }
7231         CloseHandle(handle);
7232     }
7233     else
7234         ERR("Unable to open font file %s\n", debugstr_w(filename));
7235
7236     TRACE("Returning fontname %s\n",debugstr_w(ret));
7237     return ret;
7238 }
7239
7240 static UINT ACTION_RegisterFonts(MSIPACKAGE *package)
7241 {
7242     UINT rc;
7243     MSIQUERY * view;
7244     MSIRECORD * row = 0;
7245     static const WCHAR ExecSeqQuery[] =
7246         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7247          '`','F','o','n','t','`',0};
7248     static const WCHAR regfont1[] =
7249         {'S','o','f','t','w','a','r','e','\\',
7250          'M','i','c','r','o','s','o','f','t','\\',
7251          'W','i','n','d','o','w','s',' ','N','T','\\',
7252          'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
7253          'F','o','n','t','s',0};
7254     static const WCHAR regfont2[] =
7255         {'S','o','f','t','w','a','r','e','\\',
7256          'M','i','c','r','o','s','o','f','t','\\',
7257          'W','i','n','d','o','w','s','\\',
7258          'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
7259          'F','o','n','t','s',0};
7260     HKEY hkey1;
7261     HKEY hkey2;
7262
7263     TRACE("%p\n", package);
7264
7265     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
7266     if (rc != ERROR_SUCCESS)
7267     {
7268         TRACE("MSI_DatabaseOpenViewW failed: %d\n", rc);
7269         return ERROR_SUCCESS;
7270     }
7271
7272     rc = MSI_ViewExecute(view, 0);
7273     if (rc != ERROR_SUCCESS)
7274     {
7275         MSI_ViewClose(view);
7276         msiobj_release(&view->hdr);
7277         TRACE("MSI_ViewExecute returned %d\n", rc);
7278         return ERROR_SUCCESS;
7279     }
7280
7281     RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont1,&hkey1);
7282     RegCreateKeyW(HKEY_LOCAL_MACHINE,regfont2,&hkey2);
7283     
7284     while (1)
7285     {
7286         LPWSTR name;
7287         LPCWSTR file;
7288         UINT index;
7289         DWORD size;
7290
7291         rc = MSI_ViewFetch(view,&row);
7292         if (rc != ERROR_SUCCESS)
7293         {
7294             rc = ERROR_SUCCESS;
7295             break;
7296         }
7297
7298         file = MSI_RecordGetString(row,1);
7299         index = get_loaded_file(package,file);
7300         if (index < 0)
7301         {
7302             ERR("Unable to load file\n");
7303             continue;
7304         }
7305
7306         /* check to make sure that component is installed */
7307         if (!ACTION_VerifyComponentForAction(package, 
7308                 package->files[index].ComponentIndex, INSTALLSTATE_LOCAL))
7309         {
7310             TRACE("Skipping: Component not scheduled for install\n");
7311
7312             msiobj_release(&row->hdr);
7313
7314             continue;
7315         }
7316
7317         if (MSI_RecordIsNull(row,2))
7318             name = load_ttfname_from(package->files[index].TargetPath);
7319         else
7320             name = load_dynamic_stringW(row,2);
7321
7322         if (name)
7323         {
7324             size = strlenW(package->files[index].FileName) * sizeof(WCHAR);
7325             RegSetValueExW(hkey1,name,0,REG_SZ,
7326                         (LPBYTE)package->files[index].FileName,size);
7327             RegSetValueExW(hkey2,name,0,REG_SZ,
7328                         (LPBYTE)package->files[index].FileName,size);
7329         }
7330         
7331         HeapFree(GetProcessHeap(),0,name);
7332         msiobj_release(&row->hdr);
7333     }
7334     MSI_ViewClose(view);
7335     msiobj_release(&view->hdr);
7336
7337     RegCloseKey(hkey1);
7338     RegCloseKey(hkey2);
7339
7340     TRACE("returning %d\n", rc);
7341     return rc;
7342 }
7343
7344 static UINT ITERATE_PublishComponent(MSIRECORD *rec, LPVOID param)
7345 {
7346     MSIPACKAGE *package = (MSIPACKAGE*)param;
7347     LPCWSTR compgroupid=NULL;
7348     LPCWSTR feature=NULL;
7349     LPCWSTR text = NULL;
7350     LPCWSTR qualifier = NULL;
7351     LPCWSTR component = NULL;
7352     LPWSTR advertise = NULL;
7353     LPWSTR output = NULL;
7354     HKEY hkey;
7355     UINT rc = ERROR_SUCCESS;
7356     UINT index;
7357     DWORD sz = 0;
7358
7359     component = MSI_RecordGetString(rec,3);
7360     index = get_loaded_component(package,component);
7361
7362     if (!ACTION_VerifyComponentForAction(package, index,
7363                             INSTALLSTATE_LOCAL) && 
7364        !ACTION_VerifyComponentForAction(package, index,
7365                             INSTALLSTATE_SOURCE) &&
7366        !ACTION_VerifyComponentForAction(package, index,
7367                             INSTALLSTATE_ADVERTISED))
7368     {
7369         TRACE("Skipping: Component %s not scheduled for install\n",
7370                         debugstr_w(component));
7371
7372         return ERROR_SUCCESS;
7373     }
7374
7375     compgroupid = MSI_RecordGetString(rec,1);
7376
7377     rc = MSIREG_OpenUserComponentsKey(compgroupid, &hkey, TRUE);
7378     if (rc != ERROR_SUCCESS)
7379         goto end;
7380     
7381     text = MSI_RecordGetString(rec,4);
7382     qualifier = MSI_RecordGetString(rec,2);
7383     feature = MSI_RecordGetString(rec,5);
7384   
7385     advertise = create_component_advertise_string(package, 
7386                     &package->components[index], feature);
7387
7388     sz = strlenW(advertise);
7389
7390     if (text)
7391         sz += lstrlenW(text);
7392
7393     sz+=3;
7394     sz *= sizeof(WCHAR);
7395            
7396     output = HeapAlloc(GetProcessHeap(),0,sz);
7397     memset(output,0,sz);
7398     strcpyW(output,advertise);
7399
7400     if (text)
7401         strcatW(output,text);
7402
7403     sz = (lstrlenW(output)+2) * sizeof(WCHAR);
7404     RegSetValueExW(hkey, qualifier,0,REG_MULTI_SZ, (LPBYTE)output, sz);
7405     
7406 end:
7407     RegCloseKey(hkey);
7408     HeapFree(GetProcessHeap(),0,output);
7409     
7410     return rc;
7411 }
7412
7413 /*
7414  * At present I am ignorning the advertised components part of this and only
7415  * focusing on the qualified component sets
7416  */
7417 static UINT ACTION_PublishComponents(MSIPACKAGE *package)
7418 {
7419     UINT rc;
7420     MSIQUERY * view;
7421     static const WCHAR ExecSeqQuery[] =
7422         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
7423          '`','P','u','b','l','i','s','h',
7424          'C','o','m','p','o','n','e','n','t','`',0};
7425     
7426     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
7427     if (rc != ERROR_SUCCESS)
7428         return ERROR_SUCCESS;
7429
7430     rc = MSI_IterateRecords(view, NULL, ITERATE_PublishComponent, package);
7431     msiobj_release(&view->hdr);
7432
7433     return rc;
7434 }
7435
7436 /* Msi functions that seem appropriate here */
7437
7438 /***********************************************************************
7439  * MsiDoActionA       (MSI.@)
7440  */
7441 UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
7442 {
7443     LPWSTR szwAction;
7444     UINT rc;
7445
7446     TRACE(" exteral attempt at action %s\n",szAction);
7447
7448     if (!szAction)
7449         return ERROR_FUNCTION_FAILED;
7450     if (hInstall == 0)
7451         return ERROR_FUNCTION_FAILED;
7452
7453     szwAction = strdupAtoW(szAction);
7454
7455     if (!szwAction)
7456         return ERROR_FUNCTION_FAILED; 
7457
7458
7459     rc = MsiDoActionW(hInstall, szwAction);
7460     HeapFree(GetProcessHeap(),0,szwAction);
7461     return rc;
7462 }
7463
7464 /***********************************************************************
7465  * MsiDoActionW       (MSI.@)
7466  */
7467 UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction )
7468 {
7469     MSIPACKAGE *package;
7470     UINT ret = ERROR_INVALID_HANDLE;
7471
7472     TRACE(" external attempt at action %s \n",debugstr_w(szAction));
7473
7474     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
7475     if( package )
7476     {
7477         ret = ACTION_PerformUIAction(package,szAction);
7478         msiobj_release( &package->hdr );
7479     }
7480     return ret;
7481 }
7482
7483 UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder, 
7484                                LPSTR szPathBuf, DWORD* pcchPathBuf) 
7485 {
7486     LPWSTR szwFolder;
7487     LPWSTR szwPathBuf;
7488     UINT rc;
7489
7490     TRACE("getting folder %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
7491
7492     if (!szFolder)
7493         return ERROR_FUNCTION_FAILED;
7494     if (hInstall == 0)
7495         return ERROR_FUNCTION_FAILED;
7496
7497     szwFolder = strdupAtoW(szFolder);
7498
7499     if (!szwFolder)
7500         return ERROR_FUNCTION_FAILED; 
7501
7502     szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
7503
7504     rc = MsiGetTargetPathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
7505
7506     WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
7507                          *pcchPathBuf, NULL, NULL );
7508
7509     HeapFree(GetProcessHeap(),0,szwFolder);
7510     HeapFree(GetProcessHeap(),0,szwPathBuf);
7511
7512     return rc;
7513 }
7514
7515 UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
7516                                 szPathBuf, DWORD* pcchPathBuf) 
7517 {
7518     LPWSTR path;
7519     UINT rc = ERROR_FUNCTION_FAILED;
7520     MSIPACKAGE *package;
7521
7522     TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
7523
7524     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
7525     if (!package)
7526         return ERROR_INVALID_HANDLE;
7527     path = resolve_folder(package, szFolder, FALSE, FALSE, NULL);
7528     msiobj_release( &package->hdr );
7529
7530     if (path && (strlenW(path) > *pcchPathBuf))
7531     {
7532         *pcchPathBuf = strlenW(path)+1;
7533         rc = ERROR_MORE_DATA;
7534     }
7535     else if (path)
7536     {
7537         *pcchPathBuf = strlenW(path)+1;
7538         strcpyW(szPathBuf,path);
7539         TRACE("Returning Path %s\n",debugstr_w(path));
7540         rc = ERROR_SUCCESS;
7541     }
7542     HeapFree(GetProcessHeap(),0,path);
7543     
7544     return rc;
7545 }
7546
7547
7548 UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder, 
7549                                LPSTR szPathBuf, DWORD* pcchPathBuf) 
7550 {
7551     LPWSTR szwFolder;
7552     LPWSTR szwPathBuf;
7553     UINT rc;
7554
7555     TRACE("getting source %s %p %li\n",szFolder,szPathBuf, *pcchPathBuf);
7556
7557     if (!szFolder)
7558         return ERROR_FUNCTION_FAILED;
7559     if (hInstall == 0)
7560         return ERROR_FUNCTION_FAILED;
7561
7562     szwFolder = strdupAtoW(szFolder);
7563     if (!szwFolder)
7564         return ERROR_FUNCTION_FAILED; 
7565
7566     szwPathBuf = HeapAlloc( GetProcessHeap(), 0 , *pcchPathBuf * sizeof(WCHAR));
7567
7568     rc = MsiGetSourcePathW(hInstall, szwFolder, szwPathBuf,pcchPathBuf);
7569
7570     WideCharToMultiByte( CP_ACP, 0, szwPathBuf, *pcchPathBuf, szPathBuf,
7571                          *pcchPathBuf, NULL, NULL );
7572
7573     HeapFree(GetProcessHeap(),0,szwFolder);
7574     HeapFree(GetProcessHeap(),0,szwPathBuf);
7575
7576     return rc;
7577 }
7578
7579 UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
7580                                 szPathBuf, DWORD* pcchPathBuf) 
7581 {
7582     LPWSTR path;
7583     UINT rc = ERROR_FUNCTION_FAILED;
7584     MSIPACKAGE *package;
7585
7586     TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
7587
7588     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
7589     if( !package )
7590         return ERROR_INVALID_HANDLE;
7591     path = resolve_folder(package, szFolder, TRUE, FALSE, NULL);
7592     msiobj_release( &package->hdr );
7593
7594     if (path && strlenW(path) > *pcchPathBuf)
7595     {
7596         *pcchPathBuf = strlenW(path)+1;
7597         rc = ERROR_MORE_DATA;
7598     }
7599     else if (path)
7600     {
7601         *pcchPathBuf = strlenW(path)+1;
7602         strcpyW(szPathBuf,path);
7603         TRACE("Returning Path %s\n",debugstr_w(path));
7604         rc = ERROR_SUCCESS;
7605     }
7606     HeapFree(GetProcessHeap(),0,path);
7607     
7608     return rc;
7609 }
7610
7611
7612 /***********************************************************************
7613  * MsiSetTargetPathA  (MSI.@)
7614  */
7615 UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder, 
7616                              LPCSTR szFolderPath)
7617 {
7618     LPWSTR szwFolder;
7619     LPWSTR szwFolderPath;
7620     UINT rc;
7621
7622     if (!szFolder)
7623         return ERROR_FUNCTION_FAILED;
7624     if (hInstall == 0)
7625         return ERROR_FUNCTION_FAILED;
7626
7627     szwFolder = strdupAtoW(szFolder);
7628     if (!szwFolder)
7629         return ERROR_FUNCTION_FAILED; 
7630
7631     szwFolderPath = strdupAtoW(szFolderPath);
7632     if (!szwFolderPath)
7633     {
7634         HeapFree(GetProcessHeap(),0,szwFolder);
7635         return ERROR_FUNCTION_FAILED; 
7636     }
7637
7638     rc = MsiSetTargetPathW(hInstall, szwFolder, szwFolderPath);
7639
7640     HeapFree(GetProcessHeap(),0,szwFolder);
7641     HeapFree(GetProcessHeap(),0,szwFolderPath);
7642
7643     return rc;
7644 }
7645
7646 UINT MSI_SetTargetPathW(MSIPACKAGE *package, LPCWSTR szFolder, 
7647                              LPCWSTR szFolderPath)
7648 {
7649     DWORD i;
7650     LPWSTR path = NULL;
7651     LPWSTR path2 = NULL;
7652     MSIFOLDER *folder;
7653
7654     TRACE("(%p %s %s)\n",package, debugstr_w(szFolder),debugstr_w(szFolderPath));
7655
7656     if (package==NULL)
7657         return ERROR_INVALID_HANDLE;
7658
7659     if (szFolderPath[0]==0)
7660         return ERROR_FUNCTION_FAILED;
7661
7662     if (GetFileAttributesW(szFolderPath) == INVALID_FILE_ATTRIBUTES)
7663         return ERROR_FUNCTION_FAILED;
7664
7665     path = resolve_folder(package,szFolder,FALSE,FALSE,&folder);
7666
7667     if (!path)
7668         return ERROR_INVALID_PARAMETER;
7669
7670     HeapFree(GetProcessHeap(),0,folder->Property);
7671     folder->Property = build_directory_name(2, szFolderPath, NULL);
7672
7673     if (lstrcmpiW(path, folder->Property) == 0)
7674     {
7675         /*
7676          *  Resolved Target has not really changed, so just 
7677          *  set this folder and do not recalculate everything.
7678          */
7679         HeapFree(GetProcessHeap(),0,folder->ResolvedTarget);
7680         folder->ResolvedTarget = NULL;
7681         path2 = resolve_folder(package,szFolder,FALSE,TRUE,NULL);
7682         HeapFree(GetProcessHeap(),0,path2);
7683     }
7684     else
7685     {
7686         for (i = 0; i < package->loaded_folders; i++)
7687         {
7688             HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget);
7689             package->folders[i].ResolvedTarget=NULL;
7690         }
7691
7692         for (i = 0; i < package->loaded_folders; i++)
7693         {
7694             path2=resolve_folder(package, package->folders[i].Directory, FALSE,
7695                        TRUE, NULL);
7696             HeapFree(GetProcessHeap(),0,path2);
7697         }
7698     }
7699     HeapFree(GetProcessHeap(),0,path);
7700
7701     return ERROR_SUCCESS;
7702 }
7703
7704 /***********************************************************************
7705  * MsiSetTargetPathW  (MSI.@)
7706  */
7707 UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder, 
7708                              LPCWSTR szFolderPath)
7709 {
7710     MSIPACKAGE *package;
7711     UINT ret;
7712
7713     TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
7714
7715     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
7716     ret = MSI_SetTargetPathW( package, szFolder, szFolderPath );
7717     msiobj_release( &package->hdr );
7718     return ret;
7719 }
7720
7721 /***********************************************************************
7722  *           MsiGetMode    (MSI.@)
7723  *
7724  * Returns an internal installer state (if it is running in a mode iRunMode)
7725  *
7726  * PARAMS
7727  *   hInstall    [I]  Handle to the installation
7728  *   hRunMode    [I]  Checking run mode
7729  *        MSIRUNMODE_ADMIN             Administrative mode
7730  *        MSIRUNMODE_ADVERTISE         Advertisement mode
7731  *        MSIRUNMODE_MAINTENANCE       Maintenance mode
7732  *        MSIRUNMODE_ROLLBACKENABLED   Rollback is enabled
7733  *        MSIRUNMODE_LOGENABLED        Log file is writing
7734  *        MSIRUNMODE_OPERATIONS        Operations in progress??
7735  *        MSIRUNMODE_REBOOTATEND       We need to reboot after installation completed
7736  *        MSIRUNMODE_REBOOTNOW         We need to reboot to continue the installation
7737  *        MSIRUNMODE_CABINET           Files from cabinet are installed
7738  *        MSIRUNMODE_SOURCESHORTNAMES  Long names in source files is suppressed
7739  *        MSIRUNMODE_TARGETSHORTNAMES  Long names in destination files is suppressed
7740  *        MSIRUNMODE_RESERVED11        Reserved
7741  *        MSIRUNMODE_WINDOWS9X         Running under Windows95/98
7742  *        MSIRUNMODE_ZAWENABLED        Demand installation is supported
7743  *        MSIRUNMODE_RESERVED14        Reserved
7744  *        MSIRUNMODE_RESERVED15        Reserved
7745  *        MSIRUNMODE_SCHEDULED         called from install script
7746  *        MSIRUNMODE_ROLLBACK          called from rollback script
7747  *        MSIRUNMODE_COMMIT            called from commit script
7748  *
7749  * RETURNS
7750  *    In the state: TRUE
7751  *    Not in the state: FALSE
7752  *
7753  */
7754
7755 BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, MSIRUNMODE iRunMode)
7756 {
7757     FIXME("STUB (iRunMode=%i)\n",iRunMode);
7758     return TRUE;
7759 }
7760
7761 /***********************************************************************
7762  * MsiSetFeatureStateA (MSI.@)
7763  *
7764  * According to the docs, when this is called it immediately recalculates
7765  * all the component states as well
7766  */
7767 UINT WINAPI MsiSetFeatureStateA(MSIHANDLE hInstall, LPCSTR szFeature,
7768                                 INSTALLSTATE iState)
7769 {
7770     LPWSTR szwFeature = NULL;
7771     UINT rc;
7772
7773     szwFeature = strdupAtoW(szFeature);
7774
7775     if (!szwFeature)
7776         return ERROR_FUNCTION_FAILED;
7777    
7778     rc = MsiSetFeatureStateW(hInstall,szwFeature, iState); 
7779
7780     HeapFree(GetProcessHeap(),0,szwFeature);
7781
7782     return rc;
7783 }
7784
7785
7786
7787 UINT WINAPI MSI_SetFeatureStateW(MSIPACKAGE* package, LPCWSTR szFeature,
7788                                 INSTALLSTATE iState)
7789 {
7790     INT index, i;
7791     UINT rc = ERROR_SUCCESS;
7792
7793     TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
7794
7795     index = get_loaded_feature(package,szFeature);
7796     if (index < 0)
7797         return ERROR_UNKNOWN_FEATURE;
7798
7799     if (iState == INSTALLSTATE_ADVERTISED && 
7800         package->features[index].Attributes & 
7801             msidbFeatureAttributesDisallowAdvertise)
7802         return ERROR_FUNCTION_FAILED;
7803
7804     package->features[index].ActionRequest= iState;
7805     package->features[index].Action= iState;
7806
7807     ACTION_UpdateComponentStates(package,szFeature);
7808
7809     /* update all the features that are children of this feature */
7810     for (i = 0; i < package->loaded_features; i++)
7811     {
7812         if (strcmpW(szFeature, package->features[i].Feature_Parent) == 0)
7813             MSI_SetFeatureStateW(package, package->features[i].Feature, iState);
7814     }
7815     
7816     return rc;
7817 }
7818
7819 /***********************************************************************
7820  * MsiSetFeatureStateW (MSI.@)
7821  */
7822 UINT WINAPI MsiSetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
7823                                 INSTALLSTATE iState)
7824 {
7825     MSIPACKAGE* package;
7826     UINT rc = ERROR_SUCCESS;
7827
7828     TRACE(" %s to %i\n",debugstr_w(szFeature), iState);
7829
7830     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
7831     if (!package)
7832         return ERROR_INVALID_HANDLE;
7833
7834     rc = MSI_SetFeatureStateW(package,szFeature,iState);
7835
7836     msiobj_release( &package->hdr );
7837     return rc;
7838 }
7839
7840 UINT WINAPI MsiGetFeatureStateA(MSIHANDLE hInstall, LPSTR szFeature,
7841                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
7842 {
7843     LPWSTR szwFeature = NULL;
7844     UINT rc;
7845     
7846     szwFeature = strdupAtoW(szFeature);
7847
7848     rc = MsiGetFeatureStateW(hInstall,szwFeature,piInstalled, piAction);
7849
7850     HeapFree( GetProcessHeap(), 0 , szwFeature);
7851
7852     return rc;
7853 }
7854
7855 UINT MSI_GetFeatureStateW(MSIPACKAGE *package, LPWSTR szFeature,
7856                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
7857 {
7858     INT index;
7859
7860     index = get_loaded_feature(package,szFeature);
7861     if (index < 0)
7862         return ERROR_UNKNOWN_FEATURE;
7863
7864     if (piInstalled)
7865         *piInstalled = package->features[index].Installed;
7866
7867     if (piAction)
7868         *piAction = package->features[index].Action;
7869
7870     TRACE("returning %i %i\n",*piInstalled,*piAction);
7871
7872     return ERROR_SUCCESS;
7873 }
7874
7875 UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPWSTR szFeature,
7876                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
7877 {
7878     MSIPACKAGE* package;
7879     UINT ret;
7880
7881     TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szFeature), piInstalled,
7882 piAction);
7883
7884     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
7885     if (!package)
7886         return ERROR_INVALID_HANDLE;
7887     ret = MSI_GetFeatureStateW(package, szFeature, piInstalled, piAction);
7888     msiobj_release( &package->hdr );
7889     return ret;
7890 }
7891
7892 /***********************************************************************
7893  * MsiGetComponentStateA (MSI.@)
7894  */
7895 UINT WINAPI MsiGetComponentStateA(MSIHANDLE hInstall, LPSTR szComponent,
7896                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
7897 {
7898     LPWSTR szwComponent= NULL;
7899     UINT rc;
7900     
7901     szwComponent= strdupAtoW(szComponent);
7902
7903     rc = MsiGetComponentStateW(hInstall,szwComponent,piInstalled, piAction);
7904
7905     HeapFree( GetProcessHeap(), 0 , szwComponent);
7906
7907     return rc;
7908 }
7909
7910 UINT MSI_GetComponentStateW(MSIPACKAGE *package, LPWSTR szComponent,
7911                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
7912 {
7913     INT index;
7914
7915     TRACE("%p %s %p %p\n", package, debugstr_w(szComponent), piInstalled,
7916 piAction);
7917
7918     index = get_loaded_component(package,szComponent);
7919     if (index < 0)
7920         return ERROR_UNKNOWN_COMPONENT;
7921
7922     if (piInstalled)
7923         *piInstalled = package->components[index].Installed;
7924
7925     if (piAction)
7926         *piAction = package->components[index].Action;
7927
7928     TRACE("states (%i, %i)\n",
7929 (piInstalled)?*piInstalled:-1,(piAction)?*piAction:-1);
7930
7931     return ERROR_SUCCESS;
7932 }
7933
7934 /***********************************************************************
7935  * MsiGetComponentStateW (MSI.@)
7936  */
7937 UINT WINAPI MsiGetComponentStateW(MSIHANDLE hInstall, LPWSTR szComponent,
7938                   INSTALLSTATE *piInstalled, INSTALLSTATE *piAction)
7939 {
7940     MSIPACKAGE* package;
7941     UINT ret;
7942
7943     TRACE("%ld %s %p %p\n", hInstall, debugstr_w(szComponent),
7944            piInstalled, piAction);
7945
7946     package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
7947     if (!package)
7948         return ERROR_INVALID_HANDLE;
7949     ret = MSI_GetComponentStateW( package, szComponent, piInstalled, piAction);
7950     msiobj_release( &package->hdr );
7951     return ret;
7952 }