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