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