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