Sync to Wine-20050111: Vitaly Lipatov lav@etersoft.ru - Get real screen properties. - Add description for MsiGetMode, MSIRUNMODE constants. - Add ScreenX, ScreenY, ColorBits installer properties. Mike McCormack mike@codeweavers.com - Add a simple test case for MSI databases. - Remove unneeded whitespace, indent correctly. - Remove more fixed length buffers, rewrite functions to return malloc'ed memory. - Remove a lot of fixed length buffers. - Implement thread safety for records. - Fix selecting string columns and matching against a wildcard. - Implement MsiRecordSetStreamA/W and add tests for records containing streams. - Fix records according to test cases. - Fix transposition of 4 byte values when reading in table data from storage. - MsiCloseAllHandles only closes handles allocated in the calling thread. Francois Gouget fgouget@free.fr - Assorted spelling fixes. Aric Stewart aric@codeweavers.com - Make all custom type 1 actions happen in a seperate thread and close all handles for that thread when it exits. Honors the concept of temporary MSI handles for custom actions. - Properly deformat keys written to the registry. - Because directory mappings can change between the CostFinalize step and the InstallFiles step we need to do a final resolution of the target file name before installing. - When checking for an existing .lnk shortcut extension on the filename do not just search for '.' but actually verify it is '.lnk'. - CustomAction 35 should call SetTargetPath not just set the property. - TARGETDIR and SOURCEDIR may not be entries 0 in the directory tables. So when resolving the folder we need to seek them out. - When we handle SetTargetPath we need to be sure to recalculate the resulting paths as things with the now set Directory as the parent will change. - Change how we install files so that we extract files as we need them, cuts down on extraction time and unused files. - Improve progress bar tracking. - Be sure that set paths are terminated with a backslash. - Free allocated buffers. - Parse out the full features by using the ',' character and do comparisons based on the full feature names. - Continue when a duplicate component is found and loaded. - Rework how we handle Feature and Component States. I have confirmed from testing that, although documented nowhere, having ADDLOCAL on the install line overrides INSTALLLEVEL. - Track all files extracted from cabinents as tempfiles so they can be removed at the end of the install to not leave uninstalled but uncabbed files laying around. - Move Install Features selection and evaluation into CostFinalize. - Allow for end of install actions. - Create the shortcut directory if it does not exist. - Set the INSTALLLEVEL in CostFinalize if it is not set. - Eliminate some fixed length buffers. - Enable asynchronous dll custom action calls. - Make sure to include trailing backslash in path. - Move around and rename some functions. - Fix incorrect return code check. - Fix folder resolution. - Let negative number be parsed correctly. Needed for accessing actions with sequences such as -1. - Added MsiSetExternalUIW. - Include a System16Folder definition. - Free allocated buffers. - Blank the property buffers even if the property is not found. - Include the trailing backslash on the Windows volume. - Fix folder resolution. Eric Pouech pouech-eric@wanadoo.fr - Fixed some errors in function prototypes. Steven Edwards steven@codeweavers.com - Add and fix some stubs. Ulrich Czekalla ulrich@codeweavers.com - Set the out buffer count to zero on read error. Michael Stefaniuc mstefani@redhat.de - Add missing HeapFree's (found by smatch). Paul Vriens Paul.Vriens@xs4all.nl - Use Interlocked* functions in AddRef and Release. Modified: trunk/reactos/include/wine/msiquery.h Modified: trunk/reactos/lib/msi/Makefile.in Modified: trunk/reactos/lib/msi/action.c Modified: trunk/reactos/lib/msi/handle.c Modified: trunk/reactos/lib/msi/msi.c Modified: trunk/reactos/lib/msi/msi.spec Modified: trunk/reactos/lib/msi/msipriv.h Modified: trunk/reactos/lib/msi/package.c Modified: trunk/reactos/lib/msi/query.h Modified: trunk/reactos/lib/msi/record.c Modified: trunk/reactos/lib/msi/sql.tab.c Modified: trunk/reactos/lib/msi/sql.tab.h Modified: trunk/reactos/lib/msi/sql.y Modified: trunk/reactos/lib/msi/table.c Modified: trunk/reactos/lib/msi/where.c _____
Modified: trunk/reactos/include/wine/msiquery.h --- trunk/reactos/include/wine/msiquery.h 2005-01-12 09:03:31 UTC (rev 12947) +++ trunk/reactos/include/wine/msiquery.h 2005-01-12 09:31:44 UTC (rev 12948) @@ -59,7 +59,30 @@
#define MSIDBOPEN_TRANSACT (LPCTSTR)1 #define MSIDBOPEN_DIRECT (LPCTSTR)2 #define MSIDBOPEN_CREATE (LPCTSTR)3 +#define MSIDBOPEN_CREATEDIRECT (LPCTSTR)4
+typedef enum tagMSIRUNMODE +{ + MSIRUNMODE_ADMIN = 0, + MSIRUNMODE_ADVERTISE = 1, + MSIRUNMODE_MAINTENANCE = 2, + MSIRUNMODE_ROLLBACKENABLED = 3, + MSIRUNMODE_LOGENABLED = 4, + MSIRUNMODE_OPERATIONS = 5, + MSIRUNMODE_REBOOTATEND = 6, + MSIRUNMODE_REBOOTNOW = 7, + MSIRUNMODE_CABINET = 8, + MSIRUNMODE_SOURCESHORTNAMES = 9, + MSIRUNMODE_TARGETSHORTNAMES = 10, + MSIRUNMODE_RESERVED11 = 11, + MSIRUNMODE_WINDOWS9X = 12, + MSIRUNMODE_ZAWENABLED = 13, + MSIRUNMODE_RESERVED14 = 14, + MSIRUNMODE_RESERVED15 = 15, + MSIRUNMODE_SCHEDULED = 16, + MSIRUNMODE_ROLLBACK = 17, + MSIRUNMODE_COMMIT = 18 +} MSIRUNMODE;
/* view manipulation */ UINT WINAPI MsiViewFetch(MSIHANDLE,MSIHANDLE*); @@ -123,15 +146,12 @@ #define MsiEvaluateCondition WINELIB_NAME_AW(MsiEvaluateCondition)
/* property functions */ -UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, - LPSTR szValueBuf, DWORD* pchValueBuf); -UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName, - LPWSTR szValueBuf, DWORD* pchValueBuf); +UINT WINAPI MsiGetPropertyA(MSIHANDLE, LPCSTR, LPSTR, DWORD*); +UINT WINAPI MsiGetPropertyW(MSIHANDLE, LPCWSTR, LPWSTR, DWORD*); #define MsiGetProperty WINELIB_NAME_AW(MsiGetProperty)
-UINT WINAPI MsiSetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue); -UINT WINAPI MsiSetPropertyW(MSIHANDLE hInstall, LPCWSTR szName, - LPCWSTR szValue); +UINT WINAPI MsiSetPropertyA(MSIHANDLE, LPCSTR, LPCSTR); +UINT WINAPI MsiSetPropertyW(MSIHANDLE, LPCWSTR, LPCWSTR); #define MsiSetProperty WINELIB_NAME_AW(MsiSetProperty)
UINT WINAPI MsiGetTargetPathA(MSIHANDLE,LPCSTR,LPSTR,DWORD*); @@ -148,11 +168,13 @@
MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE);
-UINT WINAPI MsiViewGetColumnInfo( MSIHANDLE, MSICOLINFO, MSIHANDLE*); -INT WINAPI MsiProcessMessage( MSIHANDLE, INSTALLMESSAGE, MSIHANDLE); +UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE, MSICOLINFO, MSIHANDLE*); +INT WINAPI MsiProcessMessage(MSIHANDLE, INSTALLMESSAGE, MSIHANDLE);
-UINT WINAPI MsiSetFeatureStateA( MSIHANDLE, LPCSTR, INSTALLSTATE); -UINT WINAPI MsiSetFeatureStateW( MSIHANDLE, LPCWSTR, INSTALLSTATE); +UINT WINAPI MsiSetFeatureStateA(MSIHANDLE, LPCSTR, INSTALLSTATE); +UINT WINAPI MsiSetFeatureStateW(MSIHANDLE, LPCWSTR, INSTALLSTATE); #define MsiSetFeatureState WINELIB_NAME_AW(MsiSetFeatureState)
+BOOL WINAPI MsiGetMode(MSIHANDLE, MSIRUNMODE); + #endif /* __WINE_MSIQUERY_H */ _____
Modified: trunk/reactos/lib/msi/Makefile.in --- trunk/reactos/lib/msi/Makefile.in 2005-01-12 09:03:31 UTC (rev 12947) +++ trunk/reactos/lib/msi/Makefile.in 2005-01-12 09:31:44 UTC (rev 12948) @@ -3,7 +3,7 @@
SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = msi.dll -IMPORTS = shell32 cabinet oleaut32 ole32 version user32 advapi32 kernel32 +IMPORTS = shell32 cabinet oleaut32 ole32 version user32 gdi32 advapi32 kernel32 EXTRALIBS = -luuid $(LIBUNICODE)
C_SRCS = \ @@ -31,6 +31,8 @@ EXTRA_SRCS = sql.y cond.y EXTRA_OBJS = sql.tab.o cond.tab.o
+SUBDIRS = tests + @MAKE_DLL_RULES@
sql.tab.c sql.tab.h: sql.y _____
Modified: trunk/reactos/lib/msi/action.c --- trunk/reactos/lib/msi/action.c 2005-01-12 09:03:31 UTC (rev 12947) +++ trunk/reactos/lib/msi/action.c 2005-01-12 09:31:44 UTC (rev 12948) @@ -51,6 +51,8 @@
#include "ver.h"
#define CUSTOM_ACTION_TYPE_MASK 0x3F +#define REG_PROGRESS_VALUE 13200 +#define COMPONENT_PROGRESS_VALUE 24000
WINE_DEFAULT_DEBUG_CHANNEL(msi);
@@ -65,8 +67,10 @@ WCHAR Directory[96]; INT Attributes;
- INSTALLSTATE State; - BOOL Enabled; + INSTALLSTATE Installed; + INSTALLSTATE ActionRequest; + INSTALLSTATE Action; + INT ComponentCount; INT Components[1024]; /* yes hardcoded limit.... I am bad */ INT Cost; @@ -81,21 +85,23 @@ WCHAR Condition[0x100]; WCHAR KeyPath[96];
- INSTALLSTATE State; - BOOL FeatureState; + INSTALLSTATE Installed; + INSTALLSTATE ActionRequest; + INSTALLSTATE Action; + BOOL Enabled; INT Cost; } MSICOMPONENT;
typedef struct tagMSIFOLDER { - WCHAR Directory[96]; - WCHAR TargetDefault[96]; - WCHAR SourceDefault[96]; + LPWSTR Directory; + LPWSTR TargetDefault; + LPWSTR SourceDefault;
- WCHAR ResolvedTarget[MAX_PATH]; - WCHAR ResolvedSource[MAX_PATH]; - WCHAR Property[MAX_PATH]; /* initially set property */ + LPWSTR ResolvedTarget; + LPWSTR ResolvedSource; + LPWSTR Property; /* initially set property */ INT ParentIndex; INT State; /* 0 = uninitialized */ @@ -108,12 +114,12 @@
typedef struct tagMSIFILE { - WCHAR File[72]; + LPWSTR File; INT ComponentIndex; - WCHAR FileName[MAX_PATH]; + LPWSTR FileName; INT FileSize; - WCHAR Version[72]; - WCHAR Language[20]; + LPWSTR Version; + LPWSTR Language; INT Attributes; INT Sequence;
@@ -123,8 +129,8 @@ /* 2 = present but replace */ /* 3 = present do not replace */ /* 4 = Installed */ - WCHAR SourcePath[MAX_PATH]; - WCHAR TargetPath[MAX_PATH]; + LPWSTR SourcePath; + LPWSTR TargetPath; BOOL Temporary; }MSIFILE;
@@ -134,6 +140,7 @@ static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran); static UINT ACTION_ProcessUISequence(MSIPACKAGE *package);
+static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq); UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action);
static UINT ACTION_LaunchConditions(MSIPACKAGE *package); @@ -158,15 +165,15 @@ const LPWSTR target, const INT type); static UINT HANDLE_CustomType2(MSIPACKAGE *package, const LPWSTR source, const LPWSTR target, const INT type); -static UINT HANDLE_CustomType18(MSIPACKAGE *package, const LPWSTR source, +static UINT HANDLE_CustomType18(MSIPACKAGE *package, const LPWSTR source, const LPWSTR target, const INT type); -static UINT HANDLE_CustomType50(MSIPACKAGE *package, const LPWSTR source, +static UINT HANDLE_CustomType50(MSIPACKAGE *package, const LPWSTR source, const LPWSTR target, const INT type); -static UINT HANDLE_CustomType34(MSIPACKAGE *package, const LPWSTR source, +static UINT HANDLE_CustomType34(MSIPACKAGE *package, const LPWSTR source, const LPWSTR target, const INT type);
static DWORD deformat_string(MSIPACKAGE *package, WCHAR* ptr,WCHAR** data); -static UINT resolve_folder(MSIPACKAGE *package, LPCWSTR name, LPWSTR path, +static LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, BOOL set_prop, MSIFOLDER **folder);
static int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path); @@ -223,12 +230,9 @@ ********************************************************/ inline static void reduce_to_longfilename(WCHAR* filename) { - if (strchrW(filename,'|')) - { - WCHAR newname[MAX_PATH]; - strcpyW(newname,strchrW(filename,'|')+1); - strcpyW(filename,newname); - } + LPWSTR p = strchrW(filename,'|'); + if (p) + memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR)); }
inline static char *strdupWtoA( const WCHAR *str ) @@ -256,6 +260,15 @@ return ret; }
+static LPWSTR dupstrW(LPCWSTR src) +{ + LPWSTR dest; + if (!src) return NULL; + dest = HeapAlloc(GetProcessHeap(), 0, (strlenW(src)+1)*sizeof(WCHAR)); + strcpyW(dest, src); + return dest; +} + inline static WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index) { UINT rc; @@ -263,16 +276,58 @@ LPWSTR ret;
sz = 0; - rc = MSI_RecordGetStringW(row,index,NULL,&sz); - if (sz <= 0) + if (MSI_RecordIsNull(row,index)) return NULL;
+ rc = MSI_RecordGetStringW(row,index,NULL,&sz); + + /* having an empty string is different than NULL */ + if (sz == 0) + { + ret = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)); + ret[0] = 0; + return ret; + } + sz ++; ret = HeapAlloc(GetProcessHeap(),0,sz * sizeof (WCHAR)); rc = MSI_RecordGetStringW(row,index,ret,&sz); + if (rc!=ERROR_SUCCESS) + { + ERR("Unable to load dynamic string\n"); + HeapFree(GetProcessHeap(), 0, ret); + ret = NULL; + } return ret; }
+inline static LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, + UINT* rc) +{ + DWORD sz = 0; + LPWSTR str; + UINT r; + + r = MSI_GetPropertyW(package, prop, NULL, &sz); + if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA) + { + if (rc) + *rc = r; + return NULL; + } + sz++; + str = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR)); + r = MSI_GetPropertyW(package, prop, str, &sz); + if (r != ERROR_SUCCESS) + { + HeapFree(GetProcessHeap(),0,str); + str = NULL; + } + if (rc) + *rc = r; + return str; +} + inline static int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component ) { int rc = -1; @@ -321,6 +376,7 @@ return rc; }
+ static int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path) { DWORD i; @@ -343,8 +399,8 @@
memset(&package->files[index],0,sizeof(MSIFILE));
- strcpyW(package->files[index].File,name); - strcpyW(package->files[index].TargetPath,path); + package->files[index].File = dupstrW(name); + package->files[index].TargetPath = dupstrW(path); package->files[index].Temporary = TRUE;
TRACE("Tracking tempfile (%s)\n",debugstr_w(package->files[index].File)); @@ -362,11 +418,103 @@ for (i = 0; i < package->loaded_files; i++) { if (package->files[i].Temporary) + { + TRACE("Cleaning up %s\n",debugstr_w(package->files[i].TargetPath)); DeleteFileW(package->files[i].TargetPath); + }
} }
+/* Called when the package is being closed */ +extern void ACTION_free_package_structures( MSIPACKAGE* package) +{ + INT i; + + TRACE("Freeing package action data\n"); + + /* No dynamic buffers in features */ + if (package->features && package->loaded_features > 0) + HeapFree(GetProcessHeap(),0,package->features); + + for (i = 0; i < package->loaded_folders; i++) + { + HeapFree(GetProcessHeap(),0,package->folders[i].Directory); + HeapFree(GetProcessHeap(),0,package->folders[i].TargetDefault); + HeapFree(GetProcessHeap(),0,package->folders[i].SourceDefault); + HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedTarget); + HeapFree(GetProcessHeap(),0,package->folders[i].ResolvedSource); + HeapFree(GetProcessHeap(),0,package->folders[i].Property); + } + if (package->folders && package->loaded_folders > 0) + HeapFree(GetProcessHeap(),0,package->folders); + + /* no dynamic buffers in components */ + if (package->components && package->loaded_components > 0) + HeapFree(GetProcessHeap(),0,package->components); + + for (i = 0; i < package->loaded_files; i++) + { + HeapFree(GetProcessHeap(),0,package->files[i].File); + HeapFree(GetProcessHeap(),0,package->files[i].FileName); + HeapFree(GetProcessHeap(),0,package->files[i].Version); + HeapFree(GetProcessHeap(),0,package->files[i].Language); + HeapFree(GetProcessHeap(),0,package->files[i].SourcePath); + HeapFree(GetProcessHeap(),0,package->files[i].TargetPath); + } + + if (package->files && package->loaded_files > 0) + HeapFree(GetProcessHeap(),0,package->files); +} + +static UINT ACTION_OpenQuery( MSIDATABASE *db, MSIQUERY **view, LPCWSTR fmt, ... ) +{ + LPWSTR szQuery; + LPCWSTR p; + UINT sz, rc; + va_list va; + + /* figure out how much space we need to allocate */ + va_start(va, fmt); + sz = strlenW(fmt) + 1; + p = fmt; + while (*p) + { + p = strchrW(p, '%'); + if (!p) + break; + p++; + switch (*p) + { + case 's': /* a string */ + sz += strlenW(va_arg(va,LPCWSTR)); + break; + case 'd': + case 'i': /* an integer -2147483648 seems to be longest */ + sz += 3*sizeof(int); + (void)va_arg(va,int); + break; + case '%': /* a single % - leave it alone */ + break; + default: + FIXME("Unhandled character type %c\n",*p); + } + p++; + } + va_end(va); + + /* construct the string */ + szQuery = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR)); + va_start(va, fmt); + vsnprintfW(szQuery, sz, fmt, va); + va_end(va); + + /* perform the query */ + rc = MSI_DatabaseOpenViewW(db, szQuery, view); + HeapFree(GetProcessHeap(), 0, szQuery); + return rc; +} + static void ui_progress(MSIPACKAGE *package, int a, int b, int c, int d ) { MSIRECORD * row; @@ -390,17 +538,14 @@ UINT rc; MSIQUERY * view; MSIRECORD * row = 0; - static WCHAR *ActionFormat=NULL; - static WCHAR LastAction[0x100] = {0}; - WCHAR Query[1024]; LPWSTR ptr;
- if (strcmpW(LastAction,action)!=0) + if (!package->LastAction || strcmpW(package->LastAction,action)) { - sprintfW(Query,Query_t,action); - rc = MSI_DatabaseOpenViewW(package->db, Query, &view); + rc = ACTION_OpenQuery(package->db, &view, Query_t, action); if (rc != ERROR_SUCCESS) return; + rc = MSI_ViewExecute(view, 0); if (rc != ERROR_SUCCESS) { @@ -422,18 +567,22 @@ return; }
- if (ActionFormat) - HeapFree(GetProcessHeap(),0,ActionFormat); + /* update the cached actionformat */ + if (package->ActionFormat) + HeapFree(GetProcessHeap(),0,package->ActionFormat); + package->ActionFormat = load_dynamic_stringW(row,3);
- ActionFormat = load_dynamic_stringW(row,3); - strcpyW(LastAction,action); + if (package->LastAction) + HeapFree(GetProcessHeap(),0,package->LastAction); + package->LastAction = dupstrW(action); + msiobj_release(&row->hdr); MSI_ViewClose(view); msiobj_release(&view->hdr); }
message[0]=0; - ptr = ActionFormat; + ptr = package->ActionFormat; while (*ptr) { LPWSTR ptr2; @@ -489,12 +638,10 @@ MSIQUERY * view; MSIRECORD * row = 0; WCHAR *ActionText=NULL; - WCHAR Query[1024];
GetTimeFormatW(LOCALE_USER_DEFAULT, 0, NULL, format, timet, 0x100);
- sprintfW(Query,Query_t,action); - rc = MSI_DatabaseOpenViewW(package->db, Query, &view); + rc = ACTION_OpenQuery(package->db, &view, Query_t, action); if (rc != ERROR_SUCCESS) return; rc = MSI_ViewExecute(view, 0); @@ -555,6 +702,58 @@ msiobj_release(&row->hdr); }
+/* + * build_directory_name() + * + * This function is to save messing round with directory names + * It handles adding backslashes between path segments, + * and can add \ at the end of the directory name if told to. + * + * It takes a variable number of arguments. + * It always allocates a new string for the result, so make sure + * to free the return value when finished with it. + * + * The first arg is the number of path segments that follow. + * The arguments following count are a list of path segments. + * A path segment may be NULL. + * + * Path segments will be added with a \ separating them. + * A \ will not be added after the last segment, however if the + * last segment is NULL, then the last character will be a \ + * + */ +static LPWSTR build_directory_name(DWORD count, ...) +{ + DWORD sz = 1, i; + LPWSTR dir; + va_list va; + + va_start(va,count); + for(i=0; i<count; i++) + { + LPCWSTR str = va_arg(va,LPCWSTR); + if (str) + sz += strlenW(str) + 1; + } + va_end(va); + + dir = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR)); + dir[0]=0; + + va_start(va,count); + for(i=0; i<count; i++) + { + LPCWSTR str = va_arg(va,LPCWSTR); + if (!str) + continue; + strcatW(dir, str); + if( ((i+1)!=count) && dir[strlenW(dir)-1]!='\') + strcatW(dir, cszbs); + } + return dir; +} + + /**************************************************** * TOP level entry points *****************************************************/ @@ -569,23 +768,23 @@
if (szPackagePath) { - LPWSTR p; - WCHAR check[MAX_PATH]; - WCHAR pth[MAX_PATH]; - DWORD size; + LPWSTR p, check, path;
- strcpyW(pth,szPackagePath); - p = strrchrW(pth,'\'); + path = dupstrW(szPackagePath); + p = strrchrW(path,'\'); if (p) { p++; *p=0; }
- size = MAX_PATH; - if (MSI_GetPropertyW(package,cszSourceDir,check,&size) - != ERROR_SUCCESS ) - MSI_SetPropertyW(package, cszSourceDir, pth); + check = load_dynamic_property(package, cszSourceDir,NULL); + if (!check) + MSI_SetPropertyW(package, cszSourceDir, path); + else + HeapFree(GetProcessHeap(), 0, check); + + HeapFree(GetProcessHeap(), 0, path); }
if (szCommandLine) @@ -595,8 +794,8 @@
while (*ptr) { - WCHAR prop[0x100]; - WCHAR val[0x100]; + WCHAR *prop = NULL; + WCHAR *val = NULL;
TRACE("Looking at %s\n",debugstr_w(ptr));
@@ -607,10 +806,13 @@ DWORD len = 0;
while (*ptr == ' ') ptr++; - strncpyW(prop,ptr,ptr2-ptr); - prop[ptr2-ptr]=0; + len = ptr2-ptr; + prop = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR)); + strncpyW(prop,ptr,len); + prop[len]=0; ptr2++; - + + len = 0; ptr = ptr2; while (*ptr && (quote || (!quote && *ptr!=' '))) { @@ -625,14 +827,18 @@ ptr2++; len -= 2; } + val = HeapAlloc(GetProcessHeap(),0,(len+1)*sizeof(WCHAR)); strncpyW(val,ptr2,len); - val[len]=0; + val[len] = 0;
if (strlenW(prop) > 0) { - TRACE("Found commandline property (%s) = (%s)\n", debugstr_w(prop), debugstr_w(val)); + TRACE("Found commandline property (%s) = (%s)\n", + debugstr_w(prop), debugstr_w(val)); MSI_SetPropertyW(package,prop,val); } + HeapFree(GetProcessHeap(),0,val); + HeapFree(GetProcessHeap(),0,prop); } ptr++; } @@ -653,10 +859,93 @@ else rc = ACTION_ProcessExecSequence(package,FALSE);
+ /* process the ending type action */ + if (rc == ERROR_SUCCESS) + rc = ACTION_PerformActionSequence(package,-1); + else if (rc == ERROR_FUNCTION_FAILED) + rc = ACTION_PerformActionSequence(package,-3); + return rc; }
+static UINT ACTION_PerformActionSequence(MSIPACKAGE *package, UINT seq) +{ + MSIQUERY * view; + UINT rc; + WCHAR buffer[0x100]; + DWORD sz = 0x100; + MSIRECORD * row = 0; + static const WCHAR ExecSeqQuery[] = { + 's','e','l','e','c','t',' ','*',' ', + 'f','r','o','m',' ', + 'I','n','s','t','a','l','l','E','x','e','c','u','t','e', + 'S','e','q','u','e','n','c','e',' ', + 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ', + '=',' ','%','i',0};
+ rc = ACTION_OpenQuery(package->db, &view, ExecSeqQuery, seq); + + if (rc == ERROR_SUCCESS) + { + rc = MSI_ViewExecute(view, 0); + + if (rc != ERROR_SUCCESS) + { + MSI_ViewClose(view); + msiobj_release(&view->hdr); + goto end; + } + + TRACE("Running the actions\n"); + + rc = MSI_ViewFetch(view,&row); + if (rc != ERROR_SUCCESS) + { + rc = ERROR_SUCCESS; + goto end; + } + + /* check conditions */ + if (!MSI_RecordIsNull(row,2)) + { + LPWSTR cond = NULL; + cond = load_dynamic_stringW(row,2); + + if (cond) + { + /* this is a hack to skip errors in the condition code */ + if (MSI_EvaluateConditionW(package, cond) == MSICONDITION_FALSE) + { + HeapFree(GetProcessHeap(),0,cond); + msiobj_release(&row->hdr); + goto end; + } + else + HeapFree(GetProcessHeap(),0,cond); + } + } + + sz=0x100; + rc = MSI_RecordGetStringW(row,1,buffer,&sz); + if (rc != ERROR_SUCCESS) + { + ERR("Error is %x\n",rc); + msiobj_release(&row->hdr); + goto end; + } + + rc = ACTION_PerformAction(package,buffer); + msiobj_release(&row->hdr); +end: + MSI_ViewClose(view); + msiobj_release(&view->hdr); + } + else + rc = ERROR_SUCCESS; + + return rc; +} + static UINT ACTION_ProcessExecSequence(MSIPACKAGE *package, BOOL UIran) { MSIQUERY * view; @@ -669,7 +958,6 @@ 'w','h','e','r','e',' ','S','e','q','u','e','n','c','e',' ', '>',' ','%','i',' ','o','r','d','e','r',' ', 'b','y',' ','S','e','q','u','e','n','c','e',0 }; - WCHAR Query[1024]; MSIRECORD * row = 0; static const WCHAR IVQuery[] = { 's','e','l','e','c','t',' ','S','e','q','u','e','n','c','e',' ', @@ -678,11 +966,11 @@ 'w','h','e','r','e',' ','A','c','t','i','o','n',' ','=',' ',
'`','I','n','s','t','a','l','l','V','a','l','i','d','a','t','e','`', 0}; + INT seq = 0;
+ /* get the sequence number */ if (UIran) { - INT seq = 0; - rc = MSI_DatabaseOpenViewW(package->db, IVQuery, &view); if (rc != ERROR_SUCCESS) return rc; @@ -704,12 +992,9 @@ msiobj_release(&row->hdr); MSI_ViewClose(view); msiobj_release(&view->hdr); - sprintfW(Query,ExecSeqQuery,seq); } - else - sprintfW(Query,ExecSeqQuery,0); - - rc = MSI_DatabaseOpenViewW(package->db, Query, &view); + + rc = ACTION_OpenQuery(package->db, &view, ExecSeqQuery, seq); if (rc == ERROR_SUCCESS) { rc = MSI_ViewExecute(view, 0); @@ -721,7 +1006,7 @@ goto end; }
- TRACE("Running the actions \n"); + TRACE("Running the actions\n");
while (1) { @@ -900,7 +1185,6 @@ TRACE("Performing action (%s)\n",debugstr_w(action)); ui_actioninfo(package, action, TRUE, 0); ui_actionstart(package, action); - ui_progress(package,2,1,0,0);
/* pre install, setup and configuration block */ if (strcmpW(action,szLaunchConditions)==0) @@ -961,21 +1245,16 @@ UINT rc = ERROR_SUCCESS; MSIQUERY * view; MSIRECORD * row = 0; - WCHAR ExecSeqQuery[1024] = + static const WCHAR ExecSeqQuery[] = {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','C','u','s','t','o' -,'m','A','c','t','i','o','n',' ','w','h','e','r','e',' ','`','A','c','t','i' -,'o','n','`',' ','=',' ','`',0}; - static const WCHAR end[]={'`',0}; + ,'m','A','c','t','i','o','n',' ','w','h','e','r','e',' ','`','A','c','t','i' + ,'o','n','`',' ','=',' ','`','%','s','`',0}; UINT type; LPWSTR source; LPWSTR target; WCHAR *deformated=NULL;
- strcatW(ExecSeqQuery,action); - strcatW(ExecSeqQuery,end); - - rc = MSI_DatabaseOpenViewW(package->db, ExecSeqQuery, &view); - + rc = ACTION_OpenQuery(package->db, &view, ExecSeqQuery, action); if (rc != ERROR_SUCCESS) return rc;
@@ -1022,6 +1301,10 @@ rc = HANDLE_CustomType34(package,source,target,type); break; case 35: /* Directory set with formatted text. */ + deformat_string(package,target,&deformated); + MSI_SetTargetPathW(package, source, deformated); + HeapFree(GetProcessHeap(),0,deformated); + break; case 51: /* Property set with formatted text. */ deformat_string(package,target,&deformated); rc = MSI_SetPropertyW(package,source,deformated); @@ -1063,10 +1346,9 @@ UINT rc; MSIQUERY * view; MSIRECORD * row = 0; - WCHAR Query[1024] = + static const WCHAR fmt[] = {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','B','i' -,'n','a','r','y',' ','w','h','e','r','e',' ','N','a','m','e','=','`',0}; - static const WCHAR end[]={'`',0}; +,'n','a','r','y',' ','w','h','e','r','e',' ','N','a','m','e','=','`','%','s','`',0}; HANDLE the_file; CHAR buffer[1024];
@@ -1079,10 +1361,7 @@ if (the_file == INVALID_HANDLE_VALUE) return ERROR_FUNCTION_FAILED;
- strcatW(Query,source); - strcatW(Query,end); - - rc = MSI_DatabaseOpenViewW( package->db, Query, &view); + rc = ACTION_OpenQuery(package->db, &view, fmt, source); if (rc != ERROR_SUCCESS) return rc;
@@ -1127,66 +1406,82 @@ return ERROR_SUCCESS; }
- typedef UINT __stdcall CustomEntry(MSIHANDLE); typedef struct { MSIPACKAGE *package; - WCHAR target[MAX_PATH]; - WCHAR source[MAX_PATH]; + WCHAR *target; + WCHAR *source; } thread_struct;
-#if 0 -static DWORD WINAPI DllThread(LPVOID info) +static DWORD WINAPI ACTION_CallDllFunction(thread_struct *stuff) { - HANDLE DLL; + HANDLE hModule; LPSTR proc; - thread_struct *stuff; CustomEntry *fn; - - stuff = (thread_struct*)info;
- TRACE("Asynchronous start (%s, %s) \n", debugstr_w(stuff->source), + TRACE("calling function (%s, %s) \n", debugstr_w(stuff->source), debugstr_w(stuff->target));
- DLL = LoadLibraryW(stuff->source); - if (DLL) + hModule = LoadLibraryW(stuff->source); + if (hModule) { proc = strdupWtoA( stuff->target ); - fn = (CustomEntry*)GetProcAddress(DLL,proc); + fn = (CustomEntry*)GetProcAddress(hModule,proc); if (fn) { MSIHANDLE hPackage; MSIPACKAGE *package = stuff->package;
- TRACE("Calling function\n"); + TRACE("Calling function %s\n", proc); hPackage = msiobj_findhandle( &package->hdr ); - if( !hPackage ) + if (hPackage ) + { + fn(hPackage); + msiobj_release( &package->hdr ); + } + else ERR("Handle for object %p not found\n", package ); - fn(hPackage); - msiobj_release( &package->hdr ); } else ERR("Cannot load functon\n");
HeapFree(GetProcessHeap(),0,proc); - FreeLibrary(DLL); + FreeLibrary(hModule); } else ERR("Unable to load library\n"); msiobj_release( &stuff->package->hdr ); - HeapFree( GetProcessHeap(), 0, info ); + HeapFree(GetProcessHeap(),0,stuff->source); + HeapFree(GetProcessHeap(),0,stuff->target); + HeapFree(GetProcessHeap(), 0, stuff); return 0; } -#endif
+static DWORD WINAPI DllThread(LPVOID info) +{ + thread_struct *stuff; + DWORD rc = 0; + + TRACE("MSI Thread (0x%lx) started for custom action\n", + GetCurrentThreadId()); + + stuff = (thread_struct*)info; + rc = ACTION_CallDllFunction(stuff); + + TRACE("MSI Thread (0x%lx) finished\n",GetCurrentThreadId()); + /* clse all handles for this thread */ + MsiCloseAllHandles(); + return rc; +} + static UINT HANDLE_CustomType1(MSIPACKAGE *package, const LPWSTR source, const LPWSTR target, const INT type) { WCHAR tmp_file[MAX_PATH]; - CustomEntry *fn; - HANDLE DLL; - LPSTR proc; + thread_struct *info; + DWORD ThreadId; + HANDLE ThreadHandle;
store_binary_to_temp(package, source, tmp_file);
@@ -1199,76 +1494,57 @@ strcatW(tmp_file,dot); }
- if (type & 0xc0) - { - /* DWORD ThreadId; */ - thread_struct *info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info) ); + info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info) ); + msiobj_addref( &package->hdr ); + info->package = package; + info->target = dupstrW(target); + info->source = dupstrW(tmp_file);
- /* msiobj_addref( &package->hdr ); */ - info->package = package; - strcpyW(info->target,target); - strcpyW(info->source,tmp_file); - TRACE("Start Asynchronous execution\n"); - FIXME("DATABASE NOT THREADSAFE... not starting\n"); - /* CreateThread(NULL,0,DllThread,(LPVOID)&info,0,&ThreadId); */ - /* FIXME: release the package if the CreateThread fails */ - HeapFree( GetProcessHeap(), 0, info ); - return ERROR_SUCCESS; - } - - DLL = LoadLibraryW(tmp_file); - if (DLL) - { - proc = strdupWtoA( target ); - fn = (CustomEntry*)GetProcAddress(DLL,proc); - if (fn) - { - MSIHANDLE hPackage; + ThreadHandle = CreateThread(NULL,0,DllThread,(LPVOID)info,0,&ThreadId);
- TRACE("Calling function\n"); - hPackage = msiobj_findhandle( &package->hdr ); - if( !hPackage ) - ERR("Handle for object %p not found\n", package ); - fn(hPackage); - msiobj_release( &package->hdr ); - } - else - ERR("Cannot load functon\n"); + if (!(type & 0xc0)) + WaitForSingleObject(ThreadHandle,INFINITE);
- HeapFree(GetProcessHeap(),0,proc); - FreeLibrary(DLL); - } - else - ERR("Unable to load library\n"); - [truncated at 1000 lines; 8611 more skipped]