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