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