msi: action split and MSIFormatRecord

Aric Stewart aric at codeweavers.com
Tue Jan 25 06:49:31 CST 2005


Alot here.
1) action.c is getting too big. So i split out all the handling of 
CustomActions into custom.c. In doing so I cleaned up alot of the 
handling of custom actions including scripting actions and processing 
return codes.
2) Mike McCormack pointed out that MsiFormatRecord is basically the same 
as my internal function deformat_string. So i broke deformat_string out 
and updated it to function as MsiFormatRecord and implemented 
MsiFormatRecord.
3) a number of random fixes to action.c including properly calculating 
the length for the LocalPackage name, not forcing a reboot when really 
we should just return ERROR_INSTALL_SUSPEND and handling REG_MULTI_SZ 
now that we can deformat the properly.
-------------- next part --------------
Index: dlls/msi/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/msi/Makefile.in,v
retrieving revision 1.19
diff -u -u -r1.19 Makefile.in
--- dlls/msi/Makefile.in	25 Jan 2005 10:58:36 -0000	1.19
+++ dlls/msi/Makefile.in	25 Jan 2005 12:40:20 -0000
@@ -9,7 +9,9 @@
 C_SRCS = \
 	action.c \
 	create.c \
+	custom.c \
 	distinct.c \
+	format.c \
 	handle.c \
 	insert.c \
 	msi.c \
Index: dlls/msi/action.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/action.c,v
retrieving revision 1.73
diff -u -u -r1.73 action.c
--- dlls/msi/action.c	25 Jan 2005 11:05:37 -0000	1.73
+++ dlls/msi/action.c	25 Jan 2005 12:40:22 -0000
@@ -48,91 +48,13 @@
 #include "shlobj.h"
 #include "wine/unicode.h"
 #include "ver.h"
+#include "action.h"
 
-#define CUSTOM_ACTION_TYPE_MASK 0x3F
 #define REG_PROGRESS_VALUE 13200
 #define COMPONENT_PROGRESS_VALUE 24000
 
 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 Installed;
-    INSTALLSTATE ActionRequest;
-    INSTALLSTATE Action;
-
-    INT ComponentCount;
-    INT Components[1024]; /* yes hardcoded limit.... I am bad */
-    INT Cost;
-} MSIFEATURE;
-
-typedef struct tagMSICOMPONENT
-{
-    WCHAR Component[96];
-    WCHAR ComponentId[96];
-    WCHAR Directory[96];
-    INT Attributes;
-    WCHAR Condition[0x100];
-    WCHAR KeyPath[96];
-
-    INSTALLSTATE Installed;
-    INSTALLSTATE ActionRequest;
-    INSTALLSTATE Action;
-
-    BOOL Enabled;
-    INT  Cost;
-} MSICOMPONENT;
-
-typedef struct tagMSIFOLDER
-{
-    LPWSTR Directory;
-    LPWSTR TargetDefault;
-    LPWSTR SourceDefault;
-
-    LPWSTR ResolvedTarget;
-    LPWSTR ResolvedSource;
-    LPWSTR Property;   /* initially set property */
-    INT   ParentIndex;
-    INT   State;
-        /* 0 = uninitialized */
-        /* 1 = existing */
-        /* 2 = created remove if empty */
-        /* 3 = created persist if empty */
-    INT   Cost;
-    INT   Space;
-}MSIFOLDER;
-
-typedef struct tagMSIFILE
-{
-    LPWSTR File;
-    INT ComponentIndex;
-    LPWSTR FileName;
-    INT FileSize;
-    LPWSTR Version;
-    LPWSTR Language;
-    INT Attributes;
-    INT Sequence;   
-
-    INT State;
-       /* 0 = uninitialize */
-       /* 1 = not present */
-       /* 2 = present but replace */
-       /* 3 = present do not replace */
-       /* 4 = Installed */
-    LPWSTR  SourcePath;
-    LPWSTR  TargetPath;
-    BOOL    Temporary; 
-}MSIFILE;
-
 /*
  * Prototypes
  */
@@ -150,8 +72,6 @@
 static UINT ACTION_InstallFiles(MSIPACKAGE *package);
 static UINT ACTION_DuplicateFiles(MSIPACKAGE *package);
 static UINT ACTION_WriteRegistryValues(MSIPACKAGE *package);
-static UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action, 
-                                BOOL execute);
 static UINT ACTION_InstallInitialize(MSIPACKAGE *package);
 static UINT ACTION_InstallValidate(MSIPACKAGE *package);
 static UINT ACTION_ProcessComponents(MSIPACKAGE *package);
@@ -168,23 +88,9 @@
 static UINT ACTION_InstallFinalize(MSIPACKAGE *package);
 static UINT ACTION_ForceReboot(MSIPACKAGE *package);
 
-static UINT HANDLE_CustomType1(MSIPACKAGE *package, const LPWSTR source, 
-                                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,
-                                const LPWSTR target, const INT type);
-static UINT HANDLE_CustomType50(MSIPACKAGE *package, const LPWSTR source,
-                                const LPWSTR target, const INT type);
-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 LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name,
-                           BOOL source, BOOL set_prop, MSIFOLDER **folder);
+
 static UINT build_icon_path(MSIPACKAGE *package, LPCWSTR icon_name, 
                             LPWSTR *FilePath);
-static int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path);
  
 /*
  * consts and values used
@@ -196,8 +102,6 @@
 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};
-static const WCHAR cszrsb[]={']',0};
 static const WCHAR cszbs[]={'\\',0};
 
 const static WCHAR szCreateFolders[] =
@@ -259,41 +163,7 @@
         memmove(filename, p+1, (strlenW(p+1)+1)*sizeof(WCHAR));
 }
 
-inline static char *strdupWtoA( const WCHAR *str )
-{
-    char *ret = NULL;
-    if (str)
-    {
-        DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL
-);
-        if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
-            WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
-    }
-    return ret;
-}
-
-inline static WCHAR *strdupAtoW( const char *str )
-{
-    WCHAR *ret = NULL;
-    if (str)
-    {
-        DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
-        if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
-            MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
-    }
-    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)
+WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index)
 {
     UINT rc;
     DWORD sz;
@@ -325,8 +195,7 @@
     return ret;
 }
 
-inline static LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop,
-                                           UINT* rc)
+LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, UINT* rc)
 {
     DWORD sz = 0;
     LPWSTR str;
@@ -352,7 +221,7 @@
     return str;
 }
 
-inline static int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component )
+int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component )
 {
     int rc = -1;
     DWORD i;
@@ -368,7 +237,7 @@
     return rc;
 }
 
-inline static int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature )
+int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature )
 {
     int rc = -1;
     DWORD i;
@@ -384,7 +253,7 @@
     return rc;
 }
 
-inline static int get_loaded_file(MSIPACKAGE* package, LPCWSTR file)
+int get_loaded_file(MSIPACKAGE* package, LPCWSTR file)
 {
     int rc = -1;
     DWORD i;
@@ -400,8 +269,7 @@
     return rc;
 }
 
-
-static int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path)
+int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path)
 {
     DWORD i;
     DWORD index;
@@ -432,7 +300,7 @@
     return 0;
 }
 
-void ACTION_remove_tracked_tempfiles(MSIPACKAGE* package)
+static void remove_tracked_tempfiles(MSIPACKAGE* package)
 {
     DWORD i;
 
@@ -450,13 +318,39 @@
     }
 }
 
+/* wrapper to resist a need for a full rewrite right now */
+DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data )
+{
+    if (ptr)
+    {
+        MSIRECORD *rec = MSI_CreateRecord(1);
+        DWORD size = 0;
+        WCHAR size_buf[2] = {' ',0};
+
+        MSI_RecordSetStringW(rec,0,ptr);
+        MSI_FormatRecordW(package,rec,size_buf,&size);
+        if (size > 0)
+        {
+            size++;
+            *data = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
+            MSI_FormatRecordW(package,rec,*data,&size);
+            return sizeof(WCHAR)*size;
+        }
+    }
+
+    *data = NULL;
+    return 0;
+}
+
 /* Called when the package is being closed */
