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