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