Don't hardcode c:\windows paths in msi.dll.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #define NONAMELESSUNION
22
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winreg.h"
28 #include "winnls.h"
29 #include "shlwapi.h"
30 #include "wine/debug.h"
31 #include "msi.h"
32 #include "msiquery.h"
33 #include "msipriv.h"
34 #include "objidl.h"
35 #include "wincrypt.h"
36 #include "winuser.h"
37 #include "shlobj.h"
38 #include "wine/unicode.h"
39 #include "objbase.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(msi);
42
43 /*
44  * The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR,
45  *  which is a problem because LPCTSTR isn't defined when compiling wine.
46  * To work around this problem, we need to define LPCTSTR as LPCWSTR here,
47  *  and make sure to only use it in W functions.
48  */
49 #define LPCTSTR LPCWSTR
50
51 void MSI_FreePackage( MSIOBJECTHDR *arg)
52 {
53     MSIPACKAGE *package= (MSIPACKAGE*) arg;
54
55     ACTION_remove_tracked_tempfiles(package);
56
57     if (package->features && package->loaded_features > 0)
58         HeapFree(GetProcessHeap(),0,package->features);
59
60     if (package->folders && package->loaded_folders > 0)
61         HeapFree(GetProcessHeap(),0,package->folders);
62     
63     if (package->components && package->loaded_components > 0)
64         HeapFree(GetProcessHeap(),0,package->components);
65
66     if (package->files && package->loaded_files > 0)
67         HeapFree(GetProcessHeap(),0,package->files);
68     msiobj_release( &package->db->hdr );
69 }
70
71 UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
72 {
73     LPWSTR szwPack = NULL;
74     UINT len, ret;
75
76     TRACE("%s %p\n",debugstr_a(szPackage), phPackage);
77
78     if( szPackage )
79     {
80         len = MultiByteToWideChar( CP_ACP, 0, szPackage, -1, NULL, 0 );
81         szwPack = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
82         if( szwPack )
83             MultiByteToWideChar( CP_ACP, 0, szPackage, -1, szwPack, len );
84     }
85
86     ret = MsiOpenPackageW( szwPack, phPackage );
87
88     if( szwPack )
89         HeapFree( GetProcessHeap(), 0, szwPack );
90
91     return ret;
92 }
93
94
95 static const UINT clone_properties(MSIDATABASE *db)
96 {
97     MSIQUERY * view = NULL;
98     UINT rc;
99     static const WCHAR CreateSql[] = {
100        'C','R','E','A','T','E',' ','T','A','B','L','E',' ','`','_','P','r','o',
101        'p','e','r','t','y','`',' ','(',' ','`','_','P','r','o','p','e','r','t',
102        'y','`',' ','C','H','A','R','(','5','6',')',' ','N','O','T',' ','N','U',
103        'L','L',',',' ','`','V','a','l','u','e','`',' ','C','H','A','R','(','9',
104        '8',')',' ','N','O','T',' ','N','U','L','L',' ','P','R','I','M','A','R',
105        'Y',' ','K','E','Y',' ','`','_','P','r','o','p','e','r','t','y','`',')',0};
106     static const WCHAR Query[] = {
107        'S','E','L','E','C','T',' ','*',' ',
108        'f','r','o','m',' ','P','r','o','p','e','r','t','y',0};
109     static const WCHAR Insert[] = {
110        'I','N','S','E','R','T',' ','i','n','t','o',' ',
111        '`','_','P','r','o','p','e','r','t','y','`',' ',
112        '(','`','_','P','r','o','p','e','r','t','y','`',',',
113        '`','V','a','l','u','e','`',')',' ',
114        'V','A','L','U','E','S',' ','(','?',')',0};
115
116     /* create the temporary properties table */
117     rc = MSI_DatabaseOpenViewW(db, CreateSql, &view);
118     if (rc != ERROR_SUCCESS)
119         return rc;
120     rc = MSI_ViewExecute(view,0);   
121     MSI_ViewClose(view);
122     msiobj_release(&view->hdr); 
123     if (rc != ERROR_SUCCESS)
124         return rc;
125
126     /* clone the existing properties */
127     rc = MSI_DatabaseOpenViewW(db, Query, &view);
128     if (rc != ERROR_SUCCESS)
129         return rc;
130
131     rc = MSI_ViewExecute(view, 0);
132     if (rc != ERROR_SUCCESS)
133     {
134         MSI_ViewClose(view);
135         msiobj_release(&view->hdr); 
136         return rc;
137     }
138     while (1)
139     {
140         MSIRECORD * row;
141         MSIQUERY * view2;
142
143         rc = MSI_ViewFetch(view,&row);
144         if (rc != ERROR_SUCCESS)
145             break;
146
147         rc = MSI_DatabaseOpenViewW(db,Insert,&view2);  
148         if (rc!= ERROR_SUCCESS)
149             continue;
150         rc = MSI_ViewExecute(view2,row);
151         MSI_ViewClose(view2);
152         msiobj_release(&view2->hdr);
153  
154         if (rc == ERROR_SUCCESS) 
155             msiobj_release(&row->hdr); 
156     }
157     MSI_ViewClose(view);
158     msiobj_release(&view->hdr);
159     
160     return rc;
161 }
162
163 /*
164  * There are a whole slew of these we need to set
165  *
166  *
167 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/properties.asp
168  */
169 static VOID set_installer_properties(MSIPACKAGE *package)
170 {
171     WCHAR pth[MAX_PATH];
172     OSVERSIONINFOA OSVersion;
173     DWORD verval;
174     WCHAR verstr[10], msiver[10];
175
176     static const WCHAR cszbs[]={'\\',0};
177     static const WCHAR CFF[] = 
178 {'C','o','m','m','o','n','F','i','l','e','s','F','o','l','d','e','r',0};
179     static const WCHAR PFF[] = 
180 {'P','r','o','g','r','a','m','F','i','l','e','s','F','o','l','d','e','r',0};
181     static const WCHAR CADF[] = 
182 {'C','o','m','m','o','n','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
183     static const WCHAR FaF[] = 
184 {'F','a','v','o','r','i','t','e','s','F','o','l','d','e','r',0};
185     static const WCHAR FoF[] = 
186 {'F','o','n','t','s','F','o','l','d','e','r',0};
187     static const WCHAR SendTF[] = 
188 {'S','e','n','d','T','o','F','o','l','d','e','r',0};
189     static const WCHAR SMF[] = 
190 {'S','t','a','r','t','M','e','n','u','F','o','l','d','e','r',0};
191     static const WCHAR StF[] = 
192 {'S','t','a','r','t','u','p','F','o','l','d','e','r',0};
193     static const WCHAR TemplF[] = 
194 {'T','e','m','p','l','a','t','e','F','o','l','d','e','r',0};
195     static const WCHAR DF[] = 
196 {'D','e','s','k','t','o','p','F','o','l','d','e','r',0};
197     static const WCHAR PMF[] = 
198 {'P','r','o','g','r','a','m','M','e','n','u','F','o','l','d','e','r',0};
199     static const WCHAR ATF[] = 
200 {'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0};
201     static const WCHAR ADF[] = 
202 {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
203     static const WCHAR SF[] = 
204 {'S','y','s','t','e','m','F','o','l','d','e','r',0};
205     static const WCHAR LADF[] = 
206 {'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
207     static const WCHAR MPF[] = 
208 {'M','y','P','i','c','t','u','r','e','s','F','o','l','d','e','r',0};
209     static const WCHAR PF[] = 
210 {'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0};
211     static const WCHAR WF[] = 
212 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
213     static const WCHAR TF[]=
214 {'T','e','m','p','F','o','l','d','e','r',0};
215     static const WCHAR szAdminUser[] =
216 {'A','d','m','i','n','U','s','e','r',0};
217     static const WCHAR szPriv[] =
218 {'P','r','i','v','i','l','e','g','e','d',0};
219     static const WCHAR szOne[] =
220 {'1',0};
221     static const WCHAR v9x[] = { 'V','e','r','s','i','o','n','9','X',0 };
222     static const WCHAR vNT[] = { 'V','e','r','s','i','o','n','N','T',0 };
223     static const WCHAR szFormat[] = {'%','l','i',0};
224     static const WCHAR szWinBuild[] =
225 {'W','i','n','d','o','w','s','B','u','i','l','d', 0 };
226     static const WCHAR szSPL[] = 
227 {'S','e','r','v','i','c','e','P','a','c','k','L','e','v','e','l',0 };
228     static const WCHAR szSix[] = {'6',0 };
229
230     static const WCHAR szVersionMsi[] = { 'V','e','r','s','i','o','n','M','s','i',0 };
231     static const WCHAR szFormat2[] = {'%','l','i','.','%','l','i',0};
232
233 /*
234  * Other things I notice set
235  *
236 ScreenY
237 ScreenX
238 SystemLanguageID
239 ComputerName
240 UserLanguageID
241 LogonUser
242 VirtualMemory
243 PhysicalMemory
244 Intel
245 ShellAdvSupport
246 DefaultUIFont
247 VersionDatabase
248 PackagecodeChanging
249 ProductState
250 CaptionHeight
251 BorderTop
252 BorderSide
253 TextHeight
254 ColorBits
255 RedirectedDllSupport
256 Time
257 Date
258 Privileged
259 */
260
261     SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth);
262     strcatW(pth,cszbs);
263     MSI_SetPropertyW(package, CFF, pth);
264
265     SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES,NULL,0,pth);
266     strcatW(pth,cszbs);
267     MSI_SetPropertyW(package, PFF, pth);
268
269     SHGetFolderPathW(NULL,CSIDL_COMMON_APPDATA,NULL,0,pth);
270     strcatW(pth,cszbs);
271     MSI_SetPropertyW(package, CADF, pth);
272
273     SHGetFolderPathW(NULL,CSIDL_FAVORITES,NULL,0,pth);
274     strcatW(pth,cszbs);
275     MSI_SetPropertyW(package, FaF, pth);
276
277     SHGetFolderPathW(NULL,CSIDL_FONTS,NULL,0,pth);
278     strcatW(pth,cszbs);
279     MSI_SetPropertyW(package, FoF, pth);
280
281     SHGetFolderPathW(NULL,CSIDL_SENDTO,NULL,0,pth);
282     strcatW(pth,cszbs);
283     MSI_SetPropertyW(package, SendTF, pth);
284
285     SHGetFolderPathW(NULL,CSIDL_STARTMENU,NULL,0,pth);
286     strcatW(pth,cszbs);
287     MSI_SetPropertyW(package, SMF, pth);
288
289     SHGetFolderPathW(NULL,CSIDL_STARTUP,NULL,0,pth);
290     strcatW(pth,cszbs);
291     MSI_SetPropertyW(package, StF, pth);
292
293     SHGetFolderPathW(NULL,CSIDL_TEMPLATES,NULL,0,pth);
294     strcatW(pth,cszbs);
295     MSI_SetPropertyW(package, TemplF, pth);
296
297     SHGetFolderPathW(NULL,CSIDL_DESKTOP,NULL,0,pth);
298     strcatW(pth,cszbs);
299     MSI_SetPropertyW(package, DF, pth);
300
301     SHGetFolderPathW(NULL,CSIDL_PROGRAMS,NULL,0,pth);
302     strcatW(pth,cszbs);
303     MSI_SetPropertyW(package, PMF, pth);
304
305     SHGetFolderPathW(NULL,CSIDL_ADMINTOOLS,NULL,0,pth);
306     strcatW(pth,cszbs);
307     MSI_SetPropertyW(package, ATF, pth);
308
309     SHGetFolderPathW(NULL,CSIDL_APPDATA,NULL,0,pth);
310     strcatW(pth,cszbs);
311     MSI_SetPropertyW(package, ADF, pth);
312
313     SHGetFolderPathW(NULL,CSIDL_SYSTEM,NULL,0,pth);
314     strcatW(pth,cszbs);
315     MSI_SetPropertyW(package, SF, pth);
316
317     SHGetFolderPathW(NULL,CSIDL_LOCAL_APPDATA,NULL,0,pth);
318     strcatW(pth,cszbs);
319     MSI_SetPropertyW(package, LADF, pth);
320
321     SHGetFolderPathW(NULL,CSIDL_MYPICTURES,NULL,0,pth);
322     strcatW(pth,cszbs);
323     MSI_SetPropertyW(package, MPF, pth);
324
325     SHGetFolderPathW(NULL,CSIDL_PERSONAL,NULL,0,pth);
326     strcatW(pth,cszbs);
327     MSI_SetPropertyW(package, PF, pth);
328
329     SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
330     strcatW(pth,cszbs);
331     MSI_SetPropertyW(package, WF, pth);
332
333     GetTempPathW(MAX_PATH,pth);
334     MSI_SetPropertyW(package, TF, pth);
335
336
337     /* in a wine environment the user is always admin and privileged */
338     MSI_SetPropertyW(package,szAdminUser,szOne);
339     MSI_SetPropertyW(package,szPriv,szOne);
340
341     /* set the os things */
342     OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
343     GetVersionExA(&OSVersion);
344     verval = OSVersion.dwMinorVersion+OSVersion.dwMajorVersion*100;
345     sprintfW(verstr,szFormat,verval);
346     switch (OSVersion.dwPlatformId)
347     {
348         case VER_PLATFORM_WIN32_WINDOWS:    
349             MSI_SetPropertyW(package,v9x,verstr);
350             break;
351         case VER_PLATFORM_WIN32_NT:
352             MSI_SetPropertyW(package,vNT,verstr);
353             break;
354     }
355     sprintfW(verstr,szFormat,OSVersion.dwBuildNumber);
356     MSI_SetPropertyW(package,szWinBuild,verstr);
357     /* just fudge this */
358     MSI_SetPropertyW(package,szSPL,szSix);
359
360     sprintfW( msiver, szFormat2, MSI_MAJORVERSION, MSI_MINORVERSION);
361     MSI_SetPropertyW( package, szVersionMsi, msiver );
362 }
363
364 UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
365 {
366     UINT rc;
367     MSIDATABASE *db = NULL;
368     MSIPACKAGE *package = NULL;
369     WCHAR uilevel[10];
370     UINT ret = ERROR_FUNCTION_FAILED;
371
372     static const WCHAR OriginalDatabase[] =
373 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
374     static const WCHAR Database[] =
375 {'D','A','T','A','B','A','S','E',0};
376     static const WCHAR szpi[] = {'%','i',0};
377     static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 };
378
379     TRACE("%s %p\n",debugstr_w(szPackage), pPackage);
380
381     if (szPackage[0] == '#')
382     {
383         INT handle = atoiW(&szPackage[1]);
384         db = msihandle2msiinfo( handle , MSIHANDLETYPE_DATABASE);
385     }
386     else
387     {
388         rc = MSI_OpenDatabaseW(szPackage, MSIDBOPEN_READONLY, &db);
389         if (rc != ERROR_SUCCESS)
390             return ERROR_FUNCTION_FAILED;
391     }
392
393     package = alloc_msiobject( MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE),
394                                MSI_FreePackage );
395
396     if (package)
397     {
398         msiobj_addref( &db->hdr );
399
400         package->db = db;
401         package->features = NULL;
402         package->folders = NULL;
403         package->components = NULL;
404         package->files = NULL;
405         package->loaded_features = 0;
406         package->loaded_folders = 0;
407         package->loaded_components= 0;
408         package->loaded_files = 0;
409
410         /* OK, here is where we do a slew of things to the database to 
411          * prep for all that is to come as a package */
412
413         clone_properties(db);
414         set_installer_properties(package);
415         MSI_SetPropertyW(package, OriginalDatabase, szPackage);
416         MSI_SetPropertyW(package, Database, szPackage);
417         sprintfW(uilevel,szpi,gUILevel);
418         MSI_SetPropertyW(package, szLevel, uilevel);
419
420         msiobj_addref( &package->hdr );
421         *pPackage = package;
422         ret = ERROR_SUCCESS;
423     }
424
425     if( package )
426         msiobj_release( &package->hdr );
427     if( db )
428         msiobj_release( &db->hdr );
429
430     return ret;
431 }
432
433 UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
434 {
435     MSIPACKAGE *package = NULL;
436     UINT ret;
437
438     ret = MSI_OpenPackageW( szPackage, &package);
439     if( ret == ERROR_SUCCESS )
440     {
441         *phPackage = alloc_msihandle( &package->hdr );
442         msiobj_release( &package->hdr );
443     }
444     return ret;
445 }
446
447 UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
448 {
449     FIXME("%s 0x%08lx %p\n",debugstr_a(szPackage), dwOptions, phPackage);
450     return ERROR_CALL_NOT_IMPLEMENTED;
451 }
452
453 UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
454 {
455     FIXME("%s 0x%08lx %p\n",debugstr_w(szPackage), dwOptions, phPackage);
456     return ERROR_CALL_NOT_IMPLEMENTED;
457 }
458
459 MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
460 {
461     MSIPACKAGE *package;
462     MSIHANDLE handle = 0;
463
464     TRACE("(%ld)\n",hInstall);
465
466     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
467     if( package)
468     {
469         handle = alloc_msihandle( &package->db->hdr );
470         msiobj_release( &package->hdr );
471     }
472
473     return handle;
474 }
475
476 INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
477                                MSIRECORD *record)
478 {
479     DWORD log_type = 0;
480     LPWSTR message;
481     DWORD sz;
482     DWORD total_size = 0;
483     INT msg_field=1;
484     INT i;
485     INT rc;
486     char *msg;
487     int len;
488
489     TRACE("%x \n",eMessageType);
490     rc = 0;
491
492     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR)
493         log_type |= INSTALLLOGMODE_ERROR;
494     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_WARNING)
495         log_type |= INSTALLLOGMODE_WARNING;
496     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_USER)
497         log_type |= INSTALLLOGMODE_USER;
498     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INFO)
499         log_type |= INSTALLLOGMODE_INFO;
500     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA)
501         log_type |= INSTALLLOGMODE_COMMONDATA;
502     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
503         log_type |= INSTALLLOGMODE_ACTIONSTART;
504     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONDATA)
505         log_type |= INSTALLLOGMODE_ACTIONDATA;
506     /* just a guess */
507     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS)
508         log_type |= 0x800;
509
510     message = HeapAlloc(GetProcessHeap(),0,1*sizeof (WCHAR));
511     message[0]=0;
512     msg_field = MSI_RecordGetFieldCount(record);
513     for (i = 1; i <= msg_field; i++)
514     {
515         LPWSTR tmp;
516         WCHAR number[3];
517         const static WCHAR format[] = { '%','i',':',' ',0};
518         const static WCHAR space[] = { ' ',0};
519         sz = 0;
520         MSI_RecordGetStringW(record,i,NULL,&sz);
521         sz+=4;
522         total_size+=sz*sizeof(WCHAR);
523         tmp = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
524         message = HeapReAlloc(GetProcessHeap(),0,message,total_size*sizeof (WCHAR));
525
526         MSI_RecordGetStringW(record,i,tmp,&sz);
527
528         if (msg_field > 1)
529         {
530             sprintfW(number,format,i);
531             strcatW(message,number);
532         }
533         strcatW(message,tmp);
534         if (msg_field > 1)
535             strcatW(message,space);
536
537         HeapFree(GetProcessHeap(),0,tmp);
538     }
539
540     TRACE("(%p %lx %lx %s)\n",gUIHandler, gUIFilter, log_type,
541                              debugstr_w(message));
542
543     /* convert it to ASCII */
544     len = WideCharToMultiByte( CP_ACP, 0, message, -1,
545                                NULL, 0, NULL, NULL );
546     msg = HeapAlloc( GetProcessHeap(), 0, len );
547     WideCharToMultiByte( CP_ACP, 0, message, -1,
548                          msg, len, NULL, NULL );
549
550     if (gUIHandler && (gUIFilter & log_type))
551     {
552         rc = gUIHandler(gUIContext,eMessageType,msg);
553     }
554
555     if ((!rc) && (gszLogFile[0]) && !((eMessageType & 0xff000000) ==
556                                       INSTALLMESSAGE_PROGRESS))
557     {
558         DWORD write;
559         HANDLE log_file = CreateFileW(gszLogFile,GENERIC_WRITE, 0, NULL,
560                                   OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
561
562         if (log_file != INVALID_HANDLE_VALUE)
563         {
564             SetFilePointer(log_file,0, NULL, FILE_END);
565             WriteFile(log_file,msg,strlen(msg),&write,NULL);
566             WriteFile(log_file,"\n",1,&write,NULL);
567             CloseHandle(log_file);
568         }
569     }
570     HeapFree( GetProcessHeap(), 0, msg );
571     
572     HeapFree(GetProcessHeap(),0,message);
573     return ERROR_SUCCESS;
574 }
575
576 INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
577                               MSIHANDLE hRecord)
578 {
579     UINT ret = ERROR_INVALID_HANDLE;
580     MSIPACKAGE *package = NULL;
581     MSIRECORD *record = NULL;
582
583     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
584     if( !package )
585         goto out;
586
587     record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
588     if( !record )
589         goto out;
590
591     ret = MSI_ProcessMessage( package, eMessageType, record );
592
593 out:
594     if( package )
595         msiobj_release( &package->hdr );
596     if( record )
597         msiobj_release( &record->hdr );
598
599     return ret;
600 }
601
602 /* property code */
603 UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue)
604 {
605     LPWSTR szwName = NULL, szwValue = NULL;
606     UINT hr = ERROR_INSTALL_FAILURE;
607     UINT len;
608
609     if (0 == hInstall) {
610       return ERROR_INVALID_HANDLE;
611     }
612     if (NULL == szName) {
613       return ERROR_INVALID_PARAMETER;
614     }
615     if (NULL == szValue) {
616       return ERROR_INVALID_PARAMETER;
617     }
618
619     len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
620     szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
621     if( !szwName )
622         goto end;
623     MultiByteToWideChar( CP_ACP, 0, szName, -1, szwName, len );
624
625     len = MultiByteToWideChar( CP_ACP, 0, szValue, -1, NULL, 0 );
626     szwValue = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
627     if( !szwValue)
628         goto end;
629     MultiByteToWideChar( CP_ACP, 0, szValue , -1, szwValue, len );
630
631     hr = MsiSetPropertyW( hInstall, szwName, szwValue);
632
633 end:
634     if( szwName )
635         HeapFree( GetProcessHeap(), 0, szwName );
636     if( szwValue )
637         HeapFree( GetProcessHeap(), 0, szwValue );
638
639     return hr;
640 }
641
642 UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
643 {
644     MSIQUERY *view;
645     MSIRECORD *row;
646     UINT rc;
647     DWORD sz = 0;
648     static const WCHAR Insert[]=
649      {'I','N','S','E','R','T',' ','i','n','t','o',' ','`','_','P','r','o','p'
650 ,'e','r','t','y','`',' ','(','`','_','P','r','o','p','e','r','t','y','`'
651 ,',','`','V','a','l','u','e','`',')',' ','V','A','L','U','E','S'
652 ,' ','(','?',')',0};
653     static const WCHAR Update[]=
654      {'U','P','D','A','T','E',' ','_','P','r','o','p','e'
655 ,'r','t','y',' ','s','e','t',' ','`','V','a','l','u','e','`',' ','='
656 ,' ','?',' ','w','h','e','r','e',' ','`','_','P','r','o','p'
657 ,'e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
658     WCHAR Query[1024];
659
660     TRACE("Setting property (%s %s)\n",debugstr_w(szName),
661           debugstr_w(szValue));
662
663     rc = MSI_GetPropertyW(package,szName,0,&sz);
664     if (rc==ERROR_MORE_DATA || rc == ERROR_SUCCESS)
665     {
666         sprintfW(Query,Update,szName);
667
668         row = MSI_CreateRecord(1);
669         MSI_RecordSetStringW(row,1,szValue);
670
671     }
672     else
673     {
674        strcpyW(Query,Insert);
675
676         row = MSI_CreateRecord(2);
677         MSI_RecordSetStringW(row,1,szName);
678         MSI_RecordSetStringW(row,2,szValue);
679     }
680
681
682     rc = MSI_DatabaseOpenViewW(package->db,Query,&view);
683     if (rc!= ERROR_SUCCESS)
684     {
685         msiobj_release(&row->hdr);
686         return rc;
687     }
688
689     rc = MSI_ViewExecute(view,row);
690
691     msiobj_release(&row->hdr);
692     MSI_ViewClose(view);
693     msiobj_release(&view->hdr);
694
695     return rc;
696 }
697
698 UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
699 {
700     MSIPACKAGE *package;
701     UINT ret;
702
703     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
704     if( !package)
705         return ERROR_INVALID_HANDLE;
706     ret = MSI_SetPropertyW( package, szName, szValue);
707     msiobj_release( &package->hdr );
708     return ret;
709 }
710
711 UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, DWORD* pchValueBuf) 
712 {
713     LPWSTR szwName = NULL, szwValueBuf = NULL;
714     UINT hr = ERROR_INSTALL_FAILURE;
715
716     if (0 == hInstall) {
717       return ERROR_INVALID_HANDLE;
718     }
719     if (NULL == szName) {
720       return ERROR_INVALID_PARAMETER;
721     }
722
723     TRACE("%lu %s %lu\n", hInstall, debugstr_a(szName), *pchValueBuf);
724
725     if (NULL != szValueBuf && NULL == pchValueBuf) {
726       return ERROR_INVALID_PARAMETER;
727     }
728     if( szName )
729     {
730         UINT len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
731         szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
732         if( !szwName )
733             goto end;
734         MultiByteToWideChar( CP_ACP, 0, szName, -1, szwName, len );
735     } else {
736       return ERROR_INVALID_PARAMETER;
737     }
738     if( szValueBuf )
739     {
740         szwValueBuf = HeapAlloc( GetProcessHeap(), 0, (*pchValueBuf) * sizeof(WCHAR) );
741         if( !szwValueBuf )       
742             goto end;
743     }
744
745     if(  *pchValueBuf > 0 )
746     {
747         /* be sure to blank the string first */
748         szValueBuf[0]=0;      
749     }
750
751     hr = MsiGetPropertyW( hInstall, szwName, szwValueBuf, pchValueBuf );
752
753     if(  *pchValueBuf > 0 )
754     {
755         WideCharToMultiByte(CP_ACP, 0, szwValueBuf, -1, szValueBuf, *pchValueBuf, NULL, NULL);
756     }
757
758 end:
759     if( szwName )
760         HeapFree( GetProcessHeap(), 0, szwName );
761     if( szwValueBuf )
762         HeapFree( GetProcessHeap(), 0, szwValueBuf );
763
764     return hr;
765 }
766
767 UINT MSI_GetPropertyW(MSIPACKAGE *package, LPCWSTR szName, 
768                            LPWSTR szValueBuf, DWORD* pchValueBuf)
769 {
770     MSIQUERY *view;
771     MSIRECORD *row;
772     UINT rc;
773     WCHAR Query[1024]=
774     {'s','e','l','e','c','t',' ','V','a','l','u','e',' ','f','r','o','m',' '
775      ,'_','P','r','o','p','e','r','t','y',' ','w','h','e','r','e',' '
776      ,'_','P','r','o','p','e','r','t','y','=','`',0};
777
778     static const WCHAR szEnd[]={'`',0};
779
780     if (NULL == szName) {
781       return ERROR_INVALID_PARAMETER;
782     }
783
784     strcatW(Query,szName);
785     strcatW(Query,szEnd);
786     
787     rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
788     if (rc == ERROR_SUCCESS)
789     {
790         DWORD sz;
791         WCHAR value[0x100];
792     
793         /* even on unsuccessful lookup native msi blanks this string */
794         if (*pchValueBuf > 0)
795             szValueBuf[0] = 0;
796             
797         rc = MSI_ViewExecute(view, 0);
798         if (rc != ERROR_SUCCESS)
799         {
800             MSI_ViewClose(view);
801             msiobj_release(&view->hdr);
802             return rc;
803         }
804
805         rc = MSI_ViewFetch(view,&row);
806         if (rc == ERROR_SUCCESS)
807         {
808             sz=0x100;
809             rc = MSI_RecordGetStringW(row,1,value,&sz);
810             strncpyW(szValueBuf,value,min(sz+1,*pchValueBuf));
811             *pchValueBuf = sz+1;
812             msiobj_release(&row->hdr);
813         }
814         MSI_ViewClose(view);
815         msiobj_release(&view->hdr);
816     }
817
818     if (rc == ERROR_SUCCESS)
819         TRACE("returning %s for property %s\n", debugstr_w(szValueBuf),
820             debugstr_w(szName));
821     else
822     {
823         *pchValueBuf = 0;
824         TRACE("property not found\n");
825     }
826
827     return rc;
828 }
829
830   
831 UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName, 
832                            LPWSTR szValueBuf, DWORD* pchValueBuf)
833 {
834     MSIPACKAGE *package;
835     UINT ret;
836
837     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
838     if( !package)
839         return ERROR_INVALID_HANDLE;
840     ret = MSI_GetPropertyW(package, szName, szValueBuf, pchValueBuf );
841     msiobj_release( &package->hdr );
842     return ret;
843 }