Fix MsiGetTargetPath, MsiGetSourcePath and MsiSetTargetPath.
This commit is contained in:
parent
2e9b5f7c07
commit
bdb2955296
|
@ -49,6 +49,53 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/stand
|
|||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
|
||||
typedef struct tagMSIFEATURE
|
||||
{
|
||||
WCHAR Feature[96];
|
||||
WCHAR Feature_Parent[96];
|
||||
WCHAR Title[0x100];
|
||||
WCHAR Description[0x100];
|
||||
INT Display;
|
||||
INT Level;
|
||||
WCHAR Directory[96];
|
||||
INT Attributes;
|
||||
|
||||
INSTALLSTATE State;
|
||||
INT ComponentCount;
|
||||
INT Components[1024]; /* yes hardcoded limit.... */
|
||||
} MSIFEATURE;
|
||||
|
||||
typedef struct tagMSICOMPONENT
|
||||
{
|
||||
WCHAR Component[96];
|
||||
WCHAR ComponentId[96];
|
||||
WCHAR Directory[96];
|
||||
INT Attributes;
|
||||
WCHAR Condition[0x100];
|
||||
WCHAR KeyPath[96];
|
||||
|
||||
INSTALLSTATE State;
|
||||
BOOL Enabled;
|
||||
}MSICOMPONENT;
|
||||
|
||||
typedef struct tagMSIFOLDER
|
||||
{
|
||||
WCHAR Directory[96];
|
||||
WCHAR TargetDefault[96];
|
||||
WCHAR SourceDefault[96];
|
||||
|
||||
WCHAR ResolvedTarget[MAX_PATH];
|
||||
WCHAR ResolvedSource[MAX_PATH];
|
||||
|
||||
BOOL Property; /* initialy set property */
|
||||
INT ParentIndex;
|
||||
INT State;
|
||||
/* 0 = uninitialized */
|
||||
/* 1 = existing */
|
||||
/* 2 = created remove if empty */
|
||||
/* 3 = created persist if empty */
|
||||
}MSIFOLDER;
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
|
@ -70,6 +117,9 @@ static UINT HANDLE_CustomType2(MSIHANDLE hPackage, const LPWSTR source,
|
|||
const LPWSTR target, const INT type);
|
||||
|
||||
static DWORD deformat_string(MSIHANDLE hPackage, WCHAR* ptr,WCHAR** data);
|
||||
static UINT resolve_folder(MSIHANDLE hPackage, LPCWSTR name, LPWSTR path,
|
||||
BOOL source, BOOL set_prop, MSIFOLDER **folder);
|
||||
|
||||
|
||||
/*
|
||||
* consts and values used
|
||||
|
@ -77,6 +127,8 @@ 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 cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
|
||||
static const WCHAR cszDatabase[]={'D','A','T','A','B','A','S','E',0};
|
||||
static const WCHAR c_collen[] = {'C',':','\\',0};
|
||||
|
||||
static const WCHAR cszlsb[]={'[',0};
|
||||
|
@ -100,6 +152,22 @@ inline static char *strdupWtoA( const WCHAR *str )
|
|||
return ret;
|
||||
}
|
||||
|
||||
int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component )
|
||||
{
|
||||
INT rc = -1;
|
||||
INT i;
|
||||
|
||||
for (i = 0; i < package->loaded_components; i++)
|
||||
{
|
||||
if (strcmpW(Component,package->components[i].Component)==0)
|
||||
{
|
||||
rc = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/****************************************************
|
||||
* TOP level entry points
|
||||
*****************************************************/
|
||||
|
@ -585,10 +653,10 @@ static UINT ACTION_CustomAction(MSIHANDLE hPackage,const WCHAR *action)
|
|||
static UINT store_binary_to_temp(MSIHANDLE hPackage, const LPWSTR source,
|
||||
LPWSTR tmp_file)
|
||||
{
|
||||
static const WCHAR TF[]= {'T','e','m','p','F','o','l','d','e','r',0};
|
||||
DWORD sz=MAX_PATH;
|
||||
|
||||
if (MsiGetPropertyW(hPackage, TF,tmp_file, &sz) != ERROR_SUCCESS)
|
||||
if (MsiGetPropertyW(hPackage, cszTempFolder, tmp_file, &sz)
|
||||
!= ERROR_SUCCESS)
|
||||
GetTempPathW(MAX_PATH,tmp_file);
|
||||
|
||||
strcatW(tmp_file,source);
|
||||
|
@ -820,6 +888,7 @@ static UINT ACTION_CreateFolders(MSIHANDLE hPackage)
|
|||
UINT rc;
|
||||
MSIHANDLE view;
|
||||
MSIHANDLE db;
|
||||
MSIFOLDER *folder;
|
||||
|
||||
db = MsiGetActiveDatabase(hPackage);
|
||||
rc = MsiDatabaseOpenViewA(db, ExecSeqQuery, &view);
|
||||
|
@ -861,7 +930,7 @@ static UINT ACTION_CreateFolders(MSIHANDLE hPackage)
|
|||
}
|
||||
|
||||
sz = MAX_PATH;
|
||||
rc = MsiGetPropertyW(hPackage, dir,full_path,&sz);
|
||||
rc = resolve_folder(hPackage,dir,full_path,FALSE,FALSE,&folder);
|
||||
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
|
@ -871,8 +940,11 @@ static UINT ACTION_CreateFolders(MSIHANDLE hPackage)
|
|||
}
|
||||
|
||||
TRACE("Folder is %s\n",debugstr_w(full_path));
|
||||
if (folder->State == 0)
|
||||
create_full_pathW(full_path);
|
||||
|
||||
folder->State = 3;
|
||||
|
||||
MsiCloseHandle(row);
|
||||
}
|
||||
MsiViewClose(view);
|
||||
|
@ -881,17 +953,263 @@ static UINT ACTION_CreateFolders(MSIHANDLE hPackage)
|
|||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Workhorse function for creating the directories
|
||||
* during Costing
|
||||
*/
|
||||
static UINT resolve_directory(MSIHANDLE hPackage, const WCHAR* dir,
|
||||
WCHAR* path, BOOL source)
|
||||
{
|
||||
static const WCHAR cszsrc[]={'_','S','o','u','r','c','e',0};
|
||||
static const WCHAR cszsrcroot[]=
|
||||
{'[','S','o','u','r','c','e','D','i','r',']',0};
|
||||
|
||||
static int load_component(MSIPACKAGE* package, MSIHANDLE row)
|
||||
{
|
||||
int index = package->loaded_components;
|
||||
DWORD sz;
|
||||
|
||||
/* fill in the data */
|
||||
|
||||
package->loaded_components++;
|
||||
if (package->loaded_components == 1)
|
||||
package->components = HeapAlloc(GetProcessHeap(),0,
|
||||
sizeof(MSICOMPONENT));
|
||||
else
|
||||
package->components = HeapReAlloc(GetProcessHeap(),0,
|
||||
package->components, package->loaded_components *
|
||||
sizeof(MSICOMPONENT));
|
||||
|
||||
memset(&package->components[index],0,sizeof(MSICOMPONENT));
|
||||
|
||||
sz = 96;
|
||||
MsiRecordGetStringW(row,1,package->components[index].Component,&sz);
|
||||
|
||||
TRACE("Loading Component %s\n",
|
||||
debugstr_w(package->components[index].Component));
|
||||
|
||||
sz = 0x100;
|
||||
if (!MsiRecordIsNull(row,2))
|
||||
MsiRecordGetStringW(row,2,package->components[index].ComponentId,&sz);
|
||||
|
||||
sz = 96;
|
||||
MsiRecordGetStringW(row,3,package->components[index].Directory,&sz);
|
||||
|
||||
package->components[index].Attributes = MsiRecordGetInteger(row,4);
|
||||
|
||||
sz = 0x100;
|
||||
MsiRecordGetStringW(row,5,package->components[index].Condition,&sz);
|
||||
|
||||
sz = 96;
|
||||
MsiRecordGetStringW(row,6,package->components[index].KeyPath,&sz);
|
||||
|
||||
package->components[index].State = INSTALLSTATE_UNKNOWN;
|
||||
package->components[index].Enabled = TRUE;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static void load_feature(MSIPACKAGE* package, MSIHANDLE row)
|
||||
{
|
||||
int index = package->loaded_features;
|
||||
DWORD sz;
|
||||
static const WCHAR Query1[] = {'S','E','L','E','C','T',' ','C','o','m','p',
|
||||
'o','n','e','n','t','_',' ','F','R','O','M',' ','F','e','a','t','u','r','e',
|
||||
'C','o','m','p','o','n','e','n','t','s',' ','W','H','E','R','E',' ','F','e',
|
||||
'a','t','u','r','e','_','=','\'','%','s','\'',0};
|
||||
static const WCHAR Query2[] = {'S','E','L','E','C','T',' ','*',' ','F','R',
|
||||
'O','M',' ','C','o','m','p','o','n','e','n','t',' ','W','H','E','R','E',' ','C',
|
||||
'o','m','p','o','n','e','n','t','=','\'','%','s','\'',0};
|
||||
WCHAR Query[1024];
|
||||
MSIHANDLE view;
|
||||
MSIHANDLE view2;
|
||||
MSIHANDLE row2;
|
||||
MSIHANDLE row3;
|
||||
|
||||
/* fill in the data */
|
||||
|
||||
package->loaded_features ++;
|
||||
if (package->loaded_features == 1)
|
||||
package->features = HeapAlloc(GetProcessHeap(),0,sizeof(MSIFEATURE));
|
||||
else
|
||||
package->features = HeapReAlloc(GetProcessHeap(),0,package->features,
|
||||
package->loaded_features * sizeof(MSIFEATURE));
|
||||
|
||||
memset(&package->features[index],0,sizeof(MSIFEATURE));
|
||||
|
||||
sz = 96;
|
||||
MsiRecordGetStringW(row,1,package->features[index].Feature,&sz);
|
||||
|
||||
TRACE("Loading feature %s\n",debugstr_w(package->features[index].Feature));
|
||||
|
||||
sz = 96;
|
||||
if (!MsiRecordIsNull(row,2))
|
||||
MsiRecordGetStringW(row,2,package->features[index].Feature_Parent,&sz);
|
||||
|
||||
sz = 0x100;
|
||||
if (!MsiRecordIsNull(row,3))
|
||||
MsiRecordGetStringW(row,3,package->features[index].Title,&sz);
|
||||
|
||||
sz = 0x100;
|
||||
if (!MsiRecordIsNull(row,4))
|
||||
MsiRecordGetStringW(row,4,package->features[index].Description,&sz);
|
||||
|
||||
if (!MsiRecordIsNull(row,5))
|
||||
package->features[index].Display = MsiRecordGetInteger(row,5);
|
||||
|
||||
package->features[index].Level= MsiRecordGetInteger(row,6);
|
||||
|
||||
sz = 96;
|
||||
if (!MsiRecordIsNull(row,7))
|
||||
MsiRecordGetStringW(row,7,package->features[index].Directory,&sz);
|
||||
|
||||
package->features[index].Attributes= MsiRecordGetInteger(row,8);
|
||||
package->features[index].State = INSTALLSTATE_UNKNOWN;
|
||||
|
||||
/* load feature components */
|
||||
|
||||
sprintfW(Query,Query1,package->features[index].Feature);
|
||||
MsiDatabaseOpenViewW(package->db,Query,&view);
|
||||
MsiViewExecute(view,0);
|
||||
while (1)
|
||||
{
|
||||
DWORD sz = 0x100;
|
||||
WCHAR buffer[0x100];
|
||||
DWORD rc;
|
||||
INT c_indx;
|
||||
INT cnt = package->features[index].ComponentCount;
|
||||
|
||||
rc = MsiViewFetch(view,&row2);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
break;
|
||||
|
||||
sz = 0x100;
|
||||
MsiRecordGetStringW(row2,1,buffer,&sz);
|
||||
|
||||
/* check to see if the component is already loaded */
|
||||
c_indx = get_loaded_component(package,buffer);
|
||||
if (c_indx != -1)
|
||||
{
|
||||
TRACE("Component %s already loaded at %i\n", debugstr_w(buffer),
|
||||
c_indx);
|
||||
package->features[index].Components[cnt] = c_indx;
|
||||
package->features[index].ComponentCount ++;
|
||||
}
|
||||
|
||||
sprintfW(Query,Query2,buffer);
|
||||
|
||||
MsiDatabaseOpenViewW(package->db,Query,&view2);
|
||||
MsiViewExecute(view2,0);
|
||||
while (1)
|
||||
{
|
||||
DWORD rc;
|
||||
|
||||
rc = MsiViewFetch(view2,&row3);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
break;
|
||||
c_indx = load_component(package,row3);
|
||||
MsiCloseHandle(row3);
|
||||
|
||||
package->features[index].Components[cnt] = c_indx;
|
||||
package->features[index].ComponentCount ++;
|
||||
}
|
||||
MsiViewClose(view2);
|
||||
MsiCloseHandle(view2);
|
||||
MsiCloseHandle(row2);
|
||||
}
|
||||
MsiViewClose(view);
|
||||
MsiCloseHandle(view);
|
||||
}
|
||||
|
||||
/*
|
||||
* I am not doing any of the costing functionality yet.
|
||||
* Mostly looking at doing the Component and Feature loading
|
||||
*
|
||||
* The native MSI does ALOT of modification to tables here. Mostly adding alot
|
||||
* of temporary columns to the Feature and Component tables.
|
||||
*
|
||||
* note: native msi also tracks the short filename. but i am only going to
|
||||
* track the long ones. Also looking at this directory table
|
||||
* it appears that the directory table does not get the parents
|
||||
* resolved base on property only based on their entrys in the
|
||||
* directory table.
|
||||
*/
|
||||
static UINT ACTION_CostInitialize(MSIHANDLE hPackage)
|
||||
{
|
||||
MSIHANDLE view;
|
||||
MSIHANDLE row;
|
||||
CHAR local[0x100];
|
||||
DWORD sz;
|
||||
MSIPACKAGE *package;
|
||||
|
||||
static const CHAR Query_all[] = "SELECT * FROM Feature";
|
||||
static const CHAR Query_one[] = "SELECT * FROM Feature WHERE Feature='%s'";
|
||||
CHAR Query[1023];
|
||||
|
||||
MsiSetPropertyA(hPackage,"CostingComplete","0");
|
||||
MsiSetPropertyW(hPackage, cszRootDrive , c_collen);
|
||||
|
||||
package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
|
||||
|
||||
sz = 0x100;
|
||||
if (MsiGetPropertyA(hPackage,"ADDLOCAL",local,&sz)==ERROR_SUCCESS)
|
||||
{
|
||||
if (strcasecmp(local,"ALL")==0)
|
||||
{
|
||||
MsiDatabaseOpenViewA(package->db,Query_all,&view);
|
||||
MsiViewExecute(view,0);
|
||||
while (1)
|
||||
{
|
||||
DWORD rc;
|
||||
|
||||
rc = MsiViewFetch(view,&row);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
break;
|
||||
|
||||
load_feature(package,row);
|
||||
MsiCloseHandle(row);
|
||||
}
|
||||
MsiViewClose(view);
|
||||
MsiCloseHandle(view);
|
||||
}
|
||||
else
|
||||
{
|
||||
LPSTR ptr,ptr2;
|
||||
ptr = local;
|
||||
|
||||
while (ptr && *ptr)
|
||||
{
|
||||
CHAR feature[0x100];
|
||||
DWORD rc;
|
||||
|
||||
ptr2 = strchr(ptr,',');
|
||||
|
||||
if (ptr2)
|
||||
{
|
||||
strncpy(feature,ptr,ptr2-ptr);
|
||||
feature[ptr2-ptr]=0;
|
||||
ptr2++;
|
||||
ptr = ptr2;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(feature,ptr);
|
||||
ptr = NULL;
|
||||
}
|
||||
|
||||
sprintf(Query,Query_one,feature);
|
||||
|
||||
MsiDatabaseOpenViewA(package->db,Query,&view);
|
||||
MsiViewExecute(view,0);
|
||||
rc = MsiViewFetch(view,&row);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
break;
|
||||
|
||||
load_feature(package,row);
|
||||
|
||||
MsiCloseHandle(row);
|
||||
MsiViewClose(view);
|
||||
MsiCloseHandle(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static INT load_folder(MSIHANDLE hPackage, const WCHAR* dir)
|
||||
|
||||
{
|
||||
WCHAR Query[1024] =
|
||||
{'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','D','i','r','e','c',
|
||||
't','o','r','y',' ','w','h','e','r','e',' ','`','D','i','r','e','c','t',
|
||||
|
@ -902,59 +1220,56 @@ static UINT resolve_directory(MSIHANDLE hPackage, const WCHAR* dir,
|
|||
WCHAR targetbuffer[0x100];
|
||||
WCHAR *srcdir = NULL;
|
||||
WCHAR *targetdir = NULL;
|
||||
WCHAR buffer[0x100];
|
||||
WCHAR parent[0x100];
|
||||
WCHAR parent_path[MAX_PATH];
|
||||
DWORD sz=0x100;
|
||||
MSIHANDLE row = 0;
|
||||
WCHAR full_path[MAX_PATH];
|
||||
WCHAR name_source[0x100];
|
||||
MSIHANDLE db;
|
||||
MSIPACKAGE *package;
|
||||
INT i,index = -1;
|
||||
|
||||
sz = MAX_PATH;
|
||||
if (MsiGetPropertyW(hPackage,dir,path,&sz)==ERROR_SUCCESS)
|
||||
return ERROR_SUCCESS;
|
||||
package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
|
||||
|
||||
TRACE("Working to resolve %s\n",debugstr_w(dir));
|
||||
TRACE("Looking for dir %s\n",debugstr_w(dir));
|
||||
|
||||
/* special case... root drive */
|
||||
if (strcmpW(dir,cszTargetDir)==0)
|
||||
for (i = 0; i < package->loaded_folders; i++)
|
||||
{
|
||||
if (!source)
|
||||
if (strcmpW(package->folders[i].Directory,dir)==0)
|
||||
{
|
||||
sz = 0x100;
|
||||
if(!MsiGetPropertyW(hPackage,cszRootDrive,buffer,&sz))
|
||||
{
|
||||
MsiSetPropertyW(hPackage,cszTargetDir,buffer);
|
||||
strcpyW(path,buffer);
|
||||
TRACE(" %s retuning on index %i\n",debugstr_w(dir),i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE("Working to load %s\n",debugstr_w(dir));
|
||||
|
||||
index = package->loaded_folders;
|
||||
|
||||
package->loaded_folders++;
|
||||
if (package->loaded_folders== 1)
|
||||
package->folders = HeapAlloc(GetProcessHeap(),0,
|
||||
sizeof(MSIFOLDER));
|
||||
else
|
||||
{
|
||||
strcpyW(path,c_collen);
|
||||
}
|
||||
}
|
||||
else
|
||||
strcpyW(path,cszsrcroot);
|
||||
package->folders= HeapReAlloc(GetProcessHeap(),0,
|
||||
package->folders, package->loaded_folders*
|
||||
sizeof(MSIFOLDER));
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
memset(&package->folders[index],0,sizeof(MSIFOLDER));
|
||||
|
||||
strcpyW(package->folders[index].Directory,dir);
|
||||
|
||||
strcatW(Query,dir);
|
||||
strcatW(Query,end);
|
||||
|
||||
db = MsiGetActiveDatabase(hPackage);
|
||||
rc = MsiDatabaseOpenViewW(db, Query, &view);
|
||||
MsiCloseHandle(db);
|
||||
rc = MsiDatabaseOpenViewW(package->db, Query, &view);
|
||||
|
||||
if (rc != ERROR_SUCCESS)
|
||||
return rc;
|
||||
return -1;
|
||||
|
||||
rc = MsiViewExecute(view, 0);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
MsiViewClose(view);
|
||||
MsiCloseHandle(view);
|
||||
return rc;
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = MsiViewFetch(view,&row);
|
||||
|
@ -962,7 +1277,7 @@ static UINT resolve_directory(MSIHANDLE hPackage, const WCHAR* dir,
|
|||
{
|
||||
MsiViewClose(view);
|
||||
MsiCloseHandle(view);
|
||||
return rc;
|
||||
return -1;
|
||||
}
|
||||
|
||||
sz=0x100;
|
||||
|
@ -1000,6 +1315,14 @@ static UINT resolve_directory(MSIHANDLE hPackage, const WCHAR* dir,
|
|||
if (srcdir && srcdir[0] == '.' && srcdir[1] == 0)
|
||||
srcdir = NULL;
|
||||
|
||||
if (targetdir)
|
||||
strcpyW(package->folders[index].TargetDefault,targetdir);
|
||||
|
||||
if (srcdir)
|
||||
strcpyW(package->folders[index].SourceDefault,srcdir);
|
||||
else if (targetdir)
|
||||
strcpyW(package->folders[index].SourceDefault,targetdir);
|
||||
|
||||
if (MsiRecordIsNull(row,2))
|
||||
parent[0]=0;
|
||||
else
|
||||
|
@ -1010,187 +1333,152 @@ static UINT resolve_directory(MSIHANDLE hPackage, const WCHAR* dir,
|
|||
|
||||
if (parent[0])
|
||||
{
|
||||
resolve_directory(hPackage,parent,parent_path,FALSE);
|
||||
strcpyW(full_path,parent_path);
|
||||
if (targetdir)
|
||||
{
|
||||
strcatW(full_path,targetdir);
|
||||
strcatW(full_path,cszbs);
|
||||
i = load_folder(hPackage,parent);
|
||||
package->folders[index].ParentIndex = i;
|
||||
TRACE("Parent is index %i... %s %s\n",
|
||||
package->folders[index].ParentIndex,
|
||||
debugstr_w(package->folders[package->folders[index].ParentIndex].Directory),
|
||||
debugstr_w(parent));
|
||||
}
|
||||
MsiSetPropertyW(hPackage,dir,full_path);
|
||||
if (!source)
|
||||
strcpyW(path,full_path);
|
||||
else
|
||||
package->folders[index].ParentIndex = -2;
|
||||
|
||||
resolve_directory(hPackage,parent,parent_path,TRUE);
|
||||
strcpyW(full_path,parent_path);
|
||||
if (srcdir)
|
||||
sz = MAX_PATH;
|
||||
rc = MsiGetPropertyW(hPackage, dir, package->folders[index].ResolvedTarget,
|
||||
&sz);
|
||||
if (rc == ERROR_SUCCESS || rc == ERROR_MORE_DATA)
|
||||
package->folders[index].Property = TRUE;
|
||||
else
|
||||
{
|
||||
strcatW(full_path,srcdir);
|
||||
strcatW(full_path,cszbs);
|
||||
}
|
||||
else if (targetdir)
|
||||
{
|
||||
strcatW(full_path,targetdir);
|
||||
strcatW(full_path,cszbs);
|
||||
}
|
||||
|
||||
strcpyW(name_source,dir);
|
||||
strcatW(name_source,cszsrc);
|
||||
MsiSetPropertyW(hPackage,name_source,full_path);
|
||||
if (source)
|
||||
strcpyW(path,full_path);
|
||||
package->folders[index].Property = FALSE;
|
||||
}
|
||||
|
||||
MsiCloseHandle(row);
|
||||
MsiViewClose(view);
|
||||
MsiCloseHandle(view);
|
||||
return rc;
|
||||
TRACE(" %s retuning on index %i\n",debugstr_w(dir),index);
|
||||
return index;
|
||||
}
|
||||
|
||||
/*
|
||||
* I am not doing any of the costing functionality yet.
|
||||
* Mostly looking at doing the Component and Feature loading
|
||||
*
|
||||
* The native MSI does ALOT of modification to tables here. Mostly adding alot
|
||||
* of temporary columns to the Feature and Component tables.
|
||||
* Unfortunately I cannot add temporary columns yet, nor can I really figure
|
||||
* out what all the columns are for. So I am going to attack this another way
|
||||
* and make some temporary tables to hold the data I think I need.
|
||||
*
|
||||
* WINE_Feature
|
||||
* Feature Identifier : key into the Feature table
|
||||
* Enabled Int : 1 if being installed, 0 if not
|
||||
*/
|
||||
static UINT ACTION_CostInitialize(MSIHANDLE hPackage)
|
||||
static UINT resolve_folder(MSIHANDLE hPackage, LPCWSTR name, LPWSTR path,
|
||||
BOOL source, BOOL set_prop, MSIFOLDER **folder)
|
||||
{
|
||||
MSIHANDLE db;
|
||||
MSIHANDLE view;
|
||||
MSIHANDLE row;
|
||||
CHAR local[0x100];
|
||||
WCHAR buffer[0x100];
|
||||
MSIPACKAGE *package;
|
||||
INT i;
|
||||
UINT rc = ERROR_SUCCESS;
|
||||
DWORD sz;
|
||||
|
||||
static const CHAR CreateSql[] = "CREATE TABLE `WINE_Feature` ( `Feature`"
|
||||
"CHAR(56) NOT NULL, `Enabled` INT NOT NULL PRIMARY KEY `Feature`)";
|
||||
static const CHAR Insert[] =
|
||||
"INSERT into `WINE_Feature` (`Feature`, `Enabled`) VALUES (?)";
|
||||
static const CHAR Query_all[] = "SELECT * FROM Feature";
|
||||
static const CHAR Query_one[] = "SELECT * FROM Feature WHERE Feature='%s'";
|
||||
CHAR Query[1023];
|
||||
package = msihandle2msiinfo(hPackage, MSIHANDLETYPE_PACKAGE);
|
||||
|
||||
MsiSetPropertyA(hPackage,"CostingComplete","0");
|
||||
MsiSetPropertyW(hPackage, cszRootDrive , c_collen);
|
||||
TRACE("Working to resolve %s\n",debugstr_w(name));
|
||||
|
||||
db = MsiGetActiveDatabase(hPackage);
|
||||
MsiDatabaseOpenViewA(db,CreateSql,&view);
|
||||
MsiViewExecute(view,0);
|
||||
MsiViewClose(view);
|
||||
MsiCloseHandle(view);
|
||||
|
||||
sz = 0x100;
|
||||
if (MsiGetPropertyA(hPackage,"ADDLOCAL",local,&sz)==ERROR_SUCCESS)
|
||||
/* special resolving for Target and Source root dir */
|
||||
if (strcmpW(name,cszTargetDir)==0 || strcmpW(name,cszSourceDir)==0)
|
||||
{
|
||||
if (strcasecmp(local,"ALL")==0)
|
||||
if (!source)
|
||||
{
|
||||
MsiDatabaseOpenViewA(db,Query_all,&view);
|
||||
MsiViewExecute(view,0);
|
||||
while (1)
|
||||
{
|
||||
MSIHANDLE view2;
|
||||
MSIHANDLE row2;
|
||||
DWORD rc;
|
||||
|
||||
rc = MsiViewFetch(view,&row);
|
||||
sz = MAX_PATH;
|
||||
rc = MsiGetPropertyW(hPackage,cszTargetDir,path,&sz);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
break;
|
||||
|
||||
row2 = MsiCreateRecord(2);
|
||||
|
||||
sz=0x100;
|
||||
MsiRecordGetStringW(row,1,buffer,&sz);
|
||||
MsiRecordSetStringW(row2,1,buffer);
|
||||
MsiRecordSetInteger(row2,2,1);
|
||||
|
||||
MsiDatabaseOpenViewA(db,Insert,&view2);
|
||||
MsiViewExecute(view2,row2);
|
||||
MsiCloseHandle(row2);
|
||||
MsiCloseHandle(row);
|
||||
MsiViewClose(view2);
|
||||
MsiCloseHandle(view2);
|
||||
TRACE("Enabling feature %s\n",debugstr_w(buffer));
|
||||
{
|
||||
rc = MsiGetPropertyW(hPackage,cszRootDrive,path,&sz);
|
||||
if (set_prop)
|
||||
MsiSetPropertyW(hPackage,cszTargetDir,path);
|
||||
}
|
||||
MsiViewClose(view);
|
||||
MsiCloseHandle(view);
|
||||
return rc;
|
||||
}
|
||||
else
|
||||
{
|
||||
LPSTR ptr,ptr2;
|
||||
ptr = local;
|
||||
|
||||
while (ptr && *ptr)
|
||||
{
|
||||
CHAR feature[0x100];
|
||||
MSIHANDLE view2;
|
||||
MSIHANDLE row2;
|
||||
DWORD rc;
|
||||
|
||||
ptr2 = strchr(ptr,',');
|
||||
|
||||
if (ptr2)
|
||||
{
|
||||
strncpy(feature,ptr,ptr2-ptr);
|
||||
feature[ptr2-ptr]=0;
|
||||
ptr2++;
|
||||
ptr = ptr2;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(feature,ptr);
|
||||
ptr = NULL;
|
||||
}
|
||||
|
||||
sprintf(Query,Query_one,feature);
|
||||
|
||||
MsiDatabaseOpenViewA(db,Query,&view);
|
||||
MsiViewExecute(view,0);
|
||||
rc = MsiViewFetch(view,&row);
|
||||
sz = MAX_PATH;
|
||||
rc = MsiGetPropertyW(hPackage,cszSourceDir,path,&sz);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
sz = MAX_PATH;
|
||||
rc = MsiGetPropertyW(hPackage,cszDatabase,path,&sz);
|
||||
if (rc == ERROR_SUCCESS)
|
||||
{
|
||||
LPWSTR ptr = strrchrW(path,'\\');
|
||||
if (ptr)
|
||||
{
|
||||
ptr++;
|
||||
*ptr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < package->loaded_folders; i++)
|
||||
{
|
||||
if (strcmpW(package->folders[i].Directory,name)==0)
|
||||
break;
|
||||
|
||||
row2 = MsiCreateRecord(2);
|
||||
|
||||
sz=0x100;
|
||||
MsiRecordGetStringW(row,1,buffer,&sz);
|
||||
MsiRecordSetStringW(row2,1,buffer);
|
||||
MsiRecordSetInteger(row2,2,1);
|
||||
|
||||
MsiDatabaseOpenViewA(db,Insert,&view2);
|
||||
MsiViewExecute(view,row2);
|
||||
MsiCloseHandle(row2);
|
||||
MsiCloseHandle(row);
|
||||
MsiViewClose(view2);
|
||||
MsiCloseHandle(view2);
|
||||
MsiViewClose(view);
|
||||
MsiCloseHandle(view);
|
||||
TRACE("Enabling feature %s\n",feature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MsiCloseHandle(db);
|
||||
if (i >= package->loaded_folders)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
|
||||
if (folder)
|
||||
*folder = &(package->folders[i]);
|
||||
|
||||
if (!source && package->folders[i].ResolvedTarget[0])
|
||||
{
|
||||
strcpyW(path,package->folders[i].ResolvedTarget);
|
||||
TRACE(" already resolved to %s\n",debugstr_w(path));
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
else if (source && package->folders[i].ResolvedSource[0])
|
||||
{
|
||||
strcpyW(path,package->folders[i].ResolvedSource);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
if (!source && package->folders[i].Property)
|
||||
{
|
||||
sz = MAX_PATH;
|
||||
rc = MsiGetPropertyW(hPackage, name, package->folders[i].ResolvedTarget,
|
||||
&sz);
|
||||
if (rc == ERROR_SUCCESS)
|
||||
{
|
||||
strcpyW(path,package->folders[i].ResolvedTarget);
|
||||
TRACE(" found as property %s\n",debugstr_w(path));
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
if (package->folders[i].ParentIndex >= 0)
|
||||
{
|
||||
TRACE(" ! Parent is %s\n", debugstr_w(package->folders[
|
||||
package->folders[i].ParentIndex].Directory));
|
||||
resolve_folder(hPackage, package->folders[
|
||||
package->folders[i].ParentIndex].Directory, path,source,
|
||||
set_prop, NULL);
|
||||
|
||||
if (!source && package->folders[i].TargetDefault[0])
|
||||
{
|
||||
strcatW(path,package->folders[i].TargetDefault);
|
||||
strcatW(path,cszbs);
|
||||
strcpyW(package->folders[i].ResolvedTarget,path);
|
||||
TRACE(" resolved into %s\n",debugstr_w(path));
|
||||
if (set_prop)
|
||||
MsiSetPropertyW(hPackage,name,path);
|
||||
}
|
||||
else if (package->folders[i].SourceDefault[0])
|
||||
{
|
||||
strcatW(path,package->folders[i].SourceDefault);
|
||||
strcatW(path,cszbs);
|
||||
strcpyW(package->folders[i].ResolvedSource,path);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Alot is done in this function aside from just the costing.
|
||||
* The costing needs to be implemented at some point but for now I am going
|
||||
* to focus on the directory building
|
||||
*
|
||||
* WINE_Directory
|
||||
* Directory Identifier: key into the Directory Table
|
||||
* Source Path : resolved source path without SourceDir
|
||||
* Target Path : resolved target path wihout TARGETDIR
|
||||
* Created Int : 0 uncreated, 1 created but if empty remove, 2 created
|
||||
*
|
||||
*/
|
||||
static UINT ACTION_CostFinalize(MSIHANDLE hPackage)
|
||||
|
@ -1237,7 +1525,8 @@ static UINT ACTION_CostFinalize(MSIHANDLE hPackage)
|
|||
|
||||
/* This helper function now does ALL the work */
|
||||
TRACE("Dir %s ...\n",debugstr_w(name));
|
||||
resolve_directory(hPackage,name,path,FALSE);
|
||||
load_folder(hPackage,name);
|
||||
resolve_folder(hPackage,name,path,FALSE,TRUE,NULL);
|
||||
TRACE("resolves to %s\n",debugstr_w(path));
|
||||
|
||||
MsiCloseHandle(row);
|
||||
|
@ -1270,13 +1559,9 @@ static UINT writeout_cabinet_stream(MSIHANDLE hPackage, WCHAR* stream_name,
|
|||
if (rc != ERROR_SUCCESS)
|
||||
return rc;
|
||||
|
||||
write = 0x100;
|
||||
if (MsiGetPropertyW(hPackage, cszSourceDir, source, &write))
|
||||
{
|
||||
ERR("No Source dir defined \n");
|
||||
rc = ERROR_FUNCTION_FAILED;
|
||||
goto end;
|
||||
}
|
||||
write = MAX_PATH;
|
||||
if (MsiGetPropertyW(hPackage, cszTempFolder, source, &write))
|
||||
GetTempPathW(MAX_PATH,source);
|
||||
|
||||
strcatW(source,stream_name);
|
||||
the_file = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
|
||||
|
@ -1408,7 +1693,7 @@ static UINT ready_media_for_file(MSIHANDLE hPackage, UINT sequence,
|
|||
MSIHANDLE row = 0;
|
||||
WCHAR source[MAX_PATH];
|
||||
static const CHAR *ExecSeqQuery =
|
||||
"select * from Media where LastSequence > %i order by LastSequence";
|
||||
"select * from Media where LastSequence >= %i order by LastSequence";
|
||||
CHAR Query[1024];
|
||||
WCHAR cab[0x100];
|
||||
DWORD sz=0x100;
|
||||
|
@ -1453,6 +1738,7 @@ static UINT ready_media_for_file(MSIHANDLE hPackage, UINT sequence,
|
|||
{
|
||||
sz=0x100;
|
||||
MsiRecordGetStringW(row,4,cab,&sz);
|
||||
TRACE("Source is CAB %s\n",debugstr_w(cab));
|
||||
/* the stream does not contain the # character */
|
||||
if (cab[0]=='#')
|
||||
{
|
||||
|
@ -1472,6 +1758,11 @@ static UINT ready_media_for_file(MSIHANDLE hPackage, UINT sequence,
|
|||
{
|
||||
strcpyW(path,source);
|
||||
strcatW(source,cab);
|
||||
/* extract the cab file into a folder in the temp folder */
|
||||
sz = MAX_PATH;
|
||||
if (MsiGetPropertyW(hPackage, cszTempFolder,path, &sz)
|
||||
!= ERROR_SUCCESS)
|
||||
GetTempPathW(MAX_PATH,path);
|
||||
}
|
||||
}
|
||||
rc = !extract_cabinet_file(source,path);
|
||||
|
@ -1506,6 +1797,7 @@ static UINT get_directory_for_component(MSIHANDLE hPackage,
|
|||
WCHAR dir[0x100];
|
||||
DWORD sz=0x100;
|
||||
MSIHANDLE db;
|
||||
MSIFOLDER *folder;
|
||||
|
||||
strcatW(ExecSeqQuery,component);
|
||||
strcatW(ExecSeqQuery,end);
|
||||
|
@ -1537,11 +1829,19 @@ static UINT get_directory_for_component(MSIHANDLE hPackage,
|
|||
sz=0x100;
|
||||
MsiRecordGetStringW(row,3,dir,&sz);
|
||||
sz=MAX_PATH;
|
||||
rc = MsiGetPropertyW(hPackage, dir, install_path, &sz);
|
||||
rc = resolve_folder(hPackage, dir, install_path, FALSE, FALSE, &folder);
|
||||
|
||||
MsiCloseHandle(row);
|
||||
MsiViewClose(view);
|
||||
MsiCloseHandle(view);
|
||||
|
||||
/* create the path */
|
||||
if (folder->State == 0)
|
||||
{
|
||||
create_full_pathW(install_path);
|
||||
folder->State = 2;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1639,8 +1939,6 @@ static UINT ACTION_InstallFiles(MSIHANDLE hPackage)
|
|||
}
|
||||
reduce_to_longfilename(filename);
|
||||
|
||||
/* create the path */
|
||||
create_full_pathW(install_path);
|
||||
|
||||
strcatW(install_path,filename);
|
||||
|
||||
|
@ -2115,8 +2413,26 @@ UINT WINAPI MsiGetTargetPathA( MSIHANDLE hInstall, LPCSTR szFolder,
|
|||
UINT WINAPI MsiGetTargetPathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
|
||||
szPathBuf, DWORD* pcchPathBuf)
|
||||
{
|
||||
WCHAR path[MAX_PATH];
|
||||
UINT rc;
|
||||
|
||||
TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
|
||||
return MsiGetPropertyW(hInstall,szFolder,szPathBuf,pcchPathBuf);
|
||||
|
||||
rc = resolve_folder(hInstall, szFolder, path, FALSE, FALSE, NULL);
|
||||
|
||||
if (rc == ERROR_SUCCESS && strlenW(path) > *pcchPathBuf)
|
||||
{
|
||||
*pcchPathBuf = strlenW(path)+1;
|
||||
return ERROR_MORE_DATA;
|
||||
}
|
||||
else if (rc == ERROR_SUCCESS)
|
||||
{
|
||||
*pcchPathBuf = strlenW(path)+1;
|
||||
strcpyW(szPathBuf,path);
|
||||
TRACE("Returning Path %s\n",debugstr_w(path));
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2158,23 +2474,24 @@ UINT WINAPI MsiGetSourcePathA( MSIHANDLE hInstall, LPCSTR szFolder,
|
|||
UINT WINAPI MsiGetSourcePathW( MSIHANDLE hInstall, LPCWSTR szFolder, LPWSTR
|
||||
szPathBuf, DWORD* pcchPathBuf)
|
||||
{
|
||||
static const WCHAR cszsrc[]={'_','S','o','u','r','c','e',0};
|
||||
LPWSTR newfolder;
|
||||
WCHAR path[MAX_PATH];
|
||||
UINT rc;
|
||||
|
||||
TRACE("(%s %p %li)\n",debugstr_w(szFolder),szPathBuf,*pcchPathBuf);
|
||||
rc = resolve_folder(hInstall, szFolder, path, TRUE, FALSE, NULL);
|
||||
|
||||
if (strcmpW(szFolder, cszSourceDir) != 0)
|
||||
if (rc == ERROR_SUCCESS && strlenW(path) > *pcchPathBuf)
|
||||
{
|
||||
newfolder = HeapAlloc(GetProcessHeap(),0,
|
||||
(strlenW(szFolder)+8)*sizeof(WCHAR));
|
||||
strcpyW(newfolder,szFolder);
|
||||
strcatW(newfolder,cszsrc);
|
||||
rc = MsiGetPropertyW(hInstall,newfolder,szPathBuf,pcchPathBuf);
|
||||
HeapFree(GetProcessHeap(),0,newfolder);
|
||||
*pcchPathBuf = strlenW(path)+1;
|
||||
return ERROR_MORE_DATA;
|
||||
}
|
||||
else
|
||||
rc = MsiGetPropertyW(hInstall,szFolder,szPathBuf,pcchPathBuf);
|
||||
else if (rc == ERROR_SUCCESS)
|
||||
{
|
||||
*pcchPathBuf = strlenW(path)+1;
|
||||
strcpyW(szPathBuf,path);
|
||||
TRACE("Returning Path %s\n",debugstr_w(path));
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -2221,9 +2538,37 @@ UINT WINAPI MsiSetTargetPathA(MSIHANDLE hInstall, LPCSTR szFolder,
|
|||
UINT WINAPI MsiSetTargetPathW(MSIHANDLE hInstall, LPCWSTR szFolder,
|
||||
LPCWSTR szFolderPath)
|
||||
{
|
||||
MSIPACKAGE *package;
|
||||
INT i;
|
||||
WCHAR path[MAX_PATH];
|
||||
|
||||
TRACE("(%s %s)\n",debugstr_w(szFolder),debugstr_w(szFolderPath));
|
||||
|
||||
return MsiSetPropertyW(hInstall,szFolder,szFolderPath);
|
||||
if (szFolderPath[0]==0)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
package = msihandle2msiinfo(hInstall, MSIHANDLETYPE_PACKAGE);
|
||||
|
||||
if (package==NULL)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
MsiSetPropertyW(hInstall,szFolder,szFolderPath);
|
||||
|
||||
for (i = 0; i < package->loaded_folders; i++)
|
||||
{
|
||||
package->folders[i].ResolvedTarget[0]=0;
|
||||
|
||||
if (strcmpW(package->folders[i].Directory,szFolder)==0)
|
||||
package->folders[i].Property = TRUE;
|
||||
}
|
||||
|
||||
for (i = 0; i < package->loaded_folders; i++)
|
||||
{
|
||||
resolve_folder(hInstall, package->folders[i].Directory, path, FALSE,
|
||||
TRUE, NULL);
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
BOOL WINAPI MsiGetMode(MSIHANDLE hInstall, DWORD iRunMode)
|
||||
|
|
|
@ -140,6 +140,17 @@ typedef struct tagMSIHANDLEINFO
|
|||
struct tagMSIHANDLEINFO *prev;
|
||||
} MSIHANDLEINFO;
|
||||
|
||||
typedef struct tagMSIPACKAGE
|
||||
{
|
||||
MSIHANDLE db;
|
||||
struct tagMSIFEATURE *features;
|
||||
UINT loaded_features;
|
||||
struct tagMSIFOLDER *folders;
|
||||
UINT loaded_folders;
|
||||
struct tagMSICOMPONENT *components;
|
||||
UINT loaded_components;
|
||||
} MSIPACKAGE;
|
||||
|
||||
#define MSIHANDLETYPE_ANY 0
|
||||
#define MSIHANDLETYPE_DATABASE 1
|
||||
#define MSIHANDLETYPE_SUMMARYINFO 2
|
||||
|
|
|
@ -50,16 +50,20 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
|||
|
||||
void MSI_FreePackage( VOID *arg);
|
||||
|
||||
typedef struct tagMSIPACKAGE
|
||||
{
|
||||
MSIHANDLE db;
|
||||
} MSIPACKAGE;
|
||||
|
||||
void MSI_FreePackage( VOID *arg)
|
||||
{
|
||||
MSIPACKAGE *package= arg;
|
||||
|
||||
MsiCloseHandle(package->db);
|
||||
|
||||
if (package->features && package->loaded_features > 0)
|
||||
HeapFree(GetProcessHeap(),0,package->features);
|
||||
|
||||
if (package->folders && package->loaded_folders > 0)
|
||||
HeapFree(GetProcessHeap(),0,package->folders);
|
||||
|
||||
if (package->components && package->loaded_components > 0)
|
||||
HeapFree(GetProcessHeap(),0,package->components);
|
||||
}
|
||||
|
||||
UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
|
||||
|
@ -292,6 +296,12 @@ UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
|
|||
}
|
||||
|
||||
package->db = db;
|
||||
package->features = NULL;
|
||||
package->folders = NULL;
|
||||
package->components = NULL;
|
||||
package->loaded_features = 0;
|
||||
package->loaded_folders = 0;
|
||||
package->loaded_components= 0;
|
||||
|
||||
/* ok here is where we do a slew of things to the database to
|
||||
* prep for all that is to come as a package */
|
||||
|
@ -341,7 +351,9 @@ INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
|
|||
DWORD log_type = 0;
|
||||
LPSTR message;
|
||||
DWORD sz;
|
||||
DWORD total_size = 0;
|
||||
INT msg_field=1;
|
||||
INT i;
|
||||
FIXME("STUB: %x \n",eMessageType);
|
||||
|
||||
if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR)
|
||||
|
@ -355,24 +367,40 @@ INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
|
|||
if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA)
|
||||
log_type |= INSTALLLOGMODE_COMMONDATA;
|
||||
if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
|
||||
{
|
||||
log_type |= INSTALLLOGMODE_ACTIONSTART;
|
||||
msg_field = 2;
|
||||
}
|
||||
if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONDATA)
|
||||
log_type |= INSTALLLOGMODE_ACTIONDATA;
|
||||
|
||||
message = HeapAlloc(GetProcessHeap(),0,1);
|
||||
message[0]=0;
|
||||
msg_field = MsiRecordGetFieldCount(hRecord);
|
||||
for (i = 1; i <= msg_field; i++)
|
||||
{
|
||||
LPSTR tmp;
|
||||
CHAR number[3];
|
||||
sz = 0;
|
||||
MsiRecordGetStringA(hRecord,msg_field,NULL,&sz);
|
||||
sz++;
|
||||
message = HeapAlloc(GetProcessHeap(),0,sz);
|
||||
MsiRecordGetStringA(hRecord,msg_field,message,&sz);
|
||||
MsiRecordGetStringA(hRecord,i,NULL,&sz);
|
||||
sz+=4;
|
||||
total_size+=sz;
|
||||
tmp = HeapAlloc(GetProcessHeap(),0,sz);
|
||||
message = HeapReAlloc(GetProcessHeap(),0,message,total_size);
|
||||
|
||||
MsiRecordGetStringA(hRecord,i,tmp,&sz);
|
||||
|
||||
if (msg_field > 1)
|
||||
{
|
||||
sprintf(number,"%i: ",i);
|
||||
strcat(message,number);
|
||||
}
|
||||
strcat(message,tmp);
|
||||
HeapFree(GetProcessHeap(),0,tmp);
|
||||
}
|
||||
|
||||
TRACE("(%p %lx %lx %s)\n",gUIHandler, gUIFilter, log_type,
|
||||
debugstr_a(message));
|
||||
|
||||
TRACE("(%p %lx %lx)\n",gUIHandler, gUIFilter, log_type);
|
||||
if (gUIHandler && (gUIFilter & log_type))
|
||||
gUIHandler(gUIContext,eMessageType,message);
|
||||
else
|
||||
TRACE("%s\n",debugstr_a(message));
|
||||
|
||||
HeapFree(GetProcessHeap(),0,message);
|
||||
return ERROR_SUCCESS;
|
||||
|
|
Loading…
Reference in New Issue