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