Use the newly implemented UPDATE code to set properties.
[wine/multimedia.git] / dlls / msi / package.c
blobd147b1623050d93d95490908bbc51be2e52e7c2e
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( VOID *arg);
53 typedef struct tagMSIPACKAGE
55 MSIHANDLE db;
56 } MSIPACKAGE;
58 void MSI_FreePackage( VOID *arg)
60 MSIPACKAGE *package= arg;
62 MsiCloseHandle(package->db);
65 UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
67 LPWSTR szwPack = NULL;
68 UINT len, ret;
70 TRACE("%s %p\n",debugstr_a(szPackage), phPackage);
72 if( szPackage )
74 len = MultiByteToWideChar( CP_ACP, 0, szPackage, -1, NULL, 0 );
75 szwPack = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
76 if( szwPack )
77 MultiByteToWideChar( CP_ACP, 0, szPackage, -1, szwPack, len );
80 ret = MsiOpenPackageW( szwPack, phPackage );
82 if( szwPack )
83 HeapFree( GetProcessHeap(), 0, szwPack );
85 return ret;
89 static const void clone_properties(MSIHANDLE db)
91 MSIHANDLE view;
92 UINT rc;
93 static const CHAR CreateSql[] = "CREATE TABLE `_Property` ( `_Property` "
94 "CHAR(56) NOT NULL, `Value` CHAR(98) NOT NULL PRIMARY KEY `_Property`)";
95 static const CHAR Query[] = "SELECT * from Property";
96 static const CHAR Insert[] =
97 "INSERT into `_Property` (`_Property`,`Value`) VALUES (?)";
99 /* create the temporary properties table */
100 MsiDatabaseOpenViewA(db, CreateSql, &view);
101 MsiViewExecute(view,0);
102 MsiViewClose(view);
103 MsiCloseHandle(view);
105 /* clone the existing properties */
106 MsiDatabaseOpenViewA(db, Query, &view);
108 MsiViewExecute(view, 0);
109 while (1)
111 MSIHANDLE row;
112 MSIHANDLE view2;
114 rc = MsiViewFetch(view,&row);
115 if (rc != ERROR_SUCCESS)
116 break;
118 MsiDatabaseOpenViewA(db,Insert,&view2);
119 MsiViewExecute(view2,row);
120 MsiViewClose(view2);
121 MsiCloseHandle(view2);
123 MsiCloseHandle(row);
125 MsiViewClose(view);
126 MsiCloseHandle(view);
131 * There are a whole slew of these we need to set
134 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/properties.asp
136 static VOID set_installer_properties(MSIHANDLE hPackage)
138 WCHAR pth[MAX_PATH];
140 static const WCHAR cszbs[]={'\\',0};
141 static const WCHAR CFF[] =
142 {'C','o','m','m','o','n','F','i','l','e','s','F','o','l','d','e','r',0};
143 static const WCHAR PFF[] =
144 {'P','r','o','g','r','a','m','F','i','l','e','s','F','o','l','d','e','r',0};
145 static const WCHAR CADF[] =
146 {'C','o','m','m','o','n','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
147 static const WCHAR ATF[] =
148 {'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0};
149 static const WCHAR ADF[] =
150 {'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
151 static const WCHAR SF[] =
152 {'S','y','s','t','e','m','F','o','l','d','e','r',0};
153 static const WCHAR LADF[] =
154 {'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
155 static const WCHAR MPF[] =
156 {'M','y','P','i','c','t','u','r','e','s','F','o','l','d','e','r',0};
157 static const WCHAR PF[] =
158 {'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0};
159 static const WCHAR WF[] =
160 {'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
161 static const WCHAR TF[]=
162 {'T','e','m','p','F','o','l','d','e','r',0};
164 /* Not yet set ... but needed by iTunes
166 DesktopFolder
167 FavoritesFolder
168 FontsFolder
169 PrimaryVolumePath
170 ProgramFiles64Folder
171 ProgramMenuFolder
172 SendToFolder
173 StartMenuFolder
174 StartupFolder
175 System16Folder
176 System64Folder
177 TemplateFolder
180 /* asked for by iTunes ... but are they installer set?
182 * GlobalAssemblyCache
186 * Other things i notice set
188 ScreenY
189 ScreenX
190 SystemLanguageID
191 ComputerName
192 UserLanguageID
193 LogonUser
194 VirtualMemory
195 PhysicalMemory
196 Intel
197 ShellAdvSupport
198 ServicePackLevel
199 WindowsBuild
200 Version9x
201 Version95
202 VersionNT
203 AdminUser
204 DefaultUIFont
205 VersionMsi
206 VersionDatabase
207 PackagecodeChanging
208 ProductState
209 CaptionHeight
210 BorderTop
211 BorderSide
212 TextHeight
213 ColorBits
214 RedirectedDllSupport
215 Time
216 Date
217 Privilaged
220 SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth);
221 strcatW(pth,cszbs);
222 MsiSetPropertyW(hPackage, CFF, pth);
224 SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES,NULL,0,pth);
225 strcatW(pth,cszbs);
226 MsiSetPropertyW(hPackage, PFF, pth);
228 SHGetFolderPathW(NULL,CSIDL_COMMON_APPDATA,NULL,0,pth);
229 strcatW(pth,cszbs);
230 MsiSetPropertyW(hPackage, CADF, pth);
232 SHGetFolderPathW(NULL,CSIDL_ADMINTOOLS,NULL,0,pth);
233 strcatW(pth,cszbs);
234 MsiSetPropertyW(hPackage, ATF, pth);
236 SHGetFolderPathW(NULL,CSIDL_APPDATA,NULL,0,pth);
237 strcatW(pth,cszbs);
238 MsiSetPropertyW(hPackage, ADF, pth);
240 SHGetFolderPathW(NULL,CSIDL_SYSTEM,NULL,0,pth);
241 strcatW(pth,cszbs);
242 MsiSetPropertyW(hPackage, SF, pth);
244 SHGetFolderPathW(NULL,CSIDL_LOCAL_APPDATA,NULL,0,pth);
245 strcatW(pth,cszbs);
246 MsiSetPropertyW(hPackage, LADF, pth);
248 SHGetFolderPathW(NULL,CSIDL_MYPICTURES,NULL,0,pth);
249 strcatW(pth,cszbs);
250 MsiSetPropertyW(hPackage, MPF, pth);
252 SHGetFolderPathW(NULL,CSIDL_PERSONAL,NULL,0,pth);
253 strcatW(pth,cszbs);
254 MsiSetPropertyW(hPackage, PF, pth);
256 SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
257 strcatW(pth,cszbs);
258 MsiSetPropertyW(hPackage, WF, pth);
260 GetTempPathW(MAX_PATH,pth);
261 MsiSetPropertyW(hPackage, TF, pth);
265 UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
267 UINT rc;
268 MSIHANDLE handle;
269 MSIHANDLE db;
270 MSIPACKAGE *package;
271 CHAR uilevel[10];
273 static const WCHAR OriginalDatabase[] =
274 {'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
275 static const WCHAR Database[] =
276 {'D','A','T','A','B','A','S','E',0};
278 TRACE("%s %p\n",debugstr_w(szPackage), phPackage);
280 rc = MsiOpenDatabaseW(szPackage, MSIDBOPEN_READONLY, &db);
282 if (rc != ERROR_SUCCESS)
283 return ERROR_FUNCTION_FAILED;
285 handle = alloc_msihandle(MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE),
286 MSI_FreePackage, (void**)&package);
288 if (!handle)
290 MsiCloseHandle(db);
291 return ERROR_FUNCTION_FAILED;
294 package->db = db;
296 /* ok here is where we do a slew of things to the database to
297 * prep for all that is to come as a package */
299 clone_properties(db);
300 set_installer_properties(handle);
301 MsiSetPropertyW(handle, OriginalDatabase, szPackage);
302 MsiSetPropertyW(handle, Database, szPackage);
303 sprintf(uilevel,"%i",gUILevel);
304 MsiSetPropertyA(handle, "UILevel", uilevel);
306 *phPackage = handle;
308 return ERROR_SUCCESS;
311 UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
313 FIXME("%s 0x%08lx %p\n",debugstr_a(szPackage), dwOptions, phPackage);
314 return ERROR_CALL_NOT_IMPLEMENTED;
317 UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
319 FIXME("%s 0x%08lx %p\n",debugstr_w(szPackage), dwOptions, phPackage);
320 return ERROR_CALL_NOT_IMPLEMENTED;
323 MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
325 MSIPACKAGE *package;
327 TRACE("(%ld)\n",hInstall);
329 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
331 if( !package)
332 return ERROR_INVALID_HANDLE;
334 msihandle_addref(package->db);
335 return package->db;
338 INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
339 MSIHANDLE hRecord)
341 DWORD log_type = 0;
342 LPSTR message;
343 DWORD sz;
344 INT msg_field=1;
345 FIXME("STUB: %x \n",eMessageType);
347 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR)
348 log_type |= INSTALLLOGMODE_ERROR;
349 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_WARNING)
350 log_type |= INSTALLLOGMODE_WARNING;
351 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_USER)
352 log_type |= INSTALLLOGMODE_USER;
353 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INFO)
354 log_type |= INSTALLLOGMODE_INFO;
355 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA)
356 log_type |= INSTALLLOGMODE_COMMONDATA;
357 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
359 log_type |= INSTALLLOGMODE_ACTIONSTART;
360 msg_field = 2;
362 if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONDATA)
363 log_type |= INSTALLLOGMODE_ACTIONDATA;
365 sz = 0;
366 MsiRecordGetStringA(hRecord,msg_field,NULL,&sz);
367 sz++;
368 message = HeapAlloc(GetProcessHeap(),0,sz);
369 MsiRecordGetStringA(hRecord,msg_field,message,&sz);
371 TRACE("(%p %lx %lx)\n",gUIHandler, gUIFilter, log_type);
372 if (gUIHandler && (gUIFilter & log_type))
373 gUIHandler(gUIContext,eMessageType,message);
374 else
375 TRACE("%s\n",debugstr_a(message));
377 HeapFree(GetProcessHeap(),0,message);
378 return ERROR_SUCCESS;
381 /* property code */
382 UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue)
384 LPWSTR szwName = NULL, szwValue = NULL;
385 UINT hr = ERROR_INSTALL_FAILURE;
386 UINT len;
388 if (0 == hInstall) {
389 return ERROR_INVALID_HANDLE;
391 if (NULL == szName) {
392 return ERROR_INVALID_PARAMETER;
394 if (NULL == szValue) {
395 return ERROR_INVALID_PARAMETER;
398 len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
399 szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
400 if( !szwName )
401 goto end;
402 MultiByteToWideChar( CP_ACP, 0, szName, -1, szwName, len );
404 len = MultiByteToWideChar( CP_ACP, 0, szValue, -1, NULL, 0 );
405 szwValue = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
406 if( !szwValue)
407 goto end;
408 MultiByteToWideChar( CP_ACP, 0, szValue , -1, szwValue, len );
410 hr = MsiSetPropertyW( hInstall, szwName, szwValue);
412 end:
413 if( szwName )
414 HeapFree( GetProcessHeap(), 0, szwName );
415 if( szwValue )
416 HeapFree( GetProcessHeap(), 0, szwValue );
418 return hr;
421 UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
423 MSIPACKAGE *package;
424 MSIHANDLE view,row;
425 UINT rc;
426 DWORD sz = 0;
427 static const WCHAR Insert[]=
428 {'I','N','S','E','R','T',' ','i','n','t','o',' ','`','_','P','r','o','p'
429 ,'e','r','t','y','`',' ','(','`','_','P','r','o','p','e','r','t','y','`'
430 ,',','`','V','a','l','u','e','`',')',' ','V','A','L','U','E','S'
431 ,' ','(','?',')',0};
432 static const WCHAR Update[]=
433 {'U','P','D','A','T','E',' ','_','P','r','o','p','e'
434 ,'r','t','y',' ','s','e','t',' ','`','V','a','l','u','e','`',' ','='
435 ,' ','?',' ','w','h','e','r','e',' ','`','_','P','r','o','p'
436 ,'e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
437 WCHAR Query[1024];
439 TRACE("Setting property (%s %s)\n",debugstr_w(szName),
440 debugstr_w(szValue));
442 if (!hInstall)
443 return ERROR_INVALID_HANDLE;
445 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
446 if( !package)
447 return ERROR_INVALID_HANDLE;
449 rc = MsiGetPropertyW(hInstall,szName,0,&sz);
450 if (rc==ERROR_MORE_DATA || rc == ERROR_SUCCESS)
452 sprintfW(Query,Update,szName);
454 row = MsiCreateRecord(1);
455 MsiRecordSetStringW(row,1,szValue);
458 else
460 strcpyW(Query,Insert);
462 row = MsiCreateRecord(2);
463 MsiRecordSetStringW(row,1,szName);
464 MsiRecordSetStringW(row,2,szValue);
468 rc = MsiDatabaseOpenViewW(package->db,Query,&view);
469 if (rc!= ERROR_SUCCESS)
471 MsiCloseHandle(row);
472 return rc;
475 rc = MsiViewExecute(view,row);
477 MsiCloseHandle(row);
478 MsiViewClose(view);
479 MsiCloseHandle(view);
481 return rc;
484 UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, DWORD* pchValueBuf)
486 LPWSTR szwName = NULL, szwValueBuf = NULL;
487 UINT hr = ERROR_INSTALL_FAILURE;
489 if (0 == hInstall) {
490 return ERROR_INVALID_HANDLE;
492 if (NULL == szName) {
493 return ERROR_INVALID_PARAMETER;
496 TRACE("%lu %s %lu\n", hInstall, debugstr_a(szName), *pchValueBuf);
498 if (NULL != szValueBuf && NULL == pchValueBuf) {
499 return ERROR_INVALID_PARAMETER;
501 if( szName )
503 UINT len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
504 szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
505 if( !szwName )
506 goto end;
507 MultiByteToWideChar( CP_ACP, 0, szName, -1, szwName, len );
508 } else {
509 return ERROR_INVALID_PARAMETER;
511 if( szValueBuf )
513 szwValueBuf = HeapAlloc( GetProcessHeap(), 0, (*pchValueBuf) * sizeof(WCHAR) );
514 if( !szwValueBuf )
515 goto end;
518 hr = MsiGetPropertyW( hInstall, szwName, szwValueBuf, pchValueBuf );
520 if( *pchValueBuf > 0 )
522 WideCharToMultiByte(CP_ACP, 0, szwValueBuf, -1, szValueBuf, *pchValueBuf, NULL, NULL);
525 end:
526 if( szwName )
527 HeapFree( GetProcessHeap(), 0, szwName );
528 if( szwValueBuf )
529 HeapFree( GetProcessHeap(), 0, szwValueBuf );
531 return hr;
534 UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName,
535 LPWSTR szValueBuf, DWORD* pchValueBuf)
537 MSIHANDLE view,row;
538 UINT rc;
539 WCHAR Query[1024]=
540 {'s','e','l','e','c','t',' ','V','a','l','u','e',' ','f','r','o','m',' '
541 ,'_','P','r','o','p','e','r','t','y',' ','w','h','e','r','e',' '
542 ,'_','P','r','o','p','e','r','t','y','=','`',0};
544 static const WCHAR szEnd[]={'`',0};
545 MSIPACKAGE *package;
547 if (0 == hInstall) {
548 return ERROR_INVALID_HANDLE;
550 if (NULL == szName) {
551 return ERROR_INVALID_PARAMETER;
554 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
555 if( !package)
556 return ERROR_INVALID_HANDLE;
558 strcatW(Query,szName);
559 strcatW(Query,szEnd);
561 rc = MsiDatabaseOpenViewW(package->db, Query, &view);
562 if (rc == ERROR_SUCCESS)
564 DWORD sz;
565 WCHAR value[0x100];
567 rc = MsiViewExecute(view, 0);
568 if (rc != ERROR_SUCCESS)
570 MsiViewClose(view);
571 MsiCloseHandle(view);
572 return rc;
575 rc = MsiViewFetch(view,&row);
576 if (rc == ERROR_SUCCESS)
578 sz=0x100;
579 rc = MsiRecordGetStringW(row,1,value,&sz);
580 strncpyW(szValueBuf,value,min(sz+1,*pchValueBuf));
581 *pchValueBuf = sz+1;
582 MsiCloseHandle(row);
584 MsiViewClose(view);
585 MsiCloseHandle(view);
588 if (rc == ERROR_SUCCESS)
589 TRACE("returning %s for property %s\n", debugstr_w(szValueBuf),
590 debugstr_w(szName));
591 else
593 *pchValueBuf = 0;
594 TRACE("property not found\n");
597 return rc;