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