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