Implement MsiVerifyPackage, cosmetic fixes.
[wine/multimedia.git] / dlls / msi / package.c
blob287209008ed90c611b0532bc455391992cf781b1
1 /*
2 * Implementation of the Microsoft Installer (msi.dll)
4 * Copyright 2004 Aric Stewart for CodeWeavers
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.
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.
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
21 #define NONAMELESSUNION
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"
41 WINE_DEFAULT_DEBUG_CHANNEL(msi);
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.
49 #define LPCTSTR LPCWSTR
51 void MSI_FreePackage( MSIOBJECTHDR *arg)
53 MSIPACKAGE *package= (MSIPACKAGE*) arg;
55 ACTION_remove_tracked_tempfiles(package);
57 if (package->features && package->loaded_features > 0)
58 HeapFree(GetProcessHeap(),0,package->features);
60 if (package->folders && package->loaded_folders > 0)
61 HeapFree(GetProcessHeap(),0,package->folders);
63 if (package->components && package->loaded_components > 0)
64 HeapFree(GetProcessHeap(),0,package->components);
66 if (package->files && package->loaded_files > 0)
67 HeapFree(GetProcessHeap(),0,package->files);
68 msiobj_release( &package->db->hdr );
71 UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
73 LPWSTR szwPack = NULL;
74 UINT len, ret;
76 TRACE("%s %p\n",debugstr_a(szPackage), phPackage);
78 if( szPackage )
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 );
86 ret = MsiOpenPackageW( szwPack, phPackage );
88 if( szwPack )
89 HeapFree( GetProcessHeap(), 0, szwPack );
91 return ret;
95 static const UINT clone_properties(MSIDATABASE *db)
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};
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;
126 /* clone the existing properties */
127 rc = MSI_DatabaseOpenViewW(db, Query, &view);
128 if (rc != ERROR_SUCCESS)
129 return rc;
131 rc = MSI_ViewExecute(view, 0);
132 if (rc != ERROR_SUCCESS)
134 MSI_ViewClose(view);
135 msiobj_release(&view->hdr);
136 return rc;
138 while (1)
140 MSIRECORD * row;
141 MSIQUERY * view2;
143 rc = MSI_ViewFetch(view,&row);
144 if (rc != ERROR_SUCCESS)
145 break;
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);
154 if (rc == ERROR_SUCCESS)
155 msiobj_release(&row->hdr);
157 MSI_ViewClose(view);
158 msiobj_release(&view->hdr);
160 return rc;
164 * There are a whole slew of these we need to set
167 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/properties.asp
169 static VOID set_installer_properties(MSIPACKAGE *package)
171 WCHAR pth[MAX_PATH];
172 OSVERSIONINFOA OSVersion;
173 DWORD verval;
174 WCHAR verstr[10];
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 ATF[] =
184 {'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0};
185 static const WCHAR ADF[] =
186 {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
187 static const WCHAR SF[] =
188 {'S','y','s','t','e','m','F','o','l','d','e','r',0};
189 static const WCHAR LADF[] =
190 {'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
191 static const WCHAR MPF[] =
192 {'M','y','P','i','c','t','u','r','e','s','F','o','l','d','e','r',0};
193 static const WCHAR PF[] =
194 {'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0};
195 static const WCHAR WF[] =
196 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
197 static const WCHAR TF[]=
198 {'T','e','m','p','F','o','l','d','e','r',0};
199 static const WCHAR szAdminUser[] =
200 {'A','d','m','i','n','U','s','e','r',0};
201 static const WCHAR szPriv[] =
202 {'P','r','i','v','i','l','e','g','e','d',0};
203 static const WCHAR szOne[] =
204 {'1',0};
205 static const WCHAR v9x[] = { 'V','e','r','s','i','o','n','9','X',0 };
206 static const WCHAR vNT[] = { 'V','e','r','s','i','o','n','N','T',0 };
207 static const WCHAR szFormat[] = {'%','l','i',0};
208 static const WCHAR szWinBuild[] =
209 {'W','i','n','d','o','w','s','B','u','i','l','d', 0 };
210 static const WCHAR szSPL[] =
211 {'S','e','r','v','i','c','e','P','a','c','k','L','e','v','e','l',0 };
212 static const WCHAR szSix[] = {'6',0 };
214 /* these need to be dynamically descovered sometime */
216 static const WCHAR ProgramMenuFolder[] =
217 {'P','r','o','g','r','a','m','M','e','n','u','F','o','l','d','e','r',0};
218 static const WCHAR PMFPath[] =
219 {'C',':','\\','W','i','n','d','o','w','s','\\','S','t','a','r','t',' ',
220 'M','e','n','u','\\','P','r','o','g','r','a','m','s','\\',0};
221 static const WCHAR FavoritesFolder[] =
222 {'F','a','v','o','r','i','t','e','s','F','o','l','d','e','r',0};
223 static const WCHAR FFPath[] =
224 {'C',':','\\','W','i','n','d','o','w','s','\\',
225 'F','a','v','o','r','i','t','e','s','\\',0};
226 static const WCHAR FontsFolder[] =
227 {'F','o','n','t','s','F','o','l','d','e','r',0};
228 static const WCHAR FoFPath[] =
229 {'C',':','\\','W','i','n','d','o','w','s','\\','F','o','n','t','s','\\',0};
230 static const WCHAR SendToFolder[] =
231 {'S','e','n','d','T','o','F','o','l','d','e','r',0};
232 static const WCHAR STFPath[] =
233 {'C',':','\\','W','i','n','d','o','w','s','\\','S','e','n','d','T','o','\\',0};
234 static const WCHAR StartMenuFolder[] =
235 {'S','t','a','r','t','M','e','n','u','F','o','l','d','e','r',0};
236 static const WCHAR SMFPath[] =
237 {'C',':','\\','W','i','n','d','o','w','s','\\','S','t','a','r','t',' ',
238 'M','e','n','u','\\',0};
239 static const WCHAR StartupFolder[] =
240 {'S','t','a','r','t','u','p','F','o','l','d','e','r',0};
241 static const WCHAR SFPath[] =
242 {'C',':','\\','W','i','n','d','o','w','s','\\','S','t','a','r','t',' ',
243 'M','e','n','u','\\','P','r','o','g','r','a','m','s','\\',
244 'S','t','a','r','t','u','p','\\',0};
245 static const WCHAR TemplateFolder[] =
246 {'T','e','m','p','l','a','t','e','F','o','l','d','e','r',0};
247 static const WCHAR TFPath[] =
248 {'C',':','\\','W','i','n','d','o','w','s','\\',
249 'S','h','e','l','l','N','e','w','\\',0};
250 static const WCHAR DesktopFolder[] =
251 {'D','e','s','k','t','o','p','F','o','l','d','e','r',0};
252 static const WCHAR DFPath[] =
253 {'C',':','\\','W','i','n','d','o','w','s','\\',
254 'D','e','s','k','t','o','p','\\',0};
257 * Other things I notice set
259 ScreenY
260 ScreenX
261 SystemLanguageID
262 ComputerName
263 UserLanguageID
264 LogonUser
265 VirtualMemory
266 PhysicalMemory
267 Intel
268 ShellAdvSupport
269 DefaultUIFont
270 VersionMsi
271 VersionDatabase
272 PackagecodeChanging
273 ProductState
274 CaptionHeight
275 BorderTop
276 BorderSide
277 TextHeight
278 ColorBits
279 RedirectedDllSupport
280 Time
281 Date
282 Privilaged
285 SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth);
286 strcatW(pth,cszbs);
287 MSI_SetPropertyW(package, CFF, pth);
289 SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES,NULL,0,pth);
290 strcatW(pth,cszbs);
291 MSI_SetPropertyW(package, PFF, pth);
293 SHGetFolderPathW(NULL,CSIDL_COMMON_APPDATA,NULL,0,pth);
294 strcatW(pth,cszbs);
295 MSI_SetPropertyW(package, CADF, pth);
297 SHGetFolderPathW(NULL,CSIDL_ADMINTOOLS,NULL,0,pth);
298 strcatW(pth,cszbs);
299 MSI_SetPropertyW(package, ATF, pth);
301 SHGetFolderPathW(NULL,CSIDL_APPDATA,NULL,0,pth);
302 strcatW(pth,cszbs);
303 MSI_SetPropertyW(package, ADF, pth);
305 SHGetFolderPathW(NULL,CSIDL_SYSTEM,NULL,0,pth);
306 strcatW(pth,cszbs);
307 MSI_SetPropertyW(package, SF, pth);
309 SHGetFolderPathW(NULL,CSIDL_LOCAL_APPDATA,NULL,0,pth);
310 strcatW(pth,cszbs);
311 MSI_SetPropertyW(package, LADF, pth);
313 SHGetFolderPathW(NULL,CSIDL_MYPICTURES,NULL,0,pth);
314 strcatW(pth,cszbs);
315 MSI_SetPropertyW(package, MPF, pth);
317 SHGetFolderPathW(NULL,CSIDL_PERSONAL,NULL,0,pth);
318 strcatW(pth,cszbs);
319 MSI_SetPropertyW(package, PF, pth);
321 SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
322 strcatW(pth,cszbs);
323 MSI_SetPropertyW(package, WF, pth);
325 GetTempPathW(MAX_PATH,pth);
326 MSI_SetPropertyW(package, TF, pth);
329 /* in a wine environment the user is always admin and privileged */
330 MSI_SetPropertyW(package,szAdminUser,szOne);
331 MSI_SetPropertyW(package,szPriv,szOne);
333 /* set the os things */
334 OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
335 GetVersionExA(&OSVersion);
336 verval = OSVersion.dwMinorVersion+OSVersion.dwMajorVersion*100;
337 sprintfW(verstr,szFormat,verval);
338 switch (OSVersion.dwPlatformId)
340 case VER_PLATFORM_WIN32_WINDOWS:
341 MSI_SetPropertyW(package,v9x,verstr);
342 break;
343 case VER_PLATFORM_WIN32_NT:
344 MSI_SetPropertyW(package,vNT,verstr);
345 break;
347 sprintfW(verstr,szFormat,OSVersion.dwBuildNumber);
348 MSI_SetPropertyW(package,szWinBuild,verstr);
349 /* just fudge this */
350 MSI_SetPropertyW(package,szSPL,szSix);
352 /* FIXME: these need to be set properly */
354 MSI_SetPropertyW(package,ProgramMenuFolder,PMFPath);
355 MSI_SetPropertyW(package,FavoritesFolder,FFPath);
356 MSI_SetPropertyW(package,FontsFolder,FoFPath);
357 MSI_SetPropertyW(package,SendToFolder,STFPath);
358 MSI_SetPropertyW(package,StartMenuFolder,SMFPath);
359 MSI_SetPropertyW(package,StartupFolder,SFPath);
360 MSI_SetPropertyW(package,TemplateFolder,TFPath);
361 MSI_SetPropertyW(package,DesktopFolder,DFPath);
364 UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
366 UINT rc;
367 MSIDATABASE *db = NULL;
368 MSIPACKAGE *package = NULL;
369 WCHAR uilevel[10];
370 UINT ret = ERROR_FUNCTION_FAILED;
372 static const WCHAR OriginalDatabase[] =
373 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
374 static const WCHAR Database[] =
375 {'D','A','T','A','B','A','S','E',0};
376 static const WCHAR szpi[] = {'%','i',0};
377 static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 };
379 TRACE("%s %p\n",debugstr_w(szPackage), pPackage);
381 rc = MSI_OpenDatabaseW(szPackage, MSIDBOPEN_READONLY, &db);
382 if (rc != ERROR_SUCCESS)
383 return ERROR_FUNCTION_FAILED;
385 package = alloc_msiobject( MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE),
386 MSI_FreePackage );
388 if (package)
390 msiobj_addref( &db->hdr );
392 package->db = db;
393 package->features = NULL;
394 package->folders = NULL;
395 package->components = NULL;
396 package->files = NULL;
397 package->loaded_features = 0;
398 package->loaded_folders = 0;
399 package->loaded_components= 0;
400 package->loaded_files = 0;
402 /* OK, here is where we do a slew of things to the database to
403 * prep for all that is to come as a package */
405 clone_properties(db);
406 set_installer_properties(package);
407 MSI_SetPropertyW(package, OriginalDatabase, szPackage);
408 MSI_SetPropertyW(package, Database, szPackage);
409 sprintfW(uilevel,szpi,gUILevel);
410 MSI_SetPropertyW(package, szLevel, uilevel);
412 msiobj_addref( &package->hdr );
413 *pPackage = package;
414 ret = ERROR_SUCCESS;
417 if( package )
418 msiobj_release( &package->hdr );
419 if( db )
420 msiobj_release( &db->hdr );
422 return ret;
425 UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
427 MSIPACKAGE *package = NULL;
428 UINT ret;
430 ret = MSI_OpenPackageW( szPackage, &package);
431 if( ret == ERROR_SUCCESS )
433 *phPackage = alloc_msihandle( &package->hdr );
434 msiobj_release( &package->hdr );
436 return ret;
439 UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
441 FIXME("%s 0x%08lx %p\n",debugstr_a(szPackage), dwOptions, phPackage);
442 return ERROR_CALL_NOT_IMPLEMENTED;
445 UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
447 FIXME("%s 0x%08lx %p\n",debugstr_w(szPackage), dwOptions, phPackage);
448 return ERROR_CALL_NOT_IMPLEMENTED;
451 MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
453 MSIPACKAGE *package;
454 MSIHANDLE handle = 0;
456 TRACE("(%ld)\n",hInstall);
458 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
459 if( package)
461 handle = alloc_msihandle( &package->db->hdr );
462 msiobj_release( &package->hdr );
465 return handle;
468 INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
469 MSIRECORD *record)
471 DWORD log_type = 0;
472 LPWSTR message;
473 DWORD sz;
474 DWORD total_size = 0;
475 INT msg_field=1;
476 INT i;
477 INT rc;
478 char *msg;
479 int len;
481 TRACE("%x \n",eMessageType);
482 rc = 0;
484 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR)
485 log_type |= INSTALLLOGMODE_ERROR;
486 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_WARNING)
487 log_type |= INSTALLLOGMODE_WARNING;
488 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_USER)
489 log_type |= INSTALLLOGMODE_USER;
490 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INFO)
491 log_type |= INSTALLLOGMODE_INFO;
492 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA)
493 log_type |= INSTALLLOGMODE_COMMONDATA;
494 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
495 log_type |= INSTALLLOGMODE_ACTIONSTART;
496 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONDATA)
497 log_type |= INSTALLLOGMODE_ACTIONDATA;
498 /* just a guess */
499 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS)
500 log_type |= 0x800;
502 message = HeapAlloc(GetProcessHeap(),0,1*sizeof (WCHAR));
503 message[0]=0;
504 msg_field = MSI_RecordGetFieldCount(record);
505 for (i = 1; i <= msg_field; i++)
507 LPWSTR tmp;
508 WCHAR number[3];
509 const static WCHAR format[] = { '%','i',':',' ',0};
510 const static WCHAR space[] = { ' ',0};
511 sz = 0;
512 MSI_RecordGetStringW(record,i,NULL,&sz);
513 sz+=4;
514 total_size+=sz*sizeof(WCHAR);
515 tmp = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
516 message = HeapReAlloc(GetProcessHeap(),0,message,total_size*sizeof (WCHAR));
518 MSI_RecordGetStringW(record,i,tmp,&sz);
520 if (msg_field > 1)
522 sprintfW(number,format,i);
523 strcatW(message,number);
525 strcatW(message,tmp);
526 if (msg_field > 1)
527 strcatW(message,space);
529 HeapFree(GetProcessHeap(),0,tmp);
532 TRACE("(%p %lx %lx %s)\n",gUIHandler, gUIFilter, log_type,
533 debugstr_w(message));
535 /* convert it to ASCII */
536 len = WideCharToMultiByte( CP_ACP, 0, message, -1,
537 NULL, 0, NULL, NULL );
538 msg = HeapAlloc( GetProcessHeap(), 0, len );
539 WideCharToMultiByte( CP_ACP, 0, message, -1,
540 msg, len, NULL, NULL );
542 if (gUIHandler && (gUIFilter & log_type))
544 rc = gUIHandler(gUIContext,eMessageType,msg);
547 if ((!rc) && (gszLogFile[0]) && !((eMessageType & 0xff000000) ==
548 INSTALLMESSAGE_PROGRESS))
550 DWORD write;
551 HANDLE log_file = CreateFileW(gszLogFile,GENERIC_WRITE, 0, NULL,
552 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
554 if (log_file != INVALID_HANDLE_VALUE)
556 SetFilePointer(log_file,0, NULL, FILE_END);
557 WriteFile(log_file,msg,strlen(msg),&write,NULL);
558 WriteFile(log_file,"\n",1,&write,NULL);
559 CloseHandle(log_file);
562 HeapFree( GetProcessHeap(), 0, msg );
564 HeapFree(GetProcessHeap(),0,message);
565 return ERROR_SUCCESS;
568 INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
569 MSIHANDLE hRecord)
571 UINT ret = ERROR_INVALID_HANDLE;
572 MSIPACKAGE *package = NULL;
573 MSIRECORD *record = NULL;
575 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
576 if( !package )
577 goto out;
579 record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
580 if( !record )
581 goto out;
583 ret = MSI_ProcessMessage( package, eMessageType, record );
585 out:
586 if( package )
587 msiobj_release( &package->hdr );
588 if( record )
589 msiobj_release( &record->hdr );
591 return ret;
594 /* property code */
595 UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue)
597 LPWSTR szwName = NULL, szwValue = NULL;
598 UINT hr = ERROR_INSTALL_FAILURE;
599 UINT len;
601 if (0 == hInstall) {
602 return ERROR_INVALID_HANDLE;
604 if (NULL == szName) {
605 return ERROR_INVALID_PARAMETER;
607 if (NULL == szValue) {
608 return ERROR_INVALID_PARAMETER;
611 len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
612 szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
613 if( !szwName )
614 goto end;
615 MultiByteToWideChar( CP_ACP, 0, szName, -1, szwName, len );
617 len = MultiByteToWideChar( CP_ACP, 0, szValue, -1, NULL, 0 );
618 szwValue = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
619 if( !szwValue)
620 goto end;
621 MultiByteToWideChar( CP_ACP, 0, szValue , -1, szwValue, len );
623 hr = MsiSetPropertyW( hInstall, szwName, szwValue);
625 end:
626 if( szwName )
627 HeapFree( GetProcessHeap(), 0, szwName );
628 if( szwValue )
629 HeapFree( GetProcessHeap(), 0, szwValue );
631 return hr;
634 UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
636 MSIQUERY *view;
637 MSIRECORD *row;
638 UINT rc;
639 DWORD sz = 0;
640 static const WCHAR Insert[]=
641 {'I','N','S','E','R','T',' ','i','n','t','o',' ','`','_','P','r','o','p'
642 ,'e','r','t','y','`',' ','(','`','_','P','r','o','p','e','r','t','y','`'
643 ,',','`','V','a','l','u','e','`',')',' ','V','A','L','U','E','S'
644 ,' ','(','?',')',0};
645 static const WCHAR Update[]=
646 {'U','P','D','A','T','E',' ','_','P','r','o','p','e'
647 ,'r','t','y',' ','s','e','t',' ','`','V','a','l','u','e','`',' ','='
648 ,' ','?',' ','w','h','e','r','e',' ','`','_','P','r','o','p'
649 ,'e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
650 WCHAR Query[1024];
652 TRACE("Setting property (%s %s)\n",debugstr_w(szName),
653 debugstr_w(szValue));
655 rc = MSI_GetPropertyW(package,szName,0,&sz);
656 if (rc==ERROR_MORE_DATA || rc == ERROR_SUCCESS)
658 sprintfW(Query,Update,szName);
660 row = MSI_CreateRecord(1);
661 MSI_RecordSetStringW(row,1,szValue);
664 else
666 strcpyW(Query,Insert);
668 row = MSI_CreateRecord(2);
669 MSI_RecordSetStringW(row,1,szName);
670 MSI_RecordSetStringW(row,2,szValue);
674 rc = MSI_DatabaseOpenViewW(package->db,Query,&view);
675 if (rc!= ERROR_SUCCESS)
677 msiobj_release(&row->hdr);
678 return rc;
681 rc = MSI_ViewExecute(view,row);
683 msiobj_release(&row->hdr);
684 MSI_ViewClose(view);
685 msiobj_release(&view->hdr);
687 return rc;
690 UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
692 MSIPACKAGE *package;
693 UINT ret;
695 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
696 if( !package)
697 return ERROR_INVALID_HANDLE;
698 ret = MSI_SetPropertyW( package, szName, szValue);
699 msiobj_release( &package->hdr );
700 return ret;
703 UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, DWORD* pchValueBuf)
705 LPWSTR szwName = NULL, szwValueBuf = NULL;
706 UINT hr = ERROR_INSTALL_FAILURE;
708 if (0 == hInstall) {
709 return ERROR_INVALID_HANDLE;
711 if (NULL == szName) {
712 return ERROR_INVALID_PARAMETER;
715 TRACE("%lu %s %lu\n", hInstall, debugstr_a(szName), *pchValueBuf);
717 if (NULL != szValueBuf && NULL == pchValueBuf) {
718 return ERROR_INVALID_PARAMETER;
720 if( szName )
722 UINT len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
723 szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
724 if( !szwName )
725 goto end;
726 MultiByteToWideChar( CP_ACP, 0, szName, -1, szwName, len );
727 } else {
728 return ERROR_INVALID_PARAMETER;
730 if( szValueBuf )
732 szwValueBuf = HeapAlloc( GetProcessHeap(), 0, (*pchValueBuf) * sizeof(WCHAR) );
733 if( !szwValueBuf )
734 goto end;
737 if( *pchValueBuf > 0 )
739 /* be sure to blank the string first */
740 szValueBuf[0]=0;
743 hr = MsiGetPropertyW( hInstall, szwName, szwValueBuf, pchValueBuf );
745 if( *pchValueBuf > 0 )
747 WideCharToMultiByte(CP_ACP, 0, szwValueBuf, -1, szValueBuf, *pchValueBuf, NULL, NULL);
750 end:
751 if( szwName )
752 HeapFree( GetProcessHeap(), 0, szwName );
753 if( szwValueBuf )
754 HeapFree( GetProcessHeap(), 0, szwValueBuf );
756 return hr;
759 UINT MSI_GetPropertyW(MSIPACKAGE *package, LPCWSTR szName,
760 LPWSTR szValueBuf, DWORD* pchValueBuf)
762 MSIQUERY *view;
763 MSIRECORD *row;
764 UINT rc;
765 WCHAR Query[1024]=
766 {'s','e','l','e','c','t',' ','V','a','l','u','e',' ','f','r','o','m',' '
767 ,'_','P','r','o','p','e','r','t','y',' ','w','h','e','r','e',' '
768 ,'_','P','r','o','p','e','r','t','y','=','`',0};
770 static const WCHAR szEnd[]={'`',0};
772 if (NULL == szName) {
773 return ERROR_INVALID_PARAMETER;
776 strcatW(Query,szName);
777 strcatW(Query,szEnd);
779 rc = MSI_DatabaseOpenViewW(package->db, Query, &view);
780 if (rc == ERROR_SUCCESS)
782 DWORD sz;
783 WCHAR value[0x100];
785 /* even on unsuccessful lookup native msi blanks this string */
786 if (*pchValueBuf > 0)
787 szValueBuf[0] = 0;
789 rc = MSI_ViewExecute(view, 0);
790 if (rc != ERROR_SUCCESS)
792 MSI_ViewClose(view);
793 msiobj_release(&view->hdr);
794 return rc;
797 rc = MSI_ViewFetch(view,&row);
798 if (rc == ERROR_SUCCESS)
800 sz=0x100;
801 rc = MSI_RecordGetStringW(row,1,value,&sz);
802 strncpyW(szValueBuf,value,min(sz+1,*pchValueBuf));
803 *pchValueBuf = sz+1;
804 msiobj_release(&row->hdr);
806 MSI_ViewClose(view);
807 msiobj_release(&view->hdr);
810 if (rc == ERROR_SUCCESS)
811 TRACE("returning %s for property %s\n", debugstr_w(szValueBuf),
812 debugstr_w(szName));
813 else
815 *pchValueBuf = 0;
816 TRACE("property not found\n");
819 return rc;
823 UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName,
824 LPWSTR szValueBuf, DWORD* pchValueBuf)
826 MSIPACKAGE *package;
827 UINT ret;
829 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
830 if( !package)
831 return ERROR_INVALID_HANDLE;
832 ret = MSI_GetPropertyW(package, szName, szValueBuf, pchValueBuf );
833 msiobj_release( &package->hdr );
834 return ret;