Reverse the order for deleting the items in resetcontent to correctly
[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         goto out;
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     if( package )
630         msiobj_release( &package->hdr );
631     if( record )
632         msiobj_release( &record->hdr );
633
634     return ret;
635 }
636
637 /* property code */
638 UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue)
639 {
640     LPWSTR szwName = NULL, szwValue = NULL;
641     UINT hr = ERROR_INSTALL_FAILURE;
642     UINT len;
643
644     if (0 == hInstall) {
645       return ERROR_INVALID_HANDLE;
646     }
647     if (NULL == szName) {
648       return ERROR_INVALID_PARAMETER;
649     }
650     if (NULL == szValue) {
651       return ERROR_INVALID_PARAMETER;
652     }
653
654     len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
655     szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
656     if( !szwName )
657         goto end;
658     MultiByteToWideChar( CP_ACP, 0, szName, -1, szwName, len );
659
660     len = MultiByteToWideChar( CP_ACP, 0, szValue, -1, NULL, 0 );
661     szwValue = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
662     if( !szwValue)
663         goto end;
664     MultiByteToWideChar( CP_ACP, 0, szValue , -1, szwValue, len );
665
666     hr = MsiSetPropertyW( hInstall, szwName, szwValue);
667
668 end:
669     HeapFree( GetProcessHeap(), 0, szwName );
670     HeapFree( GetProcessHeap(), 0, szwValue );
671
672     return hr;
673 }
674
675 UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
676 {
677     MSIQUERY *view;
678     MSIRECORD *row;
679     UINT rc;
680     DWORD sz = 0;
681     static const WCHAR Insert[]=
682      {'I','N','S','E','R','T',' ','i','n','t','o',' ','`','_','P','r','o','p'
683 ,'e','r','t','y','`',' ','(','`','_','P','r','o','p','e','r','t','y','`'
684 ,',','`','V','a','l','u','e','`',')',' ','V','A','L','U','E','S'
685 ,' ','(','?',',','?',')',0};
686     static const WCHAR Update[]=
687      {'U','P','D','A','T','E',' ','_','P','r','o','p','e'
688 ,'r','t','y',' ','s','e','t',' ','`','V','a','l','u','e','`',' ','='
689 ,' ','?',' ','w','h','e','r','e',' ','`','_','P','r','o','p'
690 ,'e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
691     WCHAR Query[1024];
692
693     TRACE("Setting property (%s %s)\n",debugstr_w(szName),
694           debugstr_w(szValue));
695
696     rc = MSI_GetPropertyW(package,szName,0,&sz);
697     if (rc==ERROR_MORE_DATA || rc == ERROR_SUCCESS)
698     {
699         sprintfW(Query,Update,szName);
700
701         row = MSI_CreateRecord(1);
702         MSI_RecordSetStringW(row,1,szValue);
703
704     }
705     else
706     {
707        strcpyW(Query,Insert);
708
709         row = MSI_CreateRecord(2);
710         MSI_RecordSetStringW(row,1,szName);
711         MSI_RecordSetStringW(row,2,szValue);
712     }
713
714
715     rc = MSI_DatabaseOpenViewW(package->db,Query,&view);
716     if (rc!= ERROR_SUCCESS)
717     {
718         msiobj_release(&row->hdr);
719         return rc;
720     }
721
722     rc = MSI_ViewExecute(view,row);
723
724     msiobj_release(&row->hdr);
725     MSI_ViewClose(view);
726     msiobj_release(&view->hdr);
727
728     return rc;
729 }
730
731 UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
732 {
733     MSIPACKAGE *package;
734     UINT ret;
735
736     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
737     if( !package)
738         return ERROR_INVALID_HANDLE;
739     ret = MSI_SetPropertyW( package, szName, szValue);
740     msiobj_release( &package->hdr );
741     return ret;
742 }
743
744 static UINT MSI_GetPropertyRow(MSIPACKAGE *package, LPCWSTR szName, MSIRECORD **row)
745 {
746     MSIQUERY *view;
747     UINT rc, sz;
748     static const WCHAR select[]=
749     {'s','e','l','e','c','t',' ','V','a','l','u','e',' ','f','r','o','m',' '
750      ,'_','P','r','o','p','e','r','t','y',' ','w','h','e','r','e',' '
751      ,'_','P','r','o','p','e','r','t','y','=','`','%','s','`',0};
752     LPWSTR query;
753
754     if (!szName)
755         return ERROR_INVALID_PARAMETER;
756
757     sz = sizeof select + strlenW(szName)*sizeof(WCHAR);
758     query = HeapAlloc(GetProcessHeap(), 0, sz);
759     sprintfW(query,select,szName);
760
761     rc = MSI_DatabaseOpenViewW(package->db, query, &view);
762     HeapFree(GetProcessHeap(), 0, query);
763     if (rc == ERROR_SUCCESS)
764     {
765         rc = MSI_ViewExecute(view, 0);
766         if (rc == ERROR_SUCCESS)
767             rc = MSI_ViewFetch(view,row);
768
769         MSI_ViewClose(view);
770         msiobj_release(&view->hdr);
771     }
772
773     return rc;
774 }
775
776 UINT MSI_GetPropertyW(MSIPACKAGE *package, LPCWSTR szName, 
777                            LPWSTR szValueBuf, DWORD* pchValueBuf)
778 {
779     MSIRECORD *row;
780     UINT rc;
781
782     rc = MSI_GetPropertyRow(package, szName, &row);
783
784     if (*pchValueBuf > 0)
785         szValueBuf[0] = 0;
786
787     if (rc == ERROR_SUCCESS)
788     {
789         rc = MSI_RecordGetStringW(row,1,szValueBuf,pchValueBuf);
790         msiobj_release(&row->hdr);
791     }
792
793     if (rc == ERROR_SUCCESS)
794         TRACE("returning %s for property %s\n", debugstr_w(szValueBuf),
795             debugstr_w(szName));
796     else if (rc == ERROR_MORE_DATA)
797         TRACE("need %li sized buffer for %s\n", *pchValueBuf,
798             debugstr_w(szName));
799     else
800     {
801         *pchValueBuf = 0;
802         TRACE("property not found\n");
803     }
804
805     return rc;
806 }
807
808 UINT MSI_GetPropertyA(MSIPACKAGE *package, LPCSTR szName, 
809                            LPSTR szValueBuf, DWORD* pchValueBuf)
810 {
811     MSIRECORD *row;
812     UINT rc, len;
813     LPWSTR szwName;
814
815     if (*pchValueBuf > 0)
816         szValueBuf[0] = 0;
817     
818     len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
819     szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
820     if (!szwName)
821         return ERROR_NOT_ENOUGH_MEMORY;
822     MultiByteToWideChar( CP_ACP, 0, szName, -1, szwName, len );
823
824     rc = MSI_GetPropertyRow(package, szwName, &row);
825     if (rc == ERROR_SUCCESS)
826     {
827         rc = MSI_RecordGetStringA(row,1,szValueBuf,pchValueBuf);
828         msiobj_release(&row->hdr);
829     }
830
831     if (rc == ERROR_SUCCESS)
832         TRACE("returning %s for property %s\n", debugstr_a(szValueBuf),
833             debugstr_a(szName));
834     else if (rc == ERROR_MORE_DATA)
835         TRACE("need %ld sized buffer for %s\n", *pchValueBuf,
836             debugstr_a(szName));
837     else
838     {
839         *pchValueBuf = 0;
840         TRACE("property not found\n");
841     }
842     HeapFree( GetProcessHeap(), 0, szwName );
843
844     return rc;
845 }
846
847 UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, DWORD* pchValueBuf) 
848 {
849     MSIPACKAGE *package;
850     UINT ret;
851
852     TRACE("%lu %s %lu\n", hInstall, debugstr_a(szName), *pchValueBuf);
853
854     if (0 == hInstall)
855         return ERROR_INVALID_HANDLE;
856     if (NULL == szName)
857         return ERROR_INVALID_PARAMETER;
858     if (NULL != szValueBuf && NULL == pchValueBuf)
859         return ERROR_INVALID_PARAMETER;
860
861     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
862     if (!package)
863         return ERROR_INVALID_HANDLE;
864     ret = MSI_GetPropertyA(package, szName, szValueBuf, pchValueBuf );
865     msiobj_release( &package->hdr );
866
867     /* MsiGetProperty does not return error codes on missing properties */
868     if (ret!= ERROR_MORE_DATA)
869         return ERROR_SUCCESS;
870     else
871         return ret;
872 }
873
874   
875 UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName, 
876                            LPWSTR szValueBuf, DWORD* pchValueBuf)
877 {
878     MSIPACKAGE *package;
879     UINT ret;
880
881     if (0 == hInstall)
882         return ERROR_INVALID_HANDLE;
883     if (NULL == szName)
884         return ERROR_INVALID_PARAMETER;
885     if (NULL != szValueBuf && NULL == pchValueBuf)
886         return ERROR_INVALID_PARAMETER;
887
888     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
889     if (!package)
890         return ERROR_INVALID_HANDLE;
891     ret = MSI_GetPropertyW(package, szName, szValueBuf, pchValueBuf );
892     msiobj_release( &package->hdr );
893
894     /* MsiGetProperty does not return error codes on missing properties */
895     if (ret!= ERROR_MORE_DATA)
896         return ERROR_SUCCESS;
897     else
898         return ret;
899 }