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