MSI: start implementing Feature and Component level install control
Mike McCormack
mike at codeweavers.com
Thu Jul 1 10:10:17 CDT 2004
ChangeLog:
<aric at codeweaver.com>
* start implementing Feature and Component level install control
-------------- next part --------------
Index: dlls/msi/action.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/action.c,v
retrieving revision 1.6
diff -u -r1.6 action.c
--- dlls/msi/action.c 30 Jun 2004 19:38:36 -0000 1.6
+++ dlls/msi/action.c 1 Jul 2004 16:05:52 -0000
@@ -132,6 +132,49 @@
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);
rc = MsiDatabaseOpenViewA(db, ExecSeqQuery, &view);
MsiCloseHandle(db);
@@ -514,6 +557,12 @@
return ERROR_SUCCESS;
}
+ if (!strchrW(tmp_file,'.'))
+ {
+ static const WCHAR dot[]={'.',0};
+ strcatW(tmp_file,dot);
+ }
+
DLL = LoadLibraryW(tmp_file);
if (DLL)
{
@@ -633,7 +682,7 @@
*/
static UINT ACTION_CreateFolders(MSIHANDLE hPackage)
{
- static const CHAR *ExecSeqQuery = "select * from CreateFolder";
+ static const CHAR *ExecSeqQuery = "select Directory_ from CreateFolder";
UINT rc;
MSIHANDLE view;
MSIHANDLE db;
@@ -865,12 +914,136 @@
}
/*
- * This is the action where all the features and components are loaded into
- * memory... so when we start doing that that will be important.
- *
+ * 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.
+ * 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)
{
+ 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;
}
@@ -879,9 +1052,12 @@
* The costing needs to be implemented at some point but for now i am going
* to focus on the directory building
*
- * Note about directory names: I know that directory names get processed into
- * properties. I am still very unclear where the name_source
- * part is used but I am preserving it just as a precaution
+ * 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)
{
@@ -990,26 +1166,74 @@
*
* 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};
/* from cabinet.h */
+
+ struct ExtractFileList {
+ LPSTR filename;
+ struct ExtractFileList *next;
+ BOOL unknown; /* always 1L */
+ } ;
+
typedef struct {
long result1; /* 0x000 */
long unknown1[3]; /* 0x004 */
- void* filelist; /* 0x010 */
+ struct ExtractFileList* filelist; /* 0x010 */
long filecount; /* 0x014 */
long unknown2; /* 0x018 */
char directory[0x104]; /* 0x01c */
char lastfile[0x20c]; /* 0x120 */
} EXTRACTdest;
- extern HRESULT WINAPI Extract(EXTRACTdest*, LPCSTR);
+
+ HRESULT WINAPI Extract(EXTRACTdest *dest, LPCSTR what);
char *cab_path, *src_path;
int len = strlenW( cabinet );
EXTRACTdest exd;
+ struct ExtractFileList fl;
/* make sure the cabinet file has a .cab extension */
if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE;
@@ -1019,12 +1243,27 @@
memset(&exd,0,sizeof(exd));
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);
+
HeapFree( GetProcessHeap(), 0, cab_path );
HeapFree( GetProcessHeap(), 0, src_path );
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,
WCHAR* path)
{
@@ -1263,6 +1502,10 @@
break;
}
reduce_to_longfilename(filename);
+
+ /* create the path */
+ create_full_pathW(install_path);
+
strcatW(install_path,filename);
TRACE("Installing file %s to %s\n",debugstr_w(src_path),
More information about the wine-patches
mailing list