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