Start implementing Feature and Component level install control.
This commit is contained in:
parent
1510cfc474
commit
36eee236ea
@ -132,6 +132,49 @@ UINT ACTION_DoTopLevelINSTALL(MSIHANDLE hPackage, LPCWSTR szPackagePath,
|
|||||||
MsiSetPropertyW(hPackage, cszSourceDir, pth);
|
MsiSetPropertyW(hPackage, cszSourceDir, pth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (szCommandLine)
|
||||||
|
{
|
||||||
|
LPWSTR ptr,ptr2;
|
||||||
|
ptr = (LPWSTR)szCommandLine;
|
||||||
|
|
||||||
|
while (*ptr)
|
||||||
|
{
|
||||||
|
BOOL quote=FALSE;
|
||||||
|
WCHAR prop[0x100];
|
||||||
|
WCHAR val[0x100];
|
||||||
|
|
||||||
|
ptr2 = strchrW(ptr,'=');
|
||||||
|
if (ptr2)
|
||||||
|
{
|
||||||
|
DWORD len = 0;
|
||||||
|
strncpyW(prop,ptr,ptr2-ptr);
|
||||||
|
prop[ptr2-ptr]=0;
|
||||||
|
ptr2++;
|
||||||
|
|
||||||
|
ptr = ptr2;
|
||||||
|
while (*ptr && (!quote && *ptr!=' '))
|
||||||
|
{
|
||||||
|
if (*ptr == '"')
|
||||||
|
quote = !quote;
|
||||||
|
ptr++;
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*ptr2=='"')
|
||||||
|
{
|
||||||
|
ptr2++;
|
||||||
|
len -= 2;
|
||||||
|
}
|
||||||
|
strncpyW(val,ptr2,len);
|
||||||
|
val[len]=0;
|
||||||
|
|
||||||
|
if (*ptr)
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
MsiSetPropertyW(hPackage,prop,val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
db = MsiGetActiveDatabase(hPackage);
|
db = MsiGetActiveDatabase(hPackage);
|
||||||
rc = MsiDatabaseOpenViewA(db, ExecSeqQuery, &view);
|
rc = MsiDatabaseOpenViewA(db, ExecSeqQuery, &view);
|
||||||
MsiCloseHandle(db);
|
MsiCloseHandle(db);
|
||||||
@ -514,6 +557,12 @@ static UINT HANDLE_CustomType1(MSIHANDLE hPackage, const LPWSTR source,
|
|||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!strchrW(tmp_file,'.'))
|
||||||
|
{
|
||||||
|
static const WCHAR dot[]={'.',0};
|
||||||
|
strcatW(tmp_file,dot);
|
||||||
|
}
|
||||||
|
|
||||||
DLL = LoadLibraryW(tmp_file);
|
DLL = LoadLibraryW(tmp_file);
|
||||||
if (DLL)
|
if (DLL)
|
||||||
{
|
{
|
||||||
@ -633,7 +682,7 @@ sizeof(WCHAR));
|
|||||||
*/
|
*/
|
||||||
static UINT ACTION_CreateFolders(MSIHANDLE hPackage)
|
static UINT ACTION_CreateFolders(MSIHANDLE hPackage)
|
||||||
{
|
{
|
||||||
static const CHAR *ExecSeqQuery = "select * from CreateFolder";
|
static const CHAR *ExecSeqQuery = "select Directory_ from CreateFolder";
|
||||||
UINT rc;
|
UINT rc;
|
||||||
MSIHANDLE view;
|
MSIHANDLE view;
|
||||||
MSIHANDLE db;
|
MSIHANDLE db;
|
||||||
@ -865,12 +914,136 @@ static UINT resolve_directory(MSIHANDLE hPackage, const WCHAR* dir,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the action where all the features and components are loaded into
|
* I am not doing any of the costing functionality yet.
|
||||||
* memory... so when we start doing that that will be important.
|
* 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.
|
||||||
|
* Unfortinatly i cannot add temporary columns yet, nor can i really figure
|
||||||
|
* out what all the colums 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 ACTION_CostInitialize(MSIHANDLE hPackage)
|
||||||
{
|
{
|
||||||
|
MSIHANDLE db;
|
||||||
|
MSIHANDLE view;
|
||||||
|
MSIHANDLE row;
|
||||||
|
CHAR local[0x100];
|
||||||
|
WCHAR buffer[0x100];
|
||||||
|
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];
|
||||||
|
|
||||||
|
MsiSetPropertyA(hPackage,"CostingComplete","0");
|
||||||
|
MsiSetPropertyW(hPackage, cszRootDrive , c_collen);
|
||||||
|
|
||||||
|
db = MsiGetActiveDatabase(hPackage);
|
||||||
|
MsiDatabaseOpenViewA(db,CreateSql,&view);
|
||||||
|
MsiViewExecute(view,0);
|
||||||
|
MsiViewClose(view);
|
||||||
|
MsiCloseHandle(view);
|
||||||
|
|
||||||
|
sz = 0x100;
|
||||||
|
if (MsiGetPropertyA(hPackage,"ADDLOCAL",local,&sz)==ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
if (strcasecmp(local,"ALL")==0)
|
||||||
|
{
|
||||||
|
MsiDatabaseOpenViewA(db,Query_all,&view);
|
||||||
|
MsiViewExecute(view,0);
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
MSIHANDLE view2;
|
||||||
|
MSIHANDLE row2;
|
||||||
|
DWORD rc;
|
||||||
|
|
||||||
|
rc = MsiViewFetch(view,&row);
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
MsiViewClose(view);
|
||||||
|
MsiCloseHandle(view);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
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(view,row2);
|
||||||
|
MsiCloseHandle(row2);
|
||||||
|
MsiCloseHandle(row);
|
||||||
|
MsiViewClose(view2);
|
||||||
|
MsiCloseHandle(view2);
|
||||||
|
MsiViewClose(view);
|
||||||
|
MsiCloseHandle(view);
|
||||||
|
TRACE("Enabling feature %s\n",feature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MsiCloseHandle(db);
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -879,9 +1052,12 @@ static UINT ACTION_CostInitialize(MSIHANDLE hPackage)
|
|||||||
* The costing needs to be implemented at some point but for now i am going
|
* The costing needs to be implemented at some point but for now i am going
|
||||||
* to focus on the directory building
|
* to focus on the directory building
|
||||||
*
|
*
|
||||||
* Note about directory names: I know that directory names get processed into
|
* WINE_Directory
|
||||||
* properties. I am still very unclear where the name_source
|
* Directory Identifier: key into the Directory Table
|
||||||
* part is used but I am preserving it just as a precaution
|
* 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)
|
static UINT ACTION_CostFinalize(MSIHANDLE hPackage)
|
||||||
{
|
{
|
||||||
@ -990,26 +1166,74 @@ end:
|
|||||||
*
|
*
|
||||||
* Extract a file from a .cab file.
|
* Extract a file from a .cab file.
|
||||||
*/
|
*/
|
||||||
static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root)
|
static void (WINAPI *pExtractFiles)( LPSTR, LPSTR, DWORD, DWORD, DWORD, DWORD );
|
||||||
|
|
||||||
|
static BOOL extract_cabinet_file_advpack( const WCHAR *cabinet,
|
||||||
|
const WCHAR *root)
|
||||||
|
{
|
||||||
|
static const WCHAR extW[] = {'.','c','a','b',0};
|
||||||
|
static HMODULE advpack;
|
||||||
|
|
||||||
|
char *cab_path, *cab_file;
|
||||||
|
int len = strlenW( cabinet );
|
||||||
|
|
||||||
|
/* make sure the cabinet file has a .cab extension */
|
||||||
|
if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE;
|
||||||
|
if (!pExtractFiles)
|
||||||
|
{
|
||||||
|
if (!advpack && !(advpack = LoadLibraryA( "advpack.dll" )))
|
||||||
|
{
|
||||||
|
ERR( "could not load advpack.dll\n" );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (!(pExtractFiles = (void *)GetProcAddress( advpack, "ExtractFiles"
|
||||||
|
)))
|
||||||
|
{
|
||||||
|
ERR( "could not find ExtractFiles in advpack.dll\n" );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(cab_file = strdupWtoA( cabinet ))) return FALSE;
|
||||||
|
if (!(cab_path = strdupWtoA( root ))) return FALSE;
|
||||||
|
|
||||||
|
FIXME( "awful hack: extracting cabinet %s\n", debugstr_a(cab_file) );
|
||||||
|
pExtractFiles( cab_file, cab_path, 0, 0, 0, 0 );
|
||||||
|
HeapFree( GetProcessHeap(), 0, cab_file );
|
||||||
|
HeapFree( GetProcessHeap(), 0, cab_path );
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL extract_cabinet_file_cabinet( const WCHAR *cabinet,
|
||||||
|
const WCHAR *root)
|
||||||
|
|
||||||
{
|
{
|
||||||
static const WCHAR extW[] = {'.','c','a','b',0};
|
static const WCHAR extW[] = {'.','c','a','b',0};
|
||||||
|
|
||||||
/* from cabinet.h */
|
/* from cabinet.h */
|
||||||
|
|
||||||
|
struct ExtractFileList {
|
||||||
|
LPSTR filename;
|
||||||
|
struct ExtractFileList *next;
|
||||||
|
BOOL unknown; /* always 1L */
|
||||||
|
} ;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
long result1; /* 0x000 */
|
long result1; /* 0x000 */
|
||||||
long unknown1[3]; /* 0x004 */
|
long unknown1[3]; /* 0x004 */
|
||||||
void* filelist; /* 0x010 */
|
struct ExtractFileList* filelist; /* 0x010 */
|
||||||
long filecount; /* 0x014 */
|
long filecount; /* 0x014 */
|
||||||
long unknown2; /* 0x018 */
|
long unknown2; /* 0x018 */
|
||||||
char directory[0x104]; /* 0x01c */
|
char directory[0x104]; /* 0x01c */
|
||||||
char lastfile[0x20c]; /* 0x120 */
|
char lastfile[0x20c]; /* 0x120 */
|
||||||
} EXTRACTdest;
|
} EXTRACTdest;
|
||||||
extern HRESULT WINAPI Extract(EXTRACTdest*, LPCSTR);
|
|
||||||
|
HRESULT WINAPI Extract(EXTRACTdest *dest, LPCSTR what);
|
||||||
|
|
||||||
char *cab_path, *src_path;
|
char *cab_path, *src_path;
|
||||||
int len = strlenW( cabinet );
|
int len = strlenW( cabinet );
|
||||||
EXTRACTdest exd;
|
EXTRACTdest exd;
|
||||||
|
struct ExtractFileList fl;
|
||||||
|
|
||||||
/* make sure the cabinet file has a .cab extension */
|
/* make sure the cabinet file has a .cab extension */
|
||||||
if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE;
|
if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE;
|
||||||
@ -1019,12 +1243,27 @@ static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root)
|
|||||||
|
|
||||||
memset(&exd,0,sizeof(exd));
|
memset(&exd,0,sizeof(exd));
|
||||||
strcpy(exd.directory,src_path);
|
strcpy(exd.directory,src_path);
|
||||||
|
exd.unknown2 = 0x1;
|
||||||
|
fl.filename = cab_path;
|
||||||
|
fl.next = NULL;
|
||||||
|
fl.unknown = 1;
|
||||||
|
exd.filelist = &fl;
|
||||||
|
FIXME( "awfuler hack: extracting cabinet %s\n", debugstr_a(cab_path) );
|
||||||
Extract(&exd,cab_path);
|
Extract(&exd,cab_path);
|
||||||
|
|
||||||
HeapFree( GetProcessHeap(), 0, cab_path );
|
HeapFree( GetProcessHeap(), 0, cab_path );
|
||||||
HeapFree( GetProcessHeap(), 0, src_path );
|
HeapFree( GetProcessHeap(), 0, src_path );
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static BOOL extract_cabinet_file(const WCHAR* source, const WCHAR* path)
|
||||||
|
{
|
||||||
|
if (!extract_cabinet_file_advpack(source,path))
|
||||||
|
return extract_cabinet_file_cabinet(source,path);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static UINT ready_media_for_file(MSIHANDLE hPackage, UINT sequence,
|
static UINT ready_media_for_file(MSIHANDLE hPackage, UINT sequence,
|
||||||
WCHAR* path)
|
WCHAR* path)
|
||||||
{
|
{
|
||||||
@ -1263,6 +1502,10 @@ static UINT ACTION_InstallFiles(MSIHANDLE hPackage)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
reduce_to_longfilename(filename);
|
reduce_to_longfilename(filename);
|
||||||
|
|
||||||
|
/* create the path */
|
||||||
|
create_full_pathW(install_path);
|
||||||
|
|
||||||
strcatW(install_path,filename);
|
strcatW(install_path,filename);
|
||||||
|
|
||||||
TRACE("Installing file %s to %s\n",debugstr_w(src_path),
|
TRACE("Installing file %s to %s\n",debugstr_w(src_path),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user