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