msi: Remove unused function pointer and definitions.
[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 )
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
470         /* OK, here is where we do a slew of things to the database to 
471          * prep for all that is to come as a package */
472
473         for (i=0; i<PROPERTY_HASH_SIZE; i++)
474             list_init( &package->props[i] );
475
476         clone_properties( package );
477         set_installer_properties(package);
478         sprintfW(uilevel,szpi,gUILevel);
479         MSI_SetPropertyW(package, szLevel, uilevel);
480
481         package->ProductCode = msi_dup_property( package, szProductCode );
482         set_installed_prop( package );
483     }
484
485     return package;
486 }
487
488 /*
489  * copy_package_to_temp   [internal]
490  *
491  * copy the msi file to a temp file to prevent locking a CD
492  * with a multi disc install 
493  *
494  * FIXME: I think this is wrong, and instead of copying the package,
495  *        we should read all the tables to memory, then open the
496  *        database to read binary streams on demand.
497  */ 
498 static LPCWSTR copy_package_to_temp( LPCWSTR szPackage, LPWSTR filename )
499 {
500     WCHAR path[MAX_PATH];
501     static const WCHAR szMSI[] = {'M','S','I',0};
502
503     GetTempPathW( MAX_PATH, path );
504     GetTempFileNameW( path, szMSI, 0, filename );
505
506     if( !CopyFileW( szPackage, filename, FALSE ) )
507     {
508         ERR("failed to copy package %s\n", debugstr_w(szPackage) );
509         return szPackage;
510     }
511
512     TRACE("Opening relocated package %s\n", debugstr_w( filename ));
513     return filename;
514 }
515
516 LPCWSTR msi_download_file( LPCWSTR szUrl, LPWSTR filename )
517 {
518     LPINTERNET_CACHE_ENTRY_INFOW cache_entry;
519     DWORD size = 0;
520     HRESULT hr;
521
522     /* call will always fail, becase size is 0,
523      * but will return ERROR_FILE_NOT_FOUND first
524      * if the file doesn't exist
525      */
526     GetUrlCacheEntryInfoW( szUrl, NULL, &size );
527     if ( GetLastError() != ERROR_FILE_NOT_FOUND )
528     {
529         cache_entry = HeapAlloc( GetProcessHeap(), 0, size );
530         if ( !GetUrlCacheEntryInfoW( szUrl, cache_entry, &size ) )
531         {
532             HeapFree( GetProcessHeap(), 0, cache_entry );
533             return szUrl;
534         }
535
536         lstrcpyW( filename, cache_entry->lpszLocalFileName );
537         HeapFree( GetProcessHeap(), 0, cache_entry );
538         return filename;
539     }
540
541     hr = URLDownloadToCacheFileW( NULL, szUrl, filename, MAX_PATH, 0, NULL );
542     if ( FAILED(hr) )
543         return szUrl;
544
545     return filename;
546 }
547
548 UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
549 {
550     MSIDATABASE *db = NULL;
551     MSIPACKAGE *package;
552     MSIHANDLE handle;
553     UINT r;
554
555     static const WCHAR OriginalDatabase[] =
556         {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
557     static const WCHAR Database[] = {'D','A','T','A','B','A','S','E',0};
558
559     TRACE("%s %p\n", debugstr_w(szPackage), pPackage);
560
561     if( szPackage[0] == '#' )
562     {
563         handle = atoiW(&szPackage[1]);
564         db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
565         if( !db )
566             return ERROR_INVALID_HANDLE;
567     }
568     else
569     {
570         WCHAR temppath[MAX_PATH];
571         LPCWSTR file;
572
573         if ( UrlIsW( szPackage, URLIS_URL ) )
574             file = msi_download_file( szPackage, temppath );
575         else
576             file = copy_package_to_temp( szPackage, temppath );
577
578         r = MSI_OpenDatabaseW( file, MSIDBOPEN_READONLY, &db );
579
580         if (file != szPackage)
581             DeleteFileW( file );
582
583         if( r != ERROR_SUCCESS )
584         {
585             if (GetLastError() == ERROR_FILE_NOT_FOUND)
586                 msi_ui_error( 4, MB_OK | MB_ICONWARNING );
587
588             return r;
589         }
590     }
591
592     package = MSI_CreatePackage( db );
593     msiobj_release( &db->hdr );
594     if( !package )
595         return ERROR_FUNCTION_FAILED;
596
597     if( szPackage[0] != '#' )
598     {
599         MSI_SetPropertyW( package, OriginalDatabase, szPackage );
600         MSI_SetPropertyW( package, Database, szPackage );
601     }
602     else
603     {
604         MSI_SetPropertyW( package, OriginalDatabase, db->path );
605         MSI_SetPropertyW( package, Database, db->path );
606     }
607
608     *pPackage = package;
609
610     return ERROR_SUCCESS;
611 }
612
613 UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
614 {
615     MSIPACKAGE *package = NULL;
616     UINT ret;
617
618     TRACE("%s %08x %p\n", debugstr_w(szPackage), dwOptions, phPackage );
619
620     if( szPackage == NULL )
621         return ERROR_INVALID_PARAMETER;
622
623     if( dwOptions )
624         FIXME("dwOptions %08x not supported\n", dwOptions);
625
626     ret = MSI_OpenPackageW( szPackage, &package );
627     if( ret == ERROR_SUCCESS )
628     {
629         *phPackage = alloc_msihandle( &package->hdr );
630         if (! *phPackage)
631             ret = ERROR_NOT_ENOUGH_MEMORY;
632         msiobj_release( &package->hdr );
633     }
634
635     return ret;
636 }
637
638 UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
639 {
640     return MsiOpenPackageExW( szPackage, 0, phPackage );
641 }
642
643 UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
644 {
645     LPWSTR szwPack = NULL;
646     UINT ret;
647
648     if( szPackage )
649     {
650         szwPack = strdupAtoW( szPackage );
651         if( !szwPack )
652             return ERROR_OUTOFMEMORY;
653     }
654
655     ret = MsiOpenPackageExW( szwPack, dwOptions, phPackage );
656
657     msi_free( szwPack );
658
659     return ret;
660 }
661
662 UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
663 {
664     return MsiOpenPackageExA( szPackage, 0, phPackage );
665 }
666
667 MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
668 {
669     MSIPACKAGE *package;
670     MSIHANDLE handle = 0;
671
672     TRACE("(%ld)\n",hInstall);
673
674     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
675     if( package)
676     {
677         handle = alloc_msihandle( &package->db->hdr );
678         msiobj_release( &package->hdr );
679     }
680
681     return handle;
682 }
683
684 INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
685                                MSIRECORD *record)
686 {
687     static const WCHAR szActionData[] =
688         {'A','c','t','i','o','n','D','a','t','a',0};
689     static const WCHAR szSetProgress[] =
690         {'S','e','t','P','r','o','g','r','e','s','s',0};
691     static const WCHAR szActionText[] =
692         {'A','c','t','i','o','n','T','e','x','t',0};
693     DWORD log_type = 0;
694     LPWSTR message;
695     DWORD sz;
696     DWORD total_size = 0;
697     INT i;
698     INT rc;
699     char *msg;
700     int len;
701
702     TRACE("%x\n", eMessageType);
703     rc = 0;
704
705     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR)
706         log_type |= INSTALLLOGMODE_ERROR;
707     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_WARNING)
708         log_type |= INSTALLLOGMODE_WARNING;
709     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_USER)
710         log_type |= INSTALLLOGMODE_USER;
711     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INFO)
712         log_type |= INSTALLLOGMODE_INFO;
713     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA)
714         log_type |= INSTALLLOGMODE_COMMONDATA;
715     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
716         log_type |= INSTALLLOGMODE_ACTIONSTART;
717     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONDATA)
718         log_type |= INSTALLLOGMODE_ACTIONDATA;
719     /* just a guess */
720     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS)
721         log_type |= 0x800;
722
723     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
724     {
725         static const WCHAR template_s[]=
726             {'A','c','t','i','o','n',' ','%','s',':',' ','%','s','.',' ',0};
727         static const WCHAR format[] = 
728             {'H','H','\'',':','\'','m','m','\'',':','\'','s','s',0};
729         WCHAR timet[0x100];
730         LPCWSTR action_text, action;
731         LPWSTR deformatted = NULL;
732
733         GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
734
735         action = MSI_RecordGetString(record, 1);
736         action_text = MSI_RecordGetString(record, 2);
737
738         if (!action || !action_text)
739             return IDOK;
740
741         deformat_string(package, action_text, &deformatted);
742
743         len = strlenW(timet) + strlenW(action) + strlenW(template_s);
744         if (deformatted)
745             len += strlenW(deformatted);
746         message = msi_alloc(len*sizeof(WCHAR));
747         sprintfW(message, template_s, timet, action);
748         if (deformatted)
749             strcatW(message, deformatted);
750         msi_free(deformatted);
751     }
752     else
753     {
754         INT msg_field=1;
755         message = msi_alloc(1*sizeof (WCHAR));
756         message[0]=0;
757         msg_field = MSI_RecordGetFieldCount(record);
758         for (i = 1; i <= msg_field; i++)
759         {
760             LPWSTR tmp;
761             WCHAR number[3];
762             static const WCHAR format[] = { '%','i',':',' ',0};
763             static const WCHAR space[] = { ' ',0};
764             sz = 0;
765             MSI_RecordGetStringW(record,i,NULL,&sz);
766             sz+=4;
767             total_size+=sz*sizeof(WCHAR);
768             tmp = msi_alloc(sz*sizeof(WCHAR));
769             message = msi_realloc(message,total_size*sizeof (WCHAR));
770
771             MSI_RecordGetStringW(record,i,tmp,&sz);
772
773             if (msg_field > 1)
774             {
775                 sprintfW(number,format,i);
776                 strcatW(message,number);
777             }
778             strcatW(message,tmp);
779             if (msg_field > 1)
780                 strcatW(message,space);
781
782             msi_free(tmp);
783         }
784     }
785
786     TRACE("(%p %x %x %s)\n", gUIHandlerA, gUIFilter, log_type,
787                              debugstr_w(message));
788
789     /* convert it to ASCII */
790     len = WideCharToMultiByte( CP_ACP, 0, message, -1,
791                                NULL, 0, NULL, NULL );
792     msg = msi_alloc( len );
793     WideCharToMultiByte( CP_ACP, 0, message, -1,
794                          msg, len, NULL, NULL );
795
796     if (gUIHandlerA && (gUIFilter & log_type))
797     {
798         rc = gUIHandlerA(gUIContext,eMessageType,msg);
799     }
800
801     if ((!rc) && (gszLogFile[0]) && !((eMessageType & 0xff000000) ==
802                                       INSTALLMESSAGE_PROGRESS))
803     {
804         DWORD write;
805         HANDLE log_file = CreateFileW(gszLogFile,GENERIC_WRITE, 0, NULL,
806                                   OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
807
808         if (log_file != INVALID_HANDLE_VALUE)
809         {
810             SetFilePointer(log_file,0, NULL, FILE_END);
811             WriteFile(log_file,msg,strlen(msg),&write,NULL);
812             WriteFile(log_file,"\n",1,&write,NULL);
813             CloseHandle(log_file);
814         }
815     }
816     msi_free( msg );
817
818     msi_free( message);
819
820     switch (eMessageType & 0xff000000)
821     {
822     case INSTALLMESSAGE_ACTIONDATA:
823         /* FIXME: format record here instead of in ui_actiondata to get the
824          * correct action data for external scripts */
825         ControlEvent_FireSubscribedEvent(package, szActionData, record);
826         break;
827     case INSTALLMESSAGE_ACTIONSTART:
828     {
829         MSIRECORD *uirow;
830         LPWSTR deformated;
831         LPCWSTR action_text = MSI_RecordGetString(record, 2);
832
833         deformat_string(package, action_text, &deformated);
834         uirow = MSI_CreateRecord(1);
835         MSI_RecordSetStringW(uirow, 1, deformated);
836         TRACE("INSTALLMESSAGE_ACTIONSTART: %s\n", debugstr_w(deformated));
837         msi_free(deformated);
838
839         ControlEvent_FireSubscribedEvent(package, szActionText, uirow);
840
841         msiobj_release(&uirow->hdr);
842         break;
843     }
844     case INSTALLMESSAGE_PROGRESS:
845         ControlEvent_FireSubscribedEvent(package, szSetProgress, record);
846         break;
847     }
848
849     return ERROR_SUCCESS;
850 }
851
852 INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
853                               MSIHANDLE hRecord)
854 {
855     UINT ret = ERROR_INVALID_HANDLE;
856     MSIPACKAGE *package = NULL;
857     MSIRECORD *record = NULL;
858
859     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
860     if( !package )
861         return ERROR_INVALID_HANDLE;
862
863     record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
864     if( !record )
865         goto out;
866
867     ret = MSI_ProcessMessage( package, eMessageType, record );
868
869 out:
870     msiobj_release( &package->hdr );
871     if( record )
872         msiobj_release( &record->hdr );
873
874     return ret;
875 }
876
877 /* property code */
878
879 typedef struct msi_property {
880     struct list entry;
881     LPWSTR key;
882     LPWSTR value;
883 } msi_property;
884
885 static UINT msi_prop_makehash( const WCHAR *str )
886 {
887     UINT hash = 0;
888
889     if (str==NULL)
890         return hash;
891
892     while( *str )
893     {
894         hash ^= *str++;
895         hash *= 53;
896         hash = (hash<<5) | (hash>>27);
897     }
898     return hash % PROPERTY_HASH_SIZE;
899 }
900
901 static msi_property *msi_prop_find( MSIPACKAGE *package, LPCWSTR key )
902 {
903     UINT hash = msi_prop_makehash( key );
904     msi_property *prop;
905
906     LIST_FOR_EACH_ENTRY( prop, &package->props[hash], msi_property, entry )
907         if (!lstrcmpW( prop->key, key ))
908             return prop;
909     return NULL;
910 }
911
912 static msi_property *msi_prop_add( MSIPACKAGE *package, LPCWSTR key )
913 {
914     UINT hash = msi_prop_makehash( key );
915     msi_property *prop;
916
917     prop = msi_alloc( sizeof *prop );
918     if (prop)
919     {
920         prop->key = strdupW( key );
921         prop->value = NULL;
922         list_add_head( &package->props[hash], &prop->entry );
923     }
924     return prop;
925 }
926
927 static void msi_delete_property( msi_property *prop )
928 {
929     list_remove( &prop->entry );
930     msi_free( prop->key );
931     msi_free( prop->value );
932     msi_free( prop );
933 }
934
935 static void msi_free_properties( MSIPACKAGE *package )
936 {
937     int i;
938
939     for ( i=0; i<PROPERTY_HASH_SIZE; i++ )
940     {
941         while ( !list_empty(&package->props[i]) )
942         {
943             msi_property *prop;
944             prop = LIST_ENTRY( list_head( &package->props[i] ),
945                                msi_property, entry );
946             msi_delete_property( prop );
947         }
948     }
949 }
950
951 UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue )
952 {
953     LPWSTR szwName = NULL, szwValue = NULL;
954     UINT r = ERROR_OUTOFMEMORY;
955
956     szwName = strdupAtoW( szName );
957     if( szName && !szwName )
958         goto end;
959
960     szwValue = strdupAtoW( szValue );
961     if( szValue && !szwValue )
962         goto end;
963
964     r = MsiSetPropertyW( hInstall, szwName, szwValue);
965
966 end:
967     msi_free( szwName );
968     msi_free( szwValue );
969
970     return r;
971 }
972
973 UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
974 {
975     msi_property *prop;
976
977     TRACE("%p %s %s\n", package, debugstr_w(szName), debugstr_w(szValue));
978
979     if (!szName)
980         return ERROR_INVALID_PARAMETER;
981
982     /* this one is weird... */
983     if (!szName[0])
984         return szValue ? ERROR_FUNCTION_FAILED : ERROR_SUCCESS;
985
986     prop = msi_prop_find( package, szName );
987     if (!prop)
988         prop = msi_prop_add( package, szName );
989
990     if (!prop)
991         return ERROR_OUTOFMEMORY;
992
993     if (szValue)
994     {
995         msi_free( prop->value );
996         prop->value = strdupW( szValue );
997     }
998     else
999         msi_delete_property( prop );
1000
1001     return ERROR_SUCCESS;
1002 }
1003
1004 UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
1005 {
1006     MSIPACKAGE *package;
1007     UINT ret;
1008
1009     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
1010     if( !package )
1011         return ERROR_INVALID_HANDLE;
1012     ret = MSI_SetPropertyW( package, szName, szValue);
1013     msiobj_release( &package->hdr );
1014     return ret;
1015 }
1016
1017 /* internal function, not compatible with MsiGetPropertyW */
1018 UINT MSI_GetPropertyW( MSIPACKAGE *package, LPCWSTR szName, 
1019                        LPWSTR szValueBuf, DWORD* pchValueBuf )
1020 {
1021     msi_property *prop;
1022     UINT r, len;
1023
1024     if (*pchValueBuf > 0)
1025         szValueBuf[0] = 0;
1026
1027     prop = msi_prop_find( package, szName );
1028     if (!prop)
1029     {
1030         *pchValueBuf = 0;
1031         TRACE("property %s not found\n", debugstr_w(szName));
1032         return ERROR_FUNCTION_FAILED;
1033     }
1034
1035     if (prop->value)
1036     {
1037         len = lstrlenW( prop->value );
1038         lstrcpynW(szValueBuf, prop->value, *pchValueBuf);
1039     }
1040     else
1041     {
1042         len = 1;
1043         if( *pchValueBuf > 0 )
1044             szValueBuf[0] = 0;
1045     }
1046
1047     TRACE("%s -> %s\n", debugstr_w(szName), debugstr_w(szValueBuf));
1048
1049     if ( *pchValueBuf <= len )
1050     {
1051         TRACE("have %u, need %u -> ERROR_MORE_DATA\n", *pchValueBuf, len);
1052         r = ERROR_MORE_DATA;
1053     }
1054     else
1055         r = ERROR_SUCCESS;
1056
1057     *pchValueBuf = len;
1058
1059     return r;
1060 }
1061
1062 LPWSTR msi_dup_property( MSIPACKAGE *package, LPCWSTR szName )
1063 {
1064     msi_property *prop;
1065     LPWSTR value = NULL;
1066
1067     prop = msi_prop_find( package, szName );
1068     if (prop)
1069         value = strdupW( prop->value );
1070
1071     return value;
1072 }
1073
1074 int msi_get_property_int( MSIPACKAGE *package, LPCWSTR name, int value )
1075 {
1076     msi_property *prop;
1077
1078     prop = msi_prop_find( package, name );
1079     if (prop)
1080         value = atoiW( prop->value );
1081     return value;
1082 }
1083
1084 static UINT MSI_GetProperty( MSIHANDLE handle, LPCWSTR name,
1085                              awstring *szValueBuf, DWORD* pchValueBuf )
1086 {
1087     static const WCHAR empty[] = {0};
1088     msi_property *prop;
1089     MSIPACKAGE *package;
1090     UINT r;
1091     LPCWSTR val = NULL;
1092
1093     TRACE("%lu %s %p %p\n", handle, debugstr_w(name),
1094           szValueBuf->str.w, pchValueBuf );
1095
1096     if (!name)
1097         return ERROR_INVALID_PARAMETER;
1098
1099     package = msihandle2msiinfo( handle, MSIHANDLETYPE_PACKAGE );
1100     if (!package)
1101         return ERROR_INVALID_HANDLE;
1102
1103     prop = msi_prop_find( package, name );
1104     if (prop)
1105         val = prop->value;
1106
1107     if (!val)
1108         val = empty;
1109
1110     r = msi_strcpy_to_awstring( val, szValueBuf, pchValueBuf );
1111
1112     msiobj_release( &package->hdr );
1113
1114     return r;
1115 }
1116
1117 UINT WINAPI MsiGetPropertyA( MSIHANDLE hInstall, LPCSTR szName,
1118                              LPSTR szValueBuf, DWORD* pchValueBuf )
1119 {
1120     awstring val;
1121     LPWSTR name;
1122     UINT r;
1123
1124     val.unicode = FALSE;
1125     val.str.a = szValueBuf;
1126
1127     name = strdupAtoW( szName );
1128     if (szName && !name)
1129         return ERROR_OUTOFMEMORY;
1130
1131     r = MSI_GetProperty( hInstall, name, &val, pchValueBuf );
1132     msi_free( name );
1133     return r;
1134 }
1135
1136 UINT WINAPI MsiGetPropertyW( MSIHANDLE hInstall, LPCWSTR szName,
1137                              LPWSTR szValueBuf, DWORD* pchValueBuf )
1138 {
1139     awstring val;
1140
1141     val.unicode = TRUE;
1142     val.str.w = szValueBuf;
1143
1144     return MSI_GetProperty( hInstall, szName, &val, pchValueBuf );
1145 }