urlmon: Cast-qual warnings fix.
[wine] / dlls / msi / package.c
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2004 Aric Stewart for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define NONAMELESSUNION
22 #define NONAMELESSSTRUCT
23
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "winnls.h"
30 #include "shlwapi.h"
31 #include "wingdi.h"
32 #include "wine/debug.h"
33 #include "msi.h"
34 #include "msiquery.h"
35 #include "objidl.h"
36 #include "wincrypt.h"
37 #include "winuser.h"
38 #include "wininet.h"
39 #include "urlmon.h"
40 #include "shlobj.h"
41 #include "wine/unicode.h"
42 #include "objbase.h"
43 #include "msidefs.h"
44
45 #include "msipriv.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(msi);
48
49 static void msi_free_properties( MSIPACKAGE *package );
50
51 static void MSI_FreePackage( MSIOBJECTHDR *arg)
52 {
53     MSIPACKAGE *package= (MSIPACKAGE*) arg;
54
55     if( package->dialog )
56         msi_dialog_destroy( package->dialog );
57
58     msiobj_release( &package->db->hdr );
59     ACTION_free_package_structures(package);
60     msi_free_properties( package );
61 }
62
63 static UINT clone_properties( MSIPACKAGE *package )
64 {
65     MSIQUERY * view = NULL;
66     UINT rc;
67     static const WCHAR Query[] = {
68        'S','E','L','E','C','T',' ','*',' ',
69        'F','R','O','M',' ','`','P','r','o','p','e','r','t','y','`',0};
70
71     /* clone the existing properties */
72     rc = MSI_DatabaseOpenViewW( package->db, Query, &view );
73     if (rc != ERROR_SUCCESS)
74         return rc;
75
76     rc = MSI_ViewExecute(view, 0);
77     if (rc != ERROR_SUCCESS)
78     {
79         MSI_ViewClose(view);
80         msiobj_release(&view->hdr);
81         return rc;
82     }
83     while (1)
84     {
85         MSIRECORD * row;
86         LPCWSTR name, value;
87
88         rc = MSI_ViewFetch(view,&row);
89         if (rc != ERROR_SUCCESS)
90             break;
91
92         name = MSI_RecordGetString( row, 1 );
93         value = MSI_RecordGetString( row, 2 );
94         MSI_SetPropertyW( package, name, value );
95
96         msiobj_release( &row->hdr );
97     }
98     MSI_ViewClose(view);
99     msiobj_release(&view->hdr);
100
101     return rc;
102 }
103
104 /*
105  * set_installed_prop
106  *
107  * Sets the "Installed" property to indicate that
108  *  the product is installed for the current user.
109  */
110 static UINT set_installed_prop( MSIPACKAGE *package )
111 {
112     static const WCHAR szInstalled[] = {
113         'I','n','s','t','a','l','l','e','d',0 };
114     WCHAR val[2] = { '1', 0 };
115     HKEY hkey = 0;
116     UINT r;
117
118     r = MSIREG_OpenUninstallKey( package->ProductCode, &hkey, FALSE );
119     if (r == ERROR_SUCCESS)
120     {
121         RegCloseKey( hkey );
122         MSI_SetPropertyW( package, szInstalled, val );
123     }
124
125     return r;
126 }
127
128 /*
129  * There are a whole slew of these we need to set
130  *
131  *
132 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/properties.asp
133  */
134 static VOID set_installer_properties(MSIPACKAGE *package)
135 {
136     WCHAR pth[MAX_PATH];
137     WCHAR *ptr;
138     OSVERSIONINFOA OSVersion;
139     MEMORYSTATUSEX msex;
140     DWORD verval;
141     WCHAR verstr[10], bufstr[20];
142     HDC dc;
143     LPWSTR check;
144     HKEY hkey;
145     LONG res;
146
147     static const WCHAR cszbs[]={'\\',0};
148     static const WCHAR CFF[] = 
149 {'C','o','m','m','o','n','F','i','l','e','s','F','o','l','d','e','r',0};
150     static const WCHAR PFF[] = 
151 {'P','r','o','g','r','a','m','F','i','l','e','s','F','o','l','d','e','r',0};
152     static const WCHAR CADF[] = 
153 {'C','o','m','m','o','n','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
154     static const WCHAR FaF[] = 
155 {'F','a','v','o','r','i','t','e','s','F','o','l','d','e','r',0};
156     static const WCHAR FoF[] = 
157 {'F','o','n','t','s','F','o','l','d','e','r',0};
158     static const WCHAR SendTF[] = 
159 {'S','e','n','d','T','o','F','o','l','d','e','r',0};
160     static const WCHAR SMF[] = 
161 {'S','t','a','r','t','M','e','n','u','F','o','l','d','e','r',0};
162     static const WCHAR StF[] = 
163 {'S','t','a','r','t','u','p','F','o','l','d','e','r',0};
164     static const WCHAR TemplF[] = 
165 {'T','e','m','p','l','a','t','e','F','o','l','d','e','r',0};
166     static const WCHAR DF[] = 
167 {'D','e','s','k','t','o','p','F','o','l','d','e','r',0};
168     static const WCHAR PMF[] = 
169 {'P','r','o','g','r','a','m','M','e','n','u','F','o','l','d','e','r',0};
170     static const WCHAR ATF[] = 
171 {'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0};
172     static const WCHAR ADF[] = 
173 {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
174     static const WCHAR SF[] = 
175 {'S','y','s','t','e','m','F','o','l','d','e','r',0};
176     static const WCHAR SF16[] = 
177 {'S','y','s','t','e','m','1','6','F','o','l','d','e','r',0};
178     static const WCHAR LADF[] = 
179 {'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
180     static const WCHAR MPF[] = 
181 {'M','y','P','i','c','t','u','r','e','s','F','o','l','d','e','r',0};
182     static const WCHAR PF[] = 
183 {'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0};
184     static const WCHAR WF[] = 
185 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
186     static const WCHAR WV[] = 
187 {'W','i','n','d','o','w','s','V','o','l','u','m','e',0};
188     static const WCHAR TF[]=
189 {'T','e','m','p','F','o','l','d','e','r',0};
190     static const WCHAR szAdminUser[] =
191 {'A','d','m','i','n','U','s','e','r',0};
192     static const WCHAR szPriv[] =
193 {'P','r','i','v','i','l','e','g','e','d',0};
194     static const WCHAR szOne[] =
195 {'1',0};
196     static const WCHAR v9x[] = { 'V','e','r','s','i','o','n','9','X',0 };
197     static const WCHAR vNT[] = { 'V','e','r','s','i','o','n','N','T',0 };
198     static const WCHAR szFormat[] = {'%','l','i',0};
199     static const WCHAR szWinBuild[] =
200 {'W','i','n','d','o','w','s','B','u','i','l','d', 0 };
201     static const WCHAR szSPL[] = 
202 {'S','e','r','v','i','c','e','P','a','c','k','L','e','v','e','l',0 };
203     static const WCHAR szSix[] = {'6',0 };
204
205     static const WCHAR szVersionMsi[] = { 'V','e','r','s','i','o','n','M','s','i',0 };
206     static const WCHAR szPhysicalMemory[] = { 'P','h','y','s','i','c','a','l','M','e','m','o','r','y',0 };
207     static const WCHAR szFormat2[] = {'%','l','i','.','%','l','i',0};
208 /* Screen properties */
209     static const WCHAR szScreenX[] = {'S','c','r','e','e','n','X',0};
210     static const WCHAR szScreenY[] = {'S','c','r','e','e','n','Y',0};
211     static const WCHAR szColorBits[] = {'C','o','l','o','r','B','i','t','s',0};
212     static const WCHAR szScreenFormat[] = {'%','d',0};
213     static const WCHAR szIntel[] = { 'I','n','t','e','l',0 };
214     static const WCHAR szAllUsers[] = { 'A','L','L','U','S','E','R','S',0 };
215     static const WCHAR szCurrentVersion[] = {
216         'S','O','F','T','W','A','R','E','\\',
217         'M','i','c','r','o','s','o','f','t','\\',
218         'W','i','n','d','o','w','s',' ','N','T','\\',
219         'C','u','r','r','e','n','t','V','e','r','s','i','o','n',0
220     };
221     static const WCHAR szRegisteredUser[] = {'R','e','g','i','s','t','e','r','e','d','O','w','n','e','r',0};
222     static const WCHAR szRegisteredOrg[] = {
223         'R','e','g','i','s','t','e','r','e','d','O','r','g','a','n','i','z','a','t','i','o','n',0
224     };
225     static const WCHAR szUSERNAME[] = {'U','S','E','R','N','A','M','E',0};
226     static const WCHAR szCOMPANYNAME[] = {'C','O','M','P','A','N','Y','N','A','M','E',0};
227     SYSTEM_INFO sys_info;
228
229     /*
230      * Other things that probably should be set:
231      *
232      * SystemLanguageID ComputerName UserLanguageID LogonUser VirtualMemory
233      * Intel ShellAdvSupport DefaultUIFont VersionDatabase PackagecodeChanging
234      * ProductState CaptionHeight BorderTop BorderSide TextHeight
235      * RedirectedDllSupport Time Date Privileged
236      */
237
238     SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth);
239     strcatW(pth,cszbs);
240     MSI_SetPropertyW(package, CFF, pth);
241
242     SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES,NULL,0,pth);
243     strcatW(pth,cszbs);
244     MSI_SetPropertyW(package, PFF, pth);
245
246     SHGetFolderPathW(NULL,CSIDL_COMMON_APPDATA,NULL,0,pth);
247     strcatW(pth,cszbs);
248     MSI_SetPropertyW(package, CADF, pth);
249
250     SHGetFolderPathW(NULL,CSIDL_FAVORITES,NULL,0,pth);
251     strcatW(pth,cszbs);
252     MSI_SetPropertyW(package, FaF, pth);
253
254     SHGetFolderPathW(NULL,CSIDL_FONTS,NULL,0,pth);
255     strcatW(pth,cszbs);
256     MSI_SetPropertyW(package, FoF, pth);
257
258     SHGetFolderPathW(NULL,CSIDL_SENDTO,NULL,0,pth);
259     strcatW(pth,cszbs);
260     MSI_SetPropertyW(package, SendTF, pth);
261
262     SHGetFolderPathW(NULL,CSIDL_STARTMENU,NULL,0,pth);
263     strcatW(pth,cszbs);
264     MSI_SetPropertyW(package, SMF, pth);
265
266     SHGetFolderPathW(NULL,CSIDL_STARTUP,NULL,0,pth);
267     strcatW(pth,cszbs);
268     MSI_SetPropertyW(package, StF, pth);
269
270     SHGetFolderPathW(NULL,CSIDL_TEMPLATES,NULL,0,pth);
271     strcatW(pth,cszbs);
272     MSI_SetPropertyW(package, TemplF, pth);
273
274     SHGetFolderPathW(NULL,CSIDL_DESKTOP,NULL,0,pth);
275     strcatW(pth,cszbs);
276     MSI_SetPropertyW(package, DF, pth);
277
278     SHGetFolderPathW(NULL,CSIDL_PROGRAMS,NULL,0,pth);
279     strcatW(pth,cszbs);
280     MSI_SetPropertyW(package, PMF, pth);
281
282     SHGetFolderPathW(NULL,CSIDL_ADMINTOOLS,NULL,0,pth);
283     strcatW(pth,cszbs);
284     MSI_SetPropertyW(package, ATF, pth);
285
286     SHGetFolderPathW(NULL,CSIDL_APPDATA,NULL,0,pth);
287     strcatW(pth,cszbs);
288     MSI_SetPropertyW(package, ADF, pth);
289
290     SHGetFolderPathW(NULL,CSIDL_SYSTEM,NULL,0,pth);
291     strcatW(pth,cszbs);
292     MSI_SetPropertyW(package, SF, pth);
293     MSI_SetPropertyW(package, SF16, pth);
294
295     SHGetFolderPathW(NULL,CSIDL_LOCAL_APPDATA,NULL,0,pth);
296     strcatW(pth,cszbs);
297     MSI_SetPropertyW(package, LADF, pth);
298
299     SHGetFolderPathW(NULL,CSIDL_MYPICTURES,NULL,0,pth);
300     strcatW(pth,cszbs);
301     MSI_SetPropertyW(package, MPF, pth);
302
303     SHGetFolderPathW(NULL,CSIDL_PERSONAL,NULL,0,pth);
304     strcatW(pth,cszbs);
305     MSI_SetPropertyW(package, PF, pth);
306
307     SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
308     strcatW(pth,cszbs);
309     MSI_SetPropertyW(package, WF, pth);
310     
311     /* Physical Memory is specified in MB. Using total amount. */
312     msex.dwLength = sizeof(msex);
313     GlobalMemoryStatusEx( &msex );
314     sprintfW( bufstr, szScreenFormat, (int)(msex.ullTotalPhys/1024/1024));
315     MSI_SetPropertyW(package, szPhysicalMemory, bufstr);
316
317     SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
318     ptr = strchrW(pth,'\\');
319     if (ptr)
320         *(ptr+1) = 0;
321     MSI_SetPropertyW(package, WV, pth);
322     
323     GetTempPathW(MAX_PATH,pth);
324     MSI_SetPropertyW(package, TF, pth);
325
326
327     /* in a wine environment the user is always admin and privileged */
328     MSI_SetPropertyW(package,szAdminUser,szOne);
329     MSI_SetPropertyW(package,szPriv,szOne);
330     MSI_SetPropertyW(package, szAllUsers, szOne);
331
332     /* set the os things */
333     OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
334     GetVersionExA(&OSVersion);
335     verval = OSVersion.dwMinorVersion+OSVersion.dwMajorVersion*100;
336     sprintfW(verstr,szFormat,verval);
337     switch (OSVersion.dwPlatformId)
338     {
339         case VER_PLATFORM_WIN32_WINDOWS:    
340             MSI_SetPropertyW(package,v9x,verstr);
341             break;
342         case VER_PLATFORM_WIN32_NT:
343             MSI_SetPropertyW(package,vNT,verstr);
344             break;
345     }
346     sprintfW(verstr,szFormat,OSVersion.dwBuildNumber);
347     MSI_SetPropertyW(package,szWinBuild,verstr);
348     /* just fudge this */
349     MSI_SetPropertyW(package,szSPL,szSix);
350
351     sprintfW( bufstr, szFormat2, MSI_MAJORVERSION, MSI_MINORVERSION);
352     MSI_SetPropertyW( package, szVersionMsi, bufstr );
353
354     GetSystemInfo( &sys_info );
355     if (sys_info.u.s.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
356     {
357         sprintfW( bufstr, szScreenFormat, sys_info.wProcessorLevel );
358         MSI_SetPropertyW( package, szIntel, bufstr );
359     }
360
361     /* Screen properties. */
362     dc = GetDC(0);
363     sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, HORZRES ) );
364     MSI_SetPropertyW( package, szScreenX, bufstr );
365     sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, VERTRES ));
366     MSI_SetPropertyW( package, szScreenY, bufstr );
367     sprintfW( bufstr, szScreenFormat, GetDeviceCaps( dc, BITSPIXEL ));
368     MSI_SetPropertyW( package, szColorBits, bufstr );
369     ReleaseDC(0, dc);
370
371     /* USERNAME and COMPANYNAME */
372     res = RegOpenKeyW( HKEY_LOCAL_MACHINE, szCurrentVersion, &hkey );
373     if (res != ERROR_SUCCESS)
374         return;
375
376     check = msi_dup_property( package, szUSERNAME );
377     if (!check)
378     {
379         LPWSTR user = msi_reg_get_val_str( hkey, szRegisteredUser );
380         MSI_SetPropertyW( package, szUSERNAME, user );
381         msi_free( user );
382     }
383
384     msi_free( check );
385
386     check = msi_dup_property( package, szCOMPANYNAME );
387     if (!check)
388     {
389         LPWSTR company = msi_reg_get_val_str( hkey, szRegisteredOrg );
390         MSI_SetPropertyW( package, szCOMPANYNAME, company );
391         msi_free( company );
392     }
393
394     msi_free( check );
395     CloseHandle( hkey );
396 }
397
398 static UINT msi_get_word_count( MSIPACKAGE *package )
399 {
400     UINT rc;
401     INT word_count;
402     MSIHANDLE suminfo;
403     MSIHANDLE hdb = alloc_msihandle( &package->db->hdr );
404
405     if (!hdb) {
406         ERR("Unable to allocate handle\n");
407         return 0;
408     }
409     rc = MsiGetSummaryInformationW( hdb, NULL, 0, &suminfo );
410     MsiCloseHandle(hdb);
411     if (rc != ERROR_SUCCESS)
412     {
413         ERR("Unable to open Summary Information\n");
414         return 0;
415     }
416
417     rc = MsiSummaryInfoGetPropertyW( suminfo, PID_WORDCOUNT, NULL,
418                                      &word_count, NULL, NULL, NULL );
419     if (rc != ERROR_SUCCESS)
420     {
421         ERR("Unable to query word count\n");
422         MsiCloseHandle(suminfo);
423         return 0;
424     }
425
426     MsiCloseHandle(suminfo);
427     return word_count;
428 }
429
430 static MSIPACKAGE *msi_alloc_package( void )
431 {
432     MSIPACKAGE *package;
433     int i;
434
435     package = alloc_msiobject( MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE),
436                                MSI_FreePackage );
437     if( package )
438     {
439         list_init( &package->components );
440         list_init( &package->features );
441         list_init( &package->files );
442         list_init( &package->tempfiles );
443         list_init( &package->folders );
444         list_init( &package->subscriptions );
445         list_init( &package->appids );
446         list_init( &package->classes );
447         list_init( &package->mimes );
448         list_init( &package->extensions );
449         list_init( &package->progids );
450         list_init( &package->RunningActions );
451
452         for (i=0; i<PROPERTY_HASH_SIZE; i++)
453             list_init( &package->props[i] );
454
455         package->ActionFormat = NULL;
456         package->LastAction = NULL;
457         package->dialog = NULL;
458         package->next_dialog = NULL;
459     }
460
461     return package;
462 }
463
464 MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db, LPWSTR base_url )
465 {
466     static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 };
467     static const WCHAR szpi[] = {'%','i',0};
468     static const WCHAR szProductCode[] = {
469         'P','r','o','d','u','c','t','C','o','d','e',0};
470     MSIPACKAGE *package;
471     WCHAR uilevel[10];
472
473     TRACE("%p\n", db);
474
475     package = msi_alloc_package();
476     if (package)
477     {
478         msiobj_addref( &db->hdr );
479         package->db = db;
480
481         package->WordCount = msi_get_word_count( package );
482         package->PackagePath = strdupW( db->path );
483         package->BaseURL = strdupW( base_url );
484
485         clone_properties( package );
486         set_installer_properties(package);
487         sprintfW(uilevel,szpi,gUILevel);
488         MSI_SetPropertyW(package, szLevel, uilevel);
489
490         package->ProductCode = msi_dup_property( package, szProductCode );
491         set_installed_prop( package );
492     }
493
494     return package;
495 }
496
497 /*
498  * copy_package_to_temp   [internal]
499  *
500  * copy the msi file to a temp file to prevent locking a CD
501  * with a multi disc install 
502  *
503  * FIXME: I think this is wrong, and instead of copying the package,
504  *        we should read all the tables to memory, then open the
505  *        database to read binary streams on demand.
506  */ 
507 static LPCWSTR copy_package_to_temp( LPCWSTR szPackage, LPWSTR filename )
508 {
509     WCHAR path[MAX_PATH];
510     static const WCHAR szMSI[] = {'m','s','i',0};
511
512     GetTempPathW( MAX_PATH, path );
513     GetTempFileNameW( path, szMSI, 0, filename );
514
515     if( !CopyFileW( szPackage, filename, FALSE ) )
516     {
517         DeleteFileW( filename );
518         ERR("failed to copy package %s\n", debugstr_w(szPackage) );
519         return szPackage;
520     }
521
522     TRACE("Opening relocated package %s\n", debugstr_w( filename ));
523     return filename;
524 }
525
526 LPCWSTR msi_download_file( LPCWSTR szUrl, LPWSTR filename )
527 {
528     LPINTERNET_CACHE_ENTRY_INFOW cache_entry;
529     DWORD size = 0;
530     HRESULT hr;
531
532     /* call will always fail, becase size is 0,
533      * but will return ERROR_FILE_NOT_FOUND first
534      * if the file doesn't exist
535      */
536     GetUrlCacheEntryInfoW( szUrl, NULL, &size );
537     if ( GetLastError() != ERROR_FILE_NOT_FOUND )
538     {
539         cache_entry = HeapAlloc( GetProcessHeap(), 0, size );
540         if ( !GetUrlCacheEntryInfoW( szUrl, cache_entry, &size ) )
541         {
542             HeapFree( GetProcessHeap(), 0, cache_entry );
543             return szUrl;
544         }
545
546         lstrcpyW( filename, cache_entry->lpszLocalFileName );
547         HeapFree( GetProcessHeap(), 0, cache_entry );
548         return filename;
549     }
550
551     hr = URLDownloadToCacheFileW( NULL, szUrl, filename, MAX_PATH, 0, NULL );
552     if ( FAILED(hr) )
553         return szUrl;
554
555     return filename;
556 }
557
558 UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
559 {
560     static const WCHAR OriginalDatabase[] =
561         {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
562     static const WCHAR Database[] = {'D','A','T','A','B','A','S','E',0};
563     MSIDATABASE *db = NULL;
564     MSIPACKAGE *package;
565     MSIHANDLE handle;
566     LPWSTR ptr, base_url = NULL;
567     UINT r;
568     WCHAR temppath[MAX_PATH];
569     LPCWSTR file = szPackage;
570
571     TRACE("%s %p\n", debugstr_w(szPackage), pPackage);
572
573     if( szPackage[0] == '#' )
574     {
575         handle = atoiW(&szPackage[1]);
576         db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
577         if( !db )
578             return ERROR_INVALID_HANDLE;
579     }
580     else
581     {
582         if ( UrlIsW( szPackage, URLIS_URL ) )
583         {
584             file = msi_download_file( szPackage, temppath );
585
586             base_url = strdupW( szPackage );
587             if ( !base_url )
588                 return ERROR_OUTOFMEMORY;
589
590             ptr = strrchrW( base_url, '/' );
591             if (ptr) *(ptr + 1) = '\0';
592         }
593         else
594             file = copy_package_to_temp( szPackage, temppath );
595
596         r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &db );
597         if( r != ERROR_SUCCESS )
598         {
599             if (GetLastError() == ERROR_FILE_NOT_FOUND)
600                 msi_ui_error( 4, MB_OK | MB_ICONWARNING );
601             if (file != szPackage)
602                 DeleteFileW( file );
603
604             return r;
605         }
606     }
607
608     package = MSI_CreatePackage( db, base_url );
609     msi_free( base_url );
610     msiobj_release( &db->hdr );
611     if( !package )
612     {
613         if (file != szPackage)
614             DeleteFileW( file );
615         return ERROR_FUNCTION_FAILED;
616     }
617
618     if( file != szPackage )
619         track_tempfile( package, file );
620
621     if( szPackage[0] != '#' )
622     {
623         MSI_SetPropertyW( package, OriginalDatabase, szPackage );
624         MSI_SetPropertyW( package, Database, szPackage );
625     }
626     else
627     {
628         MSI_SetPropertyW( package, OriginalDatabase, db->path );
629         MSI_SetPropertyW( package, Database, db->path );
630     }
631
632     *pPackage = package;
633
634     return ERROR_SUCCESS;
635 }
636
637 UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
638 {
639     MSIPACKAGE *package = NULL;
640     UINT ret;
641
642     TRACE("%s %08x %p\n", debugstr_w(szPackage), dwOptions, phPackage );
643
644     if( szPackage == NULL )
645         return ERROR_INVALID_PARAMETER;
646
647     if( dwOptions )
648         FIXME("dwOptions %08x not supported\n", dwOptions);
649
650     ret = MSI_OpenPackageW( szPackage, &package );
651     if( ret == ERROR_SUCCESS )
652     {
653         *phPackage = alloc_msihandle( &package->hdr );
654         if (! *phPackage)
655             ret = ERROR_NOT_ENOUGH_MEMORY;
656         msiobj_release( &package->hdr );
657     }
658
659     return ret;
660 }
661
662 UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
663 {
664     return MsiOpenPackageExW( szPackage, 0, phPackage );
665 }
666
667 UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
668 {
669     LPWSTR szwPack = NULL;
670     UINT ret;
671
672     if( szPackage )
673     {
674         szwPack = strdupAtoW( szPackage );
675         if( !szwPack )
676             return ERROR_OUTOFMEMORY;
677     }
678
679     ret = MsiOpenPackageExW( szwPack, dwOptions, phPackage );
680
681     msi_free( szwPack );
682
683     return ret;
684 }
685
686 UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
687 {
688     return MsiOpenPackageExA( szPackage, 0, phPackage );
689 }
690
691 MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
692 {
693     MSIPACKAGE *package;
694     MSIHANDLE handle = 0;
695
696     TRACE("(%ld)\n",hInstall);
697
698     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
699     if( package)
700     {
701         handle = alloc_msihandle( &package->db->hdr );
702         msiobj_release( &package->hdr );
703     }
704
705     return handle;
706 }
707
708 INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
709                                MSIRECORD *record)
710 {
711     static const WCHAR szActionData[] =
712         {'A','c','t','i','o','n','D','a','t','a',0};
713     static const WCHAR szSetProgress[] =
714         {'S','e','t','P','r','o','g','r','e','s','s',0};
715     static const WCHAR szActionText[] =
716         {'A','c','t','i','o','n','T','e','x','t',0};
717     DWORD log_type = 0;
718     LPWSTR message;
719     DWORD sz;
720     DWORD total_size = 0;
721     INT i;
722     INT rc;
723     char *msg;
724     int len;
725
726     TRACE("%x\n", eMessageType);
727     rc = 0;
728
729     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR)
730         log_type |= INSTALLLOGMODE_ERROR;
731     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_WARNING)
732         log_type |= INSTALLLOGMODE_WARNING;
733     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_USER)
734         log_type |= INSTALLLOGMODE_USER;
735     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INFO)
736         log_type |= INSTALLLOGMODE_INFO;
737     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA)
738         log_type |= INSTALLLOGMODE_COMMONDATA;
739     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
740         log_type |= INSTALLLOGMODE_ACTIONSTART;
741     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONDATA)
742         log_type |= INSTALLLOGMODE_ACTIONDATA;
743     /* just a guess */
744     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS)
745         log_type |= 0x800;
746
747     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
748     {
749         static const WCHAR template_s[]=
750             {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ',0};
751         static const WCHAR format[] = 
752             {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
753         WCHAR timet[0x100];
754         LPCWSTR action_text, action;
755         LPWSTR deformatted = NULL;
756
757         GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
758
759         action = MSI_RecordGetString(record, 1);
760         action_text = MSI_RecordGetString(record, 2);
761
762         if (!action || !action_text)
763             return IDOK;
764
765         deformat_string(package, action_text, &deformatted);
766
767         len = strlenW(timet) + strlenW(action) + strlenW(template_s);
768         if (deformatted)
769             len += strlenW(deformatted);
770         message = msi_alloc(len*sizeof(WCHAR));
771         sprintfW(message, template_s, timet, action);
772         if (deformatted)
773             strcatW(message, deformatted);
774         msi_free(deformatted);
775     }
776     else
777     {
778         INT msg_field=1;
779         message = msi_alloc(1*sizeof (WCHAR));
780         message[0]=0;
781         msg_field = MSI_RecordGetFieldCount(record);
782         for (i = 1; i <= msg_field; i++)
783         {
784             LPWSTR tmp;
785             WCHAR number[3];
786             static const WCHAR format[] = { '%','i',':',' ',0};
787             static const WCHAR space[] = { ' ',0};
788             sz = 0;
789             MSI_RecordGetStringW(record,i,NULL,&sz);
790             sz+=4;
791             total_size+=sz*sizeof(WCHAR);
792             tmp = msi_alloc(sz*sizeof(WCHAR));
793             message = msi_realloc(message,total_size*sizeof (WCHAR));
794
795             MSI_RecordGetStringW(record,i,tmp,&sz);
796
797             if (msg_field > 1)
798             {
799                 sprintfW(number,format,i);
800                 strcatW(message,number);
801             }
802             strcatW(message,tmp);
803             if (msg_field > 1)
804                 strcatW(message,space);
805
806             msi_free(tmp);
807         }
808     }
809
810     TRACE("(%p %x %x %s)\n", gUIHandlerA, gUIFilter, log_type,
811                              debugstr_w(message));
812
813     /* convert it to ASCII */
814     len = WideCharToMultiByte( CP_ACP, 0, message, -1,
815                                NULL, 0, NULL, NULL );
816     msg = msi_alloc( len );
817     WideCharToMultiByte( CP_ACP, 0, message, -1,
818                          msg, len, NULL, NULL );
819
820     if (gUIHandlerA && (gUIFilter & log_type))
821     {
822         rc = gUIHandlerA(gUIContext,eMessageType,msg);
823     }
824
825     if ((!rc) && (gszLogFile[0]) && !((eMessageType & 0xff000000) ==
826                                       INSTALLMESSAGE_PROGRESS))
827     {
828         DWORD write;
829         HANDLE log_file = CreateFileW(gszLogFile,GENERIC_WRITE, 0, NULL,
830                                   OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
831
832         if (log_file != INVALID_HANDLE_VALUE)
833         {
834             SetFilePointer(log_file,0, NULL, FILE_END);
835             WriteFile(log_file,msg,strlen(msg),&write,NULL);
836             WriteFile(log_file,"\n",1,&write,NULL);
837             CloseHandle(log_file);
838         }
839     }
840     msi_free( msg );
841
842     msi_free( message);
843
844     switch (eMessageType & 0xff000000)
845     {
846     case INSTALLMESSAGE_ACTIONDATA:
847         /* FIXME: format record here instead of in ui_actiondata to get the
848          * correct action data for external scripts */
849         ControlEvent_FireSubscribedEvent(package, szActionData, record);
850         break;
851     case INSTALLMESSAGE_ACTIONSTART:
852     {
853         MSIRECORD *uirow;
854         LPWSTR deformated;
855         LPCWSTR action_text = MSI_RecordGetString(record, 2);
856
857         deformat_string(package, action_text, &deformated);
858         uirow = MSI_CreateRecord(1);
859         MSI_RecordSetStringW(uirow, 1, deformated);
860         TRACE("INSTALLMESSAGE_ACTIONSTART: %s\n", debugstr_w(deformated));
861         msi_free(deformated);
862
863         ControlEvent_FireSubscribedEvent(package, szActionText, uirow);
864
865         msiobj_release(&uirow->hdr);
866         break;
867     }
868     case INSTALLMESSAGE_PROGRESS:
869         ControlEvent_FireSubscribedEvent(package, szSetProgress, record);
870         break;
871     }
872
873     return ERROR_SUCCESS;
874 }
875
876 INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
877                               MSIHANDLE hRecord)
878 {
879     UINT ret = ERROR_INVALID_HANDLE;
880     MSIPACKAGE *package = NULL;
881     MSIRECORD *record = NULL;
882
883     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
884     if( !package )
885         return ERROR_INVALID_HANDLE;
886
887     record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
888     if( !record )
889         goto out;
890
891     ret = MSI_ProcessMessage( package, eMessageType, record );
892
893 out:
894     msiobj_release( &package->hdr );
895     if( record )
896         msiobj_release( &record->hdr );
897
898     return ret;
899 }
900
901 /* property code */
902
903 typedef struct msi_property {
904     struct list entry;
905     LPWSTR key;
906     LPWSTR value;
907 } msi_property;
908
909 static UINT msi_prop_makehash( const WCHAR *str )
910 {
911     UINT hash = 0;
912
913     if (str==NULL)
914         return hash;
915
916     while( *str )
917     {
918         hash ^= *str++;
919         hash *= 53;
920         hash = (hash<<5) | (hash>>27);
921     }
922     return hash % PROPERTY_HASH_SIZE;
923 }
924
925 static msi_property *msi_prop_find( MSIPACKAGE *package, LPCWSTR key )
926 {
927     UINT hash = msi_prop_makehash( key );
928     msi_property *prop;
929
930     LIST_FOR_EACH_ENTRY( prop, &package->props[hash], msi_property, entry )
931         if (!lstrcmpW( prop->key, key ))
932             return prop;
933     return NULL;
934 }
935
936 static msi_property *msi_prop_add( MSIPACKAGE *package, LPCWSTR key )
937 {
938     UINT hash = msi_prop_makehash( key );
939     msi_property *prop;
940
941     prop = msi_alloc( sizeof *prop );
942     if (prop)
943     {
944         prop->key = strdupW( key );
945         prop->value = NULL;
946         list_add_head( &package->props[hash], &prop->entry );
947     }
948     return prop;
949 }
950
951 static void msi_delete_property( msi_property *prop )
952 {
953     list_remove( &prop->entry );
954     msi_free( prop->key );
955     msi_free( prop->value );
956     msi_free( prop );
957 }
958
959 static void msi_free_properties( MSIPACKAGE *package )
960 {
961     int i;
962
963     for ( i=0; i<PROPERTY_HASH_SIZE; i++ )
964     {
965         while ( !list_empty(&package->props[i]) )
966         {
967             msi_property *prop;
968             prop = LIST_ENTRY( list_head( &package->props[i] ),
969                                msi_property, entry );
970             msi_delete_property( prop );
971         }
972     }
973 }
974
975 UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue )
976 {
977     LPWSTR szwName = NULL, szwValue = NULL;
978     UINT r = ERROR_OUTOFMEMORY;
979
980     szwName = strdupAtoW( szName );
981     if( szName && !szwName )
982         goto end;
983
984     szwValue = strdupAtoW( szValue );
985     if( szValue && !szwValue )
986         goto end;
987
988     r = MsiSetPropertyW( hInstall, szwName, szwValue);
989
990 end:
991     msi_free( szwName );
992     msi_free( szwValue );
993
994     return r;
995 }
996
997 UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
998 {
999     msi_property *prop;
1000
1001     TRACE("%p %s %s\n", package, debugstr_w(szName), debugstr_w(szValue));
1002
1003     if (!szName)
1004         return ERROR_INVALID_PARAMETER;
1005
1006     /* this one is weird... */
1007     if (!szName[0])
1008         return szValue ? ERROR_FUNCTION_FAILED : ERROR_SUCCESS;
1009
1010     prop = msi_prop_find( package, szName );
1011     if (!prop)
1012         prop = msi_prop_add( package, szName );
1013
1014     if (!prop)
1015         return ERROR_OUTOFMEMORY;
1016
1017     if (szValue)
1018     {
1019         msi_free( prop->value );
1020         prop->value = strdupW( szValue );
1021     }
1022     else
1023         msi_delete_property( prop );
1024
1025     return ERROR_SUCCESS;
1026 }
1027
1028 UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
1029 {
1030     MSIPACKAGE *package;
1031     UINT ret;
1032
1033     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
1034     if( !package )
1035         return ERROR_INVALID_HANDLE;
1036     ret = MSI_SetPropertyW( package, szName, szValue);
1037     msiobj_release( &package->hdr );
1038     return ret;
1039 }
1040
1041 /* internal function, not compatible with MsiGetPropertyW */
1042 UINT MSI_GetPropertyW( MSIPACKAGE *package, LPCWSTR szName, 
1043                        LPWSTR szValueBuf, DWORD* pchValueBuf )
1044 {
1045     msi_property *prop;
1046     UINT r, len;
1047
1048     if (*pchValueBuf > 0)
1049         szValueBuf[0] = 0;
1050
1051     prop = msi_prop_find( package, szName );
1052     if (!prop)
1053     {
1054         *pchValueBuf = 0;
1055         TRACE("property %s not found\n", debugstr_w(szName));
1056         return ERROR_FUNCTION_FAILED;
1057     }
1058
1059     if (prop->value)
1060     {
1061         len = lstrlenW( prop->value );
1062         lstrcpynW(szValueBuf, prop->value, *pchValueBuf);
1063     }
1064     else
1065     {
1066         len = 1;
1067         if( *pchValueBuf > 0 )
1068             szValueBuf[0] = 0;
1069     }
1070
1071     TRACE("%s -> %s\n", debugstr_w(szName), debugstr_w(szValueBuf));
1072
1073     if ( *pchValueBuf <= len )
1074     {
1075         TRACE("have %u, need %u -> ERROR_MORE_DATA\n", *pchValueBuf, len);
1076         r = ERROR_MORE_DATA;
1077     }
1078     else
1079         r = ERROR_SUCCESS;
1080
1081     *pchValueBuf = len;
1082
1083     return r;
1084 }
1085
1086 LPWSTR msi_dup_property( MSIPACKAGE *package, LPCWSTR szName )
1087 {
1088     msi_property *prop;
1089     LPWSTR value = NULL;
1090
1091     prop = msi_prop_find( package, szName );
1092     if (prop)
1093         value = strdupW( prop->value );
1094
1095     return value;
1096 }
1097
1098 int msi_get_property_int( MSIPACKAGE *package, LPCWSTR name, int value )
1099 {
1100     msi_property *prop;
1101
1102     prop = msi_prop_find( package, name );
1103     if (prop)
1104         value = atoiW( prop->value );
1105     return value;
1106 }
1107
1108 static UINT MSI_GetProperty( MSIHANDLE handle, LPCWSTR name,
1109                              awstring *szValueBuf, DWORD* pchValueBuf )
1110 {
1111     static const WCHAR empty[] = {0};
1112     msi_property *prop;
1113     MSIPACKAGE *package;
1114     UINT r;
1115     LPCWSTR val = NULL;
1116
1117     TRACE("%lu %s %p %p\n", handle, debugstr_w(name),
1118           szValueBuf->str.w, pchValueBuf );
1119
1120     if (!name)
1121         return ERROR_INVALID_PARAMETER;
1122
1123     package = msihandle2msiinfo( handle, MSIHANDLETYPE_PACKAGE );
1124     if (!package)
1125         return ERROR_INVALID_HANDLE;
1126
1127     prop = msi_prop_find( package, name );
1128     if (prop)
1129         val = prop->value;
1130
1131     if (!val)
1132         val = empty;
1133
1134     r = msi_strcpy_to_awstring( val, szValueBuf, pchValueBuf );
1135
1136     msiobj_release( &package->hdr );
1137
1138     return r;
1139 }
1140
1141 UINT WINAPI MsiGetPropertyA( MSIHANDLE hInstall, LPCSTR szName,
1142                              LPSTR szValueBuf, DWORD* pchValueBuf )
1143 {
1144     awstring val;
1145     LPWSTR name;
1146     UINT r;
1147
1148     val.unicode = FALSE;
1149     val.str.a = szValueBuf;
1150
1151     name = strdupAtoW( szName );
1152     if (szName && !name)
1153         return ERROR_OUTOFMEMORY;
1154
1155     r = MSI_GetProperty( hInstall, name, &val, pchValueBuf );
1156     msi_free( name );
1157     return r;
1158 }
1159
1160 UINT WINAPI MsiGetPropertyW( MSIHANDLE hInstall, LPCWSTR szName,
1161                              LPWSTR szValueBuf, DWORD* pchValueBuf )
1162 {
1163     awstring val;
1164
1165     val.unicode = TRUE;
1166     val.str.w = szValueBuf;
1167
1168     return MSI_GetProperty( hInstall, szName, &val, pchValueBuf );
1169 }