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