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