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