Moved mciavi32 to the top-level dlls directory.
[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         list_init( &package->components );
381         list_init( &package->features );
382         list_init( &package->files );
383         list_init( &package->folders );
384         package->ActionFormat = NULL;
385         package->LastAction = NULL;
386         package->dialog = NULL;
387         package->next_dialog = NULL;
388         list_init( &package->subscriptions );
389
390         /* OK, here is where we do a slew of things to the database to 
391          * prep for all that is to come as a package */
392
393         clone_properties(db);
394         set_installer_properties(package);
395         sprintfW(uilevel,szpi,gUILevel);
396         MSI_SetPropertyW(package, szLevel, uilevel);
397     }
398
399     return package;
400 }
401
402 UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
403 {
404     MSIDATABASE *db = NULL;
405     MSIPACKAGE *package;
406     MSIHANDLE handle;
407     DWORD size;
408     static const WCHAR szProductCode[]= {'P','r','o','d','u','c','t','C','o','d','e',0};
409
410     TRACE("%s %p\n", debugstr_w(szPackage), pPackage);
411
412     if( szPackage[0] == '#' )
413     {
414         handle = atoiW(&szPackage[1]);
415         db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
416         if( !db )
417             return ERROR_INVALID_HANDLE;
418     }
419     else
420     {
421         UINT r = MSI_OpenDatabaseW(szPackage, MSIDBOPEN_READONLY, &db);
422         if( r != ERROR_SUCCESS )
423             return r;
424     }
425
426     package = MSI_CreatePackage( db );
427     msiobj_release( &db->hdr );
428     if( !package )
429         return ERROR_FUNCTION_FAILED;
430
431     /* 
432      * FIXME:  I don't think this is right.  Maybe we should be storing the
433      * name of the database in the MSIDATABASE structure and fetching this
434      * info from there, or maybe this is only relevant to cached databases.
435      */
436     if( szPackage[0] != '#' )
437     {
438         static const WCHAR OriginalDatabase[] =
439           {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
440         static const WCHAR Database[] = {'D','A','T','A','B','A','S','E',0};
441
442         MSI_SetPropertyW( package, OriginalDatabase, szPackage );
443         MSI_SetPropertyW( package, Database, szPackage );
444     }
445
446     /* this property must exist */
447     size  = 0;
448     MSI_GetPropertyW(package,szProductCode,NULL,&size);
449     size ++;
450     package->ProductCode = HeapAlloc(GetProcessHeap(),0,size * sizeof(WCHAR));
451     MSI_GetPropertyW(package,szProductCode,package->ProductCode, &size);
452     
453     *pPackage = package;
454
455     return ERROR_SUCCESS;
456 }
457
458 UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
459 {
460     MSIPACKAGE *package = NULL;
461     UINT ret;
462     WCHAR path[MAX_PATH];
463     WCHAR filename[MAX_PATH];
464     static const WCHAR szMSI[] = {'M','S','I',0};
465
466     TRACE("%s %08lx %p\n",debugstr_w(szPackage), dwOptions, phPackage);
467
468     /* copy the msi file to a temp file to pervent locking a CD
469      * with a multi disc install 
470      */ 
471     if( szPackage[0] == '#' )
472         strcpyW(filename,szPackage);
473     else
474     {
475         GetTempPathW(MAX_PATH, path);
476         GetTempFileNameW(path, szMSI, 0, filename);
477
478         CopyFileW(szPackage, filename, FALSE);
479
480         TRACE("Opening relocated package %s\n",debugstr_w(filename));
481     }
482     
483     if( dwOptions )
484         FIXME("dwOptions %08lx not supported\n", dwOptions);
485
486     ret = MSI_OpenPackageW( filename, &package);
487     if( ret == ERROR_SUCCESS )
488     {
489         *phPackage = alloc_msihandle( &package->hdr );
490         msiobj_release( &package->hdr );
491     }
492
493     if( szPackage[0] != '#' )
494         DeleteFileW(filename);
495
496     return ret;
497 }
498
499 UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
500 {
501     return MsiOpenPackageExW( szPackage, 0, phPackage );
502 }
503
504 UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
505 {
506     LPWSTR szwPack = NULL;
507     UINT ret;
508
509     if( szPackage )
510     {
511         szwPack = strdupAtoW( szPackage );
512         if( !szwPack )
513             return ERROR_OUTOFMEMORY;
514     }
515
516     ret = MsiOpenPackageExW( szwPack, dwOptions, phPackage );
517
518     HeapFree( GetProcessHeap(), 0, szwPack );
519
520     return ret;
521 }
522
523 UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
524 {
525     return MsiOpenPackageExA( szPackage, 0, phPackage );
526 }
527
528 MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
529 {
530     MSIPACKAGE *package;
531     MSIHANDLE handle = 0;
532
533     TRACE("(%ld)\n",hInstall);
534
535     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
536     if( package)
537     {
538         handle = alloc_msihandle( &package->db->hdr );
539         msiobj_release( &package->hdr );
540     }
541
542     return handle;
543 }
544
545 INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
546                                MSIRECORD *record)
547 {
548     DWORD log_type = 0;
549     LPWSTR message;
550     DWORD sz;
551     DWORD total_size = 0;
552     INT msg_field=1;
553     INT i;
554     INT rc;
555     char *msg;
556     int len;
557
558     TRACE("%x \n",eMessageType);
559     rc = 0;
560
561     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR)
562         log_type |= INSTALLLOGMODE_ERROR;
563     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_WARNING)
564         log_type |= INSTALLLOGMODE_WARNING;
565     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_USER)
566         log_type |= INSTALLLOGMODE_USER;
567     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INFO)
568         log_type |= INSTALLLOGMODE_INFO;
569     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA)
570         log_type |= INSTALLLOGMODE_COMMONDATA;
571     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
572         log_type |= INSTALLLOGMODE_ACTIONSTART;
573     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONDATA)
574         log_type |= INSTALLLOGMODE_ACTIONDATA;
575     /* just a guess */
576     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS)
577         log_type |= 0x800;
578
579     message = HeapAlloc(GetProcessHeap(),0,1*sizeof (WCHAR));
580     message[0]=0;
581     msg_field = MSI_RecordGetFieldCount(record);
582     for (i = 1; i <= msg_field; i++)
583     {
584         LPWSTR tmp;
585         WCHAR number[3];
586         const static WCHAR format[] = { '%','i',':',' ',0};
587         const static WCHAR space[] = { ' ',0};
588         sz = 0;
589         MSI_RecordGetStringW(record,i,NULL,&sz);
590         sz+=4;
591         total_size+=sz*sizeof(WCHAR);
592         tmp = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
593         message = HeapReAlloc(GetProcessHeap(),0,message,total_size*sizeof (WCHAR));
594
595         MSI_RecordGetStringW(record,i,tmp,&sz);
596
597         if (msg_field > 1)
598         {
599             sprintfW(number,format,i);
600             strcatW(message,number);
601         }
602         strcatW(message,tmp);
603         if (msg_field > 1)
604             strcatW(message,space);
605
606         HeapFree(GetProcessHeap(),0,tmp);
607     }
608
609     TRACE("(%p %lx %lx %s)\n",gUIHandlerA, gUIFilter, log_type,
610                              debugstr_w(message));
611
612     /* convert it to ASCII */
613     len = WideCharToMultiByte( CP_ACP, 0, message, -1,
614                                NULL, 0, NULL, NULL );
615     msg = HeapAlloc( GetProcessHeap(), 0, len );
616     WideCharToMultiByte( CP_ACP, 0, message, -1,
617                          msg, len, NULL, NULL );
618
619     if (gUIHandlerA && (gUIFilter & log_type))
620     {
621         rc = gUIHandlerA(gUIContext,eMessageType,msg);
622     }
623
624     if ((!rc) && (gszLogFile[0]) && !((eMessageType & 0xff000000) ==
625                                       INSTALLMESSAGE_PROGRESS))
626     {
627         DWORD write;
628         HANDLE log_file = CreateFileW(gszLogFile,GENERIC_WRITE, 0, NULL,
629                                   OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
630
631         if (log_file != INVALID_HANDLE_VALUE)
632         {
633             SetFilePointer(log_file,0, NULL, FILE_END);
634             WriteFile(log_file,msg,strlen(msg),&write,NULL);
635             WriteFile(log_file,"\n",1,&write,NULL);
636             CloseHandle(log_file);
637         }
638     }
639     HeapFree( GetProcessHeap(), 0, msg );
640     
641     HeapFree(GetProcessHeap(),0,message);
642     return ERROR_SUCCESS;
643 }
644
645 INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
646                               MSIHANDLE hRecord)
647 {
648     UINT ret = ERROR_INVALID_HANDLE;
649     MSIPACKAGE *package = NULL;
650     MSIRECORD *record = NULL;
651
652     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
653     if( !package )
654         return ERROR_INVALID_HANDLE;
655
656     record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
657     if( !record )
658         goto out;
659
660     ret = MSI_ProcessMessage( package, eMessageType, record );
661
662 out:
663     msiobj_release( &package->hdr );
664     if( record )
665         msiobj_release( &record->hdr );
666
667     return ret;
668 }
669
670 /* property code */
671 UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue)
672 {
673     LPWSTR szwName = NULL, szwValue = NULL;
674     UINT hr = ERROR_INSTALL_FAILURE;
675
676     if( szName )
677     {
678         szwName = strdupAtoW( szName );
679         if( !szwName )
680             goto end;
681     }
682
683     if( szValue )
684     {
685         szwValue = strdupAtoW( szValue );
686         if( !szwValue)
687             goto end;
688     }
689
690     hr = MsiSetPropertyW( hInstall, szwName, szwValue);
691
692 end:
693     HeapFree( GetProcessHeap(), 0, szwName );
694     HeapFree( GetProcessHeap(), 0, szwValue );
695
696     return hr;
697 }
698
699 UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
700 {
701     MSIQUERY *view;
702     MSIRECORD *row;
703     UINT rc;
704     DWORD sz = 0;
705     static const WCHAR Insert[]=
706      {'I','N','S','E','R','T',' ','i','n','t','o',' ','`','_','P','r','o','p'
707 ,'e','r','t','y','`',' ','(','`','_','P','r','o','p','e','r','t','y','`'
708 ,',','`','V','a','l','u','e','`',')',' ','V','A','L','U','E','S'
709 ,' ','(','?',',','?',')',0};
710     static const WCHAR Update[]=
711      {'U','P','D','A','T','E',' ','_','P','r','o','p','e'
712 ,'r','t','y',' ','s','e','t',' ','`','V','a','l','u','e','`',' ','='
713 ,' ','?',' ','w','h','e','r','e',' ','`','_','P','r','o','p'
714 ,'e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
715     WCHAR Query[1024];
716
717     TRACE("Setting property (%s %s)\n",debugstr_w(szName),
718           debugstr_w(szValue));
719
720     rc = MSI_GetPropertyW(package,szName,0,&sz);
721     if (rc==ERROR_MORE_DATA || rc == ERROR_SUCCESS)
722     {
723         sprintfW(Query,Update,szName);
724
725         row = MSI_CreateRecord(1);
726         MSI_RecordSetStringW(row,1,szValue);
727
728     }
729     else
730     {
731         strcpyW(Query,Insert);
732
733         row = MSI_CreateRecord(2);
734         MSI_RecordSetStringW(row,1,szName);
735         MSI_RecordSetStringW(row,2,szValue);
736     }
737
738
739     rc = MSI_DatabaseOpenViewW(package->db,Query,&view);
740     if (rc!= ERROR_SUCCESS)
741     {
742         msiobj_release(&row->hdr);
743         return rc;
744     }
745
746     rc = MSI_ViewExecute(view,row);
747
748     msiobj_release(&row->hdr);
749     MSI_ViewClose(view);
750     msiobj_release(&view->hdr);
751
752     return rc;
753 }
754
755 UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
756 {
757     MSIPACKAGE *package;
758     UINT ret;
759
760     if (NULL == szName)
761         return ERROR_INVALID_PARAMETER;
762     if (NULL == szValue)
763         return ERROR_INVALID_PARAMETER;
764
765     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
766     if( !package )
767         return ERROR_INVALID_HANDLE;
768     ret = MSI_SetPropertyW( package, szName, szValue);
769     msiobj_release( &package->hdr );
770     return ret;
771 }
772
773 static UINT MSI_GetPropertyRow(MSIPACKAGE *package, LPCWSTR szName, MSIRECORD **row)
774 {
775     MSIQUERY *view;
776     UINT rc, sz;
777     static const WCHAR select[]=
778     {'S','E','L','E','C','T',' ','`','V','a','l','u','e','`',' ',
779      'F','R','O','M',' ' ,'`','_','P','r','o','p','e','r','t','y','`',
780      ' ','W','H','E','R','E',' ' ,'`','_','P','r','o','p','e','r','t','y','`',
781      '=','\'','%','s','\'',0};
782     LPWSTR query;
783
784     if (!szName)
785         return ERROR_INVALID_PARAMETER;
786
787     sz = sizeof select + strlenW(szName)*sizeof(WCHAR);
788     query = HeapAlloc(GetProcessHeap(), 0, sz);
789     sprintfW(query,select,szName);
790
791     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
792     HeapFree(GetProcessHeap(), 0, query);
793     if (rc == ERROR_SUCCESS)
794     {
795         rc = MSI_ViewExecute(view, 0);
796         if (rc == ERROR_SUCCESS)
797             rc = MSI_ViewFetch(view,row);
798
799         MSI_ViewClose(view);
800         msiobj_release(&view->hdr);
801     }
802
803     return rc;
804 }
805
806 UINT MSI_GetPropertyW(MSIPACKAGE *package, LPCWSTR szName, 
807                            LPWSTR szValueBuf, DWORD* pchValueBuf)
808 {
809     MSIRECORD *row;
810     UINT rc;
811
812     rc = MSI_GetPropertyRow(package, szName, &row);
813
814     if (*pchValueBuf > 0)
815         szValueBuf[0] = 0;
816
817     if (rc == ERROR_SUCCESS)
818     {
819         rc = MSI_RecordGetStringW(row,1,szValueBuf,pchValueBuf);
820         msiobj_release(&row->hdr);
821     }
822
823     if (rc == ERROR_SUCCESS)
824         TRACE("returning %s for property %s\n", debugstr_w(szValueBuf),
825             debugstr_w(szName));
826     else if (rc == ERROR_MORE_DATA)
827         TRACE("need %li sized buffer for %s\n", *pchValueBuf,
828             debugstr_w(szName));
829     else
830     {
831         *pchValueBuf = 0;
832         TRACE("property %s not found\n", debugstr_w(szName));
833     }
834
835     return rc;
836 }
837
838 UINT MSI_GetPropertyA(MSIPACKAGE *package, LPCSTR szName, 
839                            LPSTR szValueBuf, DWORD* pchValueBuf)
840 {
841     MSIRECORD *row;
842     UINT rc;
843     LPWSTR szwName = NULL;
844
845     if (*pchValueBuf > 0)
846         szValueBuf[0] = 0;
847     
848     if( szName )
849     {
850         szwName = strdupAtoW( szName );
851         if (!szwName)
852             return ERROR_NOT_ENOUGH_MEMORY;
853     }
854
855     rc = MSI_GetPropertyRow(package, szwName, &row);
856     if (rc == ERROR_SUCCESS)
857     {
858         rc = MSI_RecordGetStringA(row,1,szValueBuf,pchValueBuf);
859         msiobj_release(&row->hdr);
860     }
861
862     if (rc == ERROR_SUCCESS)
863         TRACE("returning %s for property %s\n", debugstr_a(szValueBuf),
864             debugstr_a(szName));
865     else if (rc == ERROR_MORE_DATA)
866         TRACE("need %ld sized buffer for %s\n", *pchValueBuf,
867             debugstr_a(szName));
868     else
869     {
870         *pchValueBuf = 0;
871         TRACE("property not found\n");
872     }
873     HeapFree( GetProcessHeap(), 0, szwName );
874
875     return rc;
876 }
877
878 UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, DWORD* pchValueBuf) 
879 {
880     MSIPACKAGE *package;
881     UINT ret;
882
883     TRACE("%lu %s %lu\n", hInstall, debugstr_a(szName), *pchValueBuf);
884
885     if (0 == hInstall)
886         return ERROR_INVALID_HANDLE;
887     if (NULL == szName)
888         return ERROR_INVALID_PARAMETER;
889     if (NULL != szValueBuf && NULL == pchValueBuf)
890         return ERROR_INVALID_PARAMETER;
891
892     /* This was tested against native msi */
893     if (NULL == szValueBuf && NULL != pchValueBuf)
894         *pchValueBuf = 0;
895
896     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
897     if (!package)
898         return ERROR_INVALID_HANDLE;
899     ret = MSI_GetPropertyA(package, szName, szValueBuf, pchValueBuf );
900     msiobj_release( &package->hdr );
901
902     /* MsiGetProperty does not return error codes on missing properties */
903     if (ret!= ERROR_MORE_DATA)
904         return ERROR_SUCCESS;
905     else
906         return ret;
907 }
908
909   
910 UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName, 
911                            LPWSTR szValueBuf, DWORD* pchValueBuf)
912 {
913     MSIPACKAGE *package;
914     UINT ret;
915
916     if (0 == hInstall)
917         return ERROR_INVALID_HANDLE;
918     if (NULL == szName)
919         return ERROR_INVALID_PARAMETER;
920     if (NULL != szValueBuf && NULL == pchValueBuf)
921         return ERROR_INVALID_PARAMETER;
922
923     /* This was tested against native msi */
924     if (NULL == szValueBuf && NULL != pchValueBuf)
925         *pchValueBuf = 0;
926
927     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
928     if (!package)
929         return ERROR_INVALID_HANDLE;
930     ret = MSI_GetPropertyW(package, szName, szValueBuf, pchValueBuf );
931     msiobj_release( &package->hdr );
932
933     /* MsiGetProperty does not return error codes on missing properties */
934     if (ret!= ERROR_MORE_DATA)
935         return ERROR_SUCCESS;
936     else
937         return ret;
938 }