Start implementing MsiOpenPackage.

This commit is contained in:
Aric Stewart 2004-06-30 19:38:36 +00:00 committed by Alexandre Julliard
parent de8674ec6f
commit eb0e0df908
6 changed files with 633 additions and 476 deletions

View File

@ -15,6 +15,7 @@ C_SRCS = \
msi.c \
msiquery.c \
order.c \
package.c \
record.c \
regsvr.c \
select.c \

View File

@ -47,23 +47,6 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/stand
#define CUSTOM_ACTION_TYPE_MASK 0x3F
/*
* These are hacks to get around the inability to write
* to the database and the inability to select on string values
* once those values are done then it will be possible to do
* all this inside the database.
*/
#define MAX_PROP 1024
typedef struct {
WCHAR *prop_name;
WCHAR *prop_value;
} internal_property;
static internal_property PropTableHack[MAX_PROP];
static INT PropCount = -1;
WINE_DEFAULT_DEBUG_CHANNEL(msi);
/*
@ -83,13 +66,6 @@ static UINT HANDLE_CustomType1(MSIHANDLE hPackage, const LPWSTR source,
static UINT HANDLE_CustomType2(MSIHANDLE hPackage, const LPWSTR source,
const LPWSTR target, const INT type);
static UINT set_property(MSIHANDLE hPackage, const WCHAR* prop,
const WCHAR* value);
UINT get_property(MSIHANDLE hPackage, const WCHAR* prop, WCHAR* value,
DWORD* size);
static VOID blitz_propertytable();
static VOID set_installer_properties(MSIHANDLE hPackage);
static DWORD deformat_string(MSIHANDLE hPackage, WCHAR* ptr,WCHAR** data);
/*
@ -98,6 +74,7 @@ static DWORD deformat_string(MSIHANDLE hPackage, WCHAR* ptr,WCHAR** data);
static const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0};
static const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0};
static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0};
static const WCHAR c_collen[] = {'C',':','\\',0};
static const WCHAR cszlsb[]={'[',0};
static const WCHAR cszrsb[]={']',0};
@ -120,226 +97,6 @@ inline static char *strdupWtoA( const WCHAR *str )
return ret;
}
static VOID blitz_propertytable()
{
if (PropCount == -1)
{
PropCount = 0;
memset(&PropTableHack,0,sizeof(PropTableHack));
}
else if (PropCount > 0)
{
int i;
TRACE("Clearing %i properties\n",PropCount);
for (i = 0; i < PropCount; i++)
{
HeapFree(GetProcessHeap(), 0, PropTableHack[i].prop_name);
HeapFree(GetProcessHeap(), 0, PropTableHack[i].prop_value);
}
memset(&PropTableHack,0,sizeof(PropTableHack));
PropCount = 0;
}
}
UINT get_property(MSIHANDLE hPackage, const WCHAR* prop, WCHAR* value,
DWORD* size)
{
UINT rc = 1;
int index = 0;
WCHAR* pName = PropTableHack[0].prop_name;
TRACE("Looking for property %s\n",debugstr_w(prop));
/* prop table hacks take presidence */
while (pName && strcmpW(pName,prop) && index < PropCount)
{
index ++;
pName = PropTableHack[index].prop_name;
}
if (pName && index < PropCount)
{
if (*size > strlenW(PropTableHack[index].prop_value))
{
*size = strlenW(PropTableHack[index].prop_value)+1;
TRACE(" index %i\n", index);
strcpyW(value , PropTableHack[index].prop_value);
TRACE(" found value %s\n",debugstr_w(value));
return 0;
}
else
{
*size = strlenW(PropTableHack[index].prop_value);
return ERROR_MORE_DATA;
}
}
rc = MsiGetPropertyW(hPackage,prop,value,size);
if (rc == ERROR_SUCCESS)
TRACE(" found value %s\n",debugstr_w(value));
else
TRACE(" value not found\n");
return rc;
}
static UINT set_property(MSIHANDLE hPackage, const WCHAR* prop,
const WCHAR* value)
{
/* prop table hacks take precedence */
UINT rc;
int index = 0;
WCHAR* pName;
if (PropCount == -1)
blitz_propertytable();
pName = PropTableHack[0].prop_name;
TRACE("Setting property %s to %s\n",debugstr_w(prop),debugstr_w(value));
while (pName && strcmpW(pName,prop) && index < MAX_PROP)
{
index ++;
pName = PropTableHack[index].prop_name;
}
if (pName && index < MAX_PROP)
{
TRACE("property index %i\n",index);
strcpyW(PropTableHack[index].prop_value,value);
return 0;
}
else
{
if (index >= MAX_PROP)
{
ERR("EXCEEDING MAX PROP!!!!\n");
return ERROR_FUNCTION_FAILED;
}
PropTableHack[index].prop_name = HeapAlloc(GetProcessHeap(),0,1024);
PropTableHack[index].prop_value= HeapAlloc(GetProcessHeap(),0,1024);
strcpyW(PropTableHack[index].prop_name,prop);
strcpyW(PropTableHack[index].prop_value,value);
PropCount++;
TRACE("new property index %i (%i)\n",index,PropCount);
return 0;
}
/* currently unreachable */
rc = MsiSetPropertyW(hPackage,prop,value);
return rc;
}
/*
* There are a whole slew of these we need to set
*
*
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/properties.asp
*/
static VOID set_installer_properties(MSIHANDLE hPackage)
{
WCHAR pth[MAX_PATH];
static const WCHAR c_col[] =
{'C',':','\\',0};
static const WCHAR CFF[] =
{'C','o','m','m','o','n','F','i','l','e','s','F','o','l','d','e','r',0};
static const WCHAR PFF[] =
{'P','r','o','g','r','a','m','F','i','l','e','s','F','o','l','d','e','r',0};
static const WCHAR CADF[] =
{'C','o','m','m','o','n','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
static const WCHAR ATF[] =
{'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0};
static const WCHAR ADF[] =
{'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
static const WCHAR SF[] =
{'S','y','s','t','e','m','F','o','l','d','e','r',0};
static const WCHAR LADF[] =
{'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
static const WCHAR MPF[] =
{'M','y','P','i','c','t','u','r','e','s','F','o','l','d','e','r',0};
static const WCHAR PF[] =
{'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0};
static const WCHAR WF[] =
{'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
static const WCHAR TF[]=
{'T','e','m','p','F','o','l','d','e','r',0};
/* Not yet set ... but needed by iTunes
*
static const WCHAR DF[] =
{'D','e','s','k','t','o','p','F','o','l','d','e','r',0};
static const WCHAR FF[] =
{'F','a','v','o','r','i','t','e','s','F','o','l','d','e','r',0};
static const WCHAR FoF[] =
{'F','o','n','t','s','F','o','l','d','e','r',0};
PrimaryVolumePath
ProgramFiles64Folder
ProgramMenuFolder
SendToFolder
StartMenuFolder
StartupFolder
System16Folder
System64Folder
TemplateFolder
*/
/* asked for by iTunes ... but are they installer set?
*
* GlobalAssemblyCache
*/
set_property(hPackage, cszRootDrive, c_col);
SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth);
strcatW(pth,cszbs);
set_property(hPackage, CFF, pth);
SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES,NULL,0,pth);
strcatW(pth,cszbs);
set_property(hPackage, PFF, pth);
SHGetFolderPathW(NULL,CSIDL_COMMON_APPDATA,NULL,0,pth);
strcatW(pth,cszbs);
set_property(hPackage, CADF, pth);
SHGetFolderPathW(NULL,CSIDL_ADMINTOOLS,NULL,0,pth);
strcatW(pth,cszbs);
set_property(hPackage, ATF, pth);
SHGetFolderPathW(NULL,CSIDL_APPDATA,NULL,0,pth);
strcatW(pth,cszbs);
set_property(hPackage, ADF, pth);
SHGetFolderPathW(NULL,CSIDL_SYSTEM,NULL,0,pth);
strcatW(pth,cszbs);
set_property(hPackage, SF, pth);
SHGetFolderPathW(NULL,CSIDL_LOCAL_APPDATA,NULL,0,pth);
strcatW(pth,cszbs);
set_property(hPackage, LADF, pth);
SHGetFolderPathW(NULL,CSIDL_MYPICTURES,NULL,0,pth);
strcatW(pth,cszbs);
set_property(hPackage, MPF, pth);
SHGetFolderPathW(NULL,CSIDL_PERSONAL,NULL,0,pth);
strcatW(pth,cszbs);
set_property(hPackage, PF, pth);
SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
strcatW(pth,cszbs);
set_property(hPackage, WF, pth);
GetTempPathW(MAX_PATH,pth);
set_property(hPackage, TF, pth);
}
/****************************************************
* TOP level entry points
*****************************************************/
@ -351,23 +108,17 @@ UINT ACTION_DoTopLevelINSTALL(MSIHANDLE hPackage, LPCWSTR szPackagePath,
UINT rc;
static const CHAR *ExecSeqQuery =
"select * from InstallExecuteSequence where Sequence > 0 order by Sequence";
MSIHANDLE db;
FIXME("****We do not do any of the UI level stuff yet***\n");
/* reset our properties */
blitz_propertytable();
if (szPackagePath)
{
static const WCHAR OriginalDatabase[] =
{'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
LPWSTR p;
WCHAR check[MAX_PATH];
WCHAR pth[MAX_PATH];
DWORD size;
set_property(hPackage, OriginalDatabase, szPackagePath);
strcpyW(pth,szPackagePath);
p = strrchrW(pth,'\\');
if (p)
@ -377,11 +128,13 @@ UINT ACTION_DoTopLevelINSTALL(MSIHANDLE hPackage, LPCWSTR szPackagePath,
}
size = MAX_PATH;
if (get_property(hPackage,cszSourceDir,check,&size) != ERROR_SUCCESS )
set_property(hPackage, cszSourceDir, pth);
if (MsiGetPropertyW(hPackage,cszSourceDir,check,&size) != ERROR_SUCCESS )
MsiSetPropertyW(hPackage, cszSourceDir, pth);
}
rc = MsiDatabaseOpenViewA(hPackage, ExecSeqQuery, &view);
db = MsiGetActiveDatabase(hPackage);
rc = MsiDatabaseOpenViewA(db, ExecSeqQuery, &view);
MsiCloseHandle(db);
if (rc == ERROR_SUCCESS)
{
@ -456,7 +209,6 @@ UINT ACTION_DoTopLevelINSTALL(MSIHANDLE hPackage, LPCWSTR szPackagePath,
}
end:
blitz_propertytable();
return rc;
}
@ -588,10 +340,15 @@ static UINT ACTION_CustomAction(MSIHANDLE hPackage,const WCHAR *action)
WCHAR source[0x100];
WCHAR target[0x200];
WCHAR *deformated=NULL;
MSIHANDLE db;
strcatW(ExecSeqQuery,action);
strcatW(ExecSeqQuery,end);
rc = MsiDatabaseOpenViewW(hPackage, ExecSeqQuery, &view);
db = MsiGetActiveDatabase(hPackage);
rc = MsiDatabaseOpenViewW(db, ExecSeqQuery, &view);
MsiCloseHandle(db);
if (rc != ERROR_SUCCESS)
return rc;
@ -633,7 +390,7 @@ static UINT ACTION_CustomAction(MSIHANDLE hPackage,const WCHAR *action)
case 35: /* Directory set with formatted text. */
case 51: /* Property set with formatted text. */
deformat_string(hPackage,target,&deformated);
set_property(hPackage,source,deformated);
MsiSetPropertyW(hPackage,source,deformated);
HeapFree(GetProcessHeap(),0,deformated);
break;
default:
@ -654,7 +411,7 @@ static UINT store_binary_to_temp(MSIHANDLE hPackage, const LPWSTR source,
static const WCHAR TF[]= {'T','e','m','p','F','o','l','d','e','r',0};
DWORD sz=MAX_PATH;
if (get_property(hPackage, TF,tmp_file, &sz) != ERROR_SUCCESS)
if (MsiGetPropertyW(hPackage, TF,tmp_file, &sz) != ERROR_SUCCESS)
GetTempPathW(MAX_PATH,tmp_file);
strcatW(tmp_file,source);
@ -676,6 +433,7 @@ static UINT store_binary_to_temp(MSIHANDLE hPackage, const LPWSTR source,
static const WCHAR end[]={'`',0};
HANDLE the_file;
CHAR buffer[1024];
MSIHANDLE db;
the_file = CreateFileW(tmp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
@ -685,7 +443,11 @@ static UINT store_binary_to_temp(MSIHANDLE hPackage, const LPWSTR source,
strcatW(Query,source);
strcatW(Query,end);
rc = MsiDatabaseOpenViewW(hPackage, Query, &view);
db = MsiGetActiveDatabase(hPackage);
rc = MsiDatabaseOpenViewW(db, Query, &view);
MsiCloseHandle(db);
if (rc != ERROR_SUCCESS)
return rc;
@ -782,7 +544,6 @@ static UINT HANDLE_CustomType2(MSIHANDLE hPackage, const LPWSTR source,
PROCESS_INFORMATION info;
BOOL rc;
WCHAR *deformated;
static const WCHAR c_collen[] = {'C',':','\\',0};
static const WCHAR spc[] = {' ',0};
memset(&si,0,sizeof(STARTUPINFOW));
@ -875,8 +636,12 @@ static UINT ACTION_CreateFolders(MSIHANDLE hPackage)
static const CHAR *ExecSeqQuery = "select * from CreateFolder";
UINT rc;
MSIHANDLE view;
MSIHANDLE db;
db = MsiGetActiveDatabase(hPackage);
rc = MsiDatabaseOpenViewA(db, ExecSeqQuery, &view);
MsiCloseHandle(db);
rc = MsiDatabaseOpenViewA(hPackage, ExecSeqQuery, &view);
if (rc != ERROR_SUCCESS)
return rc;
@ -913,7 +678,7 @@ static UINT ACTION_CreateFolders(MSIHANDLE hPackage)
}
sz = MAX_PATH;
rc = get_property(hPackage, dir,full_path,&sz);
rc = MsiGetPropertyW(hPackage, dir,full_path,&sz);
if (rc != ERROR_SUCCESS)
{
@ -961,9 +726,10 @@ static UINT resolve_directory(MSIHANDLE hPackage, const WCHAR* dir,
MSIHANDLE row = 0;
WCHAR full_path[MAX_PATH];
WCHAR name_source[0x100];
MSIHANDLE db;
sz = MAX_PATH;
if (get_property(hPackage,dir,path,&sz)==ERROR_SUCCESS)
if (MsiGetPropertyW(hPackage,dir,path,&sz)==ERROR_SUCCESS)
return ERROR_SUCCESS;
TRACE("Working to resolve %s\n",debugstr_w(dir));
@ -974,18 +740,14 @@ static UINT resolve_directory(MSIHANDLE hPackage, const WCHAR* dir,
if (!source)
{
sz = 0x100;
if(!get_property(hPackage,cszRootDrive,buffer,&sz))
if(!MsiGetPropertyW(hPackage,cszRootDrive,buffer,&sz))
{
set_property(hPackage,cszTargetDir,buffer);
MsiSetPropertyW(hPackage,cszTargetDir,buffer);
strcpyW(path,buffer);
}
else
{
ERR("No RootDrive property defined disaster!\n");
MsiCloseHandle(row);
MsiViewClose(view);
MsiCloseHandle(view);
return ERROR_FUNCTION_FAILED;
strcpyW(path,c_collen);
}
}
else
@ -996,7 +758,11 @@ static UINT resolve_directory(MSIHANDLE hPackage, const WCHAR* dir,
strcatW(Query,dir);
strcatW(Query,end);
rc = MsiDatabaseOpenViewW(hPackage, Query, &view);
db = MsiGetActiveDatabase(hPackage);
rc = MsiDatabaseOpenViewW(db, Query, &view);
MsiCloseHandle(db);
if (rc != ERROR_SUCCESS)
return rc;
@ -1068,7 +834,7 @@ static UINT resolve_directory(MSIHANDLE hPackage, const WCHAR* dir,
strcatW(full_path,targetdir);
strcatW(full_path,cszbs);
}
set_property(hPackage,dir,full_path);
MsiSetPropertyW(hPackage,dir,full_path);
if (!source)
strcpyW(path,full_path);
@ -1087,7 +853,7 @@ static UINT resolve_directory(MSIHANDLE hPackage, const WCHAR* dir,
strcpyW(name_source,dir);
strcatW(name_source,cszsrc);
set_property(hPackage,name_source,full_path);
MsiSetPropertyW(hPackage,name_source,full_path);
if (source)
strcpyW(path,full_path);
}
@ -1122,15 +888,14 @@ static UINT ACTION_CostFinalize(MSIHANDLE hPackage)
static const CHAR *ExecSeqQuery = "select * from Directory";
UINT rc;
MSIHANDLE view;
/* According to MSDN these properties are set when CostFinalize is run
* or MsiSetInstallLevel is called */
TRACE("Setting installer properties\n");
set_installer_properties(hPackage);
MSIHANDLE db;
TRACE("Building Directory properties\n");
rc = MsiDatabaseOpenViewA(hPackage, ExecSeqQuery, &view);
db = MsiGetActiveDatabase(hPackage);
rc = MsiDatabaseOpenViewA(db, ExecSeqQuery, &view);
MsiCloseHandle(db);
if (rc != ERROR_SUCCESS)
return rc;
@ -1184,14 +949,17 @@ static UINT writeout_cabinet_stream(MSIHANDLE hPackage, WCHAR* stream_name,
UINT size;
DWORD write;
HANDLE the_file;
MSIHANDLE db;
rc = read_raw_stream_data(hPackage,stream_name,&data,&size);
db = MsiGetActiveDatabase(hPackage);
rc = read_raw_stream_data(db,stream_name,&data,&size);
MsiCloseHandle(db);
if (rc != ERROR_SUCCESS)
return rc;
write = 0x100;
if (get_property(hPackage, cszSourceDir, source, &write))
if (MsiGetPropertyW(hPackage, cszSourceDir, source, &write))
{
ERR("No Source dir defined \n");
rc = ERROR_FUNCTION_FAILED;
@ -1271,6 +1039,7 @@ static UINT ready_media_for_file(MSIHANDLE hPackage, UINT sequence,
DWORD sz=0x100;
INT seq;
static INT last_sequence = 0;
MSIHANDLE db;
if (sequence <= last_sequence)
{
@ -1280,7 +1049,10 @@ static UINT ready_media_for_file(MSIHANDLE hPackage, UINT sequence,
sprintf(Query,ExecSeqQuery,sequence);
rc = MsiDatabaseOpenViewA(hPackage, Query, &view);
db = MsiGetActiveDatabase(hPackage);
rc = MsiDatabaseOpenViewA(db, Query, &view);
MsiCloseHandle(db);
if (rc != ERROR_SUCCESS)
return rc;
@ -1316,7 +1088,7 @@ static UINT ready_media_for_file(MSIHANDLE hPackage, UINT sequence,
else
{
sz = 0x100;
if (get_property(hPackage, cszSourceDir, source, &sz))
if (MsiGetPropertyW(hPackage, cszSourceDir, source, &sz))
{
ERR("No Source dir defined \n");
rc = ERROR_FUNCTION_FAILED;
@ -1358,11 +1130,14 @@ static UINT get_directory_for_component(MSIHANDLE hPackage,
static const WCHAR end[]={'`',0};
WCHAR dir[0x100];
DWORD sz=0x100;
MSIHANDLE db;
strcatW(ExecSeqQuery,component);
strcatW(ExecSeqQuery,end);
rc = MsiDatabaseOpenViewW(hPackage, ExecSeqQuery, &view);
db = MsiGetActiveDatabase(hPackage);
rc = MsiDatabaseOpenViewW(db, ExecSeqQuery, &view);
MsiCloseHandle(db);
if (rc != ERROR_SUCCESS)
return rc;
@ -1387,7 +1162,7 @@ static UINT get_directory_for_component(MSIHANDLE hPackage,
sz=0x100;
MsiRecordGetStringW(row,3,dir,&sz);
sz=MAX_PATH;
rc = get_property(hPackage, dir, install_path, &sz);
rc = MsiGetPropertyW(hPackage, dir, install_path, &sz);
MsiCloseHandle(row);
MsiViewClose(view);
@ -1402,6 +1177,7 @@ static UINT ACTION_InstallFiles(MSIHANDLE hPackage)
MSIHANDLE row = 0;
static const CHAR *ExecSeqQuery =
"select * from File order by Sequence";
MSIHANDLE db;
/* REALLY what we want to do is go through all the enabled
* features and check all the components of that feature and
@ -1410,8 +1186,10 @@ static UINT ACTION_InstallFiles(MSIHANDLE hPackage)
* but for sheer gratification I am going to just brute force
* install all the files
*/
db = MsiGetActiveDatabase(hPackage);
rc = MsiDatabaseOpenViewA(db, ExecSeqQuery, &view);
MsiCloseHandle(db);
rc = MsiDatabaseOpenViewA(hPackage, ExecSeqQuery, &view);
if (rc != ERROR_SUCCESS)
return rc;
@ -1497,7 +1275,7 @@ static UINT ACTION_InstallFiles(MSIHANDLE hPackage)
}
/* for future use lets keep track of this file and where it went */
set_property(hPackage,sourcename,install_path);
MsiSetPropertyW(hPackage,sourcename,install_path);
MsiCloseHandle(row);
}
@ -1513,14 +1291,17 @@ static UINT ACTION_DuplicateFiles(MSIHANDLE hPackage)
MSIHANDLE view;
MSIHANDLE row = 0;
static const CHAR *ExecSeqQuery = "select * from DuplicateFile";
MSIHANDLE db;
/*
* Yes we should only do this for componenets that are installed
* but again I need to do that went I track components.
*/
db = MsiGetActiveDatabase(hPackage);
rc = MsiDatabaseOpenViewA(db, ExecSeqQuery, &view);
MsiCloseHandle(db);
rc = MsiDatabaseOpenViewA(hPackage, ExecSeqQuery, &view);
if (rc != ERROR_SUCCESS)
return rc;
@ -1558,7 +1339,7 @@ static UINT ACTION_DuplicateFiles(MSIHANDLE hPackage)
}
sz = 0x100;
rc = get_property(hPackage,file_key,file_source,&sz);
rc = MsiGetPropertyW(hPackage,file_key,file_source,&sz);
if (rc != ERROR_SUCCESS)
{
ERR("Original file unknown %s\n",debugstr_w(file_key));
@ -1586,7 +1367,7 @@ static UINT ACTION_DuplicateFiles(MSIHANDLE hPackage)
sz=0x100;
MsiRecordGetStringW(row,5,destkey,&sz);
sz = 0x100;
rc = get_property(hPackage, destkey, dest_path, &sz);
rc = MsiGetPropertyW(hPackage, destkey, dest_path, &sz);
if (rc != ERROR_SUCCESS)
{
ERR("Unable to get destination folder\n");
@ -1700,12 +1481,15 @@ static UINT ACTION_WriteRegistryValues(MSIHANDLE hPackage)
MSIHANDLE view;
MSIHANDLE row = 0;
static const CHAR *ExecSeqQuery = "select * from Registry";
MSIHANDLE db;
/* Again here we want to key off of the components being installed...
* oh well
*/
db = MsiGetActiveDatabase(hPackage);
rc = MsiDatabaseOpenViewA(db, ExecSeqQuery, &view);
MsiCloseHandle(db);
rc = MsiDatabaseOpenViewA(hPackage, ExecSeqQuery, &view);
if (rc != ERROR_SUCCESS)
return rc;
@ -1851,7 +1635,7 @@ static DWORD deformat_string(MSIHANDLE hPackage, WCHAR* ptr,WCHAR** data)
mark++;
TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
sz = 0x100;
if (get_property(hPackage, key, value,&sz) == ERROR_SUCCESS)
if (MsiGetPropertyW(hPackage, key, value,&sz) == ERROR_SUCCESS)
{
LPWSTR newdata;
chunk = (strlenW(value)+1) * sizeof(WCHAR);
@ -1953,7 +1737,7 @@ UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
szPathBuf, DWORD* pcchPathBuf)
{
TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
return get_property(hInstall,szFolder,szPathBuf,pcchPathBuf);
return MsiGetPropertyW(hInstall,szFolder,szPathBuf,pcchPathBuf);
}
@ -2007,11 +1791,11 @@ UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
(strlenW(szFolder)+8)*sizeof(WCHAR));
strcpyW(newfolder,szFolder);
strcatW(newfolder,cszsrc);
rc = get_property(hInstall,newfolder,szPathBuf,pcchPathBuf);
rc = MsiGetPropertyW(hInstall,newfolder,szPathBuf,pcchPathBuf);
HeapFree(GetProcessHeap(),0,newfolder);
}
else
rc = get_property(hInstall,szFolder,szPathBuf,pcchPathBuf);
rc = MsiGetPropertyW(hInstall,szFolder,szPathBuf,pcchPathBuf);
return rc;
}
@ -2028,8 +1812,12 @@ static UINT ACTION_Template(MSIHANDLE hPackage)
MSIHANDLE view;
MSIHANDLE row = 0;
static const CHAR *ExecSeqQuery;
MSIHANDLE db;
db = MsiGetActiveDatabase(hPackage);
rc = MsiDatabaseOpenViewA(db, ExecSeqQuery, &view);
MsiCloseHandle(db);
rc = MsiDatabaseOpenViewA(hPackage, ExecSeqQuery, &view);
if (rc != ERROR_SUCCESS)
return rc;

View File

@ -449,11 +449,9 @@ symbol_s:
$$ = HeapAlloc( GetProcessHeap(), 0, 0x100*sizeof (WCHAR) );
/* Lookup the identifier */
/* This will not really work until we have write access to the table*/
/* HACK ALERT HACK ALERT... */
sz=0x100;
if (get_property(cond->hInstall,$1,$$,&sz) != ERROR_SUCCESS)
if (MsiGetPropertyW(cond->hInstall,$1,$$,&sz) != ERROR_SUCCESS)
{
$$[0]=0;
}

View File

@ -375,32 +375,6 @@ end:
return r;
}
UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
{
FIXME("%s %p\n",debugstr_a(szPackage), phPackage);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
{
UINT rc;
FIXME("%s %p\n",debugstr_w(szPackage), phPackage);
rc = MsiOpenDatabaseW(szPackage,MSIDBOPEN_READONLY,phPackage);
return rc;
}
UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
{
FIXME("%s 0x%08lx %p\n",debugstr_a(szPackage), dwOptions, phPackage);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
{
FIXME("%s 0x%08lx %p\n",debugstr_w(szPackage), dwOptions, phPackage);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiAdvertiseProductA(LPCSTR szPackagePath, LPCSTR szScriptfilePath, LPCSTR szTransforms, LANGID lgidLanguage)
{
FIXME("%s %s %s 0x%08x\n",debugstr_a(szPackagePath), debugstr_a(szScriptfilePath), debugstr_a(szTransforms), lgidLanguage);
@ -466,7 +440,7 @@ end:
UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine)
{
MSIHANDLE dbhandle;
MSIHANDLE packagehandle;
UINT rc = ERROR_SUCCESS;
FIXME("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine));
@ -475,13 +449,13 @@ UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine)
if (rc != ERROR_SUCCESS)
return rc;
rc = MsiOpenDatabaseW(szPackagePath,MSIDBOPEN_READONLY,&dbhandle);
rc = MsiOpenPackageW(szPackagePath,&packagehandle);
if (rc != ERROR_SUCCESS)
return rc;
ACTION_DoTopLevelINSTALL(dbhandle, szPackagePath, szCommandLine);
ACTION_DoTopLevelINSTALL(packagehandle, szPackagePath, szCommandLine);
MsiCloseHandle(dbhandle);
MsiCloseHandle(packagehandle);
return rc;
}
@ -1224,151 +1198,6 @@ BOOL WINAPI MSI_DllCanUnloadNow(void)
return S_FALSE;
}
/* property code */
UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue)
{
FIXME("STUB until write access is done: (%s %s)\n", szName,
szValue);
if (!hInstall)
return ERROR_INVALID_HANDLE;
return ERROR_SUCCESS;
}
UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
{
FIXME("STUB until write access is done: (%s %s)\n",debugstr_w(szName),
debugstr_w(szValue));
if (!hInstall)
return ERROR_INVALID_HANDLE;
return ERROR_SUCCESS;
}
UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, DWORD* pchValueBuf)
{
LPWSTR szwName = NULL, szwValueBuf = NULL;
UINT hr = ERROR_INSTALL_FAILURE;
if (0 == hInstall) {
return ERROR_INVALID_HANDLE;
}
if (NULL == szName) {
return ERROR_INVALID_PARAMETER;
}
FIXME("%lu %s %lu\n", hInstall, debugstr_a(szName), *pchValueBuf);
if (NULL != szValueBuf && NULL == pchValueBuf) {
return ERROR_INVALID_PARAMETER;
}
if( szName )
{
UINT len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
if( !szwName )
goto end;
MultiByteToWideChar( CP_ACP, 0, szName, -1, szwName, len );
} else {
return ERROR_INVALID_PARAMETER;
}
if( szValueBuf )
{
szwValueBuf = HeapAlloc( GetProcessHeap(), 0, (*pchValueBuf) * sizeof(WCHAR) );
if( !szwValueBuf )
goto end;
}
hr = MsiGetPropertyW( hInstall, szwName, szwValueBuf, pchValueBuf );
if( ERROR_SUCCESS == hr )
{
WideCharToMultiByte(CP_ACP, 0, szwValueBuf, -1, szValueBuf, *pchValueBuf, NULL, NULL);
}
end:
if( szwName )
HeapFree( GetProcessHeap(), 0, szwName );
if( szwValueBuf )
HeapFree( GetProcessHeap(), 0, szwValueBuf );
return hr;
}
UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName,
LPWSTR szValueBuf, DWORD* pchValueBuf)
{
MSIHANDLE view,row;
UINT rc;
WCHAR Query[1024]=
{'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' '
,'P','r','o','p','e','r','t','y',' ','w','h','e','r','e',' ','`'
,'P','r','o','p','e','r','t','y','`','=','`',0};
static const WCHAR szEnd[]={'`',0};
if (0 == hInstall) {
return ERROR_INVALID_HANDLE;
}
if (NULL == szName) {
return ERROR_INVALID_PARAMETER;
}
strcatW(Query,szName);
strcatW(Query,szEnd);
rc = MsiDatabaseOpenViewW(hInstall, Query, &view);
if (rc == ERROR_SUCCESS)
{
DWORD sz;
WCHAR value[0x100];
rc = MsiViewExecute(view, 0);
if (rc != ERROR_SUCCESS)
{
MsiViewClose(view);
MsiCloseHandle(view);
return rc;
}
rc = MsiViewFetch(view,&row);
if (rc == ERROR_SUCCESS)
{
sz=0x100;
rc = MsiRecordGetStringW(row,2,value,&sz);
strncpyW(szValueBuf,value,min(sz+1,*pchValueBuf));
*pchValueBuf = sz+1;
MsiCloseHandle(row);
}
MsiViewClose(view);
MsiCloseHandle(view);
}
if (rc == ERROR_SUCCESS)
TRACE("returning %s for property %s\n", debugstr_w(szValueBuf),
debugstr_w(szName));
return rc;
}
INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
MSIHANDLE hRecord)
{
FIXME("STUB: \n");
return ERROR_SUCCESS;
}
MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
{
FIXME("Is this correct?\n");
msihandle_addref(hInstall);
return hInstall;
}
UINT WINAPI MsiEnumRelatedProductsA (LPCSTR lpUpgradeCode, DWORD dwReserved,
DWORD iProductIndex, LPSTR lpProductBuf)
{

View File

@ -145,6 +145,7 @@ typedef struct tagMSIHANDLEINFO
#define MSIHANDLETYPE_SUMMARYINFO 2
#define MSIHANDLETYPE_VIEW 3
#define MSIHANDLETYPE_RECORD 4
#define MSIHANDLETYPE_PACKAGE 5
#define MSI_MAJORVERSION 1
#define MSI_MINORVERSION 10

540
dlls/msi/package.c Normal file
View File

@ -0,0 +1,540 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2004 Aric Stewart for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define NONAMELESSUNION
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "winnls.h"
#include "shlwapi.h"
#include "wine/debug.h"
#include "msi.h"
#include "msiquery.h"
#include "msipriv.h"
#include "objidl.h"
#include "wincrypt.h"
#include "winuser.h"
#include "shlobj.h"
#include "wine/unicode.h"
#include "objbase.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
/*
* The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR,
* which is a problem because LPCTSTR isn't defined when compiling wine.
* To work around this problem, we need to define LPCTSTR as LPCWSTR here,
* and make sure to only use it in W functions.
*/
#define LPCTSTR LPCWSTR
void MSI_FreePackage( VOID *arg);
typedef struct tagMSIPACKAGE
{
MSIHANDLE db;
} MSIPACKAGE;
void MSI_FreePackage( VOID *arg)
{
MSIPACKAGE *package= arg;
MsiCloseHandle(package->db);
}
UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
{
LPWSTR szwPack = NULL;
UINT len, ret;
TRACE("%s %p\n",debugstr_a(szPackage), phPackage);
if( szPackage )
{
len = MultiByteToWideChar( CP_ACP, 0, szPackage, -1, NULL, 0 );
szwPack = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
if( szwPack )
MultiByteToWideChar( CP_ACP, 0, szPackage, -1, szwPack, len );
}
ret = MsiOpenPackageW( szwPack, phPackage );
if( szwPack )
HeapFree( GetProcessHeap(), 0, szwPack );
return ret;
}
static const void clone_properties(MSIHANDLE db)
{
MSIHANDLE view;
UINT rc;
static const CHAR CreateSql[] = "CREATE TABLE `_Property` ( `_Property` "
"CHAR(56) NOT NULL, `Value` CHAR(98) NOT NULL PRIMARY KEY `_Property`)";
static const CHAR Query[] = "SELECT * from Property";
static const CHAR Insert[] =
"INSERT into `_Property` (`_Property`,`Value`) VALUES (?)";
/* create the temporary properties table */
MsiDatabaseOpenViewA(db, CreateSql, &view);
MsiViewExecute(view,0);
MsiViewClose(view);
MsiCloseHandle(view);
/* clone the existing properties */
MsiDatabaseOpenViewA(db, Query, &view);
MsiViewExecute(view, 0);
while (1)
{
MSIHANDLE row;
MSIHANDLE view2;
rc = MsiViewFetch(view,&row);
if (rc != ERROR_SUCCESS)
break;
MsiDatabaseOpenViewA(db,Insert,&view2);
MsiViewExecute(view2,row);
MsiViewClose(view2);
MsiCloseHandle(view2);
MsiCloseHandle(row);
}
MsiViewClose(view);
MsiCloseHandle(view);
}
/*
* There are a whole slew of these we need to set
*
*
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/properties.asp
*/
static VOID set_installer_properties(MSIHANDLE hPackage)
{
WCHAR pth[MAX_PATH];
static const WCHAR cszbs[]={'\\',0};
static const WCHAR CFF[] =
{'C','o','m','m','o','n','F','i','l','e','s','F','o','l','d','e','r',0};
static const WCHAR PFF[] =
{'P','r','o','g','r','a','m','F','i','l','e','s','F','o','l','d','e','r',0};
static const WCHAR CADF[] =
{'C','o','m','m','o','n','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
static const WCHAR ATF[] =
{'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0};
static const WCHAR ADF[] =
{'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
static const WCHAR SF[] =
{'S','y','s','t','e','m','F','o','l','d','e','r',0};
static const WCHAR LADF[] =
{'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
static const WCHAR MPF[] =
{'M','y','P','i','c','t','u','r','e','s','F','o','l','d','e','r',0};
static const WCHAR PF[] =
{'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0};
static const WCHAR WF[] =
{'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
static const WCHAR TF[]=
{'T','e','m','p','F','o','l','d','e','r',0};
/* Not yet set ... but needed by iTunes
*
DesktopFolder
FavoritesFolder
FontsFolder
PrimaryVolumePath
ProgramFiles64Folder
ProgramMenuFolder
SendToFolder
StartMenuFolder
StartupFolder
System16Folder
System64Folder
TemplateFolder
*/
/* asked for by iTunes ... but are they installer set?
*
* GlobalAssemblyCache
*/
/*
* Other things i notice set
*
ScreenY
ScreenX
SystemLanguageID
ComputerName
UserLanguageID
LogonUser
VirtualMemory
PhysicalMemory
Intel
ShellAdvSupport
ServicePackLevel
WindowsBuild
Version9x
Version95
VersionNT
AdminUser
DefaultUIFont
VersionMsi
VersionDatabase
PackagecodeChanging
ProductState
CaptionHeight
BorderTop
BorderSide
TextHeight
ColorBits
RedirectedDllSupport
Time
Date
Privilaged
DATABASE
OriginalDatabase
UILevel
*/
SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth);
strcatW(pth,cszbs);
MsiSetPropertyW(hPackage, CFF, pth);
SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES,NULL,0,pth);
strcatW(pth,cszbs);
MsiSetPropertyW(hPackage, PFF, pth);
SHGetFolderPathW(NULL,CSIDL_COMMON_APPDATA,NULL,0,pth);
strcatW(pth,cszbs);
MsiSetPropertyW(hPackage, CADF, pth);
SHGetFolderPathW(NULL,CSIDL_ADMINTOOLS,NULL,0,pth);
strcatW(pth,cszbs);
MsiSetPropertyW(hPackage, ATF, pth);
SHGetFolderPathW(NULL,CSIDL_APPDATA,NULL,0,pth);
strcatW(pth,cszbs);
MsiSetPropertyW(hPackage, ADF, pth);
SHGetFolderPathW(NULL,CSIDL_SYSTEM,NULL,0,pth);
strcatW(pth,cszbs);
MsiSetPropertyW(hPackage, SF, pth);
SHGetFolderPathW(NULL,CSIDL_LOCAL_APPDATA,NULL,0,pth);
strcatW(pth,cszbs);
MsiSetPropertyW(hPackage, LADF, pth);
SHGetFolderPathW(NULL,CSIDL_MYPICTURES,NULL,0,pth);
strcatW(pth,cszbs);
MsiSetPropertyW(hPackage, MPF, pth);
SHGetFolderPathW(NULL,CSIDL_PERSONAL,NULL,0,pth);
strcatW(pth,cszbs);
MsiSetPropertyW(hPackage, PF, pth);
SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
strcatW(pth,cszbs);
MsiSetPropertyW(hPackage, WF, pth);
GetTempPathW(MAX_PATH,pth);
MsiSetPropertyW(hPackage, TF, pth);
}
UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
{
UINT rc;
MSIHANDLE handle;
MSIHANDLE db;
MSIPACKAGE *package;
static const WCHAR OriginalDatabase[] =
{'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
static const WCHAR Database[] =
{'D','A','T','A','B','A','S','E',0};
TRACE("%s %p\n",debugstr_w(szPackage), phPackage);
rc = MsiOpenDatabaseW(szPackage, MSIDBOPEN_READONLY, &db);
if (rc != ERROR_SUCCESS)
return ERROR_FUNCTION_FAILED;
handle = alloc_msihandle(MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE),
MSI_FreePackage, (void**)&package);
if (!handle)
{
MsiCloseHandle(db);
return ERROR_FUNCTION_FAILED;
}
package->db = db;
/* ok here is where we do a slew of things to the database to
* prep for all that is to come as a package */
clone_properties(db);
set_installer_properties(handle);
MsiSetPropertyW(handle, OriginalDatabase, szPackage);
MsiSetPropertyW(handle, Database, szPackage);
*phPackage = handle;
return ERROR_SUCCESS;
}
UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
{
FIXME("%s 0x%08lx %p\n",debugstr_a(szPackage), dwOptions, phPackage);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
{
FIXME("%s 0x%08lx %p\n",debugstr_w(szPackage), dwOptions, phPackage);
return ERROR_CALL_NOT_IMPLEMENTED;
}
MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
{
MSIPACKAGE *package;
TRACE("(%i)\n",(INT)hInstall);
package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
if( !package)
return ERROR_INVALID_HANDLE;
msihandle_addref(package->db);
return package->db;
}
INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
MSIHANDLE hRecord)
{
FIXME("STUB: \n");
return ERROR_SUCCESS;
}
/* property code */
UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue)
{
LPWSTR szwName = NULL, szwValue = NULL;
UINT hr = ERROR_INSTALL_FAILURE;
UINT len;
if (0 == hInstall) {
return ERROR_INVALID_HANDLE;
}
if (NULL == szName) {
return ERROR_INVALID_PARAMETER;
}
if (NULL == szValue) {
return ERROR_INVALID_PARAMETER;
}
len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
if( !szwName )
goto end;
MultiByteToWideChar( CP_ACP, 0, szName, -1, szwName, len );
len = MultiByteToWideChar( CP_ACP, 0, szValue, -1, NULL, 0 );
szwValue = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
if( !szwValue)
goto end;
MultiByteToWideChar( CP_ACP, 0, szValue , -1, szwValue, len );
hr = MsiSetPropertyW( hInstall, szwName, szwValue);
end:
if( szwName )
HeapFree( GetProcessHeap(), 0, szwName );
if( szwValue )
HeapFree( GetProcessHeap(), 0, szwValue );
return hr;
}
UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
{
MSIPACKAGE *package;
MSIHANDLE view,row;
UINT rc;
DWORD sz = 0;
static const CHAR Insert[]=
"INSERT into `_Property` (`_Property`,`Value`) VALUES (?)";
TRACE("Setting property (%s %s)\n",debugstr_w(szName),
debugstr_w(szValue));
if (!hInstall)
return ERROR_INVALID_HANDLE;
if (MsiGetPropertyW(hInstall,szName,0,&sz)==ERROR_MORE_DATA)
{
FIXME("Cannot set exising properties! FIXME MIKE!\n");
return ERROR_FUNCTION_FAILED;
}
package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
if( !package)
return ERROR_INVALID_HANDLE;
rc = MsiDatabaseOpenViewA(package->db,Insert,&view);
if (rc!= ERROR_SUCCESS)
return rc;
row = MsiCreateRecord(2);
MsiRecordSetStringW(row,1,szName);
MsiRecordSetStringW(row,2,szValue);
rc = MsiViewExecute(view,row);
MsiCloseHandle(row);
MsiViewClose(view);
MsiCloseHandle(view);
return rc;
}
UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, DWORD* pchValueBuf)
{
LPWSTR szwName = NULL, szwValueBuf = NULL;
UINT hr = ERROR_INSTALL_FAILURE;
if (0 == hInstall) {
return ERROR_INVALID_HANDLE;
}
if (NULL == szName) {
return ERROR_INVALID_PARAMETER;
}
TRACE("%lu %s %lu\n", hInstall, debugstr_a(szName), *pchValueBuf);
if (NULL != szValueBuf && NULL == pchValueBuf) {
return ERROR_INVALID_PARAMETER;
}
if( szName )
{
UINT len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
if( !szwName )
goto end;
MultiByteToWideChar( CP_ACP, 0, szName, -1, szwName, len );
} else {
return ERROR_INVALID_PARAMETER;
}
if( szValueBuf )
{
szwValueBuf = HeapAlloc( GetProcessHeap(), 0, (*pchValueBuf) * sizeof(WCHAR) );
if( !szwValueBuf )
goto end;
}
hr = MsiGetPropertyW( hInstall, szwName, szwValueBuf, pchValueBuf );
if( *pchValueBuf > 0 )
{
WideCharToMultiByte(CP_ACP, 0, szwValueBuf, -1, szValueBuf, *pchValueBuf, NULL, NULL);
}
end:
if( szwName )
HeapFree( GetProcessHeap(), 0, szwName );
if( szwValueBuf )
HeapFree( GetProcessHeap(), 0, szwValueBuf );
return hr;
}
UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName,
LPWSTR szValueBuf, DWORD* pchValueBuf)
{
MSIHANDLE view,row;
UINT rc;
WCHAR Query[1024]=
{'s','e','l','e','c','t',' ','V','a','l','u','e',' ','f','r','o','m',' '
,'_','P','r','o','p','e','r','t','y',' ','w','h','e','r','e',' '
,'_','P','r','o','p','e','r','t','y','=','`',0};
static const WCHAR szEnd[]={'`',0};
MSIPACKAGE *package;
if (0 == hInstall) {
return ERROR_INVALID_HANDLE;
}
if (NULL == szName) {
return ERROR_INVALID_PARAMETER;
}
package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
if( !package)
return ERROR_INVALID_HANDLE;
strcatW(Query,szName);
strcatW(Query,szEnd);
rc = MsiDatabaseOpenViewW(package->db, Query, &view);
if (rc == ERROR_SUCCESS)
{
DWORD sz;
WCHAR value[0x100];
rc = MsiViewExecute(view, 0);
if (rc != ERROR_SUCCESS)
{
MsiViewClose(view);
MsiCloseHandle(view);
return rc;
}
rc = MsiViewFetch(view,&row);
if (rc == ERROR_SUCCESS)
{
sz=0x100;
rc = MsiRecordGetStringW(row,1,value,&sz);
strncpyW(szValueBuf,value,min(sz+1,*pchValueBuf));
*pchValueBuf = sz+1;
MsiCloseHandle(row);
}
MsiViewClose(view);
MsiCloseHandle(view);
}
if (rc == ERROR_SUCCESS)
TRACE("returning %s for property %s\n", debugstr_w(szValueBuf),
debugstr_w(szName));
else
{
*pchValueBuf = 0;
TRACE("property not found\n");
}
return rc;
}