Sync to Wine-20050111:
Vitaly Lipatov <lav(a)etersoft.ru>
- Get real screen properties.
- Add description for MsiGetMode, MSIRUNMODE constants.
- Add ScreenX, ScreenY, ColorBits installer properties.
Mike McCormack <mike(a)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(a)free.fr>
- Assorted spelling fixes.
Aric Stewart <aric(a)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(a)wanadoo.fr>
- Fixed some errors in function prototypes.
Steven Edwards <steven(a)codeweavers.com>
- Add and fix some stubs.
Ulrich Czekalla <ulrich(a)codeweavers.com>
- Set the out buffer count to zero on read error.
Michael Stefaniuc <mstefani(a)redhat.de>
- Add missing HeapFree's (found by smatch).
Paul Vriens <Paul.Vriens(a)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]