~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/msi/action.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

  1 /*
  2  * Implementation of the Microsoft Installer (msi.dll)
  3  *
  4  * Copyright 2004,2005 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 19  */
 20 
 21 #include <stdarg.h>
 22 
 23 #define COBJMACROS
 24 
 25 #include "windef.h"
 26 #include "winbase.h"
 27 #include "winerror.h"
 28 #include "winreg.h"
 29 #include "winsvc.h"
 30 #include "odbcinst.h"
 31 #include "wine/debug.h"
 32 #include "msidefs.h"
 33 #include "msipriv.h"
 34 #include "winuser.h"
 35 #include "shlobj.h"
 36 #include "objbase.h"
 37 #include "mscoree.h"
 38 #include "fusion.h"
 39 #include "shlwapi.h"
 40 #include "wine/unicode.h"
 41 #include "winver.h"
 42 
 43 #define REG_PROGRESS_VALUE 13200
 44 #define COMPONENT_PROGRESS_VALUE 24000
 45 
 46 WINE_DEFAULT_DEBUG_CHANNEL(msi);
 47 
 48 /*
 49  * consts and values used
 50  */
 51 static const WCHAR c_colon[] = {'C',':','\\',0};
 52 
 53 static const WCHAR szCreateFolders[] =
 54     {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
 55 static const WCHAR szCostFinalize[] =
 56     {'C','o','s','t','F','i','n','a','l','i','z','e',0};
 57 static const WCHAR szWriteRegistryValues[] =
 58     {'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
 59 static const WCHAR szCostInitialize[] =
 60     {'C','o','s','t','I','n','i','t','i','a','l','i','z','e',0};
 61 static const WCHAR szFileCost[] = 
 62     {'F','i','l','e','C','o','s','t',0};
 63 static const WCHAR szInstallInitialize[] = 
 64     {'I','n','s','t','a','l','l','I','n','i','t','i','a','l','i','z','e',0};
 65 static const WCHAR szInstallValidate[] = 
 66     {'I','n','s','t','a','l','l','V','a','l','i','d','a','t','e',0};
 67 static const WCHAR szLaunchConditions[] = 
 68     {'L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','s',0};
 69 static const WCHAR szProcessComponents[] = 
 70     {'P','r','o','c','e','s','s','C','o','m','p','o','n','e','n','t','s',0};
 71 static const WCHAR szRegisterTypeLibraries[] = 
 72     {'R','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
 73 static const WCHAR szCreateShortcuts[] = 
 74     {'C','r','e','a','t','e','S','h','o','r','t','c','u','t','s',0};
 75 static const WCHAR szPublishProduct[] = 
 76     {'P','u','b','l','i','s','h','P','r','o','d','u','c','t',0};
 77 static const WCHAR szWriteIniValues[] = 
 78     {'W','r','i','t','e','I','n','i','V','a','l','u','e','s',0};
 79 static const WCHAR szSelfRegModules[] = 
 80     {'S','e','l','f','R','e','g','M','o','d','u','l','e','s',0};
 81 static const WCHAR szPublishFeatures[] = 
 82     {'P','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
 83 static const WCHAR szRegisterProduct[] = 
 84     {'R','e','g','i','s','t','e','r','P','r','o','d','u','c','t',0};
 85 static const WCHAR szInstallExecute[] = 
 86     {'I','n','s','t','a','l','l','E','x','e','c','u','t','e',0};
 87 static const WCHAR szInstallExecuteAgain[] = 
 88     {'I','n','s','t','a','l','l','E','x','e','c','u','t','e','A','g','a','i','n',0};
 89 static const WCHAR szInstallFinalize[] = 
 90     {'I','n','s','t','a','l','l','F','i','n','a','l','i','z','e',0};
 91 static const WCHAR szForceReboot[] = 
 92     {'F','o','r','c','e','R','e','b','o','o','t',0};
 93 static const WCHAR szResolveSource[] =
 94     {'R','e','s','o','l','v','e','S','o','u','r','c','e',0};
 95 static const WCHAR szAppSearch[] = 
 96     {'A','p','p','S','e','a','r','c','h',0};
 97 static const WCHAR szAllocateRegistrySpace[] = 
 98     {'A','l','l','o','c','a','t','e','R','e','g','i','s','t','r','y','S','p','a','c','e',0};
 99 static const WCHAR szBindImage[] = 
100     {'B','i','n','d','I','m','a','g','e',0};
101 static const WCHAR szCCPSearch[] = 
102     {'C','C','P','S','e','a','r','c','h',0};
103 static const WCHAR szDeleteServices[] = 
104     {'D','e','l','e','t','e','S','e','r','v','i','c','e','s',0};
105 static const WCHAR szDisableRollback[] = 
106     {'D','i','s','a','b','l','e','R','o','l','l','b','a','c','k',0};
107 static const WCHAR szExecuteAction[] = 
108     {'E','x','e','c','u','t','e','A','c','t','i','o','n',0};
109 static const WCHAR szInstallAdminPackage[] = 
110     {'I','n','s','t','a','l','l','A','d','m','i','n','P','a','c','k','a','g','e',0};
111 static const WCHAR szInstallSFPCatalogFile[] = 
112     {'I','n','s','t','a','l','l','S','F','P','C','a','t','a','l','o','g','F','i','l','e',0};
113 static const WCHAR szIsolateComponents[] = 
114     {'I','s','o','l','a','t','e','C','o','m','p','o','n','e','n','t','s',0};
115 static const WCHAR szMigrateFeatureStates[] =
116     {'M','i','g','r','a','t','e','F','e','a','t','u','r','e','S','t','a','t','e','s',0};
117 static const WCHAR szMoveFiles[] =
118     {'M','o','v','e','F','i','l','e','s',0};
119 static const WCHAR szMsiPublishAssemblies[] = 
120     {'M','s','i','P','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
121 static const WCHAR szMsiUnpublishAssemblies[] = 
122     {'M','s','i','U','n','p','u','b','l','i','s','h','A','s','s','e','m','b','l','i','e','s',0};
123 static const WCHAR szInstallODBC[] = 
124     {'I','n','s','t','a','l','l','O','D','B','C',0};
125 static const WCHAR szInstallServices[] = 
126     {'I','n','s','t','a','l','l','S','e','r','v','i','c','e','s',0};
127 static const WCHAR szPatchFiles[] =
128     {'P','a','t','c','h','F','i','l','e','s',0};
129 static const WCHAR szPublishComponents[] = 
130     {'P','u','b','l','i','s','h','C','o','m','p','o','n','e','n','t','s',0};
131 static const WCHAR szRegisterComPlus[] =
132     {'R','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
133 static const WCHAR szRegisterFonts[] =
134     {'R','e','g','i','s','t','e','r','F','o','n','t','s',0};
135 static const WCHAR szRegisterUser[] =
136     {'R','e','g','i','s','t','e','r','U','s','e','r',0};
137 static const WCHAR szRemoveDuplicateFiles[] =
138     {'R','e','m','o','v','e','D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
139 static const WCHAR szRemoveEnvironmentStrings[] =
140     {'R','e','m','o','v','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
141 static const WCHAR szRemoveExistingProducts[] =
142     {'R','e','m','o','v','e','E','x','i','s','t','i','n','g','P','r','o','d','u','c','t','s',0};
143 static const WCHAR szRemoveFolders[] =
144     {'R','e','m','o','v','e','F','o','l','d','e','r','s',0};
145 static const WCHAR szRemoveIniValues[] =
146     {'R','e','m','o','v','e','I','n','i','V','a','l','u','e','s',0};
147 static const WCHAR szRemoveODBC[] =
148     {'R','e','m','o','v','e','O','D','B','C',0};
149 static const WCHAR szRemoveRegistryValues[] =
150     {'R','e','m','o','v','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
151 static const WCHAR szRemoveShortcuts[] =
152     {'R','e','m','o','v','e','S','h','o','r','t','c','u','t','s',0};
153 static const WCHAR szRMCCPSearch[] =
154     {'R','M','C','C','P','S','e','a','r','c','h',0};
155 static const WCHAR szScheduleReboot[] =
156     {'S','c','h','e','d','u','l','e','R','e','b','o','o','t',0};
157 static const WCHAR szSelfUnregModules[] =
158     {'S','e','l','f','U','n','r','e','g','M','o','d','u','l','e','s',0};
159 static const WCHAR szSetODBCFolders[] =
160     {'S','e','t','O','D','B','C','F','o','l','d','e','r','s',0};
161 static const WCHAR szStartServices[] =
162     {'S','t','a','r','t','S','e','r','v','i','c','e','s',0};
163 static const WCHAR szStopServices[] =
164     {'S','t','o','p','S','e','r','v','i','c','e','s',0};
165 static const WCHAR szUnpublishComponents[] =
166     {'U','n','p','u','b','l','i','s','h', 'C','o','m','p','o','n','e','n','t','s',0};
167 static const WCHAR szUnpublishFeatures[] =
168     {'U','n','p','u','b','l','i','s','h','F','e','a','t','u','r','e','s',0};
169 static const WCHAR szUnregisterClassInfo[] =
170     {'U','n','r','e','g','i','s','t','e','r','C','l','a','s','s','I','n','f','o',0};
171 static const WCHAR szUnregisterComPlus[] =
172     {'U','n','r','e','g','i','s','t','e','r','C','o','m','P','l','u','s',0};
173 static const WCHAR szUnregisterExtensionInfo[] =
174     {'U','n','r','e','g','i','s','t','e','r','E','x','t','e','n','s','i','o','n','I','n','f','o',0};
175 static const WCHAR szUnregisterFonts[] =
176     {'U','n','r','e','g','i','s','t','e','r','F','o','n','t','s',0};
177 static const WCHAR szUnregisterMIMEInfo[] =
178     {'U','n','r','e','g','i','s','t','e','r','M','I','M','E','I','n','f','o',0};
179 static const WCHAR szUnregisterProgIdInfo[] =
180     {'U','n','r','e','g','i','s','t','e','r','P','r','o','g','I','d','I','n','f','o',0};
181 static const WCHAR szUnregisterTypeLibraries[] =
182     {'U','n','r','e','g','i','s','t','e','r','T','y','p','e','L','i','b','r','a','r','i','e','s',0};
183 static const WCHAR szValidateProductID[] =
184     {'V','a','l','i','d','a','t','e','P','r','o','d','u','c','t','I','D',0};
185 static const WCHAR szWriteEnvironmentStrings[] =
186     {'W','r','i','t','e','E','n','v','i','r','o','n','m','e','n','t','S','t','r','i','n','g','s',0};
187 
188 /********************************************************
189  * helper functions
190  ********************************************************/
191 
192 static void ui_actionstart(MSIPACKAGE *package, LPCWSTR action)
193 {
194     static const WCHAR Query_t[] = 
195         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
196          '`','A','c','t','i','o', 'n','T','e','x','t','`',' ',
197          'W','H','E','R','E', ' ','`','A','c','t','i','o','n','`',' ','=', 
198          ' ','\'','%','s','\'',0};
199     MSIRECORD * row;
200 
201     row = MSI_QueryGetRecord( package->db, Query_t, action );
202     if (!row)
203         return;
204     MSI_ProcessMessage(package, INSTALLMESSAGE_ACTIONSTART, row);
205     msiobj_release(&row->hdr);
206 }
207 
208 static void ui_actioninfo(MSIPACKAGE *package, LPCWSTR action, BOOL start, 
209                           UINT rc)
210 {
211     MSIRECORD * row;
212     static const WCHAR template_s[]=
213         {'A','c','t','i','o','n',' ','s','t','a','r','t',' ','%','s',':',' ',
214          '%','s', '.',0};
215     static const WCHAR template_e[]=
216         {'A','c','t','i','o','n',' ','e','n','d','e','d',' ','%','s',':',' ',
217          '%','s', '.',' ','R','e','t','u','r','n',' ','v','a','l','u','e',' ',
218          '%','i','.',0};
219     static const WCHAR format[] = 
220         {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
221     WCHAR message[1024];
222     WCHAR timet[0x100];
223 
224     GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
225     if (start)
226         sprintfW(message,template_s,timet,action);
227     else
228         sprintfW(message,template_e,timet,action,rc);
229     
230     row = MSI_CreateRecord(1);
231     MSI_RecordSetStringW(row,1,message);
232  
233     MSI_ProcessMessage(package, INSTALLMESSAGE_INFO, row);
234     msiobj_release(&row->hdr);
235 }
236 
237 UINT msi_parse_command_line( MSIPACKAGE *package, LPCWSTR szCommandLine,
238                              BOOL preserve_case )
239 {
240     LPCWSTR ptr,ptr2;
241     BOOL quote;
242     DWORD len;
243     LPWSTR prop = NULL, val = NULL;
244 
245     if (!szCommandLine)
246         return ERROR_SUCCESS;
247 
248     ptr = szCommandLine;
249        
250     while (*ptr)
251     {
252         if (*ptr==' ')
253         {
254             ptr++;
255             continue;
256         }
257 
258         TRACE("Looking at %s\n",debugstr_w(ptr));
259 
260         ptr2 = strchrW(ptr,'=');
261         if (!ptr2)
262         {
263             ERR("command line contains unknown string : %s\n", debugstr_w(ptr));
264             break;
265         }
266  
267         quote = FALSE;
268 
269         len = ptr2-ptr;
270         prop = msi_alloc((len+1)*sizeof(WCHAR));
271         memcpy(prop,ptr,len*sizeof(WCHAR));
272         prop[len]=0;
273 
274         if (!preserve_case)
275             struprW(prop);
276 
277         ptr2++;
278        
279         len = 0; 
280         ptr = ptr2; 
281         while (*ptr && (quote || (!quote && *ptr!=' ')))
282         {
283             if (*ptr == '"')
284                 quote = !quote;
285             ptr++;
286             len++;
287         }
288        
289         if (*ptr2=='"')
290         {
291             ptr2++;
292             len -= 2;
293         }
294         val = msi_alloc((len+1)*sizeof(WCHAR));
295         memcpy(val,ptr2,len*sizeof(WCHAR));
296         val[len] = 0;
297 
298         if (lstrlenW(prop) > 0)
299         {
300             TRACE("Found commandline property (%s) = (%s)\n", 
301                    debugstr_w(prop), debugstr_w(val));
302             MSI_SetPropertyW(package,prop,val);
303         }
304         msi_free(val);
305         msi_free(prop);
306     }
307 
308     return ERROR_SUCCESS;
309 }
310 
311 
312 static LPWSTR* msi_split_string( LPCWSTR str, WCHAR sep )
313 {
314     LPCWSTR pc;
315     LPWSTR p, *ret = NULL;
316     UINT count = 0;
317 
318     if (!str)
319         return ret;
320 
321     /* count the number of substrings */
322     for ( pc = str, count = 0; pc; count++ )
323     {
324         pc = strchrW( pc, sep );
325         if (pc)
326             pc++;
327     }
328 
329     /* allocate space for an array of substring pointers and the substrings */
330     ret = msi_alloc( (count+1) * sizeof (LPWSTR) +
331                      (lstrlenW(str)+1) * sizeof(WCHAR) );
332     if (!ret)
333         return ret;
334 
335     /* copy the string and set the pointers */
336     p = (LPWSTR) &ret[count+1];
337     lstrcpyW( p, str );
338     for( count = 0; (ret[count] = p); count++ )
339     {
340         p = strchrW( p, sep );
341         if (p)
342             *p++ = 0;
343     }
344 
345     return ret;
346 }
347 
348 static UINT msi_check_transform_applicable( MSIPACKAGE *package, IStorage *patch )
349 {
350     static const WCHAR szSystemLanguageID[] =
351         { 'S','y','s','t','e','m','L','a','n','g','u','a','g','e','I','D',0 };
352 
353     LPWSTR prod_code, patch_product, langid = NULL, template = NULL;
354     UINT ret = ERROR_FUNCTION_FAILED;
355 
356     prod_code = msi_dup_property( package, szProductCode );
357     patch_product = msi_get_suminfo_product( patch );
358 
359     TRACE("db = %s patch = %s\n", debugstr_w(prod_code), debugstr_w(patch_product));
360 
361     if ( strstrW( patch_product, prod_code ) )
362     {
363         MSISUMMARYINFO *si;
364         const WCHAR *p;
365 
366         si = MSI_GetSummaryInformationW( patch, 0 );
367         if (!si)
368         {
369             ERR("no summary information!\n");
370             goto end;
371         }
372 
373         template = msi_suminfo_dup_string( si, PID_TEMPLATE );
374         if (!template)
375         {
376             ERR("no template property!\n");
377             msiobj_release( &si->hdr );
378             goto end;
379         }
380 
381         if (!template[0])
382         {
383             ret = ERROR_SUCCESS;
384             msiobj_release( &si->hdr );
385             goto end;
386         }
387 
388         langid = msi_dup_property( package, szSystemLanguageID );
389         if (!langid)
390         {
391             msiobj_release( &si->hdr );
392             goto end;
393         }
394 
395         p = strchrW( template, ';' );
396         if (p && (!strcmpW( p + 1, langid ) || !strcmpW( p + 1, szZero )))
397         {
398             TRACE("applicable transform\n");
399             ret = ERROR_SUCCESS;
400         }
401 
402         /* FIXME: check platform */
403 
404         msiobj_release( &si->hdr );
405     }
406 
407 end:
408     msi_free( patch_product );
409     msi_free( prod_code );
410     msi_free( template );
411     msi_free( langid );
412 
413     return ret;
414 }
415 
416 static UINT msi_apply_substorage_transform( MSIPACKAGE *package,
417                                  MSIDATABASE *patch_db, LPCWSTR name )
418 {
419     UINT ret = ERROR_FUNCTION_FAILED;
420     IStorage *stg = NULL;
421     HRESULT r;
422 
423     TRACE("%p %s\n", package, debugstr_w(name) );
424 
425     if (*name++ != ':')
426     {
427         ERR("expected a colon in %s\n", debugstr_w(name));
428         return ERROR_FUNCTION_FAILED;
429     }
430 
431     r = IStorage_OpenStorage( patch_db->storage, name, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &stg );
432     if (SUCCEEDED(r))
433     {
434         ret = msi_check_transform_applicable( package, stg );
435         if (ret == ERROR_SUCCESS)
436             msi_table_apply_transform( package->db, stg );
437         else
438             TRACE("substorage transform %s wasn't applicable\n", debugstr_w(name));
439         IStorage_Release( stg );
440     }
441     else
442         ERR("failed to open substorage %s\n", debugstr_w(name));
443 
444     return ERROR_SUCCESS;
445 }
446 
447 UINT msi_check_patch_applicable( MSIPACKAGE *package, MSISUMMARYINFO *si )
448 {
449     LPWSTR guid_list, *guids, product_code;
450     UINT i, ret = ERROR_FUNCTION_FAILED;
451 
452     product_code = msi_dup_property( package, szProductCode );
453     if (!product_code)
454     {
455         /* FIXME: the property ProductCode should be written into the DB somewhere */
456         ERR("no product code to check\n");
457         return ERROR_SUCCESS;
458     }
459 
460     guid_list = msi_suminfo_dup_string( si, PID_TEMPLATE );
461     guids = msi_split_string( guid_list, ';' );
462     for ( i = 0; guids[i] && ret != ERROR_SUCCESS; i++ )
463     {
464         if (!lstrcmpW( guids[i], product_code ))
465             ret = ERROR_SUCCESS;
466     }
467     msi_free( guids );
468     msi_free( guid_list );
469     msi_free( product_code );
470 
471     return ret;
472 }
473 
474 static UINT msi_set_media_source_prop(MSIPACKAGE *package)
475 {
476     MSIQUERY *view;
477     MSIRECORD *rec = NULL;
478     LPWSTR patch;
479     LPCWSTR prop;
480     UINT r;
481 
482     static const WCHAR query[] = {'S','E','L','E','C','T',' ',
483         '`','S','o','u','r','c','e','`',' ','F','R','O','M',' ',
484         '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
485         '`','S','o','u','r','c','e','`',' ','I','S',' ',
486         'N','O','T',' ','N','U','L','L',0};
487 
488     r = MSI_DatabaseOpenViewW(package->db, query, &view);
489     if (r != ERROR_SUCCESS)
490         return r;
491 
492     r = MSI_ViewExecute(view, 0);
493     if (r != ERROR_SUCCESS)
494         goto done;
495 
496     if (MSI_ViewFetch(view, &rec) == ERROR_SUCCESS)
497     {
498         prop = MSI_RecordGetString(rec, 1);
499         patch = msi_dup_property(package, szPatch);
500         MSI_SetPropertyW(package, prop, patch);
501         msi_free(patch);
502     }
503 
504 done:
505     if (rec) msiobj_release(&rec->hdr);
506     msiobj_release(&view->hdr);
507 
508     return r;
509 }
510 
511 static UINT msi_parse_patch_summary( MSIPACKAGE *package, MSIDATABASE *patch_db )
512 {
513     MSISUMMARYINFO *si;
514     LPWSTR str, *substorage;
515     UINT i, r = ERROR_SUCCESS;
516 
517     si = MSI_GetSummaryInformationW( patch_db->storage, 0 );
518     if (!si)
519         return ERROR_FUNCTION_FAILED;
520 
521     if (msi_check_patch_applicable( package, si ) != ERROR_SUCCESS)
522     {
523         TRACE("Patch not applicable\n");
524         return ERROR_SUCCESS;
525     }
526 
527     package->patch = msi_alloc(sizeof(MSIPATCHINFO));
528     if (!package->patch)
529         return ERROR_OUTOFMEMORY;
530 
531     package->patch->patchcode = msi_suminfo_dup_string(si, PID_REVNUMBER);
532     if (!package->patch->patchcode)
533         return ERROR_OUTOFMEMORY;
534 
535     /* enumerate the substorage */
536     str = msi_suminfo_dup_string( si, PID_LASTAUTHOR );
537     package->patch->transforms = str;
538 
539     substorage = msi_split_string( str, ';' );
540     for ( i = 0; substorage && substorage[i] && r == ERROR_SUCCESS; i++ )
541         r = msi_apply_substorage_transform( package, patch_db, substorage[i] );
542 
543     msi_free( substorage );
544     msiobj_release( &si->hdr );
545 
546     msi_set_media_source_prop(package);
547 
548     return r;
549 }
550 
551 static UINT msi_apply_patch_package( MSIPACKAGE *package, LPCWSTR file )
552 {
553     MSIDATABASE *patch_db = NULL;
554     UINT r;
555 
556     TRACE("%p %s\n", package, debugstr_w( file ) );
557 
558     /* FIXME:
559      *  We probably want to make sure we only open a patch collection here.
560      *  Patch collections (.msp) and databases (.msi) have different GUIDs
561      *  but currently MSI_OpenDatabaseW will accept both.
562      */
563     r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &patch_db );
564     if ( r != ERROR_SUCCESS )
565     {
566         ERR("failed to open patch collection %s\n", debugstr_w( file ) );
567         return r;
568     }
569 
570     msi_parse_patch_summary( package, patch_db );
571 
572     /*
573      * There might be a CAB file in the patch package,
574      * so append it to the list of storage to search for streams.
575      */
576     append_storage_to_db( package->db, patch_db->storage );
577 
578     msiobj_release( &patch_db->hdr );
579 
580     return ERROR_SUCCESS;
581 }
582 
583 /* get the PATCH property, and apply all the patches it specifies */
584 static UINT msi_apply_patches( MSIPACKAGE *package )
585 {
586     LPWSTR patch_list, *patches;
587     UINT i, r = ERROR_SUCCESS;
588 
589     patch_list = msi_dup_property( package, szPatch );
590 
591     TRACE("patches to be applied: %s\n", debugstr_w( patch_list ) );
592 
593     patches = msi_split_string( patch_list, ';' );
594     for( i=0; patches && patches[i] && r == ERROR_SUCCESS; i++ )
595         r = msi_apply_patch_package( package, patches[i] );
596 
597     msi_free( patches );
598     msi_free( patch_list );
599 
600     return r;
601 }
602 
603 static UINT msi_apply_transforms( MSIPACKAGE *package )
604 {
605     static const WCHAR szTransforms[] = {
606         'T','R','A','N','S','F','O','R','M','S',0 };
607     LPWSTR xform_list, *xforms;
608     UINT i, r = ERROR_SUCCESS;
609 
610     xform_list = msi_dup_property( package, szTransforms );
611     xforms = msi_split_string( xform_list, ';' );
612 
613     for( i=0; xforms && xforms[i] && r == ERROR_SUCCESS; i++ )
614     {
615         if (xforms[i][0] == ':')
616             r = msi_apply_substorage_transform( package, package->db, xforms[i] );
617         else
618             r = MSI_DatabaseApplyTransformW( package->db, xforms[i], 0 );
619     }
620 
621     msi_free( xforms );
622     msi_free( xform_list );
623 
624     return r;
625 }
626 
627 static BOOL ui_sequence_exists( MSIPACKAGE *package )
628 {
629     MSIQUERY *view;
630     UINT rc;
631 
632     static const WCHAR ExecSeqQuery [] =
633         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
634          '`','I','n','s','t','a','l','l',
635          'U','I','S','e','q','u','e','n','c','e','`',
636          ' ','W','H','E','R','E',' ',
637          '`','S','e','q','u','e','n','c','e','`',' ',
638          '>',' ','',' ','O','R','D','E','R',' ','B','Y',' ',
639          '`','S','e','q','u','e','n','c','e','`',0};
640 
641     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
642     if (rc == ERROR_SUCCESS)
643     {
644         msiobj_release(&view->hdr);
645         return TRUE;
646     }
647 
648     return FALSE;
649 }
650 
651 static UINT msi_set_sourcedir_props(MSIPACKAGE *package, BOOL replace)
652 {
653     LPWSTR p, db;
654     LPWSTR source, check;
655     DWORD len;
656 
657     static const WCHAR szOriginalDatabase[] =
658         {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
659 
660     db = msi_dup_property( package, szOriginalDatabase );
661     if (!db)
662         return ERROR_OUTOFMEMORY;
663 
664     p = strrchrW( db, '\\' );
665     if (!p)
666     {
667         p = strrchrW( db, '/' );
668         if (!p)
669         {
670             msi_free(db);
671             return ERROR_SUCCESS;
672         }
673     }
674 
675     len = p - db + 2;
676     source = msi_alloc( len * sizeof(WCHAR) );
677     lstrcpynW( source, db, len );
678 
679     check = msi_dup_property( package, cszSourceDir );
680     if (!check || replace)
681         MSI_SetPropertyW( package, cszSourceDir, source );
682 
683     msi_free( check );
684 
685     check = msi_dup_property( package, cszSOURCEDIR );
686     if (!check || replace)
687         MSI_SetPropertyW( package, cszSOURCEDIR, source );
688 
689     msi_free( check );
690     msi_free( source );
691     msi_free( db );
692 
693     return ERROR_SUCCESS;
694 }
695 
696 static BOOL needs_ui_sequence(MSIPACKAGE *package)
697 {
698     INT level = msi_get_property_int(package, szUILevel, 0);
699     return (level & INSTALLUILEVEL_MASK) >= INSTALLUILEVEL_REDUCED;
700 }
701 
702 static UINT msi_set_context(MSIPACKAGE *package)
703 {
704     WCHAR val[10];
705     DWORD sz = 10;
706     DWORD num;
707     UINT r;
708 
709     package->Context = MSIINSTALLCONTEXT_USERUNMANAGED;
710 
711     r = MSI_GetPropertyW(package, szAllUsers, val, &sz);
712     if (r == ERROR_SUCCESS)
713     {
714         num = atolW(val);
715         if (num == 1 || num == 2)
716             package->Context = MSIINSTALLCONTEXT_MACHINE;
717     }
718 
719     MSI_SetPropertyW(package, szAllUsers, szOne);
720     return ERROR_SUCCESS;
721 }
722 
723 static UINT ITERATE_Actions(MSIRECORD *row, LPVOID param)
724 {
725     UINT rc;
726     LPCWSTR cond, action;
727     MSIPACKAGE *package = param;
728 
729     action = MSI_RecordGetString(row,1);
730     if (!action)
731     {
732         ERR("Error is retrieving action name\n");
733         return ERROR_FUNCTION_FAILED;
734     }
735 
736     /* check conditions */
737     cond = MSI_RecordGetString(row,2);
738 
739     /* this is a hack to skip errors in the condition code */
740     if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE)
741     {
742         TRACE("Skipping action: %s (condition is false)\n", debugstr_w(action));
743         return ERROR_SUCCESS;
744     }
745 
746     if (needs_ui_sequence(package))
747         rc = ACTION_PerformUIAction(package, action, -1);
748     else
749         rc = ACTION_PerformAction(package, action, -1, FALSE);
750 
751     msi_dialog_check_messages( NULL );
752 
753     if (package->CurrentInstallState != ERROR_SUCCESS)
754         rc = package->CurrentInstallState;
755 
756     if (rc == ERROR_FUNCTION_NOT_CALLED)
757         rc = ERROR_SUCCESS;
758 
759     if (rc != ERROR_SUCCESS)
760         ERR("Execution halted, action %s returned %i\n", debugstr_w(action), rc);
761 
762     return rc;
763 }
764 
765 UINT MSI_Sequence( MSIPACKAGE *package, LPCWSTR szTable, INT iSequenceMode )
766 {
767     MSIQUERY * view;
768     UINT r;
769     static const WCHAR query[] =
770         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
771          '`','%','s','`',
772          ' ','W','H','E','R','E',' ', 
773          '`','S','e','q','u','e','n','c','e','`',' ',
774          '>',' ','',' ','O','R','D','E','R',' ','B','Y',' ',
775          '`','S','e','q','u','e','n','c','e','`',0};
776 
777     TRACE("%p %s %i\n", package, debugstr_w(szTable), iSequenceMode );
778 
779     r = MSI_OpenQuery( package->db, &view, query, szTable );
780     if (r == ERROR_SUCCESS)
781     {
782         r = MSI_IterateRecords( view, NULL, ITERATE_Actions, package );
783         msiobj_release(&view->hdr);
784     }
785 
786     return r;
787 }
788 
789 static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran)
790 {
791     MSIQUERY * view;
792     UINT rc;
793     static const WCHAR ExecSeqQuery[] =
794         {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
795          '`','I','n','s','t','a','l','l','E','x','e','c','u','t','e',
796          'S','e','q','u','e','n','c','e','`',' ', 'W','H','E','R','E',' ',
797          '`','S','e','q','u','e','n','c','e','`',' ', '>',' ','%','i',' ',
798          'O','R','D','E','R',' ', 'B','Y',' ',
799          '`','S','e','q','u','e','n','c','e','`',0 };
800     static const WCHAR IVQuery[] =
801         {'S','E','L','E','C','T',' ','`','S','e','q','u','e','n','c','e','`',
802          ' ', 'F','R','O','M',' ','`','I','n','s','t','a','l','l',
803          'E','x','e','c','u','t','e','S','e','q','u','e','n','c','e','`',' ',
804          'W','H','E','R','E',' ','`','A','c','t','i','o','n','`',' ','=',
805          ' ','\'', 'I','n','s','t','a','l','l',
806          'V','a','l','i','d','a','t','e','\'', 0};
807     INT seq = 0;
808 
809     if (package->script->ExecuteSequenceRun)
810     {
811         TRACE("Execute Sequence already Run\n");
812         return ERROR_SUCCESS;
813     }
814 
815     package->script->ExecuteSequenceRun = TRUE;
816 
817     /* get the sequence number */
818     if (UIran)
819     {
820         MSIRECORD *row = MSI_QueryGetRecord(package->db, IVQuery);
821         if( !row )
822             return ERROR_FUNCTION_FAILED;
823         seq = MSI_RecordGetInteger(row,1);
824         msiobj_release(&row->hdr);
825     }
826 
827     rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, seq);
828     if (rc == ERROR_SUCCESS)
829     {
830         TRACE("Running the actions\n");
831 
832         rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
833         msiobj_release(&view->hdr);
834     }
835 
836     return rc;
837 }
838 
839 static UINT ACTION_ProcessUISequence(MSIPACKAGE *package)
840 {
841     MSIQUERY * view;
842     UINT rc;
843     static const WCHAR ExecSeqQuery [] =
844         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
845          '`','I','n','s','t','a','l','l',
846          'U','I','S','e','q','u','e','n','c','e','`',
847          ' ','W','H','E','R','E',' ', 
848          '`','S','e','q','u','e','n','c','e','`',' ',
849          '>',' ','',' ','O','R','D','E','R',' ','B','Y',' ',
850          '`','S','e','q','u','e','n','c','e','`',0};
851 
852     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
853     if (rc == ERROR_SUCCESS)
854     {
855         TRACE("Running the actions\n"); 
856 
857         rc = MSI_IterateRecords(view, NULL, ITERATE_Actions, package);
858         msiobj_release(&view->hdr);
859     }
860 
861     return rc;
862 }
863 
864 /********************************************************
865  * ACTION helper functions and functions that perform the actions
866  *******************************************************/
867 static BOOL ACTION_HandleCustomAction( MSIPACKAGE* package, LPCWSTR action,
868                                        UINT* rc, UINT script, BOOL force )
869 {
870     BOOL ret=FALSE;
871     UINT arc;
872 
873     arc = ACTION_CustomAction(package, action, script, force);
874 
875     if (arc != ERROR_CALL_NOT_IMPLEMENTED)
876     {
877         *rc = arc;
878         ret = TRUE;
879     }
880     return ret;
881 }
882 
883 /*
884  * Actual Action Handlers
885  */
886 
887 static UINT ITERATE_CreateFolders(MSIRECORD *row, LPVOID param)
888 {
889     MSIPACKAGE *package = param;
890     LPCWSTR dir;
891     LPWSTR full_path;
892     MSIRECORD *uirow;
893     MSIFOLDER *folder;
894 
895     dir = MSI_RecordGetString(row,1);
896     if (!dir)
897     {
898         ERR("Unable to get folder id\n");
899         return ERROR_SUCCESS;
900     }
901 
902     full_path = resolve_folder(package,dir,FALSE,FALSE,TRUE,&folder);
903     if (!full_path)
904     {
905         ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
906         return ERROR_SUCCESS;
907     }
908 
909     TRACE("Folder is %s\n",debugstr_w(full_path));
910 
911     /* UI stuff */
912     uirow = MSI_CreateRecord(1);
913     MSI_RecordSetStringW(uirow,1,full_path);
914     ui_actiondata(package,szCreateFolders,uirow);
915     msiobj_release( &uirow->hdr );
916 
917     if (folder->State == 0)
918         create_full_pathW(full_path);
919 
920     folder->State = 3;
921 
922     msi_free(full_path);
923     return ERROR_SUCCESS;
924 }
925 
926 /* FIXME: probably should merge this with the above function */
927 static UINT msi_create_directory( MSIPACKAGE* package, LPCWSTR dir )
928 {
929     UINT rc = ERROR_SUCCESS;
930     MSIFOLDER *folder;
931     LPWSTR install_path;
932 
933     install_path = resolve_folder(package, dir, FALSE, FALSE, TRUE, &folder);
934     if (!install_path)
935         return ERROR_FUNCTION_FAILED; 
936 
937     /* create the path */
938     if (folder->State == 0)
939     {
940         create_full_pathW(install_path);
941         folder->State = 2;
942     }
943     msi_free(install_path);
944 
945     return rc;
946 }
947 
948 UINT msi_create_component_directories( MSIPACKAGE *package )
949 {
950     MSICOMPONENT *comp;
951 
952     /* create all the folders required by the components are going to install */
953     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
954     {
955         if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
956             continue;
957         msi_create_directory( package, comp->Directory );
958     }
959 
960     return ERROR_SUCCESS;
961 }
962 
963 /*
964  * Also we cannot enable/disable components either, so for now I am just going 
965  * to do all the directories for all the components.
966  */
967 static UINT ACTION_CreateFolders(MSIPACKAGE *package)
968 {
969     static const WCHAR ExecSeqQuery[] =
970         {'S','E','L','E','C','T',' ',
971          '`','D','i','r','e','c','t','o','r','y','_','`',
972          ' ','F','R','O','M',' ',
973          '`','C','r','e','a','t','e','F','o','l','d','e','r','`',0 };
974     UINT rc;
975     MSIQUERY *view;
976 
977     /* create all the empty folders specified in the CreateFolder table */
978     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view );
979     if (rc != ERROR_SUCCESS)
980         return ERROR_SUCCESS;
981 
982     rc = MSI_IterateRecords(view, NULL, ITERATE_CreateFolders, package);
983     msiobj_release(&view->hdr);
984 
985     msi_create_component_directories( package );
986 
987     return rc;
988 }
989 
990 static UINT load_component( MSIRECORD *row, LPVOID param )
991 {
992     MSIPACKAGE *package = param;
993     MSICOMPONENT *comp;
994 
995     comp = msi_alloc_zero( sizeof(MSICOMPONENT) );
996     if (!comp)
997         return ERROR_FUNCTION_FAILED;
998 
999     list_add_tail( &package->components, &comp->entry );
1000 
1001     /* fill in the data */
1002     comp->Component = msi_dup_record_field( row, 1 );
1003 
1004     TRACE("Loading Component %s\n", debugstr_w(comp->Component));
1005 
1006     comp->ComponentId = msi_dup_record_field( row, 2 );
1007     comp->Directory = msi_dup_record_field( row, 3 );
1008     comp->Attributes = MSI_RecordGetInteger(row,4);
1009     comp->Condition = msi_dup_record_field( row, 5 );
1010     comp->KeyPath = msi_dup_record_field( row, 6 );
1011 
1012     comp->Installed = INSTALLSTATE_UNKNOWN;
1013     msi_component_set_state(package, comp, INSTALLSTATE_UNKNOWN);
1014 
1015     return ERROR_SUCCESS;
1016 }
1017 
1018 static UINT load_all_components( MSIPACKAGE *package )
1019 {
1020     static const WCHAR query[] = {
1021         'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ', 
1022          '`','C','o','m','p','o','n','e','n','t','`',0 };
1023     MSIQUERY *view;
1024     UINT r;
1025 
1026     if (!list_empty(&package->components))
1027         return ERROR_SUCCESS;
1028 
1029     r = MSI_DatabaseOpenViewW( package->db, query, &view );
1030     if (r != ERROR_SUCCESS)
1031         return r;
1032 
1033     r = MSI_IterateRecords(view, NULL, load_component, package);
1034     msiobj_release(&view->hdr);
1035     return r;
1036 }
1037 
1038 typedef struct {
1039     MSIPACKAGE *package;
1040     MSIFEATURE *feature;
1041 } _ilfs;
1042 
1043 static UINT add_feature_component( MSIFEATURE *feature, MSICOMPONENT *comp )
1044 {
1045     ComponentList *cl;
1046 
1047     cl = msi_alloc( sizeof (*cl) );
1048     if ( !cl )
1049         return ERROR_NOT_ENOUGH_MEMORY;
1050     cl->component = comp;
1051     list_add_tail( &feature->Components, &cl->entry );
1052 
1053     return ERROR_SUCCESS;
1054 }
1055 
1056 static UINT add_feature_child( MSIFEATURE *parent, MSIFEATURE *child )
1057 {
1058     FeatureList *fl;
1059 
1060     fl = msi_alloc( sizeof(*fl) );
1061     if ( !fl )
1062         return ERROR_NOT_ENOUGH_MEMORY;
1063     fl->feature = child;
1064     list_add_tail( &parent->Children, &fl->entry );
1065 
1066     return ERROR_SUCCESS;
1067 }
1068 
1069 static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
1070 {
1071     _ilfs* ilfs = param;
1072     LPCWSTR component;
1073     MSICOMPONENT *comp;
1074 
1075     component = MSI_RecordGetString(row,1);
1076 
1077     /* check to see if the component is already loaded */
1078     comp = get_loaded_component( ilfs->package, component );
1079     if (!comp)
1080     {
1081         ERR("unknown component %s\n", debugstr_w(component));
1082         return ERROR_FUNCTION_FAILED;
1083     }
1084 
1085     add_feature_component( ilfs->feature, comp );
1086     comp->Enabled = TRUE;
1087 
1088     return ERROR_SUCCESS;
1089 }
1090 
1091 static MSIFEATURE *find_feature_by_name( MSIPACKAGE *package, LPCWSTR name )
1092 {
1093     MSIFEATURE *feature;
1094 
1095     if ( !name )
1096         return NULL;
1097 
1098     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1099     {
1100         if ( !lstrcmpW( feature->Feature, name ) )
1101             return feature;
1102     }
1103 
1104     return NULL;
1105 }
1106 
1107 static UINT load_feature(MSIRECORD * row, LPVOID param)
1108 {
1109     MSIPACKAGE* package = param;
1110     MSIFEATURE* feature;
1111     static const WCHAR Query1[] = 
1112         {'S','E','L','E','C','T',' ',
1113          '`','C','o','m','p','o','n','e','n','t','_','`',
1114          ' ','F','R','O','M',' ','`','F','e','a','t','u','r','e',
1115          'C','o','m','p','o','n','e','n','t','s','`',' ',
1116          'W','H','E','R','E',' ',
1117          '`','F','e', 'a','t','u','r','e','_','`',' ','=','\'','%','s','\'',0};
1118     MSIQUERY * view;
1119     UINT    rc;
1120     _ilfs ilfs;
1121 
1122     /* fill in the data */
1123 
1124     feature = msi_alloc_zero( sizeof (MSIFEATURE) );
1125     if (!feature)
1126         return ERROR_NOT_ENOUGH_MEMORY;
1127 
1128     list_init( &feature->Children );
1129     list_init( &feature->Components );
1130     
1131     feature->Feature = msi_dup_record_field( row, 1 );
1132 
1133     TRACE("Loading feature %s\n",debugstr_w(feature->Feature));
1134 
1135     feature->Feature_Parent = msi_dup_record_field( row, 2 );
1136     feature->Title = msi_dup_record_field( row, 3 );
1137     feature->Description = msi_dup_record_field( row, 4 );
1138 
1139     if (!MSI_RecordIsNull(row,5))
1140         feature->Display = MSI_RecordGetInteger(row,5);
1141   
1142     feature->Level= MSI_RecordGetInteger(row,6);
1143     feature->Directory = msi_dup_record_field( row, 7 );
1144     feature->Attributes = MSI_RecordGetInteger(row,8);
1145 
1146     feature->Installed = INSTALLSTATE_UNKNOWN;
1147     msi_feature_set_state(package, feature, INSTALLSTATE_UNKNOWN);
1148 
1149     list_add_tail( &package->features, &feature->entry );
1150 
1151     /* load feature components */
1152 
1153     rc = MSI_OpenQuery( package->db, &view, Query1, feature->Feature );
1154     if (rc != ERROR_SUCCESS)
1155         return ERROR_SUCCESS;
1156 
1157     ilfs.package = package;
1158     ilfs.feature = feature;
1159 
1160     MSI_IterateRecords(view, NULL, iterate_load_featurecomponents , &ilfs);
1161     msiobj_release(&view->hdr);
1162 
1163     return ERROR_SUCCESS;
1164 }
1165 
1166 static UINT find_feature_children(MSIRECORD * row, LPVOID param)
1167 {
1168     MSIPACKAGE* package = param;
1169     MSIFEATURE *parent, *child;
1170 
1171     child = find_feature_by_name( package, MSI_RecordGetString( row, 1 ) );
1172     if (!child)
1173         return ERROR_FUNCTION_FAILED;
1174 
1175     if (!child->Feature_Parent)
1176         return ERROR_SUCCESS;
1177 
1178     parent = find_feature_by_name( package, child->Feature_Parent );
1179     if (!parent)
1180         return ERROR_FUNCTION_FAILED;
1181 
1182     add_feature_child( parent, child );
1183     return ERROR_SUCCESS;
1184 }
1185 
1186 static UINT load_all_features( MSIPACKAGE *package )
1187 {
1188     static const WCHAR query[] = {
1189         'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1190         '`','F','e','a','t','u','r','e','`',' ','O','R','D','E','R',
1191         ' ','B','Y',' ','`','D','i','s','p','l','a','y','`',0};
1192     MSIQUERY *view;
1193     UINT r;
1194 
1195     if (!list_empty(&package->features))
1196         return ERROR_SUCCESS;
1197  
1198     r = MSI_DatabaseOpenViewW( package->db, query, &view );
1199     if (r != ERROR_SUCCESS)
1200         return r;
1201 
1202     r = MSI_IterateRecords( view, NULL, load_feature, package );
1203     if (r != ERROR_SUCCESS)
1204         return r;
1205 
1206     r = MSI_IterateRecords( view, NULL, find_feature_children, package );
1207     msiobj_release( &view->hdr );
1208 
1209     return r;
1210 }
1211 
1212 static LPWSTR folder_split_path(LPWSTR p, WCHAR ch)
1213 {
1214     if (!p)
1215         return p;
1216     p = strchrW(p, ch);
1217     if (!p)
1218         return p;
1219     *p = 0;
1220     return p+1;
1221 }
1222 
1223 static UINT load_file_hash(MSIPACKAGE *package, MSIFILE *file)
1224 {
1225     static const WCHAR query[] = {
1226         'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1227         '`','M','s','i','F','i','l','e','H','a','s','h','`',' ',
1228         'W','H','E','R','E',' ','`','F','i','l','e','_','`',' ','=',' ','\'','%','s','\'',0};
1229     MSIQUERY *view = NULL;
1230     MSIRECORD *row = NULL;
1231     UINT r;
1232 
1233     TRACE("%s\n", debugstr_w(file->File));
1234 
1235     r = MSI_OpenQuery(package->db, &view, query, file->File);
1236     if (r != ERROR_SUCCESS)
1237         goto done;
1238 
1239     r = MSI_ViewExecute(view, NULL);
1240     if (r != ERROR_SUCCESS)
1241         goto done;
1242 
1243     r = MSI_ViewFetch(view, &row);
1244     if (r != ERROR_SUCCESS)
1245         goto done;
1246 
1247     file->hash.dwFileHashInfoSize = sizeof(MSIFILEHASHINFO);
1248     file->hash.dwData[0] = MSI_RecordGetInteger(row, 3);
1249     file->hash.dwData[1] = MSI_RecordGetInteger(row, 4);
1250     file->hash.dwData[2] = MSI_RecordGetInteger(row, 5);
1251     file->hash.dwData[3] = MSI_RecordGetInteger(row, 6);
1252 
1253 done:
1254     if (view) msiobj_release(&view->hdr);
1255     if (row) msiobj_release(&row->hdr);
1256     return r;
1257 }
1258 
1259 static UINT load_file(MSIRECORD *row, LPVOID param)
1260 {
1261     MSIPACKAGE* package = param;
1262     LPCWSTR component;
1263     MSIFILE *file;
1264 
1265     /* fill in the data */
1266 
1267     file = msi_alloc_zero( sizeof (MSIFILE) );
1268     if (!file)
1269         return ERROR_NOT_ENOUGH_MEMORY;
1270  
1271     file->File = msi_dup_record_field( row, 1 );
1272 
1273     component = MSI_RecordGetString( row, 2 );
1274     file->Component = get_loaded_component( package, component );
1275 
1276     if (!file->Component)
1277     {
1278         WARN("Component not found: %s\n", debugstr_w(component));
1279         msi_free(file->File);
1280         msi_free(file);
1281         return ERROR_SUCCESS;
1282     }
1283 
1284     file->FileName = msi_dup_record_field( row, 3 );
1285     reduce_to_longfilename( file->FileName );
1286 
1287     file->ShortName = msi_dup_record_field( row, 3 );
1288     file->LongName = strdupW( folder_split_path(file->ShortName, '|'));
1289     
1290     file->FileSize = MSI_RecordGetInteger( row, 4 );
1291     file->Version = msi_dup_record_field( row, 5 );
1292     file->Language = msi_dup_record_field( row, 6 );
1293     file->Attributes = MSI_RecordGetInteger( row, 7 );
1294     file->Sequence = MSI_RecordGetInteger( row, 8 );
1295 
1296     file->state = msifs_invalid;
1297 
1298     /* if the compressed bits are not set in the file attributes,
1299      * then read the information from the package word count property
1300      */
1301     if (package->WordCount & msidbSumInfoSourceTypeAdminImage)
1302     {
1303         file->IsCompressed = FALSE;
1304     }
1305     else if (file->Attributes &
1306              (msidbFileAttributesCompressed | msidbFileAttributesPatchAdded))
1307     {
1308         file->IsCompressed = TRUE;
1309     }
1310     else if (file->Attributes & msidbFileAttributesNoncompressed)
1311     {
1312         file->IsCompressed = FALSE;
1313     }
1314     else
1315     {
1316         file->IsCompressed = package->WordCount & msidbSumInfoSourceTypeCompressed;
1317     }
1318 
1319     load_file_hash(package, file);
1320 
1321     TRACE("File Loaded (%s)\n",debugstr_w(file->File));  
1322 
1323     list_add_tail( &package->files, &file->entry );
1324  
1325     return ERROR_SUCCESS;
1326 }
1327 
1328 static UINT load_all_files(MSIPACKAGE *package)
1329 {
1330     MSIQUERY * view;
1331     UINT rc;
1332     static const WCHAR Query[] =
1333         {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
1334          '`','F','i','l','e','`',' ', 'O','R','D','E','R',' ','B','Y',' ',
1335          '`','S','e','q','u','e','n','c','e','`', 0};
1336 
1337     if (!list_empty(&package->files))
1338         return ERROR_SUCCESS;
1339 
1340     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
1341     if (rc != ERROR_SUCCESS)
1342         return ERROR_SUCCESS;
1343 
1344     rc = MSI_IterateRecords(view, NULL, load_file, package);
1345     msiobj_release(&view->hdr);
1346 
1347     return ERROR_SUCCESS;
1348 }
1349 
1350 static UINT load_folder( MSIRECORD *row, LPVOID param )
1351 {
1352     MSIPACKAGE *package = param;
1353     static WCHAR szEmpty[] = { 0 };
1354     LPWSTR p, tgt_short, tgt_long, src_short, src_long;
1355     MSIFOLDER *folder;
1356 
1357     folder = msi_alloc_zero( sizeof (MSIFOLDER) );
1358     if (!folder)
1359         return ERROR_NOT_ENOUGH_MEMORY;
1360 
1361     folder->Directory = msi_dup_record_field( row, 1 );
1362 
1363     TRACE("%s\n", debugstr_w(folder->Directory));
1364 
1365     p = msi_dup_record_field(row, 3);
1366 
1367     /* split src and target dir */
1368     tgt_short = p;
1369     src_short = folder_split_path( p, ':' );
1370 
1371     /* split the long and short paths */
1372     tgt_long = folder_split_path( tgt_short, '|' );
1373     src_long = folder_split_path( src_short, '|' );
1374 
1375     /* check for no-op dirs */
1376     if (!lstrcmpW(szDot, tgt_short))
1377         tgt_short = szEmpty;
1378     if (!lstrcmpW(szDot, src_short))
1379         src_short = szEmpty;
1380 
1381     if (!tgt_long)
1382         tgt_long = tgt_short;
1383 
1384     if (!src_short) {
1385         src_short = tgt_short;
1386         src_long = tgt_long;
1387     }
1388 
1389     if (!src_long)
1390         src_long = src_short;
1391 
1392     /* FIXME: use the target short path too */
1393     folder->TargetDefault = strdupW(tgt_long);
1394     folder->SourceShortPath = strdupW(src_short);
1395     folder->SourceLongPath = strdupW(src_long);
1396     msi_free(p);
1397 
1398     TRACE("TargetDefault = %s\n",debugstr_w( folder->TargetDefault ));
1399     TRACE("SourceLong = %s\n", debugstr_w( folder->SourceLongPath ));
1400     TRACE("SourceShort = %s\n", debugstr_w( folder->SourceShortPath ));
1401 
1402     folder->Parent = msi_dup_record_field( row, 2 );
1403 
1404     folder->Property = msi_dup_property( package, folder->Directory );
1405 
1406     list_add_tail( &package->folders, &folder->entry );
1407 
1408     TRACE("returning %p\n", folder);
1409 
1410     return ERROR_SUCCESS;
1411 }
1412 
1413 static UINT load_all_folders( MSIPACKAGE *package )
1414 {
1415     static const WCHAR query[] = {
1416         'S','E','L','E','C','T',' ','*',' ','F','R', 'O','M',' ',
1417          '`','D','i','r','e','c','t','o','r','y','`',0 };
1418     MSIQUERY *view;
1419     UINT r;
1420 
1421     if (!list_empty(&package->folders))
1422         return ERROR_SUCCESS;
1423 
1424     r = MSI_DatabaseOpenViewW( package->db, query, &view );
1425     if (r != ERROR_SUCCESS)
1426         return r;
1427 
1428     r = MSI_IterateRecords(view, NULL, load_folder, package);
1429     msiobj_release(&view->hdr);
1430     return r;
1431 }
1432 
1433 /*
1434  * I am not doing any of the costing functionality yet.
1435  * Mostly looking at doing the Component and Feature loading
1436  *
1437  * The native MSI does A LOT of modification to tables here. Mostly adding
1438  * a lot of temporary columns to the Feature and Component tables.
1439  *
1440  *    note: Native msi also tracks the short filename. But I am only going to
1441  *          track the long ones.  Also looking at this directory table
1442  *          it appears that the directory table does not get the parents
1443  *          resolved base on property only based on their entries in the
1444  *          directory table.
1445  */
1446 static UINT ACTION_CostInitialize(MSIPACKAGE *package)
1447 {
1448     static const WCHAR szCosting[] =
1449         {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1450 
1451     MSI_SetPropertyW(package, szCosting, szZero);
1452     MSI_SetPropertyW(package, cszRootDrive, c_colon);
1453 
1454     load_all_folders( package );
1455     load_all_components( package );
1456     load_all_features( package );
1457     load_all_files( package );
1458 
1459     return ERROR_SUCCESS;
1460 }
1461 
1462 static UINT execute_script(MSIPACKAGE *package, UINT script )
1463 {
1464     UINT i;
1465     UINT rc = ERROR_SUCCESS;
1466 
1467     TRACE("Executing Script %i\n",script);
1468 
1469     if (!package->script)
1470     {
1471         ERR("no script!\n");
1472         return ERROR_FUNCTION_FAILED;
1473     }
1474 
1475     for (i = 0; i < package->script->ActionCount[script]; i++)
1476     {
1477         LPWSTR action;
1478         action = package->script->Actions[script][i];
1479         ui_actionstart(package, action);
1480         TRACE("Executing Action (%s)\n",debugstr_w(action));
1481         rc = ACTION_PerformAction(package, action, script, TRUE);
1482         if (rc != ERROR_SUCCESS)
1483             break;
1484     }
1485     msi_free_action_script(package, script);
1486     return rc;
1487 }
1488 
1489 static UINT ACTION_FileCost(MSIPACKAGE *package)
1490 {
1491     return ERROR_SUCCESS;
1492 }
1493 
1494 static void ACTION_GetComponentInstallStates(MSIPACKAGE *package)
1495 {
1496     MSICOMPONENT *comp;
1497     INSTALLSTATE state;
1498     UINT r;
1499 
1500     state = MsiQueryProductStateW(package->ProductCode);
1501 
1502     LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry)
1503     {
1504         if (!comp->ComponentId)
1505             continue;
1506 
1507         if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1508             comp->Installed = INSTALLSTATE_ABSENT;
1509         else
1510         {
1511             r = MsiQueryComponentStateW(package->ProductCode, NULL,
1512                                         package->Context, comp->ComponentId,
1513                                         &comp->Installed);
1514             if (r != ERROR_SUCCESS)
1515                 comp->Installed = INSTALLSTATE_ABSENT;
1516         }
1517     }
1518 }
1519 
1520 static void ACTION_GetFeatureInstallStates(MSIPACKAGE *package)
1521 {
1522     MSIFEATURE *feature;
1523     INSTALLSTATE state;
1524 
1525     state = MsiQueryProductStateW(package->ProductCode);
1526 
1527     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1528     {
1529         if (state != INSTALLSTATE_LOCAL && state != INSTALLSTATE_DEFAULT)
1530             feature->Installed = INSTALLSTATE_ABSENT;
1531         else
1532         {
1533             feature->Installed = MsiQueryFeatureStateW(package->ProductCode,
1534                                                        feature->Feature);
1535         }
1536     }
1537 }
1538 
1539 static BOOL process_state_property(MSIPACKAGE* package, int level,
1540                                    LPCWSTR property, INSTALLSTATE state)
1541 {
1542     LPWSTR override;
1543     MSIFEATURE *feature;
1544 
1545     override = msi_dup_property( package, property );
1546     if (!override)
1547         return FALSE;
1548 
1549     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1550     {
1551         if (lstrcmpW(property, szRemove) &&
1552             (feature->Level <= 0 || feature->Level > level))
1553             continue;
1554 
1555         if (!strcmpW(property, szReinstall)) state = feature->Installed;
1556 
1557         if (strcmpiW(override, szAll)==0)
1558             msi_feature_set_state(package, feature, state);
1559         else
1560         {
1561             LPWSTR ptr = override;
1562             LPWSTR ptr2 = strchrW(override,',');
1563 
1564             while (ptr)
1565             {
1566                 if ((ptr2 && strncmpW(ptr,feature->Feature, ptr2-ptr)==0)
1567                     || (!ptr2 && strcmpW(ptr,feature->Feature)==0))
1568                 {
1569                     msi_feature_set_state(package, feature, state);
1570                     break;
1571                 }
1572                 if (ptr2)
1573                 {
1574                     ptr=ptr2+1;
1575                     ptr2 = strchrW(ptr,',');
1576                 }
1577                 else
1578                     break;
1579             }
1580         }
1581     }
1582     msi_free(override);
1583 
1584     return TRUE;
1585 }
1586 
1587 UINT MSI_SetFeatureStates(MSIPACKAGE *package)
1588 {
1589     int level;
1590     static const WCHAR szlevel[] =
1591         {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1592     static const WCHAR szAddLocal[] =
1593         {'A','D','D','L','O','C','A','L',0};
1594     static const WCHAR szAddSource[] =
1595         {'A','D','D','S','O','U','R','C','E',0};
1596     static const WCHAR szAdvertise[] =
1597         {'A','D','V','E','R','T','I','S','E',0};
1598     BOOL override = FALSE;
1599     MSICOMPONENT* component;
1600     MSIFEATURE *feature;
1601 
1602 
1603     /* I do not know if this is where it should happen.. but */
1604 
1605     TRACE("Checking Install Level\n");
1606 
1607     level = msi_get_property_int(package, szlevel, 1);
1608 
1609     /* ok here is the _real_ rub
1610      * all these activation/deactivation things happen in order and things
1611      * later on the list override things earlier on the list.
1612      * 0) INSTALLLEVEL processing
1613      * 1) ADDLOCAL
1614      * 2) REMOVE
1615      * 3) ADDSOURCE
1616      * 4) ADDDEFAULT
1617      * 5) REINSTALL
1618      * 6) ADVERTISE
1619      * 7) COMPADDLOCAL
1620      * 8) COMPADDSOURCE
1621      * 9) FILEADDLOCAL
1622      * 10) FILEADDSOURCE
1623      * 11) FILEADDDEFAULT
1624      *
1625      * I am still ignoring a lot of these. But that is ok for now, ADDLOCAL and
1626      * REMOVE are the big ones, since we don't handle administrative installs
1627      * yet anyway.
1628      */
1629     override |= process_state_property(package, level, szAddLocal, INSTALLSTATE_LOCAL);
1630     override |= process_state_property(package, level, szRemove, INSTALLSTATE_ABSENT);
1631     override |= process_state_property(package, level, szAddSource, INSTALLSTATE_SOURCE);
1632     override |= process_state_property(package, level, szReinstall, INSTALLSTATE_UNKNOWN);
1633     override |= process_state_property(package, level, szAdvertise, INSTALLSTATE_ADVERTISED);
1634 
1635     if (!override)
1636     {
1637         LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1638         {
1639             BOOL feature_state = ((feature->Level > 0) &&
1640                                   (feature->Level <= level));
1641 
1642             if ((feature_state) && (feature->Action == INSTALLSTATE_UNKNOWN))
1643             {
1644                 if (feature->Attributes & msidbFeatureAttributesFavorSource)
1645                     msi_feature_set_state(package, feature, INSTALLSTATE_SOURCE);
1646                 else if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1647                     msi_feature_set_state(package, feature, INSTALLSTATE_ADVERTISED);
1648                 else
1649                     msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1650             }
1651         }
1652 
1653         /* disable child features of unselected parent features */
1654         LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1655         {
1656             FeatureList *fl;
1657 
1658             if (feature->Level > 0 && feature->Level <= level)
1659                 continue;
1660 
1661             LIST_FOR_EACH_ENTRY( fl, &feature->Children, FeatureList, entry )
1662                 msi_feature_set_state(package, fl->feature, INSTALLSTATE_UNKNOWN);
1663         }
1664     }
1665     else
1666         MSI_SetPropertyW(package, szPreselected, szOne);
1667 
1668     /*
1669      * now we want to enable or disable components base on feature
1670      */
1671 
1672     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
1673     {
1674         ComponentList *cl;
1675 
1676         TRACE("Examining Feature %s (Level %i, Installed %i, Action %i)\n",
1677               debugstr_w(feature->Feature), feature->Level, feature->Installed, feature->Action);
1678 
1679         if (!feature->Level)
1680             continue;
1681 
1682         /* features with components that have compressed files are made local */
1683         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1684         {
1685             if (cl->component->Enabled &&
1686                 cl->component->ForceLocalState &&
1687                 feature->Action == INSTALLSTATE_SOURCE)
1688             {
1689                 msi_feature_set_state(package, feature, INSTALLSTATE_LOCAL);
1690                 break;
1691             }
1692         }
1693 
1694         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
1695         {
1696             component = cl->component;
1697 
1698             if (!component->Enabled)
1699                 continue;
1700 
1701             switch (feature->Action)
1702             {
1703             case INSTALLSTATE_ABSENT:
1704                 component->anyAbsent = 1;
1705                 break;
1706             case INSTALLSTATE_ADVERTISED:
1707                 component->hasAdvertiseFeature = 1;
1708                 break;
1709             case INSTALLSTATE_SOURCE:
1710                 component->hasSourceFeature = 1;
1711                 break;
1712             case INSTALLSTATE_LOCAL:
1713                 component->hasLocalFeature = 1;
1714                 break;
1715             case INSTALLSTATE_DEFAULT:
1716                 if (feature->Attributes & msidbFeatureAttributesFavorAdvertise)
1717                     component->hasAdvertiseFeature = 1;
1718                 else if (feature->Attributes & msidbFeatureAttributesFavorSource)
1719                     component->hasSourceFeature = 1;
1720                 else
1721                     component->hasLocalFeature = 1;
1722                 break;
1723             default:
1724                 break;
1725             }
1726         }
1727     }
1728 
1729     LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1730     {
1731         /* if the component isn't enabled, leave it alone */
1732         if (!component->Enabled)
1733             continue;
1734 
1735         /* check if it's local or source */
1736         if (!(component->Attributes & msidbComponentAttributesOptional) &&
1737              (component->hasLocalFeature || component->hasSourceFeature))
1738         {
1739             if ((component->Attributes & msidbComponentAttributesSourceOnly) &&
1740                  !component->ForceLocalState)
1741                 msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1742             else
1743                 msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1744             continue;
1745         }
1746 
1747         /* if any feature is local, the component must be local too */
1748         if (component->hasLocalFeature)
1749         {
1750             msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1751             continue;
1752         }
1753 
1754         if (component->hasSourceFeature)
1755         {
1756             msi_component_set_state(package, component, INSTALLSTATE_SOURCE);
1757             continue;
1758         }
1759 
1760         if (component->hasAdvertiseFeature)
1761         {
1762             msi_component_set_state(package, component, INSTALLSTATE_ADVERTISED);
1763             continue;
1764         }
1765 
1766         TRACE("nobody wants component %s\n", debugstr_w(component->Component));
1767         if (component->anyAbsent)
1768             msi_component_set_state(package, component, INSTALLSTATE_ABSENT);
1769     }
1770 
1771     LIST_FOR_EACH_ENTRY( component, &package->components, MSICOMPONENT, entry )
1772     {
1773         if (component->Action == INSTALLSTATE_DEFAULT)
1774         {
1775             TRACE("%s was default, setting to local\n", debugstr_w(component->Component));
1776             msi_component_set_state(package, component, INSTALLSTATE_LOCAL);
1777         }
1778 
1779         TRACE("Result: Component %s (Installed %i, Action %i)\n",
1780             debugstr_w(component->Component), component->Installed, component->Action);
1781     }
1782 
1783 
1784     return ERROR_SUCCESS;
1785 }
1786 
1787 static UINT ITERATE_CostFinalizeDirectories(MSIRECORD *row, LPVOID param)
1788 {
1789     MSIPACKAGE *package = param;
1790     LPCWSTR name;
1791     LPWSTR path;
1792     MSIFOLDER *f;
1793 
1794     name = MSI_RecordGetString(row,1);
1795 
1796     f = get_loaded_folder(package, name);
1797     if (!f) return ERROR_SUCCESS;
1798 
1799     /* reset the ResolvedTarget */
1800     msi_free(f->ResolvedTarget);
1801     f->ResolvedTarget = NULL;
1802 
1803     /* This helper function now does ALL the work */
1804     TRACE("Dir %s ...\n",debugstr_w(name));
1805     path = resolve_folder(package,name,FALSE,TRUE,TRUE,NULL);
1806     TRACE("resolves to %s\n",debugstr_w(path));
1807     msi_free(path);
1808 
1809     return ERROR_SUCCESS;
1810 }
1811 
1812 static UINT ITERATE_CostFinalizeConditions(MSIRECORD *row, LPVOID param)
1813 {
1814     MSIPACKAGE *package = param;
1815     LPCWSTR name;
1816     MSIFEATURE *feature;
1817 
1818     name = MSI_RecordGetString( row, 1 );
1819 
1820     feature = get_loaded_feature( package, name );
1821     if (!feature)
1822         ERR("FAILED to find loaded feature %s\n",debugstr_w(name));
1823     else
1824     {
1825         LPCWSTR Condition;
1826         Condition = MSI_RecordGetString(row,3);
1827 
1828         if (MSI_EvaluateConditionW(package,Condition) == MSICONDITION_TRUE)
1829         {
1830             int level = MSI_RecordGetInteger(row,2);
1831             TRACE("Resetting feature %s to level %i\n", debugstr_w(name), level);
1832             feature->Level = level;
1833         }
1834     }
1835     return ERROR_SUCCESS;
1836 }
1837 
1838 static LPWSTR msi_get_disk_file_version( LPCWSTR filename )
1839 {
1840     static const WCHAR name_fmt[] =
1841         {'%','u','.','%','u','.','%','u','.','%','u',0};
1842     static const WCHAR name[] = {'\\',0};
1843     VS_FIXEDFILEINFO *lpVer;
1844     WCHAR filever[0x100];
1845     LPVOID version;
1846     DWORD versize;
1847     DWORD handle;
1848     UINT sz;
1849 
1850     TRACE("%s\n", debugstr_w(filename));
1851 
1852     versize = GetFileVersionInfoSizeW( filename, &handle );
1853     if (!versize)
1854         return NULL;
1855 
1856     version = msi_alloc( versize );
1857     GetFileVersionInfoW( filename, 0, versize, version );
1858 
1859     if (!VerQueryValueW( version, name, (LPVOID*)&lpVer, &sz ))
1860     {
1861         msi_free( version );
1862         return NULL;
1863     }
1864 
1865     sprintfW( filever, name_fmt,
1866         HIWORD(lpVer->dwFileVersionMS),
1867         LOWORD(lpVer->dwFileVersionMS),
1868         HIWORD(lpVer->dwFileVersionLS),
1869         LOWORD(lpVer->dwFileVersionLS));
1870 
1871     msi_free( version );
1872 
1873     return strdupW( filever );
1874 }
1875 
1876 static UINT msi_check_file_install_states( MSIPACKAGE *package )
1877 {
1878     LPWSTR file_version;
1879     MSIFILE *file;
1880 
1881     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
1882     {
1883         MSICOMPONENT* comp = file->Component;
1884         LPWSTR p;
1885 
1886         if (!comp)
1887             continue;
1888 
1889         if (file->IsCompressed)
1890             comp->ForceLocalState = TRUE;
1891 
1892         /* calculate target */
1893         p = resolve_folder(package, comp->Directory, FALSE, FALSE, TRUE, NULL);
1894 
1895         msi_free(file->TargetPath);
1896 
1897         TRACE("file %s is named %s\n",
1898                debugstr_w(file->File), debugstr_w(file->FileName));
1899 
1900         file->TargetPath = build_directory_name(2, p, file->FileName);
1901 
1902         msi_free(p);
1903 
1904         TRACE("file %s resolves to %s\n",
1905                debugstr_w(file->File), debugstr_w(file->TargetPath));
1906 
1907         /* don't check files of components that aren't installed */
1908         if (comp->Installed == INSTALLSTATE_UNKNOWN ||
1909             comp->Installed == INSTALLSTATE_ABSENT)
1910         {
1911             file->state = msifs_missing;  /* assume files are missing */
1912             continue;
1913         }
1914 
1915         if (GetFileAttributesW(file->TargetPath) == INVALID_FILE_ATTRIBUTES)
1916         {
1917             file->state = msifs_missing;
1918             comp->Cost += file->FileSize;
1919             continue;
1920         }
1921 
1922         if (file->Version &&
1923             (file_version = msi_get_disk_file_version( file->TargetPath )))
1924         {
1925             TRACE("new %s old %s\n", debugstr_w(file->Version),
1926                   debugstr_w(file_version));
1927             /* FIXME: seems like a bad way to compare version numbers */
1928             if (lstrcmpiW(file_version, file->Version)<0)
1929             {
1930                 file->state = msifs_overwrite;
1931                 comp->Cost += file->FileSize;
1932             }
1933             else
1934                 file->state = msifs_present;
1935             msi_free( file_version );
1936         }
1937         else
1938             file->state = msifs_present;
1939     }
1940 
1941     return ERROR_SUCCESS;
1942 }
1943 
1944 /*
1945  * A lot is done in this function aside from just the costing.
1946  * The costing needs to be implemented at some point but for now I am going
1947  * to focus on the directory building
1948  *
1949  */
1950 static UINT ACTION_CostFinalize(MSIPACKAGE *package)
1951 {
1952     static const WCHAR ExecSeqQuery[] =
1953         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1954          '`','D','i','r','e','c','t','o','r','y','`',0};
1955     static const WCHAR ConditionQuery[] =
1956         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
1957          '`','C','o','n','d','i','t','i','o','n','`',0};
1958     static const WCHAR szCosting[] =
1959         {'C','o','s','t','i','n','g','C','o','m','p','l','e','t','e',0 };
1960     static const WCHAR szlevel[] =
1961         {'I','N','S','T','A','L','L','L','E','V','E','L',0};
1962     static const WCHAR szOutOfDiskSpace[] =
1963         {'O','u','t','O','f','D','i','s','k','S','p','a','c','e',0};
1964     MSICOMPONENT *comp;
1965     UINT rc;
1966     MSIQUERY * view;
1967     LPWSTR level;
1968 
1969     TRACE("Building Directory properties\n");
1970 
1971     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
1972     if (rc == ERROR_SUCCESS)
1973     {
1974         rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeDirectories,
1975                         package);
1976         msiobj_release(&view->hdr);
1977     }
1978 
1979     /* read components states from the registry */
1980     ACTION_GetComponentInstallStates(package);
1981     ACTION_GetFeatureInstallStates(package);
1982 
1983     TRACE("File calculations\n");
1984     msi_check_file_install_states( package );
1985 
1986     TRACE("Evaluating Condition Table\n");
1987 
1988     rc = MSI_DatabaseOpenViewW(package->db, ConditionQuery, &view);
1989     if (rc == ERROR_SUCCESS)
1990     {
1991         rc = MSI_IterateRecords(view, NULL, ITERATE_CostFinalizeConditions,
1992                     package);
1993         msiobj_release(&view->hdr);
1994     }
1995 
1996     TRACE("Enabling or Disabling Components\n");
1997     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
1998     {
1999         if (MSI_EvaluateConditionW(package, comp->Condition) == MSICONDITION_FALSE)
2000         {
2001             TRACE("Disabling component %s\n", debugstr_w(comp->Component));
2002             comp->Enabled = FALSE;
2003         }
2004         else
2005             comp->Enabled = TRUE;
2006     }
2007 
2008     MSI_SetPropertyW(package,szCosting,szOne);
2009     /* set default run level if not set */
2010     level = msi_dup_property( package, szlevel );
2011     if (!level)
2012         MSI_SetPropertyW(package,szlevel, szOne);
2013     msi_free(level);
2014 
2015     /* FIXME: check volume disk space */
2016     MSI_SetPropertyW(package, szOutOfDiskSpace, szZero);
2017 
2018     return MSI_SetFeatureStates(package);
2019 }
2020 
2021 /* OK this value is "interpreted" and then formatted based on the 
2022    first few characters */
2023 static LPSTR parse_value(MSIPACKAGE *package, LPCWSTR value, DWORD *type, 
2024                          DWORD *size)
2025 {
2026     LPSTR data = NULL;
2027 
2028     if (value[0]=='#' && value[1]!='#' && value[1]!='%')
2029     {
2030         if (value[1]=='x')
2031         {
2032             LPWSTR ptr;
2033             CHAR byte[5];
2034             LPWSTR deformated = NULL;
2035             int count;
2036 
2037             deformat_string(package, &value[2], &deformated);
2038 
2039             /* binary value type */
2040             ptr = deformated;
2041             *type = REG_BINARY;
2042             if (strlenW(ptr)%2)
2043                 *size = (strlenW(ptr)/2)+1;
2044             else
2045                 *size = strlenW(ptr)/2;
2046 
2047             data = msi_alloc(*size);
2048 
2049             byte[0] = ''; 
2050             byte[1] = 'x'; 
2051             byte[4] = 0; 
2052             count = 0;
2053             /* if uneven pad with a zero in front */
2054             if (strlenW(ptr)%2)
2055             {
2056                 byte[2]= '';
2057                 byte[3]= *ptr;
2058                 ptr++;
2059                 data[count] = (BYTE)strtol(byte,NULL,0);
2060                 count ++;
2061                 TRACE("Uneven byte count\n");
2062             }
2063             while (*ptr)
2064             {
2065                 byte[2]= *ptr;
2066                 ptr++;
2067                 byte[3]= *ptr;
2068                 ptr++;
2069                 data[count] = (BYTE)strtol(byte,NULL,0);
2070                 count ++;
2071             }
2072             msi_free(deformated);
2073 
2074             TRACE("Data %i bytes(%i)\n",*size,count);
2075         }
2076         else
2077         {
2078             LPWSTR deformated;
2079             LPWSTR p;
2080             DWORD d = 0;
2081             deformat_string(package, &value[1], &deformated);
2082 
2083             *type=REG_DWORD; 
2084             *size = sizeof(DWORD);
2085             data = msi_alloc(*size);
2086             p = deformated;
2087             if (*p == '-')
2088                 p++;
2089             while (*p)
2090             {
2091                 if ( (*p < '') || (*p > '9') )
2092                     break;
2093                 d *= 10;
2094                 d += (*p - '');
2095                 p++;
2096             }
2097             if (deformated[0] == '-')
2098                 d = -d;
2099             *(LPDWORD)data = d;
2100             TRACE("DWORD %i\n",*(LPDWORD)data);
2101 
2102             msi_free(deformated);
2103         }
2104     }
2105     else
2106     {
2107         static const WCHAR szMulti[] = {'[','~',']',0};
2108         LPCWSTR ptr;
2109         *type=REG_SZ;
2110 
2111         if (value[0]=='#')
2112         {
2113             if (value[1]=='%')
2114             {
2115                 ptr = &value[2];
2116                 *type=REG_EXPAND_SZ;
2117             }
2118             else
2119                 ptr = &value[1];
2120          }
2121          else
2122             ptr=value;
2123 
2124         if (strstrW(value,szMulti))
2125             *type = REG_MULTI_SZ;
2126 
2127         /* remove initial delimiter */
2128         if (!strncmpW(value, szMulti, 3))
2129             ptr = value + 3;
2130 
2131         *size = deformat_string(package, ptr,(LPWSTR*)&data);
2132 
2133         /* add double NULL terminator */
2134         if (*type == REG_MULTI_SZ)
2135         {
2136             *size += 2 * sizeof(WCHAR); /* two NULL terminators */
2137             data = msi_realloc_zero(data, *size);
2138         }
2139     }
2140     return data;
2141 }
2142 
2143 static UINT ITERATE_WriteRegistryValues(MSIRECORD *row, LPVOID param)
2144 {
2145     MSIPACKAGE *package = param;
2146     static const WCHAR szHCR[] = 
2147         {'H','K','E','Y','_','C','L','A','S','S','E','S','_',
2148          'R','O','O','T','\\',0};
2149     static const WCHAR szHCU[] =
2150         {'H','K','E','Y','_','C','U','R','R','E','N','T','_',
2151          'U','S','E','R','\\',0};
2152     static const WCHAR szHLM[] =
2153         {'H','K','E','Y','_','L','O','C','A','L','_',
2154          'M','A','C','H','I','N','E','\\',0};
2155     static const WCHAR szHU[] =
2156         {'H','K','E','Y','_','U','S','E','R','S','\\',0};
2157 
2158     LPSTR value_data = NULL;
2159     HKEY  root_key, hkey;
2160     DWORD type,size;
2161     LPWSTR  deformated;
2162     LPCWSTR szRoot, component, name, key, value;
2163     MSICOMPONENT *comp;
2164     MSIRECORD * uirow;
2165     LPWSTR uikey;
2166     INT   root;
2167     BOOL check_first = FALSE;
2168     UINT rc;
2169 
2170     ui_progress(package,2,0,0,0);
2171 
2172     value = NULL;
2173     key = NULL;
2174     uikey = NULL;
2175     name = NULL;
2176 
2177     component = MSI_RecordGetString(row, 6);
2178     comp = get_loaded_component(package,component);
2179     if (!comp)
2180         return ERROR_SUCCESS;
2181 
2182     if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2183     {
2184         TRACE("Skipping write due to disabled component %s\n",
2185                         debugstr_w(component));
2186 
2187         comp->Action = comp->Installed;
2188 
2189         return ERROR_SUCCESS;
2190     }
2191 
2192     comp->Action = INSTALLSTATE_LOCAL;
2193 
2194     name = MSI_RecordGetString(row, 4);
2195     if( MSI_RecordIsNull(row,5) && name )
2196     {
2197         /* null values can have special meanings */
2198         if (name[0]=='-' && name[1] == 0)
2199                 return ERROR_SUCCESS;
2200         else if ((name[0]=='+' && name[1] == 0) || 
2201                  (name[0] == '*' && name[1] == 0))
2202                 name = NULL;
2203         check_first = TRUE;
2204     }
2205 
2206     root = MSI_RecordGetInteger(row,2);
2207     key = MSI_RecordGetString(row, 3);
2208 
2209     /* get the root key */
2210     switch (root)
2211     {
2212         case -1: 
2213             {
2214                 LPWSTR all_users = msi_dup_property( package, szAllUsers );
2215                 if (all_users && all_users[0] == '1')
2216                 {
2217                     root_key = HKEY_LOCAL_MACHINE;
2218                     szRoot = szHLM;
2219                 }
2220                 else
2221                 {
2222                     root_key = HKEY_CURRENT_USER;
2223                     szRoot = szHCU;
2224                 }
2225                 msi_free(all_users);
2226             }
2227                  break;
2228         case 0:  root_key = HKEY_CLASSES_ROOT; 
2229                  szRoot = szHCR;
2230                  break;
2231         case 1:  root_key = HKEY_CURRENT_USER;
2232                  szRoot = szHCU;
2233                  break;
2234         case 2:  root_key = HKEY_LOCAL_MACHINE;
2235                  szRoot = szHLM;
2236                  break;
2237         case 3:  root_key = HKEY_USERS; 
2238                  szRoot = szHU;
2239                  break;
2240         default:
2241                  ERR("Unknown root %i\n",root);
2242                  root_key=NULL;
2243                  szRoot = NULL;
2244                  break;
2245     }
2246     if (!root_key)
2247         return ERROR_SUCCESS;
2248 
2249     deformat_string(package, key , &deformated);
2250     size = strlenW(deformated) + strlenW(szRoot) + 1;
2251     uikey = msi_alloc(size*sizeof(WCHAR));
2252     strcpyW(uikey,szRoot);
2253     strcatW(uikey,deformated);
2254 
2255     if (RegCreateKeyW( root_key, deformated, &hkey))
2256     {
2257         ERR("Could not create key %s\n",debugstr_w(deformated));
2258         msi_free(deformated);
2259         msi_free(uikey);
2260         return ERROR_SUCCESS;
2261     }
2262     msi_free(deformated);
2263 
2264     value = MSI_RecordGetString(row,5);
2265     if (value)
2266         value_data = parse_value(package, value, &type, &size); 
2267     else
2268     {
2269         value_data = (LPSTR)strdupW(szEmpty);
2270         size = sizeof(szEmpty);
2271         type = REG_SZ;
2272     }
2273 
2274     deformat_string(package, name, &deformated);
2275 
2276     if (!check_first)
2277     {
2278         TRACE("Setting value %s of %s\n",debugstr_w(deformated),
2279                         debugstr_w(uikey));
2280         RegSetValueExW(hkey, deformated, 0, type, (LPBYTE)value_data, size);
2281     }
2282     else
2283     {
2284         DWORD sz = 0;
2285         rc = RegQueryValueExW(hkey, deformated, NULL, NULL, NULL, &sz);
2286         if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
2287         {
2288             TRACE("value %s of %s checked already exists\n",
2289                             debugstr_w(deformated), debugstr_w(uikey));
2290         }
2291         else
2292         {
2293             TRACE("Checked and setting value %s of %s\n",
2294                             debugstr_w(deformated), debugstr_w(uikey));
2295             if (deformated || size)
2296                 RegSetValueExW(hkey, deformated, 0, type, (LPBYTE) value_data, size);
2297         }
2298     }
2299     RegCloseKey(hkey);
2300 
2301     uirow = MSI_CreateRecord(3);
2302     MSI_RecordSetStringW(uirow,2,deformated);
2303     MSI_RecordSetStringW(uirow,1,uikey);
2304 
2305     if (type == REG_SZ)
2306         MSI_RecordSetStringW(uirow,3,(LPWSTR)value_data);
2307     else
2308         MSI_RecordSetStringW(uirow,3,value);
2309 
2310     ui_actiondata(package,szWriteRegistryValues,uirow);
2311     msiobj_release( &uirow->hdr );
2312 
2313     msi_free(value_data);
2314     msi_free(deformated);
2315     msi_free(uikey);
2316 
2317     return ERROR_SUCCESS;
2318 }
2319 
2320 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package)
2321 {
2322     UINT rc;
2323     MSIQUERY * view;
2324     static const WCHAR ExecSeqQuery[] =
2325         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2326          '`','R','e','g','i','s','t','r','y','`',0 };
2327 
2328     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2329     if (rc != ERROR_SUCCESS)
2330         return ERROR_SUCCESS;
2331 
2332     /* increment progress bar each time action data is sent */
2333     ui_progress(package,1,REG_PROGRESS_VALUE,1,0);
2334 
2335     rc = MSI_IterateRecords(view, NULL, ITERATE_WriteRegistryValues, package);
2336 
2337     msiobj_release(&view->hdr);
2338     return rc;
2339 }
2340 
2341 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
2342 {
2343     package->script->CurrentlyScripting = TRUE;
2344 
2345     return ERROR_SUCCESS;
2346 }
2347 
2348 
2349 static UINT ACTION_InstallValidate(MSIPACKAGE *package)
2350 {
2351     MSICOMPONENT *comp;
2352     DWORD progress = 0;
2353     DWORD total = 0;
2354     static const WCHAR q1[]=
2355         {'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2356          '`','R','e','g','i','s','t','r','y','`',0};
2357     UINT rc;
2358     MSIQUERY * view;
2359     MSIFEATURE *feature;
2360     MSIFILE *file;
2361 
2362     TRACE("InstallValidate\n");
2363 
2364     rc = MSI_DatabaseOpenViewW(package->db, q1, &view);
2365     if (rc == ERROR_SUCCESS)
2366     {
2367         MSI_IterateRecords( view, &progress, NULL, package );
2368         msiobj_release( &view->hdr );
2369         total += progress * REG_PROGRESS_VALUE;
2370     }
2371 
2372     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2373         total += COMPONENT_PROGRESS_VALUE;
2374 
2375     LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2376         total += file->FileSize;
2377 
2378     ui_progress(package,0,total,0,0);
2379 
2380     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2381     {
2382         TRACE("Feature: %s; Installed: %i; Action %i; Request %i\n",
2383             debugstr_w(feature->Feature), feature->Installed, feature->Action,
2384             feature->ActionRequest);
2385     }
2386     
2387     return ERROR_SUCCESS;
2388 }
2389 
2390 static UINT ITERATE_LaunchConditions(MSIRECORD *row, LPVOID param)
2391 {
2392     MSIPACKAGE* package = param;
2393     LPCWSTR cond = NULL; 
2394     LPCWSTR message = NULL;
2395     UINT r;
2396 
2397     static const WCHAR title[]=
2398         {'I','n','s','t','a','l','l',' ','F','a', 'i','l','e','d',0};
2399 
2400     cond = MSI_RecordGetString(row,1);
2401 
2402     r = MSI_EvaluateConditionW(package,cond);
2403     if (r == MSICONDITION_FALSE)
2404     {
2405         if ((gUILevel & INSTALLUILEVEL_MASK) != INSTALLUILEVEL_NONE)
2406         {
2407             LPWSTR deformated;
2408             message = MSI_RecordGetString(row,2);
2409             deformat_string(package,message,&deformated);
2410             MessageBoxW(NULL,deformated,title,MB_OK);
2411             msi_free(deformated);
2412         }
2413 
2414         return ERROR_INSTALL_FAILURE;
2415     }
2416 
2417     return ERROR_SUCCESS;
2418 }
2419 
2420 static UINT ACTION_LaunchConditions(MSIPACKAGE *package)
2421 {
2422     UINT rc;
2423     MSIQUERY * view = NULL;
2424     static const WCHAR ExecSeqQuery[] =
2425         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2426          '`','L','a','u','n','c','h','C','o','n','d','i','t','i','o','n','`',0};
2427 
2428     TRACE("Checking launch conditions\n");
2429 
2430     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
2431     if (rc != ERROR_SUCCESS)
2432         return ERROR_SUCCESS;
2433 
2434     rc = MSI_IterateRecords(view, NULL, ITERATE_LaunchConditions, package);
2435     msiobj_release(&view->hdr);
2436 
2437     return rc;
2438 }
2439 
2440 static LPWSTR resolve_keypath( MSIPACKAGE* package, MSICOMPONENT *cmp )
2441 {
2442 
2443     if (!cmp->KeyPath)
2444         return resolve_folder(package,cmp->Directory,FALSE,FALSE,TRUE,NULL);
2445 
2446     if (cmp->Attributes & msidbComponentAttributesRegistryKeyPath)
2447     {
2448         MSIRECORD * row = 0;
2449         UINT root,len;
2450         LPWSTR deformated,buffer,deformated_name;
2451         LPCWSTR key,name;
2452         static const WCHAR ExecSeqQuery[] =
2453             {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2454              '`','R','e','g','i','s','t','r','y','`',' ',
2455              'W','H','E','R','E',' ', '`','R','e','g','i','s','t','r','y','`',
2456              ' ','=',' ' ,'\'','%','s','\'',0 };
2457         static const WCHAR fmt[]={'%','','2','i',':','\\','%','s','\\',0};
2458         static const WCHAR fmt2[]=
2459             {'%','','2','i',':','\\','%','s','\\','%','s',0};
2460 
2461         row = MSI_QueryGetRecord(package->db, ExecSeqQuery,cmp->KeyPath);
2462         if (!row)
2463             return NULL;
2464 
2465         root = MSI_RecordGetInteger(row,2);
2466         key = MSI_RecordGetString(row, 3);
2467         name = MSI_RecordGetString(row, 4);
2468         deformat_string(package, key , &deformated);
2469         deformat_string(package, name, &deformated_name);
2470 
2471         len = strlenW(deformated) + 6;
2472         if (deformated_name)
2473             len+=strlenW(deformated_name);
2474 
2475         buffer = msi_alloc( len *sizeof(WCHAR));
2476 
2477         if (deformated_name)
2478             sprintfW(buffer,fmt2,root,deformated,deformated_name);
2479         else
2480             sprintfW(buffer,fmt,root,deformated);
2481 
2482         msi_free(deformated);
2483         msi_free(deformated_name);
2484         msiobj_release(&row->hdr);
2485 
2486         return buffer;
2487     }
2488     else if (cmp->Attributes & msidbComponentAttributesODBCDataSource)
2489     {
2490         FIXME("UNIMPLEMENTED keypath as ODBC Source\n");
2491         return NULL;
2492     }
2493     else
2494     {
2495         MSIFILE *file = get_loaded_file( package, cmp->KeyPath );
2496 
2497         if (file)
2498             return strdupW( file->TargetPath );
2499     }
2500     return NULL;
2501 }
2502 
2503 static HKEY openSharedDLLsKey(void)
2504 {
2505     HKEY hkey=0;
2506     static const WCHAR path[] =
2507         {'S','o','f','t','w','a','r','e','\\',
2508          'M','i','c','r','o','s','o','f','t','\\',
2509          'W','i','n','d','o','w','s','\\',
2510          'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2511          'S','h','a','r','e','d','D','L','L','s',0};
2512 
2513     RegCreateKeyW(HKEY_LOCAL_MACHINE,path,&hkey);
2514     return hkey;
2515 }
2516 
2517 static UINT ACTION_GetSharedDLLsCount(LPCWSTR dll)
2518 {
2519     HKEY hkey;
2520     DWORD count=0;
2521     DWORD type;
2522     DWORD sz = sizeof(count);
2523     DWORD rc;
2524     
2525     hkey = openSharedDLLsKey();
2526     rc = RegQueryValueExW(hkey, dll, NULL, &type, (LPBYTE)&count, &sz);
2527     if (rc != ERROR_SUCCESS)
2528         count = 0;
2529     RegCloseKey(hkey);
2530     return count;
2531 }
2532 
2533 static UINT ACTION_WriteSharedDLLsCount(LPCWSTR path, UINT count)
2534 {
2535     HKEY hkey;
2536 
2537     hkey = openSharedDLLsKey();
2538     if (count > 0)
2539         msi_reg_set_val_dword( hkey, path, count );
2540     else
2541         RegDeleteValueW(hkey,path);
2542     RegCloseKey(hkey);
2543     return count;
2544 }
2545 
2546 /*
2547  * Return TRUE if the count should be written out and FALSE if not
2548  */
2549 static void ACTION_RefCountComponent( MSIPACKAGE* package, MSICOMPONENT *comp )
2550 {
2551     MSIFEATURE *feature;
2552     INT count = 0;
2553     BOOL write = FALSE;
2554 
2555     /* only refcount DLLs */
2556     if (comp->KeyPath == NULL || 
2557         comp->Attributes & msidbComponentAttributesRegistryKeyPath || 
2558         comp->Attributes & msidbComponentAttributesODBCDataSource)
2559         write = FALSE;
2560     else
2561     {
2562         count = ACTION_GetSharedDLLsCount( comp->FullKeypath);
2563         write = (count > 0);
2564 
2565         if (comp->Attributes & msidbComponentAttributesSharedDllRefCount)
2566             write = TRUE;
2567     }
2568 
2569     /* increment counts */
2570     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2571     {
2572         ComponentList *cl;
2573 
2574         if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
2575             continue;
2576 
2577         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2578         {
2579             if ( cl->component == comp )
2580                 count++;
2581         }
2582     }
2583 
2584     /* decrement counts */
2585     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
2586     {
2587         ComponentList *cl;
2588 
2589         if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ABSENT ))
2590             continue;
2591 
2592         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
2593         {
2594             if ( cl->component == comp )
2595                 count--;
2596         }
2597     }
2598 
2599     /* ref count all the files in the component */
2600     if (write)
2601     {
2602         MSIFILE *file;
2603 
2604         LIST_FOR_EACH_ENTRY( file, &package->files, MSIFILE, entry )
2605         {
2606             if (file->Component == comp)
2607                 ACTION_WriteSharedDLLsCount( file->TargetPath, count );
2608         }
2609     }
2610     
2611     /* add a count for permanent */
2612     if (comp->Attributes & msidbComponentAttributesPermanent)
2613         count ++;
2614     
2615     comp->RefCount = count;
2616 
2617     if (write)
2618         ACTION_WriteSharedDLLsCount( comp->FullKeypath, comp->RefCount );
2619 }
2620 
2621 static UINT ACTION_ProcessComponents(MSIPACKAGE *package)
2622 {
2623     WCHAR squished_pc[GUID_SIZE];
2624     WCHAR squished_cc[GUID_SIZE];
2625     UINT rc;
2626     MSICOMPONENT *comp;
2627     HKEY hkey;
2628 
2629     TRACE("\n");
2630 
2631     squash_guid(package->ProductCode,squished_pc);
2632     ui_progress(package,1,COMPONENT_PROGRESS_VALUE,1,0);
2633 
2634     LIST_FOR_EACH_ENTRY( comp, &package->components, MSICOMPONENT, entry )
2635     {
2636         MSIRECORD * uirow;
2637 
2638         ui_progress(package,2,0,0,0);
2639         if (!comp->ComponentId)
2640             continue;
2641 
2642         squash_guid(comp->ComponentId,squished_cc);
2643 
2644         msi_free(comp->FullKeypath);
2645         comp->FullKeypath = resolve_keypath( package, comp );
2646 
2647         ACTION_RefCountComponent( package, comp );
2648 
2649         TRACE("Component %s (%s), Keypath=%s, RefCount=%i\n",
2650                             debugstr_w(comp->Component),
2651                             debugstr_w(squished_cc),
2652                             debugstr_w(comp->FullKeypath),
2653                             comp->RefCount);
2654 
2655         if (ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL) ||
2656             ACTION_VerifyComponentForAction( comp, INSTALLSTATE_SOURCE))
2657         {
2658             if (!comp->FullKeypath)
2659                 continue;
2660 
2661             if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2662                 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, szLocalSid,
2663                                                      &hkey, TRUE);
2664             else
2665                 rc = MSIREG_OpenUserDataComponentKey(comp->ComponentId, NULL,
2666                                                      &hkey, TRUE);
2667 
2668             if (rc != ERROR_SUCCESS)
2669                 continue;
2670 
2671             if (comp->Attributes & msidbComponentAttributesPermanent)
2672             {
2673                 static const WCHAR szPermKey[] =
2674                     { '','','','','','','','','','','','',
2675                       '','','','','','','','','','','','',
2676                       '','','','','','','','',0 };
2677 
2678                 msi_reg_set_val_str(hkey, szPermKey, comp->FullKeypath);
2679             }
2680 
2681             if (comp->Action == INSTALLSTATE_LOCAL)
2682                 msi_reg_set_val_str(hkey, squished_pc, comp->FullKeypath);
2683             else
2684             {
2685                 MSIFILE *file;
2686                 MSIRECORD *row;
2687                 LPWSTR ptr, ptr2;
2688                 WCHAR source[MAX_PATH];
2689                 WCHAR base[MAX_PATH];
2690                 LPWSTR sourcepath;
2691 
2692                 static const WCHAR fmt[] = {'%','','2','d','\\',0};
2693                 static const WCHAR query[] = {
2694                     'S','E','L','E','C','T',' ','*',' ', 'F','R','O','M',' ',
2695                     '`','M','e','d','i','a','`',' ','W','H','E','R','E',' ',
2696                     '`','L','a','s','t','S','e','q','u','e','n','c','e','`',' ',
2697                     '>','=',' ','%','i',' ','O','R','D','E','R',' ','B','Y',' ',
2698                     '`','D','i','s','k','I','d','`',0};
2699 
2700                 file = get_loaded_file(package, comp->KeyPath);
2701                 if (!file)
2702                     continue;
2703 
2704                 row = MSI_QueryGetRecord(package->db, query, file->Sequence);
2705                 sprintfW(source, fmt, MSI_RecordGetInteger(row, 1));
2706                 ptr2 = strrchrW(source, '\\') + 1;
2707                 msiobj_release(&row->hdr);
2708 
2709                 lstrcpyW(base, package->PackagePath);
2710                 ptr = strrchrW(base, '\\');
2711                 *(ptr + 1) = '\0';
2712 
2713                 sourcepath = resolve_file_source(package, file);
2714                 ptr = sourcepath + lstrlenW(base);
2715                 lstrcpyW(ptr2, ptr);
2716                 msi_free(sourcepath);
2717 
2718                 msi_reg_set_val_str(hkey, squished_pc, source);
2719             }
2720             RegCloseKey(hkey);
2721         }
2722         else if (ACTION_VerifyComponentForAction(comp, INSTALLSTATE_ABSENT))
2723         {
2724             if (package->Context == MSIINSTALLCONTEXT_MACHINE)
2725                 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, szLocalSid);
2726             else
2727                 MSIREG_DeleteUserDataComponentKey(comp->ComponentId, NULL);
2728         }
2729 
2730         /* UI stuff */
2731         uirow = MSI_CreateRecord(3);
2732         MSI_RecordSetStringW(uirow,1,package->ProductCode);
2733         MSI_RecordSetStringW(uirow,2,comp->ComponentId);
2734         MSI_RecordSetStringW(uirow,3,comp->FullKeypath);
2735         ui_actiondata(package,szProcessComponents,uirow);
2736         msiobj_release( &uirow->hdr );
2737     }
2738 
2739     return ERROR_SUCCESS;
2740 }
2741 
2742 typedef struct {
2743     CLSID       clsid;
2744     LPWSTR      source;
2745 
2746     LPWSTR      path;
2747     ITypeLib    *ptLib;
2748 } typelib_struct;
2749 
2750 static BOOL CALLBACK Typelib_EnumResNameProc( HMODULE hModule, LPCWSTR lpszType, 
2751                                        LPWSTR lpszName, LONG_PTR lParam)
2752 {
2753     TLIBATTR *attr;
2754     typelib_struct *tl_struct = (typelib_struct*) lParam;
2755     static const WCHAR fmt[] = {'%','s','\\','%','i',0};
2756     int sz; 
2757     HRESULT res;
2758 
2759     if (!IS_INTRESOURCE(lpszName))
2760     {
2761         ERR("Not Int Resource Name %s\n",debugstr_w(lpszName));
2762         return TRUE;
2763     }
2764 
2765     sz = strlenW(tl_struct->source)+4;
2766     sz *= sizeof(WCHAR);
2767 
2768     if ((INT_PTR)lpszName == 1)
2769         tl_struct->path = strdupW(tl_struct->source);
2770     else
2771     {
2772         tl_struct->path = msi_alloc(sz);
2773         sprintfW(tl_struct->path,fmt,tl_struct->source, lpszName);
2774     }
2775 
2776     TRACE("trying %s\n", debugstr_w(tl_struct->path));
2777     res = LoadTypeLib(tl_struct->path,&tl_struct->ptLib);
2778     if (FAILED(res))
2779     {
2780         msi_free(tl_struct->path);
2781         tl_struct->path = NULL;
2782 
2783         return TRUE;
2784     }
2785 
2786     ITypeLib_GetLibAttr(tl_struct->ptLib, &attr);
2787     if (IsEqualGUID(&(tl_struct->clsid),&(attr->guid)))
2788     {
2789         ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2790         return FALSE;
2791     }
2792 
2793     msi_free(tl_struct->path);
2794     tl_struct->path = NULL;
2795 
2796     ITypeLib_ReleaseTLibAttr(tl_struct->ptLib, attr);
2797     ITypeLib_Release(tl_struct->ptLib);
2798 
2799     return TRUE;
2800 }
2801 
2802 static UINT ITERATE_RegisterTypeLibraries(MSIRECORD *row, LPVOID param)
2803 {
2804     MSIPACKAGE* package = param;
2805     LPCWSTR component;
2806     MSICOMPONENT *comp;
2807     MSIFILE *file;
2808     typelib_struct tl_struct;
2809     ITypeLib *tlib;
2810     HMODULE module;
2811     HRESULT hr;
2812 
2813     static const WCHAR szTYPELIB[] = {'T','Y','P','E','L','I','B',0};
2814 
2815     component = MSI_RecordGetString(row,3);
2816     comp = get_loaded_component(package,component);
2817     if (!comp)
2818         return ERROR_SUCCESS;
2819 
2820     if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
2821     {
2822         TRACE("Skipping typelib reg due to disabled component\n");
2823 
2824         comp->Action = comp->Installed;
2825 
2826         return ERROR_SUCCESS;
2827     }
2828 
2829     comp->Action = INSTALLSTATE_LOCAL;
2830 
2831     file = get_loaded_file( package, comp->KeyPath ); 
2832     if (!file)
2833         return ERROR_SUCCESS;
2834 
2835     module = LoadLibraryExW( file->TargetPath, NULL, LOAD_LIBRARY_AS_DATAFILE );
2836     if (module)
2837     {
2838         LPCWSTR guid;
2839         guid = MSI_RecordGetString(row,1);
2840         CLSIDFromString((LPWSTR)guid, &tl_struct.clsid);
2841         tl_struct.source = strdupW( file->TargetPath );
2842         tl_struct.path = NULL;
2843 
2844         EnumResourceNamesW(module, szTYPELIB, Typelib_EnumResNameProc,
2845                         (LONG_PTR)&tl_struct);
2846 
2847         if (tl_struct.path)
2848         {
2849             LPWSTR help = NULL;
2850             LPCWSTR helpid;
2851             HRESULT res;
2852 
2853             helpid = MSI_RecordGetString(row,6);
2854 
2855             if (helpid)
2856                 help = resolve_folder(package,helpid,FALSE,FALSE,TRUE,NULL);
2857             res = RegisterTypeLib(tl_struct.ptLib,tl_struct.path,help);
2858             msi_free(help);
2859 
2860             if (FAILED(res))
2861                 ERR("Failed to register type library %s\n",
2862                         debugstr_w(tl_struct.path));
2863             else
2864             {
2865                 ui_actiondata(package,szRegisterTypeLibraries,row);
2866 
2867                 TRACE("Registered %s\n", debugstr_w(tl_struct.path));
2868             }
2869 
2870             ITypeLib_Release(tl_struct.ptLib);
2871             msi_free(tl_struct.path);
2872         }
2873         else
2874             ERR("Failed to load type library %s\n",
2875                     debugstr_w(tl_struct.source));
2876 
2877         FreeLibrary(module);
2878         msi_free(tl_struct.source);
2879     }
2880     else
2881     {
2882         hr = LoadTypeLibEx(file->TargetPath, REGKIND_REGISTER, &tlib);
2883         if (FAILED(hr))
2884         {
2885             ERR("Failed to load type library: %08x\n", hr);
2886             return ERROR_FUNCTION_FAILED;
2887         }
2888 
2889         ITypeLib_Release(tlib);
2890     }
2891 
2892     return ERROR_SUCCESS;
2893 }
2894 
2895 static UINT ACTION_RegisterTypeLibraries(MSIPACKAGE *package)
2896 {
2897     /* 
2898      * OK this is a bit confusing.. I am given a _Component key and I believe
2899      * that the file that is being registered as a type library is the "key file
2900      * of that component" which I interpret to mean "The file in the KeyPath of
2901      * that component".
2902      */
2903     UINT rc;
2904     MSIQUERY * view;
2905     static const WCHAR Query[] =
2906         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
2907          '`','T','y','p','e','L','i','b','`',0};
2908 
2909     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
2910     if (rc != ERROR_SUCCESS)
2911         return ERROR_SUCCESS;
2912 
2913     rc = MSI_IterateRecords(view, NULL, ITERATE_RegisterTypeLibraries, package);
2914     msiobj_release(&view->hdr);
2915     return rc;
2916 }
2917 
2918 static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
2919 {
2920     MSIPACKAGE *package = param;
2921     LPWSTR target_file, target_folder, filename;
2922     LPCWSTR buffer, extension;
2923     MSICOMPONENT *comp;
2924     static const WCHAR szlnk[]={'.','l','n','k',0};
2925     IShellLinkW *sl = NULL;
2926     IPersistFile *pf = NULL;
2927     HRESULT res;
2928 
2929     buffer = MSI_RecordGetString(row,4);
2930     comp = get_loaded_component(package,buffer);
2931     if (!comp)
2932         return ERROR_SUCCESS;
2933 
2934     if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL ))
2935     {
2936         TRACE("Skipping shortcut creation due to disabled component\n");
2937 
2938         comp->Action = comp->Installed;
2939 
2940         return ERROR_SUCCESS;
2941     }
2942 
2943     comp->Action = INSTALLSTATE_LOCAL;
2944 
2945     ui_actiondata(package,szCreateShortcuts,row);
2946 
2947     res = CoCreateInstance( &CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
2948                     &IID_IShellLinkW, (LPVOID *) &sl );
2949 
2950     if (FAILED( res ))
2951     {
2952         ERR("CLSID_ShellLink not available\n");
2953         goto err;
2954     }
2955 
2956     res = IShellLinkW_QueryInterface( sl, &IID_IPersistFile,(LPVOID*) &pf );
2957     if (FAILED( res ))
2958     {
2959         ERR("QueryInterface(IID_IPersistFile) failed\n");
2960         goto err;
2961     }
2962 
2963     buffer = MSI_RecordGetString(row,2);
2964     target_folder = resolve_folder(package, buffer,FALSE,FALSE,TRUE,NULL);
2965 
2966     /* may be needed because of a bug somewhere else */
2967     create_full_pathW(target_folder);
2968 
2969     filename = msi_dup_record_field( row, 3 );
2970     reduce_to_longfilename(filename);
2971 
2972     extension = strchrW(filename,'.');
2973     if (!extension || strcmpiW(extension,szlnk))
2974     {
2975         int len = strlenW(filename);
2976         filename = msi_realloc(filename, len * sizeof(WCHAR) + sizeof(szlnk));
2977         memcpy(filename + len, szlnk, sizeof(szlnk));
2978     }
2979     target_file = build_directory_name(2, target_folder, filename);
2980     msi_free(target_folder);
2981     msi_free(filename);
2982 
2983     buffer = MSI_RecordGetString(row,5);
2984     if (strchrW(buffer,'['))
2985     {
2986         LPWSTR deformated;
2987         deformat_string(package,buffer,&deformated);
2988         IShellLinkW_SetPath(sl,deformated);
2989         msi_free(deformated);
2990     }
2991     else
2992     {
2993         FIXME("poorly handled shortcut format, advertised shortcut\n");
2994         IShellLinkW_SetPath(sl,comp->FullKeypath);
2995     }
2996 
2997     if (!MSI_RecordIsNull(row,6))
2998     {
2999         LPWSTR deformated;
3000         buffer = MSI_RecordGetString(row,6);
3001         deformat_string(package,buffer,&deformated);
3002         IShellLinkW_SetArguments(sl,deformated);
3003         msi_free(deformated);
3004     }
3005 
3006     if (!MSI_RecordIsNull(row,7))
3007     {
3008         buffer = MSI_RecordGetString(row,7);
3009         IShellLinkW_SetDescription(sl,buffer);
3010     }
3011 
3012     if (!MSI_RecordIsNull(row,8))
3013         IShellLinkW_SetHotkey(sl,MSI_RecordGetInteger(row,8));
3014 
3015     if (!MSI_RecordIsNull(row,9))
3016     {
3017         LPWSTR Path;
3018         INT index; 
3019 
3020         buffer = MSI_RecordGetString(row,9);
3021 
3022         Path = build_icon_path(package,buffer);
3023         index = MSI_RecordGetInteger(row,10);
3024 
3025         /* no value means 0 */
3026         if (index == MSI_NULL_INTEGER)
3027             index = 0;
3028 
3029         IShellLinkW_SetIconLocation(sl,Path,index);
3030         msi_free(Path);
3031     }
3032 
3033     if (!MSI_RecordIsNull(row,11))
3034         IShellLinkW_SetShowCmd(sl,MSI_RecordGetInteger(row,11));
3035 
3036     if (!MSI_RecordIsNull(row,12))
3037     {
3038         LPWSTR Path;
3039         buffer = MSI_RecordGetString(row,12);
3040         Path = resolve_folder(package, buffer, FALSE, FALSE, TRUE, NULL);
3041         if (Path)
3042             IShellLinkW_SetWorkingDirectory(sl,Path);
3043         msi_free(Path);
3044     }
3045 
3046     TRACE("Writing shortcut to %s\n",debugstr_w(target_file));
3047     IPersistFile_Save(pf,target_file,FALSE);
3048 
3049     msi_free(target_file);    
3050 
3051 err:
3052     if (pf)
3053         IPersistFile_Release( pf );
3054     if (sl)
3055         IShellLinkW_Release( sl );
3056 
3057     return ERROR_SUCCESS;
3058 }
3059 
3060 static UINT ACTION_CreateShortcuts(MSIPACKAGE *package)
3061 {
3062     UINT rc;
3063     HRESULT res;
3064     MSIQUERY * view;
3065     static const WCHAR Query[] =
3066         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3067          '`','S','h','o','r','t','c','u','t','`',0};
3068 
3069     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
3070     if (rc != ERROR_SUCCESS)
3071         return ERROR_SUCCESS;
3072 
3073     res = CoInitialize( NULL );
3074 
3075     rc = MSI_IterateRecords(view, NULL, ITERATE_CreateShortcuts, package);
3076     msiobj_release(&view->hdr);
3077 
3078     if (SUCCEEDED(res))
3079         CoUninitialize();
3080 
3081     return rc;
3082 }
3083 
3084 static UINT ITERATE_PublishIcon(MSIRECORD *row, LPVOID param)
3085 {
3086     MSIPACKAGE* package = param;
3087     HANDLE the_file;
3088     LPWSTR FilePath;
3089     LPCWSTR FileName;
3090     CHAR buffer[1024];
3091     DWORD sz;
3092     UINT rc;
3093     MSIRECORD *uirow;
3094 
3095     FileName = MSI_RecordGetString(row,1);
3096     if (!FileName)
3097     {
3098         ERR("Unable to get FileName\n");
3099         return ERROR_SUCCESS;
3100     }
3101 
3102     FilePath = build_icon_path(package,FileName);
3103 
3104     TRACE("Creating icon file at %s\n",debugstr_w(FilePath));
3105 
3106     the_file = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
3107                         FILE_ATTRIBUTE_NORMAL, NULL);
3108 
3109     if (the_file == INVALID_HANDLE_VALUE)
3110     {
3111         ERR("Unable to create file %s\n",debugstr_w(FilePath));
3112         msi_free(FilePath);
3113         return ERROR_SUCCESS;
3114     }
3115 
3116     do 
3117     {
3118         DWORD write;
3119         sz = 1024;
3120         rc = MSI_RecordReadStream(row,2,buffer,&sz);
3121         if (rc != ERROR_SUCCESS)
3122         {
3123             ERR("Failed to get stream\n");
3124             CloseHandle(the_file);  
3125             DeleteFileW(FilePath);
3126             break;
3127         }
3128         WriteFile(the_file,buffer,sz,&write,NULL);
3129     } while (sz == 1024);
3130 
3131     msi_free(FilePath);
3132 
3133     CloseHandle(the_file);
3134 
3135     uirow = MSI_CreateRecord(1);
3136     MSI_RecordSetStringW(uirow,1,FileName);
3137     ui_actiondata(package,szPublishProduct,uirow);
3138     msiobj_release( &uirow->hdr );
3139 
3140     return ERROR_SUCCESS;
3141 }
3142 
3143 static UINT msi_publish_icons(MSIPACKAGE *package)
3144 {
3145     UINT r;
3146     MSIQUERY *view;
3147 
3148     static const WCHAR query[]= {
3149         'S','E','L','E','C','T',' ','*',' ',
3150         'F','R','O','M',' ','`','I','c','o','n','`',0};
3151 
3152     r = MSI_DatabaseOpenViewW(package->db, query, &view);
3153     if (r == ERROR_SUCCESS)
3154     {
3155         MSI_IterateRecords(view, NULL, ITERATE_PublishIcon, package);
3156         msiobj_release(&view->hdr);
3157     }
3158 
3159     return ERROR_SUCCESS;
3160 }
3161 
3162 static UINT msi_publish_sourcelist(MSIPACKAGE *package, HKEY hkey)
3163 {
3164     UINT r;
3165     HKEY source;
3166     LPWSTR buffer;
3167     MSIMEDIADISK *disk;
3168     MSISOURCELISTINFO *info;
3169 
3170     r = RegCreateKeyW(hkey, szSourceList, &source);
3171     if (r != ERROR_SUCCESS)
3172         return r;
3173 
3174     RegCloseKey(source);
3175 
3176     buffer = strrchrW(package->PackagePath, '\\') + 1;
3177     r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3178                               package->Context, MSICODE_PRODUCT,
3179                               INSTALLPROPERTY_PACKAGENAMEW, buffer);
3180     if (r != ERROR_SUCCESS)
3181         return r;
3182 
3183     r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3184                               package->Context, MSICODE_PRODUCT,
3185                               INSTALLPROPERTY_MEDIAPACKAGEPATHW, szEmpty);
3186     if (r != ERROR_SUCCESS)
3187         return r;
3188 
3189     r = MsiSourceListSetInfoW(package->ProductCode, NULL,
3190                               package->Context, MSICODE_PRODUCT,
3191                               INSTALLPROPERTY_DISKPROMPTW, szEmpty);
3192     if (r != ERROR_SUCCESS)
3193         return r;
3194 
3195     LIST_FOR_EACH_ENTRY(info, &package->sourcelist_info, MSISOURCELISTINFO, entry)
3196     {
3197         if (!lstrcmpW(info->property, INSTALLPROPERTY_LASTUSEDSOURCEW))
3198             msi_set_last_used_source(package->ProductCode, NULL, info->context,
3199                                      info->options, info->value);
3200         else
3201             MsiSourceListSetInfoW(package->ProductCode, NULL,
3202                                   info->context, info->options,
3203                                   info->property, info->value);
3204     }
3205 
3206     LIST_FOR_EACH_ENTRY(disk, &package->sourcelist_media, MSIMEDIADISK, entry)
3207     {
3208         MsiSourceListAddMediaDiskW(package->ProductCode, NULL,
3209                                    disk->context, disk->options,
3210                                    disk->disk_id, disk->volume_label, disk->disk_prompt);
3211     }
3212 
3213     return ERROR_SUCCESS;
3214 }
3215 
3216 static UINT msi_publish_product_properties(MSIPACKAGE *package, HKEY hkey)
3217 {
3218     MSIHANDLE hdb, suminfo;
3219     WCHAR guids[MAX_PATH];
3220     WCHAR packcode[SQUISH_GUID_SIZE];
3221     LPWSTR buffer;
3222     LPWSTR ptr;
3223     DWORD langid;
3224     DWORD size;
3225     UINT r;
3226 
3227     static const WCHAR szProductLanguage[] =
3228         {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3229     static const WCHAR szARPProductIcon[] =
3230         {'A','R','P','P','R','O','D','U','C','T','I','C','O','N',0};
3231     static const WCHAR szProductVersion[] =
3232         {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3233     static const WCHAR szAssignment[] =
3234         {'A','s','s','i','g','n','m','e','n','t',0};
3235     static const WCHAR szAdvertiseFlags[] =
3236         {'A','d','v','e','r','t','i','s','e','F','l','a','g','s',0};
3237     static const WCHAR szClients[] =
3238         {'C','l','i','e','n','t','s',0};
3239     static const WCHAR szColon[] = {':',0};
3240 
3241     buffer = msi_dup_property(package, INSTALLPROPERTY_PRODUCTNAMEW);
3242     msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTNAMEW, buffer);
3243     msi_free(buffer);
3244 
3245     langid = msi_get_property_int(package, szProductLanguage, 0);
3246     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3247 
3248     /* FIXME */
3249     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_AUTHORIZED_LUA_APPW, 0);
3250 
3251     buffer = msi_dup_property(package, szARPProductIcon);
3252     if (buffer)
3253     {
3254         LPWSTR path = build_icon_path(package,buffer);
3255         msi_reg_set_val_str(hkey, INSTALLPROPERTY_PRODUCTICONW, path);
3256         msi_free(path);
3257         msi_free(buffer);
3258     }
3259 
3260     buffer = msi_dup_property(package, szProductVersion);
3261     if (buffer)
3262     {
3263         DWORD verdword = msi_version_str_to_dword(buffer);
3264         msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3265         msi_free(buffer);
3266     }
3267 
3268     msi_reg_set_val_dword(hkey, szAssignment, 0);
3269     msi_reg_set_val_dword(hkey, szAdvertiseFlags, 0x184);
3270     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_INSTANCETYPEW, 0);
3271     msi_reg_set_val_str(hkey, szClients, szColon);
3272 
3273     hdb = alloc_msihandle(&package->db->hdr);
3274     if (!hdb)
3275         return ERROR_NOT_ENOUGH_MEMORY;
3276 
3277     r = MsiGetSummaryInformationW(hdb, NULL, 0, &suminfo);
3278     MsiCloseHandle(hdb);
3279     if (r != ERROR_SUCCESS)
3280         goto done;
3281 
3282     size = MAX_PATH;
3283     r = MsiSummaryInfoGetPropertyW(suminfo, PID_REVNUMBER, NULL, NULL,
3284                                    NULL, guids, &size);
3285     if (r != ERROR_SUCCESS)
3286         goto done;
3287 
3288     ptr = strchrW(guids, ';');
3289     if (ptr) *ptr = 0;
3290     squash_guid(guids, packcode);
3291     msi_reg_set_val_str(hkey, INSTALLPROPERTY_PACKAGECODEW, packcode);
3292 
3293 done:
3294     MsiCloseHandle(suminfo);
3295     return ERROR_SUCCESS;
3296 }
3297 
3298 static UINT msi_publish_upgrade_code(MSIPACKAGE *package)
3299 {
3300     UINT r;
3301     HKEY hkey;
3302     LPWSTR upgrade;
3303     WCHAR squashed_pc[SQUISH_GUID_SIZE];
3304 
3305     static const WCHAR szUpgradeCode[] =
3306         {'U','p','g','r','a','d','e','C','o','d','e',0};
3307 
3308     upgrade = msi_dup_property(package, szUpgradeCode);
3309     if (!upgrade)
3310         return ERROR_SUCCESS;
3311 
3312     if (package->Context == MSIINSTALLCONTEXT_MACHINE)
3313     {
3314         r = MSIREG_OpenClassesUpgradeCodesKey(upgrade, &hkey, TRUE);
3315         if (r != ERROR_SUCCESS)
3316             goto done;
3317     }
3318     else
3319     {
3320         r = MSIREG_OpenUserUpgradeCodesKey(upgrade, &hkey, TRUE);
3321         if (r != ERROR_SUCCESS)
3322             goto done;
3323     }
3324 
3325     squash_guid(package->ProductCode, squashed_pc);
3326     msi_reg_set_val_str(hkey, squashed_pc, NULL);
3327 
3328     RegCloseKey(hkey);
3329 
3330 done:
3331     msi_free(upgrade);
3332     return r;
3333 }
3334 
3335 static BOOL msi_check_publish(MSIPACKAGE *package)
3336 {
3337     MSIFEATURE *feature;
3338 
3339     LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3340     {
3341         if (feature->ActionRequest == INSTALLSTATE_LOCAL)
3342             return TRUE;
3343     }
3344 
3345     return FALSE;
3346 }
3347 
3348 static BOOL msi_check_unpublish(MSIPACKAGE *package)
3349 {
3350     MSIFEATURE *feature;
3351 
3352     LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3353     {
3354         if (feature->ActionRequest != INSTALLSTATE_ABSENT)
3355             return FALSE;
3356     }
3357 
3358     return TRUE;
3359 }
3360 
3361 static UINT msi_publish_patch(MSIPACKAGE *package, HKEY prodkey, HKEY hudkey)
3362 {
3363     WCHAR patch_squashed[GUID_SIZE];
3364     HKEY patches;
3365     LONG res;
3366     UINT r = ERROR_FUNCTION_FAILED;
3367 
3368     res = RegCreateKeyExW(prodkey, szPatches, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
3369                           &patches, NULL);
3370     if (res != ERROR_SUCCESS)
3371         return ERROR_FUNCTION_FAILED;
3372 
3373     squash_guid(package->patch->patchcode, patch_squashed);
3374 
3375     res = RegSetValueExW(patches, szPatches, 0, REG_MULTI_SZ,
3376                          (const BYTE *)patch_squashed,
3377                          (lstrlenW(patch_squashed) + 1) * sizeof(WCHAR));
3378     if (res != ERROR_SUCCESS)
3379         goto done;
3380 
3381     res = RegSetValueExW(patches, patch_squashed, 0, REG_SZ,
3382                          (const BYTE *)package->patch->transforms,
3383                          (lstrlenW(package->patch->transforms) + 1) * sizeof(WCHAR));
3384     if (res == ERROR_SUCCESS)
3385         r = ERROR_SUCCESS;
3386 
3387 done:
3388     RegCloseKey(patches);
3389     return r;
3390 }
3391 
3392 /*
3393  * 99% of the work done here is only done for 
3394  * advertised installs. However this is where the
3395  * Icon table is processed and written out
3396  * so that is what I am going to do here.
3397  */
3398 static UINT ACTION_PublishProduct(MSIPACKAGE *package)
3399 {
3400     UINT rc;
3401     HKEY hukey=0;
3402     HKEY hudkey=0;
3403 
3404     /* FIXME: also need to publish if the product is in advertise mode */
3405     if (!msi_check_publish(package))
3406         return ERROR_SUCCESS;
3407 
3408     rc = MSIREG_OpenProductKey(package->ProductCode, NULL, package->Context,
3409                                &hukey, TRUE);
3410     if (rc != ERROR_SUCCESS)
3411         goto end;
3412 
3413     rc = MSIREG_OpenUserDataProductKey(package->ProductCode, package->Context,
3414                                        NULL, &hudkey, TRUE);
3415     if (rc != ERROR_SUCCESS)
3416         goto end;
3417 
3418     rc = msi_publish_upgrade_code(package);
3419     if (rc != ERROR_SUCCESS)
3420         goto end;
3421 
3422     if (package->patch)
3423     {
3424         rc = msi_publish_patch(package, hukey, hudkey);
3425         if (rc != ERROR_SUCCESS)
3426             goto end;
3427     }
3428 
3429     rc = msi_publish_product_properties(package, hukey);
3430     if (rc != ERROR_SUCCESS)
3431         goto end;
3432 
3433     rc = msi_publish_sourcelist(package, hukey);
3434     if (rc != ERROR_SUCCESS)
3435         goto end;
3436 
3437     rc = msi_publish_icons(package);
3438 
3439 end:
3440     RegCloseKey(hukey);
3441     RegCloseKey(hudkey);
3442 
3443     return rc;
3444 }
3445 
3446 static UINT ITERATE_WriteIniValues(MSIRECORD *row, LPVOID param)
3447 {
3448     MSIPACKAGE *package = param;
3449     LPCWSTR component, section, key, value, identifier, dirproperty;
3450     LPWSTR deformated_section, deformated_key, deformated_value;
3451     LPWSTR folder, filename, fullname = NULL;
3452     LPCWSTR filenameptr;
3453     MSIRECORD * uirow;
3454     INT action;
3455     MSICOMPONENT *comp;
3456     static const WCHAR szWindowsFolder[] =
3457           {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
3458 
3459     component = MSI_RecordGetString(row, 8);
3460     comp = get_loaded_component(package,component);
3461 
3462     if (!ACTION_VerifyComponentForAction( comp, INSTALLSTATE_LOCAL))
3463     {
3464         TRACE("Skipping ini file due to disabled component %s\n",
3465                         debugstr_w(component));
3466 
3467         comp->Action = comp->Installed;
3468 
3469         return ERROR_SUCCESS;
3470     }
3471 
3472     comp->Action = INSTALLSTATE_LOCAL;
3473 
3474     identifier = MSI_RecordGetString(row,1); 
3475     dirproperty = MSI_RecordGetString(row,3);
3476     section = MSI_RecordGetString(row,4);
3477     key = MSI_RecordGetString(row,5);
3478     value = MSI_RecordGetString(row,6);
3479     action = MSI_RecordGetInteger(row,7);
3480 
3481     deformat_string(package,section,&deformated_section);
3482     deformat_string(package,key,&deformated_key);
3483     deformat_string(package,value,&deformated_value);
3484 
3485     filename = msi_dup_record_field(row, 2);
3486     if (filename && (filenameptr = strchrW(filename, '|')))
3487         filenameptr++;
3488     else
3489         filenameptr = filename;
3490 
3491     if (dirproperty)
3492     {
3493         folder = resolve_folder(package, dirproperty, FALSE, FALSE, TRUE, NULL);
3494         if (!folder)
3495             folder = msi_dup_property( package, dirproperty );
3496     }
3497     else
3498         folder = msi_dup_property( package, szWindowsFolder );
3499 
3500     if (!folder)
3501     {
3502         ERR("Unable to resolve folder! (%s)\n",debugstr_w(dirproperty));
3503         goto cleanup;
3504     }
3505 
3506     fullname = build_directory_name(2, folder, filenameptr);
3507 
3508     if (action == 0)
3509     {
3510         TRACE("Adding value %s to section %s in %s\n",
3511                 debugstr_w(deformated_key), debugstr_w(deformated_section),
3512                 debugstr_w(fullname));
3513         WritePrivateProfileStringW(deformated_section, deformated_key,
3514                                    deformated_value, fullname);
3515     }
3516     else if (action == 1)
3517     {
3518         WCHAR returned[10];
3519         GetPrivateProfileStringW(deformated_section, deformated_key, NULL,
3520                                  returned, 10, fullname);
3521         if (returned[0] == 0)
3522         {
3523             TRACE("Adding value %s to section %s in %s\n",
3524                     debugstr_w(deformated_key), debugstr_w(deformated_section),
3525                     debugstr_w(fullname));
3526 
3527             WritePrivateProfileStringW(deformated_section, deformated_key,
3528                                        deformated_value, fullname);
3529         }
3530     }
3531     else if (action == 3)
3532         FIXME("Append to existing section not yet implemented\n");
3533 
3534     uirow = MSI_CreateRecord(4);
3535     MSI_RecordSetStringW(uirow,1,identifier);
3536     MSI_RecordSetStringW(uirow,2,deformated_section);
3537     MSI_RecordSetStringW(uirow,3,deformated_key);
3538     MSI_RecordSetStringW(uirow,4,deformated_value);
3539     ui_actiondata(package,szWriteIniValues,uirow);
3540     msiobj_release( &uirow->hdr );
3541 
3542 cleanup:
3543     msi_free(filename);
3544     msi_free(fullname);
3545     msi_free(folder);
3546     msi_free(deformated_key);
3547     msi_free(deformated_value);
3548     msi_free(deformated_section);
3549     return ERROR_SUCCESS;
3550 }
3551 
3552 static UINT ACTION_WriteIniValues(MSIPACKAGE *package)
3553 {
3554     UINT rc;
3555     MSIQUERY * view;
3556     static const WCHAR ExecSeqQuery[] = 
3557         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3558          '`','I','n','i','F','i','l','e','`',0};
3559 
3560     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3561     if (rc != ERROR_SUCCESS)
3562     {
3563         TRACE("no IniFile table\n");
3564         return ERROR_SUCCESS;
3565     }
3566 
3567     rc = MSI_IterateRecords(view, NULL, ITERATE_WriteIniValues, package);
3568     msiobj_release(&view->hdr);
3569     return rc;
3570 }
3571 
3572 static UINT ITERATE_SelfRegModules(MSIRECORD *row, LPVOID param)
3573 {
3574     MSIPACKAGE *package = param;
3575     LPCWSTR filename;
3576     LPWSTR FullName;
3577     MSIFILE *file;
3578     DWORD len;
3579     static const WCHAR ExeStr[] =
3580         {'r','e','g','s','v','r','3','2','.','e','x','e',' ','\"',0};
3581     static const WCHAR close[] =  {'\"',0};
3582     STARTUPINFOW si;
3583     PROCESS_INFORMATION info;
3584     BOOL brc;
3585     MSIRECORD *uirow;
3586     LPWSTR uipath, p;
3587 
3588     memset(&si,0,sizeof(STARTUPINFOW));
3589 
3590     filename = MSI_RecordGetString(row,1);
3591     file = get_loaded_file( package, filename );
3592 
3593     if (!file)
3594     {
3595         ERR("Unable to find file id %s\n",debugstr_w(filename));
3596         return ERROR_SUCCESS;
3597     }
3598 
3599     len = strlenW(ExeStr) + strlenW( file->TargetPath ) + 2;
3600 
3601     FullName = msi_alloc(len*sizeof(WCHAR));
3602     strcpyW(FullName,ExeStr);
3603     strcatW( FullName, file->TargetPath );
3604     strcatW(FullName,close);
3605 
3606     TRACE("Registering %s\n",debugstr_w(FullName));
3607     brc = CreateProcessW(NULL, FullName, NULL, NULL, FALSE, 0, NULL, c_colon,
3608                     &si, &info);
3609 
3610     if (brc)
3611     {
3612         CloseHandle(info.hThread);
3613         msi_dialog_check_messages(info.hProcess);
3614         CloseHandle(info.hProcess);
3615     }
3616 
3617     msi_free(FullName);
3618 
3619     /* the UI chunk */
3620     uirow = MSI_CreateRecord( 2 );
3621     uipath = strdupW( file->TargetPath );
3622     p = strrchrW(uipath,'\\');
3623     if (p)
3624         p[0]=0;
3625     MSI_RecordSetStringW( uirow, 1, &p[1] );
3626     MSI_RecordSetStringW( uirow, 2, uipath);
3627     ui_actiondata( package, szSelfRegModules, uirow);
3628     msiobj_release( &uirow->hdr );
3629     msi_free( uipath );
3630     /* FIXME: call ui_progress? */
3631 
3632     return ERROR_SUCCESS;
3633 }
3634 
3635 static UINT ACTION_SelfRegModules(MSIPACKAGE *package)
3636 {
3637     UINT rc;
3638     MSIQUERY * view;
3639     static const WCHAR ExecSeqQuery[] = 
3640         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
3641          '`','S','e','l','f','R','e','g','`',0};
3642 
3643     rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view);
3644     if (rc != ERROR_SUCCESS)
3645     {
3646         TRACE("no SelfReg table\n");
3647         return ERROR_SUCCESS;
3648     }
3649 
3650     MSI_IterateRecords(view, NULL, ITERATE_SelfRegModules, package);
3651     msiobj_release(&view->hdr);
3652 
3653     return ERROR_SUCCESS;
3654 }
3655 
3656 static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
3657 {
3658     MSIFEATURE *feature;
3659     UINT rc;
3660     HKEY hkey;
3661     HKEY userdata = NULL;
3662 
3663     if (!msi_check_publish(package))
3664         return ERROR_SUCCESS;
3665 
3666     rc = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
3667                                 &hkey, TRUE);
3668     if (rc != ERROR_SUCCESS)
3669         goto end;
3670 
3671     rc = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
3672                                         &userdata, TRUE);
3673     if (rc != ERROR_SUCCESS)
3674         goto end;
3675 
3676     /* here the guids are base 85 encoded */
3677     LIST_FOR_EACH_ENTRY( feature, &package->features, MSIFEATURE, entry )
3678     {
3679         ComponentList *cl;
3680         LPWSTR data = NULL;
3681         GUID clsid;
3682         INT size;
3683         BOOL absent = FALSE;
3684         MSIRECORD *uirow;
3685 
3686         if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
3687             !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_SOURCE ) &&
3688             !ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
3689             absent = TRUE;
3690 
3691         size = 1;
3692         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3693         {
3694             size += 21;
3695         }
3696         if (feature->Feature_Parent)
3697             size += strlenW( feature->Feature_Parent )+2;
3698 
3699         data = msi_alloc(size * sizeof(WCHAR));
3700 
3701         data[0] = 0;
3702         LIST_FOR_EACH_ENTRY( cl, &feature->Components, ComponentList, entry )
3703         {
3704             MSICOMPONENT* component = cl->component;
3705             WCHAR buf[21];
3706 
3707             buf[0] = 0;
3708             if (component->ComponentId)
3709             {
3710                 TRACE("From %s\n",debugstr_w(component->ComponentId));
3711                 CLSIDFromString(component->ComponentId, &clsid);
3712                 encode_base85_guid(&clsid,buf);
3713                 TRACE("to %s\n",debugstr_w(buf));
3714                 strcatW(data,buf);
3715             }
3716         }
3717 
3718         if (feature->Feature_Parent)
3719         {
3720             static const WCHAR sep[] = {'\2',0};
3721             strcatW(data,sep);
3722             strcatW(data,feature->Feature_Parent);
3723         }
3724 
3725         msi_reg_set_val_str( userdata, feature->Feature, data );
3726         msi_free(data);
3727 
3728         size = 0;
3729         if (feature->Feature_Parent)
3730             size = strlenW(feature->Feature_Parent)*sizeof(WCHAR);
3731         if (!absent)
3732         {
3733             size += sizeof(WCHAR);
3734             RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
3735                            (LPBYTE)(feature->Feature_Parent ? feature->Feature_Parent : szEmpty),size);
3736         }
3737         else
3738         {
3739             size += 2*sizeof(WCHAR);
3740             data = msi_alloc(size);
3741             data[0] = 0x6;
3742             data[1] = 0;
3743             if (feature->Feature_Parent)
3744                 strcpyW( &data[1], feature->Feature_Parent );
3745             RegSetValueExW(hkey,feature->Feature,0,REG_SZ,
3746                        (LPBYTE)data,size);
3747             msi_free(data);
3748         }
3749 
3750         /* the UI chunk */
3751         uirow = MSI_CreateRecord( 1 );
3752         MSI_RecordSetStringW( uirow, 1, feature->Feature );
3753         ui_actiondata( package, szPublishFeatures, uirow);
3754         msiobj_release( &uirow->hdr );
3755         /* FIXME: call ui_progress? */
3756     }
3757 
3758 end:
3759     RegCloseKey(hkey);
3760     RegCloseKey(userdata);
3761     return rc;
3762 }
3763 
3764 static UINT msi_unpublish_feature(MSIPACKAGE *package, MSIFEATURE *feature)
3765 {
3766     UINT r;
3767     HKEY hkey;
3768 
3769     TRACE("unpublishing feature %s\n", debugstr_w(feature->Feature));
3770 
3771     r = MSIREG_OpenFeaturesKey(package->ProductCode, package->Context,
3772                                &hkey, FALSE);
3773     if (r == ERROR_SUCCESS)
3774     {
3775         RegDeleteValueW(hkey, feature->Feature);
3776         RegCloseKey(hkey);
3777     }
3778 
3779     r = MSIREG_OpenUserDataFeaturesKey(package->ProductCode, package->Context,
3780                                        &hkey, FALSE);
3781     if (r == ERROR_SUCCESS)
3782     {
3783         RegDeleteValueW(hkey, feature->Feature);
3784         RegCloseKey(hkey);
3785     }
3786 
3787     return ERROR_SUCCESS;
3788 }
3789 
3790 static UINT ACTION_UnpublishFeatures(MSIPACKAGE *package)
3791 {
3792     MSIFEATURE *feature;
3793 
3794     if (!msi_check_unpublish(package))
3795         return ERROR_SUCCESS;
3796 
3797     LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3798     {
3799         msi_unpublish_feature(package, feature);
3800     }
3801 
3802     return ERROR_SUCCESS;
3803 }
3804 
3805 static UINT msi_publish_install_properties(MSIPACKAGE *package, HKEY hkey)
3806 {
3807     LPWSTR prop, val, key;
3808     SYSTEMTIME systime;
3809     DWORD size, langid;
3810     WCHAR date[9];
3811     LPWSTR buffer;
3812 
3813     static const WCHAR date_fmt[] = {'%','i','%','','2','i','%','','2','i',0};
3814     static const WCHAR szWindowsInstaller[] =
3815         {'W','i','n','d','o','w','s','I','n','s','t','a','l','l','e','r',0};
3816     static const WCHAR modpath_fmt[] =
3817         {'M','s','i','E','x','e','c','.','e','x','e',' ',
3818          '/','I','[','P','r','o','d','u','c','t','C','o','d','e',']',0};
3819     static const WCHAR szModifyPath[] =
3820         {'M','o','d','i','f','y','P','a','t','h',0};
3821     static const WCHAR szUninstallString[] =
3822         {'U','n','i','n','s','t','a','l','l','S','t','r','i','n','g',0};
3823     static const WCHAR szEstimatedSize[] =
3824         {'E','s','t','i','m','a','t','e','d','S','i','z','e',0};
3825     static const WCHAR szProductLanguage[] =
3826         {'P','r','o','d','u','c','t','L','a','n','g','u','a','g','e',0};
3827     static const WCHAR szProductVersion[] =
3828         {'P','r','o','d','u','c','t','V','e','r','s','i','o','n',0};
3829     static const WCHAR szProductName[] =
3830         {'P','r','o','d','u','c','t','N','a','m','e',0};
3831     static const WCHAR szDisplayName[] =
3832         {'D','i','s','p','l','a','y','N','a','m','e',0};
3833     static const WCHAR szDisplayVersion[] =
3834         {'D','i','s','p','l','a','y','V','e','r','s','i','o','n',0};
3835     static const WCHAR szManufacturer[] =
3836         {'M','a','n','u','f','a','c','t','u','r','e','r',0};
3837 
3838     static const LPCSTR propval[] = {
3839         "ARPAUTHORIZEDCDFPREFIX", "AuthorizedCDFPrefix",
3840         "ARPCONTACT",             "Contact",
3841         "ARPCOMMENTS",            "Comments",
3842         "ProductName",            "DisplayName",
3843         "ProductVersion",         "DisplayVersion",
3844         "ARPHELPLINK",            "HelpLink",
3845         "ARPHELPTELEPHONE",       "HelpTelephone",
3846         "ARPINSTALLLOCATION",     "InstallLocation",
3847         "SourceDir",              "InstallSource",
3848         "Manufacturer",           "Publisher",
3849         "ARPREADME",              "Readme",
3850         "ARPSIZE",                "Size",
3851         "ARPURLINFOABOUT",        "URLInfoAbout",
3852         "ARPURLUPDATEINFO",       "URLUpdateInfo",
3853         NULL,
3854     };
3855     const LPCSTR *p = propval;
3856 
3857     while (*p)
3858     {
3859         prop = strdupAtoW(*p++);
3860         key = strdupAtoW(*p++);
3861         val = msi_dup_property(package, prop);
3862         msi_reg_set_val_str(hkey, key, val);
3863         msi_free(val);
3864         msi_free(key);
3865         msi_free(prop);
3866     }
3867 
3868     msi_reg_set_val_dword(hkey, szWindowsInstaller, 1);
3869 
3870     size = deformat_string(package, modpath_fmt, &buffer);
3871     RegSetValueExW(hkey, szModifyPath, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
3872     RegSetValueExW(hkey, szUninstallString, 0, REG_EXPAND_SZ, (LPBYTE)buffer, size);
3873     msi_free(buffer);
3874 
3875     /* FIXME: Write real Estimated Size when we have it */
3876     msi_reg_set_val_dword(hkey, szEstimatedSize, 0);
3877 
3878     buffer = msi_dup_property(package, szProductName);
3879     msi_reg_set_val_str(hkey, szDisplayName, buffer);
3880     msi_free(buffer);
3881 
3882     buffer = msi_dup_property(package, cszSourceDir);
3883     msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLSOURCEW, buffer);
3884     msi_free(buffer);
3885 
3886     buffer = msi_dup_property(package, szManufacturer);
3887     msi_reg_set_val_str(hkey, INSTALLPROPERTY_PUBLISHERW, buffer);
3888     msi_free(buffer);
3889 
3890     GetLocalTime(&systime);
3891     sprintfW(date, date_fmt, systime.wYear, systime.wMonth, systime.wDay);
3892     msi_reg_set_val_str(hkey, INSTALLPROPERTY_INSTALLDATEW, date);
3893 
3894     langid = msi_get_property_int(package, szProductLanguage, 0);
3895     msi_reg_set_val_dword(hkey, INSTALLPROPERTY_LANGUAGEW, langid);
3896 
3897     buffer = msi_dup_property(package, szProductVersion);
3898     msi_reg_set_val_str(hkey, szDisplayVersion, buffer);
3899     if (buffer)
3900     {
3901         DWORD verdword = msi_version_str_to_dword(buffer);
3902 
3903         msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONW, verdword);
3904         msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMAJORW, verdword >> 24);
3905         msi_reg_set_val_dword(hkey, INSTALLPROPERTY_VERSIONMINORW, (verdword >> 16) & 0xFF);
3906         msi_free(buffer);
3907     }
3908 
3909     return ERROR_SUCCESS;
3910 }
3911 
3912 static UINT ACTION_RegisterProduct(MSIPACKAGE *package)
3913 {
3914     WCHAR squashed_pc[SQUISH_GUID_SIZE];
3915     LPWSTR upgrade_code;
3916     HKEY hkey, props;
3917     HKEY upgrade;
3918     UINT rc;
3919 
3920     static const WCHAR szUpgradeCode[] = {
3921         'U','p','g','r','a','d','e','C','o','d','e',0};
3922 
3923     /* FIXME: also need to publish if the product is in advertise mode */
3924     if (!msi_check_publish(package))
3925         return ERROR_SUCCESS;
3926 
3927     rc = MSIREG_OpenUninstallKey(package->ProductCode, &hkey, TRUE);
3928     if (rc != ERROR_SUCCESS)
3929         return rc;
3930 
3931     rc = MSIREG_OpenInstallProps(package->ProductCode, package->Context,
3932                                  NULL, &props, TRUE);
3933     if (rc != ERROR_SUCCESS)
3934         goto done;
3935 
3936     msi_reg_set_val_str( props, INSTALLPROPERTY_LOCALPACKAGEW, package->db->localfile );
3937     msi_free( package->db->localfile );
3938     package->db->localfile = NULL;
3939 
3940     rc = msi_publish_install_properties(package, hkey);
3941     if (rc != ERROR_SUCCESS)
3942         goto done;
3943 
3944     rc = msi_publish_install_properties(package, props);
3945     if (rc != ERROR_SUCCESS)
3946         goto done;
3947 
3948     upgrade_code = msi_dup_property(package, szUpgradeCode);
3949     if (upgrade_code)
3950     {
3951         MSIREG_OpenUpgradeCodesKey(upgrade_code, &upgrade, TRUE);
3952         squash_guid(package->ProductCode, squashed_pc);
3953         msi_reg_set_val_str(upgrade, squashed_pc, NULL);
3954         RegCloseKey(upgrade);
3955         msi_free(upgrade_code);
3956     }
3957 
3958 done:
3959     RegCloseKey(hkey);
3960 
3961     return ERROR_SUCCESS;
3962 }
3963 
3964 static UINT ACTION_InstallExecute(MSIPACKAGE *package)
3965 {
3966     return execute_script(package,INSTALL_SCRIPT);
3967 }
3968 
3969 static UINT msi_unpublish_product(MSIPACKAGE *package)
3970 {
3971     LPWSTR upgrade;
3972     LPWSTR remove = NULL;
3973     LPWSTR *features = NULL;
3974     BOOL full_uninstall = TRUE;
3975     MSIFEATURE *feature;
3976 
3977     static const WCHAR szUpgradeCode[] =
3978         {'U','p','g','r','a','d','e','C','o','d','e',0};
3979 
3980     remove = msi_dup_property(package, szRemove);
3981     if (!remove)
3982         return ERROR_SUCCESS;
3983 
3984     features = msi_split_string(remove, ',');
3985     if (!features)
3986     {
3987         msi_free(remove);
3988         ERR("REMOVE feature list is empty!\n");
3989         return ERROR_FUNCTION_FAILED;
3990     }
3991 
3992     if (!lstrcmpW(features[0], szAll))
3993         full_uninstall = TRUE;
3994     else
3995     {
3996         LIST_FOR_EACH_ENTRY(feature, &package->features, MSIFEATURE, entry)
3997         {
3998             if (feature->Action != INSTALLSTATE_ABSENT)
3999                 full_uninstall = FALSE;
4000         }
4001     }
4002 
4003     if (!full_uninstall)
4004         goto done;
4005 
4006     MSIREG_DeleteProductKey(package->ProductCode);
4007     MSIREG_DeleteUserDataProductKey(package->ProductCode);
4008     MSIREG_DeleteUninstallKey(package->ProductCode);
4009 
4010     if (package->Context == MSIINSTALLCONTEXT_MACHINE)
4011     {
4012         MSIREG_DeleteLocalClassesProductKey(package->ProductCode);
4013         MSIREG_DeleteLocalClassesFeaturesKey(package->ProductCode);
4014     }
4015     else
4016     {
4017         MSIREG_DeleteUserProductKey(package->ProductCode);
4018         MSIREG_DeleteUserFeaturesKey(package->ProductCode);
4019     }
4020 
4021