2005-01-25 21:17:09 +01:00
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
|
2005-01-31 21:41:11 +01:00
|
|
|
|
|
|
|
LPWSTR build_default_format(MSIRECORD* record)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int count;
|
|
|
|
LPWSTR rc;
|
|
|
|
static const WCHAR fmt[] = {'%','i',':',' ','[','%','i',']',' ',0};
|
|
|
|
WCHAR buf[11];
|
|
|
|
|
|
|
|
count = MSI_RecordGetFieldCount(record);
|
|
|
|
|
|
|
|
rc = HeapAlloc(GetProcessHeap(),0,(11*count)*sizeof(WCHAR));
|
|
|
|
rc[0] = 0;
|
|
|
|
for (i = 1; i <= count; i++)
|
|
|
|
{
|
|
|
|
sprintfW(buf,fmt,i,i);
|
|
|
|
strcatW(rc,buf);
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2005-01-25 21:17:09 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2005-01-31 21:41:11 +01:00
|
|
|
|
|
|
|
/* break out helper functions for deformating */
|
|
|
|
static LPWSTR deformat_component(MSIPACKAGE* package, LPCWSTR key, DWORD* sz)
|
|
|
|
{
|
|
|
|
LPWSTR value = NULL;
|
|
|
|
INT index;
|
|
|
|
|
|
|
|
*sz = 0;
|
|
|
|
if (!package)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ERR("POORLY HANDLED DEFORMAT.. [$componentkey] \n");
|
|
|
|
index = get_loaded_component(package,key);
|
|
|
|
if (index >= 0)
|
|
|
|
{
|
|
|
|
value = resolve_folder(package, package->components[index].Directory,
|
|
|
|
FALSE, FALSE, NULL);
|
|
|
|
*sz = (strlenW(value)) * sizeof(WCHAR);
|
|
|
|
}
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static LPWSTR deformat_file(MSIPACKAGE* package, LPCWSTR key, DWORD* sz)
|
|
|
|
{
|
|
|
|
LPWSTR value = NULL;
|
|
|
|
INT index;
|
|
|
|
|
|
|
|
*sz = 0;
|
|
|
|
|
|
|
|
if (!package)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
index = get_loaded_file(package,key);
|
|
|
|
if (index >=0)
|
|
|
|
{
|
|
|
|
value = dupstrW(package->files[index].TargetPath);
|
|
|
|
*sz = (strlenW(value)) * sizeof(WCHAR);
|
|
|
|
}
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static LPWSTR deformat_environment(MSIPACKAGE* package, LPCWSTR key,
|
|
|
|
DWORD* chunk)
|
|
|
|
{
|
|
|
|
LPWSTR value = NULL;
|
|
|
|
DWORD sz;
|
|
|
|
|
|
|
|
sz = GetEnvironmentVariableW(key,NULL,0);
|
|
|
|
if (sz > 0)
|
|
|
|
{
|
|
|
|
sz++;
|
|
|
|
value = HeapAlloc(GetProcessHeap(),0,sz * sizeof(WCHAR));
|
|
|
|
GetEnvironmentVariableW(&key[1],value,sz);
|
|
|
|
*chunk = (strlenW(value)) * sizeof(WCHAR);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ERR("Unknown environment variable\n");
|
|
|
|
*chunk = 0;
|
|
|
|
value = NULL;
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static LPWSTR deformat_NULL(DWORD* chunk)
|
|
|
|
{
|
|
|
|
LPWSTR value;
|
|
|
|
|
|
|
|
value = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*2);
|
|
|
|
value[0] = 0;
|
|
|
|
*chunk = sizeof(WCHAR);
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static LPWSTR deformat_escape(LPCWSTR key, DWORD* chunk)
|
|
|
|
{
|
|
|
|
LPWSTR value;
|
|
|
|
|
|
|
|
value = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR)*2);
|
|
|
|
value[0] = key[0];
|
|
|
|
*chunk = sizeof(WCHAR);
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static BOOL is_key_number(LPCWSTR key)
|
|
|
|
{
|
|
|
|
INT index = 0;
|
|
|
|
while (isdigitW(key[index])) index++;
|
|
|
|
if (key[index] == 0)
|
|
|
|
return TRUE;
|
|
|
|
else
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static LPWSTR deformat_index(MSIRECORD* record, LPCWSTR key, DWORD* chunk )
|
|
|
|
{
|
|
|
|
INT index;
|
|
|
|
LPWSTR value;
|
|
|
|
|
|
|
|
index = atoiW(key);
|
|
|
|
TRACE("record index %i\n",index);
|
|
|
|
value = load_dynamic_stringW(record,index);
|
|
|
|
if (value)
|
|
|
|
*chunk = strlenW(value) * sizeof(WCHAR);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
value = NULL;
|
|
|
|
*chunk = 0;
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static LPWSTR deformat_property(MSIPACKAGE* package, LPCWSTR key, DWORD* chunk)
|
|
|
|
{
|
|
|
|
UINT rc;
|
|
|
|
LPWSTR value;
|
|
|
|
|
|
|
|
if (!package)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
value = load_dynamic_property(package,key, &rc);
|
|
|
|
|
|
|
|
if (rc == ERROR_SUCCESS)
|
|
|
|
*chunk = (strlenW(value)) * sizeof(WCHAR);
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2005-01-25 21:17:09 +01:00
|
|
|
/*
|
|
|
|
* 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;
|
2005-01-31 21:41:11 +01:00
|
|
|
LPBYTE newdata = NULL;
|
|
|
|
const WCHAR* progress = NULL;
|
2005-01-25 21:17:09 +01:00
|
|
|
|
|
|
|
if (ptr==NULL)
|
|
|
|
{
|
|
|
|
TRACE("Deformatting NULL string\n");
|
|
|
|
*data = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
TRACE("Starting with %s\n",debugstr_w(ptr));
|
|
|
|
|
2005-01-31 21:41:11 +01:00
|
|
|
/* scan for special characters... fast exit */
|
2005-01-25 21:17:09 +01:00
|
|
|
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;
|
|
|
|
}
|
2005-01-31 21:41:11 +01:00
|
|
|
|
|
|
|
progress = ptr;
|
|
|
|
|
|
|
|
while (progress - ptr < len)
|
|
|
|
{
|
|
|
|
/* formatted string located */
|
|
|
|
mark = scanW(progress,'[',len - (progress-ptr));
|
|
|
|
if (!mark)
|
|
|
|
{
|
|
|
|
LPBYTE nd2;
|
|
|
|
|
|
|
|
TRACE("after value %s .. %s\n",debugstr_w((LPWSTR)newdata),
|
|
|
|
debugstr_w(mark));
|
|
|
|
chunk = (len - (progress - ptr)) * sizeof(WCHAR);
|
|
|
|
TRACE("after chunk is %li\n",chunk);
|
|
|
|
if (size)
|
|
|
|
nd2 = HeapReAlloc(GetProcessHeap(),0,newdata,(size+chunk));
|
2005-01-25 21:17:09 +01:00
|
|
|
else
|
2005-01-31 21:41:11 +01:00
|
|
|
nd2 = HeapAlloc(GetProcessHeap(),0,size);
|
|
|
|
|
|
|
|
newdata = nd2;
|
|
|
|
memcpy(&newdata[size],progress,chunk);
|
|
|
|
size+=chunk;
|
2005-01-25 21:17:09 +01:00
|
|
|
break;
|
2005-01-31 21:41:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mark != progress)
|
|
|
|
{
|
|
|
|
LPBYTE tgt;
|
|
|
|
DWORD old_size = size;
|
|
|
|
INT cnt = (mark - progress);
|
|
|
|
TRACE("%i (%i) characters before marker\n",cnt,(mark-progress));
|
|
|
|
size += cnt * sizeof(WCHAR);
|
|
|
|
if (!old_size)
|
|
|
|
tgt = HeapAlloc(GetProcessHeap(),0,size);
|
2005-01-25 21:17:09 +01:00
|
|
|
else
|
2005-01-31 21:41:11 +01:00
|
|
|
tgt = HeapReAlloc(GetProcessHeap(),0,newdata,size);
|
|
|
|
newdata = tgt;
|
|
|
|
memcpy(&newdata[old_size],progress,(cnt * sizeof(WCHAR)));
|
|
|
|
}
|
|
|
|
|
|
|
|
progress = mark;
|
|
|
|
|
|
|
|
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((LPWSTR)newdata),debugstr_w(key));
|
|
|
|
|
|
|
|
if (!package)
|
|
|
|
{
|
|
|
|
/* only deformat number indexs */
|
|
|
|
if (is_key_number(key))
|
|
|
|
value = deformat_index(record,key,&chunk);
|
2005-01-25 21:17:09 +01:00
|
|
|
else
|
|
|
|
{
|
2005-01-31 21:41:11 +01:00
|
|
|
chunk = (strlenW(key) + 2)*sizeof(WCHAR);
|
|
|
|
value = HeapAlloc(GetProcessHeap(),0,chunk);
|
|
|
|
memcpy(value,progress,chunk);
|
2005-01-25 21:17:09 +01:00
|
|
|
}
|
2005-01-31 21:41:11 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sz = 0;
|
|
|
|
switch (key[0])
|
2005-01-25 21:17:09 +01:00
|
|
|
{
|
2005-01-31 21:41:11 +01:00
|
|
|
case '~':
|
|
|
|
value = deformat_NULL(&chunk);
|
|
|
|
break;
|
|
|
|
case '$':
|
|
|
|
value = deformat_component(package,&key[1],&chunk);
|
|
|
|
break;
|
|
|
|
case '#':
|
|
|
|
case '!': /* should be short path */
|
|
|
|
value = deformat_file(package,&key[1], &chunk);
|
|
|
|
break;
|
|
|
|
case '\\':
|
|
|
|
value = deformat_escape(&key[1],&chunk);
|
|
|
|
break;
|
|
|
|
case '%':
|
|
|
|
value = deformat_environment(package,&key[1],&chunk);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (is_key_number(key))
|
|
|
|
value = deformat_index(record,key,&chunk);
|
|
|
|
else
|
|
|
|
value = deformat_property(package,key,&chunk);
|
|
|
|
break;
|
2005-01-25 21:17:09 +01:00
|
|
|
}
|
2005-01-31 21:41:11 +01:00
|
|
|
}
|
|
|
|
if (value!=NULL)
|
|
|
|
{
|
|
|
|
LPBYTE nd2;
|
|
|
|
TRACE("value %s, chunk %li size %li\n",debugstr_w((LPWSTR)value),
|
|
|
|
chunk, size);
|
|
|
|
if (size)
|
|
|
|
nd2= HeapReAlloc(GetProcessHeap(),0,newdata,(size + chunk));
|
2005-01-25 21:17:09 +01:00
|
|
|
else
|
2005-01-31 21:41:11 +01:00
|
|
|
nd2= HeapAlloc(GetProcessHeap(),0,chunk);
|
|
|
|
newdata = nd2;
|
|
|
|
memcpy(&newdata[size],value,chunk);
|
|
|
|
size+=chunk;
|
|
|
|
HeapFree(GetProcessHeap(),0,value);
|
|
|
|
}
|
|
|
|
|
|
|
|
progress = mark2+1;
|
2005-01-25 21:17:09 +01:00
|
|
|
}
|
|
|
|
|
2005-01-31 21:41:11 +01:00
|
|
|
TRACE("after everything %s\n",debugstr_w((LPWSTR)newdata));
|
|
|
|
|
|
|
|
*data = (LPWSTR)newdata;
|
|
|
|
return size / sizeof(WCHAR);
|
2005-01-25 21:17:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-01-31 21:41:11 +01:00
|
|
|
UINT MSI_FormatRecordW( MSIPACKAGE* package, MSIRECORD* record, LPWSTR buffer,
|
|
|
|
DWORD *size )
|
2005-01-25 21:17:09 +01:00
|
|
|
{
|
|
|
|
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)
|
2005-01-31 21:41:11 +01:00
|
|
|
rec = build_default_format(record);
|
2005-01-25 21:17:09 +01:00
|
|
|
|
|
|
|
TRACE("(%s)\n",debugstr_w(rec));
|
|
|
|
|
2005-01-31 21:41:11 +01:00
|
|
|
len = deformat_string_internal(package,rec,&deformated,strlenW(rec),
|
2005-01-25 21:17:09 +01:00
|
|
|
record);
|
2005-01-31 21:41:11 +01:00
|
|
|
|
|
|
|
if (buffer)
|
2005-01-25 21:17:09 +01:00
|
|
|
{
|
2005-01-31 21:41:11 +01:00
|
|
|
if (*size>len)
|
|
|
|
{
|
|
|
|
memcpy(buffer,deformated,len*sizeof(WCHAR));
|
|
|
|
rc = ERROR_SUCCESS;
|
|
|
|
buffer[len] = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memcpy(buffer,deformated,(*size)*sizeof(WCHAR));
|
|
|
|
rc = ERROR_MORE_DATA;
|
|
|
|
buffer[(*size)-1] = 0;
|
|
|
|
}
|
2005-01-25 21:17:09 +01:00
|
|
|
}
|
|
|
|
else
|
2005-01-31 21:41:11 +01:00
|
|
|
rc = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
*size = len;
|
2005-01-25 21:17:09 +01:00
|
|
|
|
|
|
|
HeapFree(GetProcessHeap(),0,rec);
|
|
|
|
HeapFree(GetProcessHeap(),0,deformated);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2005-01-31 21:41:11 +01:00
|
|
|
UINT MSI_FormatRecordA( MSIPACKAGE* package, MSIRECORD* record, LPSTR buffer,
|
|
|
|
DWORD *size )
|
2005-01-25 21:17:09 +01:00
|
|
|
{
|
2005-01-31 21:41:11 +01:00
|
|
|
LPWSTR deformated;
|
|
|
|
LPWSTR rec;
|
|
|
|
DWORD len,lenA;
|
|
|
|
UINT rc = ERROR_INVALID_PARAMETER;
|
2005-01-25 21:17:09 +01:00
|
|
|
|
2005-01-31 21:41:11 +01:00
|
|
|
TRACE("%p %p %p %li\n",package, record ,buffer, *size);
|
2005-01-25 21:17:09 +01:00
|
|
|
|
2005-01-31 21:41:11 +01:00
|
|
|
rec = load_dynamic_stringW(record,0);
|
|
|
|
if (!rec)
|
|
|
|
rec = build_default_format(record);
|
2005-01-25 21:17:09 +01:00
|
|
|
|
2005-01-31 21:41:11 +01:00
|
|
|
TRACE("(%s)\n",debugstr_w(rec));
|
2005-01-25 21:17:09 +01:00
|
|
|
|
2005-01-31 21:41:11 +01:00
|
|
|
len = deformat_string_internal(package,rec,&deformated,strlenW(rec),
|
|
|
|
record);
|
|
|
|
lenA = WideCharToMultiByte(CP_ACP,0,deformated,len,NULL,0,NULL,NULL);
|
2005-01-25 21:17:09 +01:00
|
|
|
|
2005-01-31 21:41:11 +01:00
|
|
|
if (buffer)
|
|
|
|
{
|
|
|
|
WideCharToMultiByte(CP_ACP,0,deformated,len,buffer,*size,NULL, NULL);
|
|
|
|
if (*size>lenA)
|
|
|
|
{
|
|
|
|
rc = ERROR_SUCCESS;
|
|
|
|
buffer[lenA] = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rc = ERROR_MORE_DATA;
|
|
|
|
buffer[(*size)-1] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
rc = ERROR_SUCCESS;
|
2005-01-25 21:17:09 +01:00
|
|
|
|
2005-01-31 21:41:11 +01:00
|
|
|
*size = lenA;
|
2005-01-25 21:17:09 +01:00
|
|
|
|
2005-01-31 21:41:11 +01:00
|
|
|
HeapFree(GetProcessHeap(),0,rec);
|
|
|
|
HeapFree(GetProcessHeap(),0,deformated);
|
2005-01-25 21:17:09 +01:00
|
|
|
return rc;
|
2005-01-31 21:41:11 +01:00
|
|
|
}
|
|
|
|
|
2005-01-25 21:17:09 +01:00
|
|
|
|
2005-01-31 21:41:11 +01:00
|
|
|
UINT WINAPI MsiFormatRecordW( MSIHANDLE hInstall, MSIHANDLE hRecord,
|
|
|
|
LPWSTR szResult, DWORD *sz )
|
|
|
|
{
|
|
|
|
UINT r = ERROR_INVALID_HANDLE;
|
|
|
|
MSIPACKAGE *package;
|
|
|
|
MSIRECORD *record;
|
|
|
|
|
|
|
|
TRACE("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
|
|
|
|
|
|
|
|
record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
|
|
|
|
|
|
|
|
if (!record)
|
|
|
|
return ERROR_INVALID_HANDLE;
|
|
|
|
if (!sz)
|
|
|
|
{
|
|
|
|
msiobj_release( &record->hdr );
|
|
|
|
if (szResult)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
else
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
|
|
|
|
|
|
|
|
if( record )
|
|
|
|
{
|
|
|
|
r = MSI_FormatRecordW( package, record, szResult, sz );
|
|
|
|
msiobj_release( &record->hdr );
|
|
|
|
}
|
|
|
|
if (package)
|
|
|
|
msiobj_release( &package->hdr );
|
|
|
|
return r;
|
2005-01-25 21:17:09 +01:00
|
|
|
}
|
|
|
|
|
2005-01-31 21:41:11 +01:00
|
|
|
UINT WINAPI MsiFormatRecordA( MSIHANDLE hInstall, MSIHANDLE hRecord,
|
|
|
|
LPSTR szResult, DWORD *sz )
|
2005-01-25 21:17:09 +01:00
|
|
|
{
|
2005-01-31 21:41:11 +01:00
|
|
|
UINT r = ERROR_INVALID_HANDLE;
|
|
|
|
MSIPACKAGE *package = NULL;
|
|
|
|
MSIRECORD *record = NULL;
|
2005-01-25 21:17:09 +01:00
|
|
|
|
|
|
|
TRACE("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
|
|
|
|
|
2005-01-31 21:41:11 +01:00
|
|
|
record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
|
2005-01-25 21:17:09 +01:00
|
|
|
|
2005-01-31 21:41:11 +01:00
|
|
|
if (!record)
|
2005-01-25 21:17:09 +01:00
|
|
|
return ERROR_INVALID_HANDLE;
|
2005-01-31 21:41:11 +01:00
|
|
|
if (!sz)
|
|
|
|
{
|
|
|
|
msiobj_release( &record->hdr );
|
|
|
|
if (szResult)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
else
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
}
|
2005-01-25 21:17:09 +01:00
|
|
|
|
2005-01-31 21:41:11 +01:00
|
|
|
package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
|
2005-01-25 21:17:09 +01:00
|
|
|
|
2005-01-31 21:41:11 +01:00
|
|
|
if( record )
|
|
|
|
{
|
|
|
|
r = MSI_FormatRecordA( package, record, szResult, sz );
|
|
|
|
msiobj_release( &record->hdr );
|
|
|
|
}
|
|
|
|
if (package)
|
|
|
|
msiobj_release( &package->hdr );
|
|
|
|
return r;
|
2005-01-25 21:17:09 +01:00
|
|
|
}
|