-extern void ACTION_free_package_structures( MSIPACKAGE* package)
+void ACTION_free_package_structures( MSIPACKAGE* package)
 {
     INT i;
     
     TRACE("Freeing package action data\n");
 
+    remove_tracked_tempfiles(package);
+
     /* No dynamic buffers in features */
     if (package->features && package->loaded_features > 0)
         HeapFree(GetProcessHeap(),0,package->features);
@@ -524,7 +418,7 @@
     UINT rc;
     MSIQUERY * view;
     MSIRECORD * row = 0;
-    LPWSTR ptr;
+    DWORD size;
 
     if (!package->LastAction || strcmpW(package->LastAction,action))
     {
@@ -565,38 +459,9 @@
         msiobj_release(&view->hdr);
     }
 
-    message[0]=0;
-    ptr = package->ActionFormat;
-    while (*ptr)
-    {
-        LPWSTR ptr2;
-        LPWSTR data=NULL;
-        WCHAR tmp[1023];
-        INT field;
-
-        ptr2 = strchrW(ptr,'[');
-        if (ptr2)
-        {
-            strncpyW(tmp,ptr,ptr2-ptr);
-            tmp[ptr2-ptr]=0;
-            strcatW(message,tmp);
-            ptr2++;
-            field = atoiW(ptr2);
-            data = load_dynamic_stringW(record,field);
-            if (data)
-            {
-                strcatW(message,data);
-                HeapFree(GetProcessHeap(),0,data);
-            }
-            ptr=strchrW(ptr2,']');
-            ptr++;
-        }
-        else
-        {
-            strcatW(message,ptr);
-            break;
-        }
-    }
+    MSI_RecordSetStringW(record,0,package->ActionFormat);
+    size = 1024;
+    MSI_FormatRecordW(package,record,message,&size);
 
     row = MSI_CreateRecord(1);
     MSI_RecordSetStringW(row,1,message);
@@ -853,6 +718,9 @@
         rc = ACTION_PerformActionSequence(package,-1);
     else if (rc == ERROR_FUNCTION_FAILED) 
         rc = ACTION_PerformActionSequence(package,-3);
+
+    /* finish up running custom actions */
+    ACTION_FinishCustomActions(package);
     
     return rc;
 }
@@ -1242,560 +1110,6 @@
     return rc;
 }
 
