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