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