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