-
-static UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action, 
-                                BOOL execute)
-{
-    UINT rc = ERROR_SUCCESS;
-    MSIQUERY * view;
-    MSIRECORD * row = 0;
-    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','`',' ','=',' ','`','%','s','`',0};
-    UINT type;
-    LPWSTR source;
-    LPWSTR target;
-    WCHAR *deformated=NULL;
-
-    rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, action);
-    if (rc != ERROR_SUCCESS)
-        return rc;
-
-    rc = MSI_ViewExecute(view, 0);
-    if (rc != ERROR_SUCCESS)
-    {
-        MSI_ViewClose(view);
-        msiobj_release(&view->hdr);
-        return rc;
-    }
-
-    rc = MSI_ViewFetch(view,&row);
-    if (rc != ERROR_SUCCESS)
-    {
-        MSI_ViewClose(view);
-        msiobj_release(&view->hdr);
-        return rc;
-    }
-
-    type = MSI_RecordGetInteger(row,2);
-
-    source = load_dynamic_stringW(row,3);
-    target = load_dynamic_stringW(row,4);
-
-    TRACE("Handling custom action %s (%x %s %s)\n",debugstr_w(action),type,
-          debugstr_w(source), debugstr_w(target));
-
-    /* handle some of the deferred actions */
-    if (type & 0x400)
-    {
-        if (type & 0x100)
-        {
-            FIXME("Rollback only action... rollbacks not supported yet\n");
-            HeapFree(GetProcessHeap(),0,source);
-            HeapFree(GetProcessHeap(),0,target);
-            msiobj_release(&row->hdr);
-            MSI_ViewClose(view);
-            msiobj_release(&view->hdr);
-            return ERROR_SUCCESS;
-        }
-        if (!execute)
-        {
-            LPWSTR *newbuf = NULL;
-            INT count;
-            if (type & 0x200)
-            {
-                TRACE("Deferring Commit Action!\n");
-                count = package->CommitActionCount;
-                package->CommitActionCount++;
-                if (count != 0)
-                    newbuf = HeapReAlloc(GetProcessHeap(),0,
-                        package->CommitAction,
-                        package->CommitActionCount * sizeof(LPWSTR));
-                else
-                    newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR));
-
-                newbuf[count] = dupstrW(action);
-                package->CommitAction = newbuf;
-            }
-            else
-            {
-                TRACE("Deferring Action!\n");
-                count = package->DeferredActionCount;
-                package->DeferredActionCount++;
-                if (count != 0)
-                    newbuf = HeapReAlloc(GetProcessHeap(),0,
-                        package->DeferredAction,
-                        package->DeferredActionCount * sizeof(LPWSTR));
-                else
-                    newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR));
-
-                newbuf[count] = dupstrW(action);
-                package->DeferredAction = newbuf;
-            }
-
-            HeapFree(GetProcessHeap(),0,source);
-            HeapFree(GetProcessHeap(),0,target);
-            msiobj_release(&row->hdr);
-            MSI_ViewClose(view);
-            msiobj_release(&view->hdr);
-            return ERROR_SUCCESS;
-        }
-        else
-        {
-            /*Set ActionData*/
-
-            static const WCHAR szActionData[] = {
-            'C','u','s','t','o','m','A','c','t','i','o','n','D','a','t','a',0};
-            LPWSTR actiondata = load_dynamic_property(package,action,NULL);
-            if (actiondata)
-                MSI_SetPropertyW(package,szActionData,actiondata);
-
-            /* dont allow asyncronous actions on forces. This is not 
-             * fully correct as some exes can run after install finishes */
-            type &= ~0xc0;
-        }
-    }
-
-    /* we are ignoring ALOT of flags and important synchronization stuff */
-    switch (type & CUSTOM_ACTION_TYPE_MASK)
-    {
-        case 1: /* DLL file stored in a Binary table stream */
-            rc = HANDLE_CustomType1(package,source,target,type);
-            break;
-        case 2: /* EXE file stored in a Binary table strem */
-            rc = HANDLE_CustomType2(package,source,target,type);
-            break;
-        case 18: /*EXE file installed with package */
-            rc = HANDLE_CustomType18(package,source,target,type);
-            break;
-        case 50: /*EXE file specified by a property value */
-            rc = HANDLE_CustomType50(package,source,target,type);
-            break;
-        case 34: /*EXE to be run in specified directory */
-            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);
-            HeapFree(GetProcessHeap(),0,deformated);
-            break;
-        default:
-            FIXME("UNHANDLED ACTION TYPE %i (%s %s)\n",
-             type & CUSTOM_ACTION_TYPE_MASK, debugstr_w(source),
-             debugstr_w(target));
-    }
-
-    HeapFree(GetProcessHeap(),0,source);
-    HeapFree(GetProcessHeap(),0,target);
-    msiobj_release(&row->hdr);
-    MSI_ViewClose(view);
-    msiobj_release(&view->hdr);
-    return rc;
-}
-
-static UINT store_binary_to_temp(MSIPACKAGE *package, const LPWSTR source, 
-                                LPWSTR tmp_file)
-{
-    DWORD sz=MAX_PATH;
-
-    if (MSI_GetPropertyW(package, cszTempFolder, tmp_file, &sz) 
-        != ERROR_SUCCESS)
-        GetTempPathW(MAX_PATH,tmp_file);
-
-    strcatW(tmp_file,source);
-
-    if (GetFileAttributesW(tmp_file) != INVALID_FILE_ATTRIBUTES)
-    {
-        TRACE("File already exists\n");
-        return ERROR_SUCCESS;
-    }
-    else
-    {
-        /* write out the file */
-        UINT rc;
-        MSIQUERY * view;
-        MSIRECORD * row = 0;
-        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','=','`','%','s','`',0};
-        HANDLE the_file;
-        CHAR buffer[1024];
-
-        if (track_tempfile(package, source, tmp_file)!=0)
-            FIXME("File Name in temp tracking collision\n");
-
-        the_file = CreateFileW(tmp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
-                           FILE_ATTRIBUTE_NORMAL, NULL);
-    
-        if (the_file == INVALID_HANDLE_VALUE)
-            return ERROR_FUNCTION_FAILED;
-
-        rc = MSI_OpenQuery(package->db, &view, fmt, source);
-        if (rc != ERROR_SUCCESS)
-            return rc;
-
-        rc = MSI_ViewExecute(view, 0);
-        if (rc != ERROR_SUCCESS)
-        {
-            MSI_ViewClose(view);
-            msiobj_release(&view->hdr);
-            return rc;
-        }
-
-        rc = MSI_ViewFetch(view,&row);
-        if (rc != ERROR_SUCCESS)
-        {
-            MSI_ViewClose(view);
-            msiobj_release(&view->hdr);
-            return rc;
-        }
-
-        do 
-        {
-            DWORD write;
-            sz = 1024;
-            rc = MSI_RecordReadStream(row,2,buffer,&sz);
-            if (rc != ERROR_SUCCESS)
-            {
-                ERR("Failed to get stream\n");
-                CloseHandle(the_file);  
-                DeleteFileW(tmp_file);
-                break;
-            }
-            WriteFile(the_file,buffer,sz,&write,NULL);
-        } while (sz == 1024);
-
-        CloseHandle(the_file);
-
-        msiobj_release(&row->hdr);
-        MSI_ViewClose(view);
-        msiobj_release(&view->hdr);
-    }
-
-    return ERROR_SUCCESS;
-}
-
-typedef UINT __stdcall CustomEntry(MSIHANDLE);
-
-typedef struct 
-{
-        MSIPACKAGE *package;
-        WCHAR *target;
-        WCHAR *source;
-} thread_struct;
-
-static DWORD WINAPI ACTION_CallDllFunction(thread_struct *stuff)
-{
-    HANDLE hModule;
-    LPSTR proc;
-    CustomEntry *fn;
-
-    TRACE("calling function (%s, %s) \n", debugstr_w(stuff->source),
-          debugstr_w(stuff->target));
-
-    hModule = LoadLibraryW(stuff->source);
-    if (hModule)
-    {
-        proc = strdupWtoA( stuff->target );
-        fn = (CustomEntry*)GetProcAddress(hModule,proc);
-        if (fn)
-        {
-            MSIHANDLE hPackage;
-            MSIPACKAGE *package = stuff->package;
-
-            TRACE("Calling function %s\n", proc);
-            hPackage = msiobj_findhandle( &package->hdr );
-            if (hPackage )
-            {
-                fn(hPackage);
-                msiobj_release( &package->hdr );
-            }
-            else
-                ERR("Handle for object %p not found\n", package );
-        }
-        else
-            ERR("Cannot load functon\n");
-
-        HeapFree(GetProcessHeap(),0,proc);
-        FreeLibrary(hModule);
-    }
-    else
-        ERR("Unable to load library\n");
-    msiobj_release( &stuff->package->hdr );
-    HeapFree(GetProcessHeap(),0,stuff->source);
-    HeapFree(GetProcessHeap(),0,stuff->target);
-    HeapFree(GetProcessHeap(), 0, stuff);
-    return 0;
-}
-
-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];
-    thread_struct *info;
-    DWORD ThreadId;
-    HANDLE ThreadHandle;
-
-    store_binary_to_temp(package, source, tmp_file);
-
-    TRACE("Calling function %s from %s\n",debugstr_w(target),
-          debugstr_w(tmp_file));
-
-    if (!strchrW(tmp_file,'.'))
-    {
-        static const WCHAR dot[]={'.',0};
-        strcatW(tmp_file,dot);
-    } 
-
-    info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info) );
-    msiobj_addref( &package->hdr );
-    info->package = package;
-    info->target = dupstrW(target);
-    info->source = dupstrW(tmp_file);
-
-    ThreadHandle = CreateThread(NULL,0,DllThread,(LPVOID)info,0,&ThreadId);
-
-    if (!(type & 0xc0))
-        WaitForSingleObject(ThreadHandle,INFINITE);
-
-    CloseHandle(ThreadHandle);
- 
-    return ERROR_SUCCESS;
-}
-
-static UINT HANDLE_CustomType2(MSIPACKAGE *package, const LPWSTR source, 
-                                const LPWSTR target, const INT type)
-{
-    WCHAR tmp_file[MAX_PATH];
-    STARTUPINFOW si;
-    PROCESS_INFORMATION info;
-    BOOL rc;
-    INT len;
-    WCHAR *deformated;
-    WCHAR *cmd;
-    static const WCHAR spc[] = {' ',0};
-
-    memset(&si,0,sizeof(STARTUPINFOW));
-
-    store_binary_to_temp(package, source, tmp_file);
-
-    deformat_string(package,target,&deformated);
-
-    len = strlenW(tmp_file)+2;
-
-    if (deformated)
-        len += strlenW(deformated);
-   
-    cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*len);
-
-    strcpyW(cmd,tmp_file);
-    if (deformated)
-    {
-        strcatW(cmd,spc);
-        strcatW(cmd,deformated);
-
-        HeapFree(GetProcessHeap(),0,deformated);
-    }
-
-    TRACE("executing exe %s \n",debugstr_w(cmd));
-
-    rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
-                  c_collen, &si, &info);
-
-    HeapFree(GetProcessHeap(),0,cmd);
-
-    if ( !rc )
-    {
-        ERR("Unable to execute command\n");
-        return ERROR_SUCCESS;
-    }
-
-    if (!(type & 0xc0))
-        WaitForSingleObject(info.hProcess,INFINITE);
-
-    CloseHandle( info.hProcess );
-    CloseHandle( info.hThread );
-    return ERROR_SUCCESS;
-}
-
-static UINT HANDLE_CustomType18(MSIPACKAGE *package, const LPWSTR source,
-                                const LPWSTR target, const INT type)
-{
-    STARTUPINFOW si;
-    PROCESS_INFORMATION info;
-    BOOL rc;
-    WCHAR *deformated;
-    WCHAR *cmd;
-    INT len;
-    static const WCHAR spc[] = {' ',0};
-    int index;
-
-    memset(&si,0,sizeof(STARTUPINFOW));
-
-    index = get_loaded_file(package,source);
-
-    len = strlenW(package->files[index].TargetPath);
-
-    deformat_string(package,target,&deformated);
-    if (deformated)
-        len += strlenW(deformated);
-    len += 2;
-
-    cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,len * sizeof(WCHAR));
-
-    strcpyW(cmd, package->files[index].TargetPath);
-    if (deformated)
-    {
-        strcatW(cmd, spc);
-        strcatW(cmd, deformated);
-
-        HeapFree(GetProcessHeap(),0,deformated);
-    }
-
-    TRACE("executing exe %s \n",debugstr_w(cmd));
-
-    rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
-                  c_collen, &si, &info);
-
-    HeapFree(GetProcessHeap(),0,cmd);
-    
-    if ( !rc )
-    {
-        ERR("Unable to execute command\n");
-        return ERROR_SUCCESS;
-    }
-
-    if (!(type & 0xc0))
-        WaitForSingleObject(info.hProcess,INFINITE);
-
-    CloseHandle( info.hProcess );
-    CloseHandle( info.hThread );
-    return ERROR_SUCCESS;
-}
-
-static UINT HANDLE_CustomType50(MSIPACKAGE *package, const LPWSTR source,
-                                const LPWSTR target, const INT type)
-{
-    STARTUPINFOW si;
-    PROCESS_INFORMATION info;
-    WCHAR *prop;
-    BOOL rc;
-    WCHAR *deformated;
-    WCHAR *cmd;
-    INT len;
-    UINT prc;
-    static const WCHAR spc[] = {' ',0};
-
-    memset(&si,0,sizeof(STARTUPINFOW));
-    memset(&info,0,sizeof(PROCESS_INFORMATION));
-
-    prop = load_dynamic_property(package,source,&prc);
-    if (!prop)
-        return prc;
-
-    deformat_string(package,target,&deformated);
-    len = strlenW(prop) + 2;
-    if (deformated)
-         len += strlenW(deformated);
-
-    cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*len);
-
-    strcpyW(cmd,prop);
-    if (deformated)
-    {
-        strcatW(cmd,spc);
-        strcatW(cmd,deformated);
-
-        HeapFree(GetProcessHeap(),0,deformated);
-    }
-
-    TRACE("executing exe %s \n",debugstr_w(cmd));
-
-    rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
-                  c_collen, &si, &info);
-
-    HeapFree(GetProcessHeap(),0,cmd);
-    
-    if ( !rc )
-    {
-        ERR("Unable to execute command\n");
-        return ERROR_SUCCESS;
-    }
-
-    if (!(type & 0xc0))
-        WaitForSingleObject(info.hProcess,INFINITE);
-
-    CloseHandle( info.hProcess );
-    CloseHandle( info.hThread );
-    return ERROR_SUCCESS;
-}
-
-static UINT HANDLE_CustomType34(MSIPACKAGE *package, const LPWSTR source,
-                                const LPWSTR target, const INT type)
-{
-    LPWSTR filename, deformated;
-    STARTUPINFOW si;
-    PROCESS_INFORMATION info;
-    BOOL rc;
-
-    memset(&si,0,sizeof(STARTUPINFOW));
-
-    filename = resolve_folder(package, source, FALSE, FALSE, NULL);
-
-    if (!filename)
-        return ERROR_FUNCTION_FAILED;
-
-    SetCurrentDirectoryW(filename);
-    HeapFree(GetProcessHeap(),0,filename);
-
-    deformat_string(package,target,&deformated);
-
-    if (!deformated)
-        return ERROR_FUNCTION_FAILED;
-
-    TRACE("executing exe %s \n",debugstr_w(deformated));
-
-    rc = CreateProcessW(NULL, deformated, NULL, NULL, FALSE, 0, NULL,
-                  c_collen, &si, &info);
-    HeapFree(GetProcessHeap(),0,deformated);
-
-    if ( !rc )
-    {
-        ERR("Unable to execute command\n");
-        return ERROR_SUCCESS;
-    }
-
-    if (!(type & 0xc0))
-        WaitForSingleObject(info.hProcess,INFINITE);
-
-    CloseHandle( info.hProcess );
-    CloseHandle( info.hThread );
-    return ERROR_SUCCESS;
-}
-
 /***********************************************************************
  *            create_full_pathW
  *
@@ -2388,8 +1702,8 @@
 }
 
 
-static LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name,
-                           BOOL source, BOOL set_prop, MSIFOLDER **folder)
+LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, 
+                      BOOL set_prop, MSIFOLDER **folder)
 {
     DWORD i;
     LPWSTR p, path = NULL;
@@ -3091,7 +2405,10 @@
 
     data.package = package;
     data.cab_path = cab_path;
-    file_name = strdupWtoA(file);
+    if (file)
+        file_name = strdupWtoA(file);
+    else
+        file_name = NULL;
     data.file_name = file_name;
 
     ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);
@@ -3129,7 +2446,7 @@
     if (sequence <= last_sequence)
     {
         TRACE("Media already ready (%u, %u)\n",sequence,last_sequence);
-        extract_a_cabinet_file(package, source,path,file);
+        //extract_a_cabinet_file(package, source,path,file);
         return ERROR_SUCCESS;
     }
 
@@ -3188,7 +2505,7 @@
                     GetTempPathW(MAX_PATH,path);
             }
         }
-        rc = !extract_a_cabinet_file(package, source,path,file);
+        rc = !extract_a_cabinet_file(package, source,path,NULL);
     }
     msiobj_release(&row->hdr);
     MSI_ViewClose(view);
@@ -3556,6 +2873,7 @@
     }
     else
     {
+        static const WCHAR szMulti[] = {'[','~',']',0};
         WCHAR *ptr;
         *type=REG_SZ;
 
@@ -3572,6 +2890,9 @@
          else
             ptr=value;
 
+        if (strstrW(value,szMulti))
+            *type = REG_MULTI_SZ;
+
         *size = deformat_string(package, ptr,(LPWSTR*)&data);
     }
     return data;
@@ -3745,148 +3066,6 @@
     return rc;
 }
 
-/*
- * This helper function should probably go alot of places
- *
- * Thinking about this, maybe this should become yet another Bison file
- */
-static DWORD deformat_string(MSIPACKAGE *package, WCHAR* ptr,WCHAR** data)
-{
-    WCHAR* mark=NULL;
-    WCHAR* mark2;
-    DWORD size=0;
-    DWORD chunk=0;
-    WCHAR key[0x100];
-    LPWSTR value = NULL;
-    DWORD sz;
-    UINT rc;
-    INT index;
-
-    if (ptr==NULL)
-    {
-        TRACE("Deformatting NULL string\n");
-        *data = NULL;
-        return 0;
-    }
-    TRACE("Starting with %s\n",debugstr_w(ptr));
-    /* scan for special characters */
-    if (!strchrW(ptr,'[') || (strchrW(ptr,'[') && !strchrW(ptr,']')))
-    {
-        /* not formatted */
-        size = (strlenW(ptr)+1) * sizeof(WCHAR);
-        *data = HeapAlloc(GetProcessHeap(),0,size);
-        strcpyW(*data,ptr);
-        return size;
-    }
-   
-    /* formatted string located */ 
-    mark = strchrW(ptr,'[');
-    if (mark != ptr)
-    {
-        INT cnt = (mark - ptr);
-        TRACE("%i  (%i) characters before marker\n",cnt,(mark-ptr));
-        size = cnt * sizeof(WCHAR);
-        size += sizeof(WCHAR);
-        *data = HeapAlloc(GetProcessHeap(),0,size);
-        strncpyW(*data,ptr,cnt);
-        (*data)[cnt]=0;
-    }
-    else
-    {
-        size = sizeof(WCHAR);
-        *data = HeapAlloc(GetProcessHeap(),0,size);
-        (*data)[0]=0;
-    }
-    mark++;
-    mark2 = strchrW(mark,']');
-    strncpyW(key,mark,mark2-mark);
-    key[mark2-mark] = 0;
-    mark = strchrW(mark,']');
-    mark++;
-    TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
-    sz = 0;
-    /* expand what we can deformat... Again, this should become a bison file */
-    switch (key[0])
-    {
-        case '~':
-            ERR("UNHANDLED DEFORMAT.. [~] should be NULL\n");
-            rc = ERROR_FUNCTION_FAILED;
-            break;
-        case '$':
-            ERR("POORLY HANDLED DEFORMAT.. [$componentkey] \n");
-            index = get_loaded_component(package,&key[1]);
-            if (index >= 0)
-            {
-                value = resolve_folder(package, 
-                                       package->components[index].Directory, 
-                                       FALSE, FALSE, NULL);
-                rc = 0;
-            }
-            else
-                rc = ERROR_FUNCTION_FAILED;
-            break;
-        case '#':
-            index = get_loaded_file(package,&key[1]);
-            if (index >=0)
-            {
-                sz = strlenW(package->files[index].TargetPath);
-                value = dupstrW(package->files[index].TargetPath);
-                rc= ERROR_SUCCESS;
-            }
-            else
-                rc = ERROR_FUNCTION_FAILED;
-            break;
-        case '\\':
-            value = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*2);
-            value[0] =  key[1];
-            rc = ERROR_SUCCESS;
-            break;
-        case '%':
-            sz  = GetEnvironmentVariableW(&key[1],NULL,0);
-            sz++;
-            value = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR));
-            GetEnvironmentVariableW(&key[1],value,sz);
-            rc = ERROR_SUCCESS;
-            break;
-        default:
-            rc = MSI_GetPropertyW(package, key, NULL, &sz);
-            sz++;
-            value = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR));
-            MSI_GetPropertyW(package, key, value, &sz);
-            break;
-    }
-    if (((rc == ERROR_SUCCESS) || (rc == ERROR_MORE_DATA))&& value!=NULL)
-    {
-        LPWSTR newdata;
-
-        chunk = (strlenW(value)+1) * sizeof(WCHAR);
-        size+=chunk;   
-        newdata = HeapReAlloc(GetProcessHeap(),0,*data,size);
-        *data = newdata;
-        strcatW(*data,value);
-    }
-    TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
-    if (*mark!=0)
-    {
-        LPWSTR newdata;
-        chunk = (strlenW(mark)+1) * sizeof(WCHAR);
-        size+=chunk;
-        newdata = HeapReAlloc(GetProcessHeap(),0,*data,size);
-        *data = newdata;
-        strcatW(*data,mark);
-    }
-    (*data)[strlenW(*data)]=0;
-    TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
-
-    /* recursively do this to clean up */
-    mark = HeapAlloc(GetProcessHeap(),0,size);
-    strcpyW(mark,*data);
-    TRACE("String at this point %s\n",debugstr_w(mark));
-    size = deformat_string(package,mark,data);
-    HeapFree(GetProcessHeap(),0,mark);
-    return size;
-}
-
 static UINT ACTION_InstallInitialize(MSIPACKAGE *package)
 {
     return ERROR_SUCCESS;
@@ -5567,8 +4746,9 @@
     } while (num != start);
 
     create_full_pathW(path);
+    TRACE("Copying to local package %s\n",debugstr_w(packagefile));
     CopyFileW(package->PackagePath,packagefile,FALSE);
-    size = strlenW(packagefile)/sizeof(WCHAR);
+    size = strlenW(packagefile)*sizeof(WCHAR);
     RegSetValueExW(hkey,szLocalPackage,0,REG_SZ,(LPSTR)packagefile,size);
     
 end:
@@ -5607,6 +4787,10 @@
     if (!package)
         return ERROR_INVALID_HANDLE;
 
+    /* first do the same as an InstallExecute */
+    ACTION_InstallExecute(package);
+
+    /* then handle Commit Actions */
     for (i = 0; i < package->CommitActionCount; i++)
     {
         LPWSTR action;
Index: dlls/msi/msipriv.h
===================================================================
RCS file: /home/wine/wine/dlls/msi/msipriv.h,v
retrieving revision 1.40
diff -u -u -r1.40 msipriv.h
--- dlls/msi/msipriv.h	25 Jan 2005 10:58:36 -0000	1.40
+++ dlls/msi/msipriv.h	25 Jan 2005 12:40:22 -0000
@@ -203,6 +203,9 @@
     LPWSTR *CommitAction;
     UINT CommitActionCount;
 
+    struct tagMSIRUNNINGACTION *RunningAction;
+    UINT RunningActionCount;
+
     LPWSTR PackagePath;
 } MSIPACKAGE;
 
@@ -329,6 +332,10 @@
 extern UINT MSI_GetComponentStateW(MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE *);
 extern UINT MSI_GetFeatureStateW(MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE *);
 
+/* for deformating */
+extern UINT MSI_FormatRecordW(MSIPACKAGE* package, MSIRECORD* record, 
+                              LPWSTR buffer, DWORD *size);
+    
 /* registry data encoding/decoding functions */
 BOOL unsquash_guid(LPCWSTR in, LPWSTR out);
 BOOL squash_guid(LPCWSTR in, LPWSTR out);
Index: dlls/msi/record.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/record.c,v
retrieving revision 1.19
diff -u -u -r1.19 record.c
--- dlls/msi/record.c	9 Jan 2005 18:24:15 -0000	1.19
+++ dlls/msi/record.c	25 Jan 2005 12:40:22 -0000
@@ -520,18 +520,6 @@
     return ret;
 }
 
-UINT WINAPI MsiFormatRecordA(MSIHANDLE hInstall, MSIHANDLE hRecord, LPSTR szResult, DWORD *sz)
-{
-    FIXME("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
-    return ERROR_CALL_NOT_IMPLEMENTED;
-}
-
-UINT WINAPI MsiFormatRecordW(MSIHANDLE hInstall, MSIHANDLE hRecord, LPWSTR szResult, DWORD *sz)
-{
-    FIXME("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
-    return ERROR_CALL_NOT_IMPLEMENTED;
-}
-
 /* read the data in a file into an IStream */
 UINT RECORD_StreamFromFile(LPCWSTR szFile, IStream **pstm)
 {
--- /dev/null	Fri Aug 31 05:30:55 2001
+++ dlls/msi/custom.c	Tue Jan 25 20:29:54 2005
@@ -0,0 +1,745 @@
+/*
+ * Custom Action processing for the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2005 Aric Stewart for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * Pages I need
+ *
+http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/summary_list_of_all_custom_action_types.asp
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "winreg.h"
+#include "wine/debug.h"
+#include "fdi.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "msvcrt/fcntl.h"
+#include "objbase.h"
+#include "objidl.h"
+#include "msipriv.h"
+#include "winnls.h"
+#include "winuser.h"
+#include "shlobj.h"
+#include "wine/unicode.h"
+#include "ver.h"
+#include "action.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+#define CUSTOM_ACTION_TYPE_MASK 0x3F
+static const WCHAR c_collen[] = {'C',':','\\',0};
+static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
+
+typedef struct tagMSIRUNNINGACTION
+{
+    HANDLE handle;
+    BOOL   process;
+    LPWSTR name;
+} MSIRUNNINGACTION;
+
+static UINT HANDLE_CustomType1(MSIPACKAGE *package, LPCWSTR source,
+                               LPCWSTR target, const INT type, LPCWSTR action);
+static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source,
+                               LPCWSTR target, const INT type, LPCWSTR action);
+static UINT HANDLE_CustomType18(MSIPACKAGE *package, LPCWSTR source,
+                                LPCWSTR target, const INT type, LPCWSTR action);
+static UINT HANDLE_CustomType50(MSIPACKAGE *package, LPCWSTR source,
+                                LPCWSTR target, const INT type, LPCWSTR action);
+static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source,
+                                LPCWSTR target, const INT type, LPCWSTR action);
+
+UINT ACTION_CustomAction(MSIPACKAGE *package,LPCWSTR action, BOOL execute)
+{
+    UINT rc = ERROR_SUCCESS;
+    MSIQUERY * view;
+    MSIRECORD * row = 0;
+    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','`',' ','=',' ','`','%','s','`',0};
+    UINT type;
+    LPWSTR source;
+    LPWSTR target;
+    WCHAR *deformated=NULL;
+
+    rc = MSI_OpenQuery(package->db, &view, ExecSeqQuery, action);
+    if (rc != ERROR_SUCCESS)
+        return rc;
+
+    rc = MSI_ViewExecute(view, 0);
+    if (rc != ERROR_SUCCESS)
+    {
+        MSI_ViewClose(view);
+        msiobj_release(&view->hdr);
+        return rc;
+    }
+
+    rc = MSI_ViewFetch(view,&row);
+    if (rc != ERROR_SUCCESS)
+    {
+        MSI_ViewClose(view);
+        msiobj_release(&view->hdr);
+        return rc;
+    }
+
+    type = MSI_RecordGetInteger(row,2);
+
+    source = load_dynamic_stringW(row,3);
+    target = load_dynamic_stringW(row,4);
+
+    TRACE("Handling custom action %s (%x %s %s)\n",debugstr_w(action),type,
+          debugstr_w(source), debugstr_w(target));
+
+    /* handle some of the deferred actions */
+    if (type & 0x400)
+    {
+        if (type & 0x100)
+        {
+            FIXME("Rollback only action... rollbacks not supported yet\n");
+            HeapFree(GetProcessHeap(),0,source);
+            HeapFree(GetProcessHeap(),0,target);
+            msiobj_release(&row->hdr);
+            MSI_ViewClose(view);
+            msiobj_release(&view->hdr);
+            return ERROR_SUCCESS;
+        }
+        if (!execute)
+        {
+            LPWSTR *newbuf = NULL;
+            INT count;
+            if (type & 0x200)
+            {
+                TRACE("Deferring Commit Action!\n");
+                count = package->CommitActionCount;
+                package->CommitActionCount++;
+                if (count != 0)
+                    newbuf = HeapReAlloc(GetProcessHeap(),0,
+                        package->CommitAction,
+                        package->CommitActionCount * sizeof(LPWSTR));
+                else
+                    newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR));
+
+                newbuf[count] = dupstrW(action);
+                package->CommitAction = newbuf;
+            }
+            else
+            {
+                TRACE("Deferring Action!\n");
+                count = package->DeferredActionCount;
+                package->DeferredActionCount++;
+                if (count != 0)
+                    newbuf = HeapReAlloc(GetProcessHeap(),0,
+                        package->DeferredAction,
+                        package->DeferredActionCount * sizeof(LPWSTR));
+                else
+                    newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(LPWSTR));
+
+                newbuf[count] = dupstrW(action);
+                package->DeferredAction = newbuf;
+            }
+
+            HeapFree(GetProcessHeap(),0,source);
+            HeapFree(GetProcessHeap(),0,target);
+            msiobj_release(&row->hdr);
+            MSI_ViewClose(view);
+            msiobj_release(&view->hdr);
+            return ERROR_SUCCESS;
+        }
+        else
+        {
+            /*Set ActionData*/
+
+            static const WCHAR szActionData[] = {
+            'C','u','s','t','o','m','A','c','t','i','o','n','D','a','t','a',0};
+            LPWSTR actiondata = load_dynamic_property(package,action,NULL);
+            if (actiondata)
+                MSI_SetPropertyW(package,szActionData,actiondata);
+        }
+    }
+
+    switch (type & CUSTOM_ACTION_TYPE_MASK)
+    {
+        case 1: /* DLL file stored in a Binary table stream */
+            rc = HANDLE_CustomType1(package,source,target,type,action);
+            break;
+        case 2: /* EXE file stored in a Binary table strem */
+            rc = HANDLE_CustomType2(package,source,target,type,action);
+            break;
+        case 18: /*EXE file installed with package */
+            rc = HANDLE_CustomType18(package,source,target,type,action);
+            break;
+        case 50: /*EXE file specified by a property value */
+            rc = HANDLE_CustomType50(package,source,target,type,action);
+            break;
+        case 34: /*EXE to be run in specified directory */
+            rc = HANDLE_CustomType34(package,source,target,type,action);
+            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);
+            HeapFree(GetProcessHeap(),0,deformated);
+            break;
+        default:
+            FIXME("UNHANDLED ACTION TYPE %i (%s %s)\n",
+             type & CUSTOM_ACTION_TYPE_MASK, debugstr_w(source),
+             debugstr_w(target));
+    }
+
+    HeapFree(GetProcessHeap(),0,source);
+    HeapFree(GetProcessHeap(),0,target);
+    msiobj_release(&row->hdr);
+    MSI_ViewClose(view);
+    msiobj_release(&view->hdr);
+    return rc;
+}
+
+
+static UINT store_binary_to_temp(MSIPACKAGE *package, LPCWSTR source, 
+                                LPWSTR tmp_file)
+{
+    DWORD sz=MAX_PATH;
+
+    if (MSI_GetPropertyW(package, cszTempFolder, tmp_file, &sz) 
+        != ERROR_SUCCESS)
+        GetTempPathW(MAX_PATH,tmp_file);
+
+    strcatW(tmp_file,source);
+
+    if (GetFileAttributesW(tmp_file) != INVALID_FILE_ATTRIBUTES)
+    {
+        TRACE("File already exists\n");
+        return ERROR_SUCCESS;
+    }
+    else
+    {
+        /* write out the file */
+        UINT rc;
+        MSIQUERY * view;
+        MSIRECORD * row = 0;
+        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','=','`','%','s','`',0};
+        HANDLE the_file;
+        CHAR buffer[1024];
+
+        if (track_tempfile(package, source, tmp_file)!=0)
+            FIXME("File Name in temp tracking collision\n");
+
+        the_file = CreateFileW(tmp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
+                           FILE_ATTRIBUTE_NORMAL, NULL);
+    
+        if (the_file == INVALID_HANDLE_VALUE)
+            return ERROR_FUNCTION_FAILED;
+
+        rc = MSI_OpenQuery(package->db, &view, fmt, source);
+        if (rc != ERROR_SUCCESS)
+            return rc;
+
+        rc = MSI_ViewExecute(view, 0);
+        if (rc != ERROR_SUCCESS)
+        {
+            MSI_ViewClose(view);
+            msiobj_release(&view->hdr);
+            return rc;
+        }
+
+        rc = MSI_ViewFetch(view,&row);
+        if (rc != ERROR_SUCCESS)
+        {
+            MSI_ViewClose(view);
+            msiobj_release(&view->hdr);
+            return rc;
+        }
+
+        do 
+        {
+            DWORD write;
+            sz = 1024;
+            rc = MSI_RecordReadStream(row,2,buffer,&sz);
+            if (rc != ERROR_SUCCESS)
+            {
+                ERR("Failed to get stream\n");
+                CloseHandle(the_file);  
+                DeleteFileW(tmp_file);
+                break;
+            }
+            WriteFile(the_file,buffer,sz,&write,NULL);
+        } while (sz == 1024);
+
+        CloseHandle(the_file);
+
+        msiobj_release(&row->hdr);
+        MSI_ViewClose(view);
+        msiobj_release(&view->hdr);
+    }
+
+    return ERROR_SUCCESS;
+}
+
+static void file_running_action(MSIPACKAGE* package, HANDLE Handle, 
+                                BOOL process, LPCWSTR name)
+{
+    MSIRUNNINGACTION *newbuf = NULL;
+    INT count;
+    count = package->RunningActionCount;
+    package->RunningActionCount++;
+    if (count != 0)
+        newbuf = HeapReAlloc(GetProcessHeap(),0,
+                        package->RunningAction,
+                        package->RunningActionCount * sizeof(MSIRUNNINGACTION));
+    else
+        newbuf = HeapAlloc(GetProcessHeap(),0, sizeof(MSIRUNNINGACTION));
+
+    newbuf[count].handle = Handle;
+    newbuf[count].process = process;
+    newbuf[count].name = dupstrW(name);
+
+    package->RunningAction = newbuf;
+}
+
+static UINT process_action_return_value(UINT type, HANDLE ThreadHandle)
+{
+    DWORD rc;
+    
+    if (type == 2)
+    {
+        GetExitCodeProcess(ThreadHandle,&rc);
+    
+        if (rc == 0)
+            return ERROR_SUCCESS;
+        else
+            return ERROR_FUNCTION_FAILED;
+    }
+
+    GetExitCodeThread(ThreadHandle,&rc);
+
+    switch (rc)
+    {
+        case ERROR_FUNCTION_NOT_CALLED:
+        case ERROR_SUCCESS:
+        case ERROR_INSTALL_USEREXIT:
+        case ERROR_INSTALL_FAILURE:
+            return rc;
+        case ERROR_NO_MORE_ITEMS:
+            return ERROR_SUCCESS;
+        default:
+            return ERROR_FUNCTION_FAILED;
+    }
+}
+
+static UINT process_handle(MSIPACKAGE* package, UINT type, 
+                           HANDLE ThreadHandle, HANDLE ProcessHandle,
+                           LPCWSTR Name)
+{
+    UINT rc = ERROR_SUCCESS;
+
+    if (!(type & 0x80))
+    {
+        /* syncronous */
+        TRACE("Syncronous Execution of action %s\n",debugstr_w(Name));
+        if (ProcessHandle)
+            WaitForSingleObject(ProcessHandle,INFINITE);
+        else
+            WaitForSingleObject(ThreadHandle,INFINITE);
+
+        if (!(type & 0x40))
+        {
+            if (ProcessHandle)
+                rc = process_action_return_value(2,ProcessHandle);
+            else
+                rc = process_action_return_value(1,ThreadHandle);
+        }
+
+        CloseHandle(ThreadHandle);
+        if (ProcessHandle);
+            CloseHandle(ProcessHandle);
+    }
+    else 
+    {
+        TRACE("Asyncronous Execution of action %s\n",debugstr_w(Name));
+        /* asyncronous */
+        if (type & 0x40)
+        {
+            if (ProcessHandle)
+            {
+                file_running_action(package, ProcessHandle, TRUE, Name);
+                CloseHandle(ThreadHandle);
+            }
+            else
+            file_running_action(package, ThreadHandle, FALSE, Name);
+        }
+        else
+        {
+            CloseHandle(ThreadHandle);
+            if (ProcessHandle);
+                CloseHandle(ProcessHandle);
+        }
+    }
+
+    return rc;
+}
+
+
+typedef UINT __stdcall CustomEntry(MSIHANDLE);
+
+typedef struct 
+{
+        MSIPACKAGE *package;
+        WCHAR *target;
+        WCHAR *source;
+} thread_struct;
+
+static DWORD WINAPI ACTION_CallDllFunction(thread_struct *stuff)
+{
+    HANDLE hModule;
+    LPSTR proc;
+    CustomEntry *fn;
+    DWORD rc = ERROR_SUCCESS;
+
+    TRACE("calling function (%s, %s) \n", debugstr_w(stuff->source),
+          debugstr_w(stuff->target));
+
+    hModule = LoadLibraryW(stuff->source);
+    if (hModule)
+    {
+        proc = strdupWtoA( stuff->target );
+        fn = (CustomEntry*)GetProcAddress(hModule,proc);
+        if (fn)
+        {
+            MSIHANDLE hPackage;
+            MSIPACKAGE *package = stuff->package;
+
+            TRACE("Calling function %s\n", proc);
+            hPackage = msiobj_findhandle( &package->hdr );
+            if (hPackage )
+            {
+                rc = fn(hPackage);
+                msiobj_release( &package->hdr );
+            }
+            else
+                ERR("Handle for object %p not found\n", package );
+        }
+        else
+            ERR("Cannot load functon\n");
+
+        HeapFree(GetProcessHeap(),0,proc);
+        FreeLibrary(hModule);
+    }
+    else
+        ERR("Unable to load library\n");
+    msiobj_release( &stuff->package->hdr );
+    HeapFree(GetProcessHeap(),0,stuff->source);
+    HeapFree(GetProcessHeap(),0,stuff->target);
+    HeapFree(GetProcessHeap(), 0, stuff);
+    return rc;
+}
+
+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, LPCWSTR source, 
+                               LPCWSTR target, const INT type, LPCWSTR action)
+{
+    WCHAR tmp_file[MAX_PATH];
+    thread_struct *info;
+    DWORD ThreadId;
+    HANDLE ThreadHandle;
+    UINT rc = ERROR_SUCCESS;
+
+    store_binary_to_temp(package, source, tmp_file);
+
+    TRACE("Calling function %s from %s\n",debugstr_w(target),
+          debugstr_w(tmp_file));
+
+    if (!strchrW(tmp_file,'.'))
+    {
+        static const WCHAR dot[]={'.',0};
+        strcatW(tmp_file,dot);
+    } 
+
+    info = HeapAlloc( GetProcessHeap(), 0, sizeof(*info) );
+    msiobj_addref( &package->hdr );
+    info->package = package;
+    info->target = dupstrW(target);
+    info->source = dupstrW(tmp_file);
+
+    ThreadHandle = CreateThread(NULL,0,DllThread,(LPVOID)info,0,&ThreadId);
+
+    rc = process_handle(package, type, ThreadHandle, NULL, action);
+ 
+    return rc;
+}
+
+static UINT HANDLE_CustomType2(MSIPACKAGE *package, LPCWSTR source, 
+                               LPCWSTR target, const INT type, LPCWSTR action)
+{
+    WCHAR tmp_file[MAX_PATH];
+    STARTUPINFOW si;
+    PROCESS_INFORMATION info;
+    BOOL rc;
+    INT len;
+    WCHAR *deformated;
+    WCHAR *cmd;
+    static const WCHAR spc[] = {' ',0};
+    UINT prc = ERROR_SUCCESS;
+
+    memset(&si,0,sizeof(STARTUPINFOW));
+
+    store_binary_to_temp(package, source, tmp_file);
+
+    deformat_string(package,target,&deformated);
+
+    len = strlenW(tmp_file)+2;
+
+    if (deformated)
+        len += strlenW(deformated);
+   
+    cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*len);
+
+    strcpyW(cmd,tmp_file);
+    if (deformated)
+    {
+        strcatW(cmd,spc);
+        strcatW(cmd,deformated);
+
+        HeapFree(GetProcessHeap(),0,deformated);
+    }
+
+    TRACE("executing exe %s \n",debugstr_w(cmd));
+
+    rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
+                  c_collen, &si, &info);
+
+    HeapFree(GetProcessHeap(),0,cmd);
+
+    if ( !rc )
+    {
+        ERR("Unable to execute command\n");
+        return ERROR_SUCCESS;
+    }
+
+    prc = process_handle(package, type, info.hThread, info.hProcess, action);
+
+    return prc;
+}
+
+static UINT HANDLE_CustomType18(MSIPACKAGE *package, LPCWSTR source,
+                                LPCWSTR target, const INT type, LPCWSTR action)
+{
+    STARTUPINFOW si;
+    PROCESS_INFORMATION info;
+    BOOL rc;
+    WCHAR *deformated;
+    WCHAR *cmd;
+    INT len;
+    static const WCHAR spc[] = {' ',0};
+    int index;
+    UINT prc;
+
+    memset(&si,0,sizeof(STARTUPINFOW));
+
+    index = get_loaded_file(package,source);
+
+    len = strlenW(package->files[index].TargetPath);
+
+    deformat_string(package,target,&deformated);
+    if (deformated)
+        len += strlenW(deformated);
+    len += 2;
+
+    cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,len * sizeof(WCHAR));
+
+    strcpyW(cmd, package->files[index].TargetPath);
+    if (deformated)
+    {
+        strcatW(cmd, spc);
+        strcatW(cmd, deformated);
+
+        HeapFree(GetProcessHeap(),0,deformated);
+    }
+
+    TRACE("executing exe %s \n",debugstr_w(cmd));
+
+    rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
+                  c_collen, &si, &info);
+
+    HeapFree(GetProcessHeap(),0,cmd);
+    
+    if ( !rc )
+    {
+        ERR("Unable to execute command\n");
+        return ERROR_SUCCESS;
+    }
+
+    prc = process_handle(package, type, info.hThread, info.hProcess, action);
+
+    return prc;
+}
+
+static UINT HANDLE_CustomType50(MSIPACKAGE *package, LPCWSTR source,
+                                LPCWSTR target, const INT type, LPCWSTR action)
+{
+    STARTUPINFOW si;
+    PROCESS_INFORMATION info;
+    WCHAR *prop;
+    BOOL rc;
+    WCHAR *deformated;
+    WCHAR *cmd;
+    INT len;
+    UINT prc;
+    static const WCHAR spc[] = {' ',0};
+
+    memset(&si,0,sizeof(STARTUPINFOW));
+    memset(&info,0,sizeof(PROCESS_INFORMATION));
+
+    prop = load_dynamic_property(package,source,&prc);
+    if (!prop)
+        return prc;
+
+    deformat_string(package,target,&deformated);
+    len = strlenW(prop) + 2;
+    if (deformated)
+         len += strlenW(deformated);
+
+    cmd = (WCHAR*)HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*len);
+
+    strcpyW(cmd,prop);
+    if (deformated)
+    {
+        strcatW(cmd,spc);
+        strcatW(cmd,deformated);
+
+        HeapFree(GetProcessHeap(),0,deformated);
+    }
+
+    TRACE("executing exe %s \n",debugstr_w(cmd));
+
+    rc = CreateProcessW(NULL, cmd, NULL, NULL, FALSE, 0, NULL,
+                  c_collen, &si, &info);
+
+    HeapFree(GetProcessHeap(),0,cmd);
+    
+    if ( !rc )
+    {
+        ERR("Unable to execute command\n");
+        return ERROR_SUCCESS;
+    }
+
+    prc = process_handle(package, type, info.hThread, info.hProcess, action);
+
+    return prc;
+}
+
+static UINT HANDLE_CustomType34(MSIPACKAGE *package, LPCWSTR source,
+                                LPCWSTR target, const INT type, LPCWSTR action)
+{
+    LPWSTR filename, deformated;
+    STARTUPINFOW si;
+    PROCESS_INFORMATION info;
+    BOOL rc;
+    UINT prc;
+
+    memset(&si,0,sizeof(STARTUPINFOW));
+
+    filename = resolve_folder(package, source, FALSE, FALSE, NULL);
+
+    if (!filename)
+        return ERROR_FUNCTION_FAILED;
+
+    SetCurrentDirectoryW(filename);
+    HeapFree(GetProcessHeap(),0,filename);
+
+    deformat_string(package,target,&deformated);
+
+    if (!deformated)
+        return ERROR_FUNCTION_FAILED;
+
+    TRACE("executing exe %s \n",debugstr_w(deformated));
+
+    rc = CreateProcessW(NULL, deformated, NULL, NULL, FALSE, 0, NULL,
+                  c_collen, &si, &info);
+    HeapFree(GetProcessHeap(),0,deformated);
+
+    if ( !rc )
+    {
+        ERR("Unable to execute command\n");
+        return ERROR_SUCCESS;
+    }
+
+    prc = process_handle(package, type, info.hThread, info.hProcess, action);
+
+    return prc;
+}
+
+
+void ACTION_FinishCustomActions(MSIPACKAGE* package)
+{
+    INT i;
+    DWORD rc;
+
+    for (i = 0; i < package->RunningActionCount; i++)
+    {
+        TRACE("Checking on action %s\n",
+               debugstr_w(package->RunningAction[i].name));
+
+        if (package->RunningAction[i].process)
+            GetExitCodeProcess(package->RunningAction[i].handle, &rc);
+        else
+            GetExitCodeThread(package->RunningAction[i].handle, &rc);
+
+        if (rc == STILL_ACTIVE)
+        {
+            TRACE("Waiting on action %s\n",
+               debugstr_w(package->RunningAction[i].name));
+            WaitForSingleObject(package->RunningAction[i].handle, INFINITE);
+        }
+
+        HeapFree(GetProcessHeap(),0,package->RunningAction[i].name);
+        CloseHandle(package->RunningAction[i].handle);
+    }
+
+    HeapFree(GetProcessHeap(),0,package->RunningAction);
+}
--- /dev/null	Fri Aug 31 05:30:55 2001
+++ dlls/msi/format.c	Tue Jan 25 21:06:32 2005
@@ -0,0 +1,333 @@
+/*
+ * Implementation of the Microsoft Installer (msi.dll)
+ *
+ * Copyright 2005 Mike McCormack for CodeWeavers
+ * Copyright 2005 Aric Stewart for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msiformatrecord.asp 
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "winreg.h"
+#include "wine/debug.h"
+#include "fdi.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "msvcrt/fcntl.h"
+#include "objbase.h"
+#include "objidl.h"
+#include "msipriv.h"
+#include "winnls.h"
+#include "winuser.h"
+#include "shlobj.h"
+#include "wine/unicode.h"
+#include "ver.h"
+#include "action.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+static const WCHAR* scanW(LPCWSTR buf, WCHAR token, DWORD len)
+{
+    DWORD i;
+    for (i = 0; i < len; i++)
+        if (buf[i] == token)
+            return &buf[i];
+    return NULL;
+}
+
+/*
+ * This helper function should probably go alot of places
+ *
+ * Thinking about this, maybe this should become yet another Bison file
+ *
+ * len is in WCHARs
+ * return is also in WCHARs
+ */
+static DWORD deformat_string_internal(MSIPACKAGE *package, LPCWSTR ptr, 
+                                     WCHAR** data, DWORD len, MSIRECORD* record)
+{
+    const WCHAR* mark=NULL;
+    WCHAR* mark2;
+    DWORD size=0;
+    DWORD chunk=0;
+    WCHAR key[0x100];
+    LPWSTR value = NULL;
+    DWORD sz;
+    UINT rc;
+    INT index;
+    LPWSTR newdata = NULL;
+
+    if (ptr==NULL)
+    {
+        TRACE("Deformatting NULL string\n");
+        *data = NULL;
+        return 0;
+    }
+
+    TRACE("Starting with %s\n",debugstr_w(ptr));
+
+    /* scan for special characters */
+    if (!scanW(ptr,'[',len) || (scanW(ptr,'[',len) && !scanW(ptr,']',len)))
+    {
+        /* not formatted */
+        *data = HeapAlloc(GetProcessHeap(),0,(len*sizeof(WCHAR)));
+        memcpy(*data,ptr,len*sizeof(WCHAR));
+        TRACE("Returning %s\n",debugstr_w(*data));
+        return len;
+    }
+   
+    /* formatted string located */ 
+    mark = scanW(ptr,'[',len);
+    if (mark != ptr)
+    {
+        INT cnt = (mark - ptr);
+        TRACE("%i  (%i) characters before marker\n",cnt,(mark-ptr));
+        size = cnt * sizeof(WCHAR);
+        newdata = HeapAlloc(GetProcessHeap(),0,size);
+        memcpy(newdata,ptr,(cnt * sizeof(WCHAR)));
+    }
+    else
+    {
+        size = 0;
+        newdata = HeapAlloc(GetProcessHeap(),0,size);
+        newdata[0]=0;
+    }
+    mark++;
+    /* there should be no null characters in a key so strchrW is ok */
+    mark2 = strchrW(mark,']');
+    strncpyW(key,mark,mark2-mark);
+    key[mark2-mark] = 0;
+    mark = strchrW(mark,']');
+    mark++;
+    TRACE("Current %s .. %s\n",debugstr_w(newdata),debugstr_w(key));
+    sz = 0;
+    /* expand what we can deformat... Again, this should become a bison file */
+    switch (key[0])
+    {
+        case '~':
+            value = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*2);
+            value[0] =  0;
+            chunk = sizeof(WCHAR);
+            rc = ERROR_SUCCESS;
+            break;
+        case '$':
+            ERR("POORLY HANDLED DEFORMAT.. [$componentkey] \n");
+            index = get_loaded_component(package,&key[1]);
+            if (index >= 0)
+            {
+                value = resolve_folder(package, 
+                                       package->components[index].Directory, 
+                                       FALSE, FALSE, NULL);
+                chunk = (strlenW(value)) * sizeof(WCHAR);
+                rc = 0;
+            }
+            else
+                rc = ERROR_FUNCTION_FAILED;
+            break;
+        case '#':
+        case '!': /* should be short path */
+            index = get_loaded_file(package,&key[1]);
+            if (index >=0)
+            {
+                sz = strlenW(package->files[index].TargetPath);
+                value = dupstrW(package->files[index].TargetPath);
+                chunk = (strlenW(value)) * sizeof(WCHAR);
+                rc= ERROR_SUCCESS;
+            }
+            else
+                rc = ERROR_FUNCTION_FAILED;
+            break;
+        case '\\':
+            value = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*2);
+            value[0] =  key[1];
+            chunk = sizeof(WCHAR);
+            rc = ERROR_SUCCESS;
+            break;
+        case '%':
+            sz  = GetEnvironmentVariableW(&key[1],NULL,0);
+            if (sz > 0)
+            {
+                sz++;
+                value = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR));
+                GetEnvironmentVariableW(&key[1],value,sz);
+                chunk = (strlenW(value)) * sizeof(WCHAR);
+                rc = ERROR_SUCCESS;
+            }
+            else
+            {
+                ERR("Unknown enviroment variable\n");
+                chunk = 0;
+                value = NULL;
+                rc = ERROR_FUNCTION_FAILED;
+            }
+            break;
+        default:
+            /* check for numaric values */
+            index = 0;
+            while (isdigitW(key[index])) index++;
+            if (key[index] == 0)
+            {
+                index = atoiW(key);
+                TRACE("record index %i\n",index);
+                value = load_dynamic_stringW(record,index);
+                if (value)
+                {
+                    chunk = strlenW(value) * sizeof(WCHAR);
+                    rc = ERROR_SUCCESS;
+                }
+                else
+                {
+                    value = NULL;
+                    rc = ERROR_FUNCTION_FAILED;
+                }
+            }
+            else
+            {
+                value = load_dynamic_property(package,key, &rc);
+                if (rc == ERROR_SUCCESS)
+                    chunk = (strlenW(value)) * sizeof(WCHAR);
+            }
+            break;      
+    }
+    if (((rc == ERROR_SUCCESS) || (rc == ERROR_MORE_DATA)) && value!=NULL)
+    {
+        LPWSTR nd2;
+        TRACE("value %s, chunk %li size %li\n",debugstr_w(value),chunk,size);
+
+        nd2= HeapReAlloc(GetProcessHeap(),0,newdata,(size + chunk));
+        newdata = nd2;
+        memcpy(&newdata[(size/sizeof(WCHAR))],value,chunk);
+        size+=chunk;   
+        HeapFree(GetProcessHeap(),0,value);
+    }
+    TRACE("after value %s .. %s\n",debugstr_w(newdata),debugstr_w(mark));
+    if (mark - ptr < len)
+    {
+        LPWSTR nd2;
+        chunk = (len - (mark - ptr)) * sizeof(WCHAR);
+        TRACE("after chunk is %li\n",chunk);
+        nd2 = HeapReAlloc(GetProcessHeap(),0,newdata,(size+chunk));
+        newdata = nd2;
+        memcpy(&newdata[(size/sizeof(WCHAR))],mark,chunk);
+        size+=chunk;
+    }
+    TRACE("after trailing %s .. %s\n",debugstr_w(newdata),debugstr_w(mark));
+
+    /* recursively do this to clean up */
+    size = deformat_string_internal(package,newdata,data,(size/sizeof(WCHAR)),
+                                    record);
+    HeapFree(GetProcessHeap(),0,newdata);
+    return size;
+}
+
+
+UINT MSI_FormatRecordW(MSIPACKAGE* package, MSIRECORD* record, LPWSTR buffer,
+                        DWORD *size)
+{
+    LPWSTR deformated;
+    LPWSTR rec;
+    DWORD len;
+    UINT rc = ERROR_INVALID_PARAMETER;
+
+    TRACE("%p %p %p %li\n",package, record ,buffer, *size);
+
+    rec = load_dynamic_stringW(record,0);
+    if (!rec)
+        return rc;
+
+    TRACE("(%s)\n",debugstr_w(rec));
+
+    len = deformat_string_internal(package,rec,&deformated,(strlenW(rec)+1),
+                                   record);
+    if (len <= *size)
+    {
+        *size = len;
+        memcpy(buffer,deformated,len*sizeof(WCHAR));
+        rc = ERROR_SUCCESS;
+    }
+    else
+    {
+        *size = len;
+        rc = ERROR_MORE_DATA;
+    }
+
+    HeapFree(GetProcessHeap(),0,rec);
+    HeapFree(GetProcessHeap(),0,deformated);
+    return rc;
+}
+
+UINT WINAPI MsiFormatRecordA(MSIHANDLE hInstall, MSIHANDLE hRecord, LPSTR
+szResult, DWORD *sz)
+{
+    UINT rc;
+    MSIPACKAGE* package;
+    MSIRECORD* record;
+    LPWSTR szwResult;
+    DWORD original_len;
+
+    TRACE("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
+
+    package = msihandle2msiinfo(hInstall,MSIHANDLETYPE_PACKAGE);
+    record = msihandle2msiinfo(hRecord,MSIHANDLETYPE_RECORD);
+
+    if (!package || !record)
+        return ERROR_INVALID_HANDLE;
+
+    original_len = *sz;
+    /* +1 just to make sure we have a buffer incase the len is 0 */
+    szwResult = HeapAlloc(GetProcessHeap(),0,(original_len+1) * sizeof(WCHAR));
+
+    rc = MSI_FormatRecordW(package, record, szwResult, sz);
+    
+    WideCharToMultiByte(CP_ACP,0,szwResult,original_len, szResult, original_len,
+                        NULL,NULL);
+
+    HeapFree(GetProcessHeap(),0,szwResult);
+
+    return rc;
+
+}
+
+UINT WINAPI MsiFormatRecordW(MSIHANDLE hInstall, MSIHANDLE hRecord, 
+                             LPWSTR szResult, DWORD *sz)
+{
+    UINT rc;
+    MSIPACKAGE* package;
+    MSIRECORD* record;
+
+    TRACE("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
+
+    package = msihandle2msiinfo(hInstall,MSIHANDLETYPE_PACKAGE);
+    record = msihandle2msiinfo(hRecord,MSIHANDLETYPE_RECORD);
+
+    if (!package || !record)
+        return ERROR_INVALID_HANDLE;
+
+    rc = MSI_FormatRecordW(package, record, szResult, sz);
+
+    return rc;
+}
+
--- /dev/null	Fri Aug 31 05:30:55 2001
+++ dlls/msi/action.h	Tue Jan 25 20:29:49 2005
@@ -0,0 +1,151 @@
+/*
+ * Common prototypes for Action handlers
+ *
+ * Copyright 2005 Aric Stewart for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+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 Installed;
+    INSTALLSTATE ActionRequest;
+    INSTALLSTATE Action;
+
+    INT ComponentCount;
+    INT Components[1024]; /* yes hardcoded limit.... I am bad */
+    INT Cost;
+} MSIFEATURE;
+
+typedef struct tagMSICOMPONENT
+{
+    WCHAR Component[96];
+    WCHAR ComponentId[96];
+    WCHAR Directory[96];
+    INT Attributes;
+    WCHAR Condition[0x100];
+    WCHAR KeyPath[96];
+
+    INSTALLSTATE Installed;
+    INSTALLSTATE ActionRequest;
+    INSTALLSTATE Action;
+
+    BOOL Enabled;
+    INT  Cost;
+} MSICOMPONENT;
+
+typedef struct tagMSIFOLDER
+{
+    LPWSTR Directory;
+    LPWSTR TargetDefault;
+    LPWSTR SourceDefault;
+
+    LPWSTR ResolvedTarget;
+    LPWSTR ResolvedSource;
+    LPWSTR Property;   /* initially set property */
+    INT   ParentIndex;
+    INT   State;
+        /* 0 = uninitialized */
+        /* 1 = existing */
+        /* 2 = created remove if empty */
+        /* 3 = created persist if empty */
+    INT   Cost;
+    INT   Space;
+}MSIFOLDER;
+
+typedef struct tagMSIFILE
+{
+    LPWSTR File;
+    INT ComponentIndex;
+    LPWSTR FileName;
+    INT FileSize;
+    LPWSTR Version;
+    LPWSTR Language;
+    INT Attributes;
+    INT Sequence;   
+
+    INT State;
+       /* 0 = uninitialize */
+       /* 1 = not present */
+       /* 2 = present but replace */
+       /* 3 = present do not replace */
+       /* 4 = Installed */
+    LPWSTR  SourcePath;
+    LPWSTR  TargetPath;
+    BOOL    Temporary; 
+}MSIFILE;
+
+
+void ACTION_FinishCustomActions( MSIPACKAGE* package);
+UINT ACTION_CustomAction(MSIPACKAGE *package,const WCHAR *action, BOOL execute);
+
+
+DWORD deformat_string(MSIPACKAGE *package, LPCWSTR ptr, WCHAR** data );
+WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index);
+LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, UINT* rc);
+LPWSTR resolve_folder(MSIPACKAGE *package, LPCWSTR name, BOOL source, 
+                      BOOL set_prop, MSIFOLDER **folder);
+int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component );
+int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature );
+int get_loaded_file(MSIPACKAGE* package, LPCWSTR file);
+int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path);
+
+
+
+inline static char *strdupWtoA( const WCHAR *str )
+{
+    char *ret = NULL;
+    if (str)
+    {
+        DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL
+);
+        if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
+            WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
+    }
+    return ret;
+}
+
+inline static WCHAR *strdupAtoW( const char *str )
+{
+    WCHAR *ret = NULL;
+    if (str)
+    {
+        DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
+        if ((ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
+            MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
+    }
+    return ret;
+}
+
+inline 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;
+}
+
+
+


More information about the wine-patches mailing list