From 54c67dd1b11fd42a34f9eda14a0a7ce96e4e8350 Mon Sep 17 00:00:00 2001 From: Aric Stewart Date: Tue, 25 Jan 2005 20:17:09 +0000 Subject: [PATCH] - action.c is getting too big, so split out all the handling of CustomActions into custom.c. Cleaned up a lot of the handling of custom actions including scripting actions and processing return codes. - Mike McCormack pointed out that MsiFormatRecord is basically the same as internal function deformat_string. So broke deformat_string out and updated it to function as MsiFormatRecord and implemented MsiFormatRecord. - 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. --- dlls/msi/Makefile.in | 2 + dlls/msi/action.c | 936 +++---------------------------------------- dlls/msi/action.h | 148 +++++++ dlls/msi/custom.c | 745 ++++++++++++++++++++++++++++++++++ dlls/msi/format.c | 332 +++++++++++++++ dlls/msi/msipriv.h | 7 + dlls/msi/package.c | 1 - dlls/msi/record.c | 12 - 8 files changed, 1294 insertions(+), 889 deletions(-) create mode 100644 dlls/msi/action.h create mode 100644 dlls/msi/custom.c create mode 100644 dlls/msi/format.c diff --git a/dlls/msi/Makefile.in b/dlls/msi/Makefile.in index 6f598bfef19..7db118bbc0d 100644 --- a/dlls/msi/Makefile.in +++ b/dlls/msi/Makefile.in @@ -9,7 +9,9 @@ EXTRALIBS = -luuid $(LIBUNICODE) C_SRCS = \ action.c \ create.c \ + custom.c \ distinct.c \ + format.c \ handle.c \ insert.c \ msi.c \ diff --git a/dlls/msi/action.c b/dlls/msi/action.c index ade6b88578f..d0953c34f29 100644 --- a/dlls/msi/action.c +++ b/dlls/msi/action.c @@ -48,91 +48,13 @@ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/stand #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_FileCost(MSIPACKAGE *package); 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_InstallExecute(MSIPACKAGE *package); 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 cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0}; 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 @@ inline static void reduce_to_longfilename(WCHAR* filename) 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 @@ inline static WCHAR *load_dynamic_stringW(MSIRECORD *row, INT index) 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 @@ inline static LPWSTR load_dynamic_property(MSIPACKAGE *package, LPCWSTR prop, 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 @@ inline static int get_loaded_component(MSIPACKAGE* package, LPCWSTR Component ) 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 @@ inline static int get_loaded_feature(MSIPACKAGE* package, LPCWSTR Feature ) 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 @@ inline static int get_loaded_file(MSIPACKAGE* package, LPCWSTR file) 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 @@ static int track_tempfile(MSIPACKAGE *package, LPCWSTR name, LPCWSTR path) return 0; } -void ACTION_remove_tracked_tempfiles(MSIPACKAGE* package) +static void remove_tracked_tempfiles(MSIPACKAGE* package) { DWORD i; @@ -450,13 +318,39 @@ void ACTION_remove_tracked_tempfiles(MSIPACKAGE* package) } } +/* 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 @@ static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * recor UINT rc; MSIQUERY * view; MSIRECORD * row = 0; - LPWSTR ptr; + DWORD size; if (!package->LastAction || strcmpW(package->LastAction,action)) { @@ -565,38 +459,9 @@ static void ui_actiondata(MSIPACKAGE *package, LPCWSTR action, MSIRECORD * recor 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 @@ UINT ACTION_DoTopLevelINSTALL(MSIPACKAGE *package, LPCWSTR szPackagePath, 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 @@ UINT ACTION_PerformAction(MSIPACKAGE *package, const WCHAR *action) 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 INT load_folder(MSIPACKAGE *package, const WCHAR* dir) } -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 @@ static BOOL extract_a_cabinet_file(MSIPACKAGE* package, const WCHAR* source, 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 @@ static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence, 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 @@ static UINT ready_media_for_file(MSIPACKAGE *package, UINT sequence, 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 @@ static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type, } else { + static const WCHAR szMulti[] = {'[','~',']',0}; WCHAR *ptr; *type=REG_SZ; @@ -3572,6 +2890,9 @@ static LPSTR parse_value(MSIPACKAGE *package, WCHAR *value, DWORD *type, else ptr=value; + if (strstrW(value,szMulti)) + *type = REG_MULTI_SZ; + *size = deformat_string(package, ptr,(LPWSTR*)&data); } return data; @@ -3745,148 +3066,6 @@ next: 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 @@ static UINT ACTION_RegisterProduct(MSIPACKAGE *package) } 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 @@ static UINT ACTION_InstallFinalize(MSIPACKAGE *package) 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; diff --git a/dlls/msi/action.h b/dlls/msi/action.h new file mode 100644 index 00000000000..a8009ef3109 --- /dev/null +++ b/dlls/msi/action.h @@ -0,0 +1,148 @@ +/* + * 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; +} diff --git a/dlls/msi/custom.c b/dlls/msi/custom.c new file mode 100644 index 00000000000..e9a2e6c7258 --- /dev/null +++ b/dlls/msi/custom.c @@ -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 +#include + +#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); +} diff --git a/dlls/msi/format.c b/dlls/msi/format.c new file mode 100644 index 00000000000..012a2d75d87 --- /dev/null +++ b/dlls/msi/format.c @@ -0,0 +1,332 @@ +/* + * 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 +#include + +#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; +} diff --git a/dlls/msi/msipriv.h b/dlls/msi/msipriv.h index 9fbc8eba2ae..ea80fa561ba 100644 --- a/dlls/msi/msipriv.h +++ b/dlls/msi/msipriv.h @@ -203,6 +203,9 @@ typedef struct tagMSIPACKAGE LPWSTR *CommitAction; UINT CommitActionCount; + struct tagMSIRUNNINGACTION *RunningAction; + UINT RunningActionCount; + LPWSTR PackagePath; } MSIPACKAGE; @@ -329,6 +332,10 @@ extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR ); 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); diff --git a/dlls/msi/package.c b/dlls/msi/package.c index 15e128553ed..54598aa7b63 100644 --- a/dlls/msi/package.c +++ b/dlls/msi/package.c @@ -53,7 +53,6 @@ void MSI_FreePackage( MSIOBJECTHDR *arg) { MSIPACKAGE *package= (MSIPACKAGE*) arg; - ACTION_remove_tracked_tempfiles(package); ACTION_free_package_structures(package); msiobj_release( &package->db->hdr ); diff --git a/dlls/msi/record.c b/dlls/msi/record.c index 7f20a1aab37..ac5487170fc 100644 --- a/dlls/msi/record.c +++ b/dlls/msi/record.c @@ -520,18 +520,6 @@ UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, unsigned int iField, LPCWSTR 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) {