MsiGetProperty should return empty strings on error.
[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( VOID *arg);
52
53 void MSI_FreePackage( VOID *arg)
54 {
55     MSIPACKAGE *package= arg;
56
57     MsiCloseHandle(package->db);
58
59     ACTION_remove_tracked_tempfiles(package);
60
61     if (package->features && package->loaded_features > 0)
62         HeapFree(GetProcessHeap(),0,package->features);
63
64     if (package->folders && package->loaded_folders > 0)
65         HeapFree(GetProcessHeap(),0,package->folders);
66     
67     if (package->components && package->loaded_components > 0)
68         HeapFree(GetProcessHeap(),0,package->components);
69
70     if (package->files && package->loaded_files > 0)
71         HeapFree(GetProcessHeap(),0,package->files);
72 }
73
74 UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
75 {
76     LPWSTR szwPack = NULL;
77     UINT len, ret;
78
79     TRACE("%s %p\n",debugstr_a(szPackage), phPackage);
80
81     if( szPackage )
82     {
83         len = MultiByteToWideChar( CP_ACP, 0, szPackage, -1, NULL, 0 );
84         szwPack = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
85         if( szwPack )
86             MultiByteToWideChar( CP_ACP, 0, szPackage, -1, szwPack, len );
87     }
88
89     ret = MsiOpenPackageW( szwPack, phPackage );
90
91     if( szwPack )
92         HeapFree( GetProcessHeap(), 0, szwPack );
93
94     return ret;
95 }
96
97
98 static const void clone_properties(MSIHANDLE db)
99 {
100     MSIHANDLE view;
101     UINT rc;
102     static const CHAR CreateSql[] = "CREATE TABLE `_Property` ( `_Property` "
103 "CHAR(56) NOT NULL, `Value` CHAR(98) NOT NULL PRIMARY KEY `_Property`)";
104     static const CHAR Query[] = "SELECT * from Property";
105     static const CHAR Insert[] = 
106       "INSERT into `_Property` (`_Property`,`Value`) VALUES (?)";
107
108     /* create the temporary properties table */
109     MsiDatabaseOpenViewA(db, CreateSql, &view);
110     MsiViewExecute(view,0);   
111     MsiViewClose(view);
112     MsiCloseHandle(view); 
113
114     /* clone the existing properties */
115     MsiDatabaseOpenViewA(db, Query, &view);
116
117     MsiViewExecute(view, 0);
118     while (1)
119     {
120         MSIHANDLE row;
121         MSIHANDLE view2;
122
123         rc = MsiViewFetch(view,&row);
124         if (rc != ERROR_SUCCESS)
125             break;
126
127         MsiDatabaseOpenViewA(db,Insert,&view2);  
128         MsiViewExecute(view2,row);
129         MsiViewClose(view2);
130         MsiCloseHandle(view2);
131  
132         MsiCloseHandle(row); 
133     }
134     MsiViewClose(view);
135     MsiCloseHandle(view);
136     
137 }
138
139 /*
140  * There are a whole slew of these we need to set
141  *
142  *
143 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/properties.asp
144  */
145 static VOID set_installer_properties(MSIHANDLE hPackage)
146 {
147     WCHAR pth[MAX_PATH];
148     OSVERSIONINFOA OSVersion;
149     DWORD verval;
150     CHAR verstr[10];
151
152     static const WCHAR cszbs[]={'\\',0};
153     static const WCHAR CFF[] = 
154 {'C','o','m','m','o','n','F','i','l','e','s','F','o','l','d','e','r',0};
155     static const WCHAR PFF[] = 
156 {'P','r','o','g','r','a','m','F','i','l','e','s','F','o','l','d','e','r',0};
157     static const WCHAR CADF[] = 
158 {'C','o','m','m','o','n','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
159     static const WCHAR ATF[] = 
160 {'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0};
161     static const WCHAR ADF[] = 
162 {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
163     static const WCHAR SF[] = 
164 {'S','y','s','t','e','m','F','o','l','d','e','r',0};
165     static const WCHAR LADF[] = 
166 {'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
167     static const WCHAR MPF[] = 
168 {'M','y','P','i','c','t','u','r','e','s','F','o','l','d','e','r',0};
169     static const WCHAR PF[] = 
170 {'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0};
171     static const WCHAR WF[] = 
172 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
173     static const WCHAR TF[]=
174 {'T','e','m','p','F','o','l','d','e','r',0};
175
176 /* Not yet set ...  but needed by iTunes
177  *
178 DesktopFolder
179 FavoritesFolder
180 FontsFolder
181 PrimaryVolumePath
182 ProgramFiles64Folder
183 ProgramMenuFolder
184 SendToFolder
185 StartMenuFolder
186 StartupFolder
187 System16Folder
188 System64Folder
189 TemplateFolder
190  */
191
192 /* asked for by iTunes ... but are they installer set? 
193  *
194  *  GlobalAssemblyCache
195  */
196
197 /*
198  * Other things i notice set
199  *
200 ScreenY
201 ScreenX
202 SystemLanguageID
203 ComputerName
204 UserLanguageID
205 LogonUser
206 VirtualMemory
207 PhysicalMemory
208 Intel
209 ShellAdvSupport
210 DefaultUIFont
211 VersionMsi
212 VersionDatabase
213 PackagecodeChanging
214 ProductState
215 CaptionHeight
216 BorderTop
217 BorderSide
218 TextHeight
219 ColorBits
220 RedirectedDllSupport
221 Time
222 Date
223 Privilaged
224 */
225
226     SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth);
227     strcatW(pth,cszbs);
228     MsiSetPropertyW(hPackage, CFF, pth);
229
230     SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES,NULL,0,pth);
231     strcatW(pth,cszbs);
232     MsiSetPropertyW(hPackage, PFF, pth);
233
234     SHGetFolderPathW(NULL,CSIDL_COMMON_APPDATA,NULL,0,pth);
235     strcatW(pth,cszbs);
236     MsiSetPropertyW(hPackage, CADF, pth);
237
238     SHGetFolderPathW(NULL,CSIDL_ADMINTOOLS,NULL,0,pth);
239     strcatW(pth,cszbs);
240     MsiSetPropertyW(hPackage, ATF, pth);
241
242     SHGetFolderPathW(NULL,CSIDL_APPDATA,NULL,0,pth);
243     strcatW(pth,cszbs);
244     MsiSetPropertyW(hPackage, ADF, pth);
245
246     SHGetFolderPathW(NULL,CSIDL_SYSTEM,NULL,0,pth);
247     strcatW(pth,cszbs);
248     MsiSetPropertyW(hPackage, SF, pth);
249
250     SHGetFolderPathW(NULL,CSIDL_LOCAL_APPDATA,NULL,0,pth);
251     strcatW(pth,cszbs);
252     MsiSetPropertyW(hPackage, LADF, pth);
253
254     SHGetFolderPathW(NULL,CSIDL_MYPICTURES,NULL,0,pth);
255     strcatW(pth,cszbs);
256     MsiSetPropertyW(hPackage, MPF, pth);
257
258     SHGetFolderPathW(NULL,CSIDL_PERSONAL,NULL,0,pth);
259     strcatW(pth,cszbs);
260     MsiSetPropertyW(hPackage, PF, pth);
261
262     SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
263     strcatW(pth,cszbs);
264     MsiSetPropertyW(hPackage, WF, pth);
265
266     GetTempPathW(MAX_PATH,pth);
267     MsiSetPropertyW(hPackage, TF, pth);
268
269     /* in a wine enviroment the user is always admin and privlaged */
270     MsiSetPropertyA(hPackage,"AdminUser","1");
271     MsiSetPropertyA(hPackage,"Privileged","1");
272
273     /* set the os things */
274     OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
275     GetVersionExA(&OSVersion);
276     verval = OSVersion.dwMinorVersion+OSVersion.dwMajorVersion*100;
277     sprintf(verstr,"%li",verval);
278     switch (OSVersion.dwPlatformId)
279     {
280         case VER_PLATFORM_WIN32_WINDOWS:    
281             MsiSetPropertyA(hPackage,"Version9X",verstr);
282             break;
283         case VER_PLATFORM_WIN32_NT:
284             MsiSetPropertyA(hPackage,"VersionNT",verstr);
285             break;
286     }
287     sprintf(verstr,"%li",OSVersion.dwBuildNumber);
288     MsiSetPropertyA(hPackage,"WindowsBuild",verstr);
289     /* just fudge this */
290     MsiSetPropertyA(hPackage,"ServicePackLevel","6");
291 }
292
293
294 UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
295 {
296     UINT rc;
297     MSIHANDLE handle;
298     MSIHANDLE db;
299     MSIPACKAGE *package;
300     CHAR uilevel[10];
301
302     static const WCHAR OriginalDatabase[] =
303 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
304     static const WCHAR Database[] =
305 {'D','A','T','A','B','A','S','E',0};
306
307     TRACE("%s %p\n",debugstr_w(szPackage), phPackage);
308
309     rc = MsiOpenDatabaseW(szPackage, MSIDBOPEN_READONLY, &db);
310
311     if (rc != ERROR_SUCCESS)
312         return ERROR_FUNCTION_FAILED;
313
314     handle = alloc_msihandle(MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE),
315                              MSI_FreePackage, (void**)&package);
316
317     if (!handle)
318     {
319         MsiCloseHandle(db);
320         return ERROR_FUNCTION_FAILED;
321     }
322
323     package->db = db;
324     package->features = NULL;
325     package->folders = NULL;
326     package->components = NULL;
327     package->files = NULL;
328     package->loaded_features = 0;
329     package->loaded_folders = 0;
330     package->loaded_components= 0;
331     package->loaded_files = 0;
332
333     /* ok here is where we do a slew of things to the database to 
334      * prep for all that is to come as a package */
335
336     clone_properties(db);
337     set_installer_properties(handle);
338     MsiSetPropertyW(handle, OriginalDatabase, szPackage);
339     MsiSetPropertyW(handle, Database, szPackage);
340     sprintf(uilevel,"%i",gUILevel);
341     MsiSetPropertyA(handle, "UILevel", uilevel);
342
343     *phPackage = handle;
344
345     return ERROR_SUCCESS;
346 }
347
348 UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
349 {
350     FIXME("%s 0x%08lx %p\n",debugstr_a(szPackage), dwOptions, phPackage);
351     return ERROR_CALL_NOT_IMPLEMENTED;
352 }
353
354 UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
355 {
356     FIXME("%s 0x%08lx %p\n",debugstr_w(szPackage), dwOptions, phPackage);
357     return ERROR_CALL_NOT_IMPLEMENTED;
358 }
359
360 MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
361 {
362     MSIPACKAGE *package;
363
364     TRACE("(%ld)\n",hInstall);
365
366     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
367
368     if( !package)
369         return ERROR_INVALID_HANDLE;
370
371     msihandle_addref(package->db);
372     return package->db;
373 }
374
375 INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
376                               MSIHANDLE hRecord)
377 {
378     DWORD log_type = 0;
379     LPSTR message;
380     DWORD sz;
381     DWORD total_size = 0;
382     INT msg_field=1;
383     INT i;
384     TRACE("%x \n",eMessageType);
385
386     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR)
387         log_type |= INSTALLLOGMODE_ERROR;
388     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_WARNING)
389         log_type |= INSTALLLOGMODE_WARNING;
390     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_USER)
391         log_type |= INSTALLLOGMODE_USER;
392     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INFO)
393         log_type |= INSTALLLOGMODE_INFO;
394     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA)
395         log_type |= INSTALLLOGMODE_COMMONDATA;
396     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
397         log_type |= INSTALLLOGMODE_ACTIONSTART;
398     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONDATA)
399         log_type |= INSTALLLOGMODE_ACTIONDATA;
400     /* just a guess */
401     if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS)
402         log_type |= 0x800;
403
404     message = HeapAlloc(GetProcessHeap(),0,1);
405     message[0]=0;
406     msg_field = MsiRecordGetFieldCount(hRecord);
407     for (i = 1; i <= msg_field; i++)
408     {
409         LPSTR tmp;
410         CHAR number[3];
411         sz = 0;
412         MsiRecordGetStringA(hRecord,i,NULL,&sz);
413         sz+=4;
414         total_size+=sz;
415         tmp = HeapAlloc(GetProcessHeap(),0,sz);
416         message = HeapReAlloc(GetProcessHeap(),0,message,total_size);
417
418         MsiRecordGetStringA(hRecord,i,tmp,&sz);
419
420         if (msg_field > 1)
421         {
422             sprintf(number,"%i: ",i);
423             strcat(message,number);
424         }
425         strcat(message,tmp);
426         if (msg_field > 1)
427             strcat(message," ");
428
429         HeapFree(GetProcessHeap(),0,tmp);
430     }
431
432     TRACE("(%p %lx %lx %s)\n",gUIHandler, gUIFilter, log_type,
433                              debugstr_a(message));
434
435     if (gUIHandler && (gUIFilter & log_type))
436         gUIHandler(gUIContext,eMessageType,message);
437
438     HeapFree(GetProcessHeap(),0,message);
439     return ERROR_SUCCESS;
440 }
441
442 /* property code */
443 UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue)
444 {
445     LPWSTR szwName = NULL, szwValue = NULL;
446     UINT hr = ERROR_INSTALL_FAILURE;
447     UINT len;
448
449     if (0 == hInstall) {
450       return ERROR_INVALID_HANDLE;
451     }
452     if (NULL == szName) {
453       return ERROR_INVALID_PARAMETER;
454     }
455     if (NULL == szValue) {
456       return ERROR_INVALID_PARAMETER;
457     }
458
459     len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
460     szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
461     if( !szwName )
462         goto end;
463     MultiByteToWideChar( CP_ACP, 0, szName, -1, szwName, len );
464
465     len = MultiByteToWideChar( CP_ACP, 0, szValue, -1, NULL, 0 );
466     szwValue = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
467     if( !szwValue)
468         goto end;
469     MultiByteToWideChar( CP_ACP, 0, szValue , -1, szwValue, len );
470
471     hr = MsiSetPropertyW( hInstall, szwName, szwValue);
472
473 end:
474     if( szwName )
475         HeapFree( GetProcessHeap(), 0, szwName );
476     if( szwValue )
477         HeapFree( GetProcessHeap(), 0, szwValue );
478
479     return hr;
480 }
481
482 UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
483 {
484     MSIPACKAGE *package;
485     MSIHANDLE view,row;
486     UINT rc;
487     DWORD sz = 0;
488     static const WCHAR Insert[]=
489      {'I','N','S','E','R','T',' ','i','n','t','o',' ','`','_','P','r','o','p'
490 ,'e','r','t','y','`',' ','(','`','_','P','r','o','p','e','r','t','y','`'
491 ,',','`','V','a','l','u','e','`',')',' ','V','A','L','U','E','S'
492 ,' ','(','?',')',0};
493     static const WCHAR Update[]=
494      {'U','P','D','A','T','E',' ','_','P','r','o','p','e'
495 ,'r','t','y',' ','s','e','t',' ','`','V','a','l','u','e','`',' ','='
496 ,' ','?',' ','w','h','e','r','e',' ','`','_','P','r','o','p'
497 ,'e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
498     WCHAR Query[1024];
499
500     TRACE("Setting property (%s %s)\n",debugstr_w(szName),
501           debugstr_w(szValue));
502
503     if (!hInstall)
504         return ERROR_INVALID_HANDLE;
505
506     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
507     if( !package)
508         return ERROR_INVALID_HANDLE;
509
510     rc = MsiGetPropertyW(hInstall,szName,0,&sz);
511     if (rc==ERROR_MORE_DATA || rc == ERROR_SUCCESS)
512     {
513         sprintfW(Query,Update,szName);
514
515         row = MsiCreateRecord(1);
516         MsiRecordSetStringW(row,1,szValue);
517
518     }
519     else
520     {
521        strcpyW(Query,Insert);
522
523         row = MsiCreateRecord(2);
524         MsiRecordSetStringW(row,1,szName);
525         MsiRecordSetStringW(row,2,szValue);
526     }
527
528
529     rc = MsiDatabaseOpenViewW(package->db,Query,&view);
530     if (rc!= ERROR_SUCCESS)
531     {
532         MsiCloseHandle(row);
533         return rc;
534     }
535
536     rc = MsiViewExecute(view,row);
537
538     MsiCloseHandle(row);
539     MsiViewClose(view);
540     MsiCloseHandle(view);
541
542     return rc;
543 }
544
545 UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, DWORD* pchValueBuf) 
546 {
547     LPWSTR szwName = NULL, szwValueBuf = NULL;
548     UINT hr = ERROR_INSTALL_FAILURE;
549
550     if (0 == hInstall) {
551       return ERROR_INVALID_HANDLE;
552     }
553     if (NULL == szName) {
554       return ERROR_INVALID_PARAMETER;
555     }
556
557     TRACE("%lu %s %lu\n", hInstall, debugstr_a(szName), *pchValueBuf);
558
559     if (NULL != szValueBuf && NULL == pchValueBuf) {
560       return ERROR_INVALID_PARAMETER;
561     }
562     if( szName )
563     {
564         UINT len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
565         szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
566         if( !szwName )
567             goto end;
568         MultiByteToWideChar( CP_ACP, 0, szName, -1, szwName, len );
569     } else {
570       return ERROR_INVALID_PARAMETER;
571     }
572     if( szValueBuf )
573     {
574         szwValueBuf = HeapAlloc( GetProcessHeap(), 0, (*pchValueBuf) * sizeof(WCHAR) );
575         if( !szwValueBuf )       
576             goto end;
577     }
578
579     if(  *pchValueBuf > 0 )
580     {
581         /* be sure to blank the string first */
582         szValueBuf[0]=0;      
583     }
584
585     hr = MsiGetPropertyW( hInstall, szwName, szwValueBuf, pchValueBuf );
586
587     if(  *pchValueBuf > 0 )
588     {
589         WideCharToMultiByte(CP_ACP, 0, szwValueBuf, -1, szValueBuf, *pchValueBuf, NULL, NULL);
590     }
591
592 end:
593     if( szwName )
594         HeapFree( GetProcessHeap(), 0, szwName );
595     if( szwValueBuf )
596         HeapFree( GetProcessHeap(), 0, szwValueBuf );
597
598     return hr;
599 }
600
601 UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName, 
602                            LPWSTR szValueBuf, DWORD* pchValueBuf)
603 {
604     MSIHANDLE view,row;
605     UINT rc;
606     WCHAR Query[1024]=
607     {'s','e','l','e','c','t',' ','V','a','l','u','e',' ','f','r','o','m',' '
608      ,'_','P','r','o','p','e','r','t','y',' ','w','h','e','r','e',' '
609      ,'_','P','r','o','p','e','r','t','y','=','`',0};
610
611     static const WCHAR szEnd[]={'`',0};
612     MSIPACKAGE *package;
613
614     if (0 == hInstall) {
615       return ERROR_INVALID_HANDLE;
616     }
617     if (NULL == szName) {
618       return ERROR_INVALID_PARAMETER;
619     }
620
621     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
622     if( !package)
623         return ERROR_INVALID_HANDLE;
624
625     strcatW(Query,szName);
626     strcatW(Query,szEnd);
627     
628     rc = MsiDatabaseOpenViewW(package->db, Query, &view);
629     if (rc == ERROR_SUCCESS)
630     {
631         DWORD sz;
632         WCHAR value[0x100];
633     
634         /* even on unsuccessful lookup native msi blanks this string */
635         if (*pchValueBuf > 0)
636             szValueBuf[0] = 0;
637             
638         rc = MsiViewExecute(view, 0);
639         if (rc != ERROR_SUCCESS)
640         {
641             MsiViewClose(view);
642             MsiCloseHandle(view);
643             return rc;
644         }
645
646         rc = MsiViewFetch(view,&row);
647         if (rc == ERROR_SUCCESS)
648         {
649             sz=0x100;
650             rc = MsiRecordGetStringW(row,1,value,&sz);
651             strncpyW(szValueBuf,value,min(sz+1,*pchValueBuf));
652             *pchValueBuf = sz+1;
653             MsiCloseHandle(row);
654         }
655         MsiViewClose(view);
656         MsiCloseHandle(view);
657     }
658
659     if (rc == ERROR_SUCCESS)
660         TRACE("returning %s for property %s\n", debugstr_w(szValueBuf),
661             debugstr_w(szName));
662     else
663     {
664         *pchValueBuf = 0;
665         TRACE("property not found\n");
666     }
667
668     return rc;
669 }