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