mirror of
https://github.com/reactos/reactos.git
synced 2025-04-27 00:50:23 +00:00
Update MSI to current Wine version.
Autosync will be put in place very soon for this dll. svn path=/trunk/; revision=23808
This commit is contained in:
parent
6d52441d10
commit
21aef1a7a7
48 changed files with 1564 additions and 726 deletions
|
@ -1,75 +0,0 @@
|
|||
TOPSRCDIR = @top_srcdir@
|
||||
TOPOBJDIR = ../..
|
||||
SRCDIR = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
MODULE = msi.dll
|
||||
IMPORTLIB = libmsi.$(IMPLIBEXT)
|
||||
IMPORTS = urlmon wininet comctl32 shell32 shlwapi cabinet oleaut32 ole32 version user32 gdi32 advapi32 kernel32
|
||||
EXTRALIBS = -luuid
|
||||
|
||||
C_SRCS = \
|
||||
action.c \
|
||||
appsearch.c \
|
||||
classes.c \
|
||||
create.c \
|
||||
custom.c \
|
||||
database.c \
|
||||
delete.c \
|
||||
dialog.c \
|
||||
distinct.c \
|
||||
events.c \
|
||||
files.c \
|
||||
format.c \
|
||||
handle.c \
|
||||
helpers.c \
|
||||
insert.c \
|
||||
install.c \
|
||||
join.c \
|
||||
msi.c \
|
||||
msi_main.c \
|
||||
msiquery.c \
|
||||
order.c \
|
||||
package.c \
|
||||
preview.c \
|
||||
record.c \
|
||||
registry.c \
|
||||
regsvr.c \
|
||||
select.c \
|
||||
source.c \
|
||||
string.c \
|
||||
suminfo.c \
|
||||
table.c \
|
||||
tokenize.c \
|
||||
update.c \
|
||||
upgrade.c \
|
||||
where.c
|
||||
|
||||
RC_SRCS = msi.rc
|
||||
RC_BINSRC = msi.rc
|
||||
RC_BINARIES = \
|
||||
instabsent.bmp \
|
||||
instadvert.bmp \
|
||||
instlocal.bmp
|
||||
|
||||
EXTRA_SRCS = sql.y cond.y
|
||||
EXTRA_OBJS = sql.tab.o cond.tab.o
|
||||
|
||||
SUBDIRS = tests
|
||||
|
||||
@MAKE_DLL_RULES@
|
||||
|
||||
sql.tab.c sql.tab.h: sql.y
|
||||
$(BISON) -p SQL_ -d $(SRCDIR)/sql.y -o sql.tab.c
|
||||
|
||||
cond.tab.c cond.tab.h: cond.y
|
||||
$(BISON) -p COND_ -d $(SRCDIR)/cond.y -o cond.tab.c
|
||||
|
||||
# hack to allow parallel make
|
||||
sql.tab.h: sql.tab.c
|
||||
sql.tab.o: sql.tab.h
|
||||
cond.tab.h: cond.tab.c
|
||||
cond.tab.o: cond.tab.h
|
||||
|
||||
tokenize.o: sql.tab.h
|
||||
|
||||
### Dependencies:
|
|
@ -1123,7 +1123,6 @@ static UINT load_component( MSIRECORD *row, LPVOID param )
|
|||
switch (comp->Attributes)
|
||||
{
|
||||
case msidbComponentAttributesLocalOnly:
|
||||
case msidbComponentAttributesOptional:
|
||||
comp->Action = INSTALLSTATE_LOCAL;
|
||||
comp->ActionRequest = INSTALLSTATE_LOCAL;
|
||||
break;
|
||||
|
@ -1131,9 +1130,13 @@ static UINT load_component( MSIRECORD *row, LPVOID param )
|
|||
comp->Action = INSTALLSTATE_SOURCE;
|
||||
comp->ActionRequest = INSTALLSTATE_SOURCE;
|
||||
break;
|
||||
case msidbComponentAttributesOptional:
|
||||
comp->Action = INSTALLSTATE_DEFAULT;
|
||||
comp->ActionRequest = INSTALLSTATE_DEFAULT;
|
||||
break;
|
||||
default:
|
||||
comp->Action = INSTALLSTATE_UNKNOWN;
|
||||
comp->ActionRequest = INSTALLSTATE_UNKNOWN;
|
||||
comp->Action = INSTALLSTATE_LOCAL;
|
||||
comp->ActionRequest = INSTALLSTATE_LOCAL;
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
|
@ -1324,6 +1327,29 @@ static UINT load_file(MSIRECORD *row, LPVOID param)
|
|||
|
||||
file->state = msifs_invalid;
|
||||
|
||||
/* if the compressed bits are not set in the file attributes,
|
||||
* then read the information from the package word count property
|
||||
*/
|
||||
if (file->Attributes & msidbFileAttributesCompressed)
|
||||
{
|
||||
file->IsCompressed = TRUE;
|
||||
}
|
||||
else if (file->Attributes & msidbFileAttributesNoncompressed)
|
||||
{
|
||||
file->IsCompressed = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
file->IsCompressed = package->WordCount & MSIWORDCOUNT_COMPRESSED;
|
||||
}
|
||||
|
||||
if (file->IsCompressed)
|
||||
{
|
||||
file->Component->ForceLocalState = TRUE;
|
||||
file->Component->Action = INSTALLSTATE_LOCAL;
|
||||
file->Component->ActionRequest = INSTALLSTATE_LOCAL;
|
||||
}
|
||||
|
||||
TRACE("File Loaded (%s)\n",debugstr_w(file->File));
|
||||
|
||||
list_add_tail( &package->files, &file->entry );
|
||||
|
@ -1708,16 +1734,20 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (feature->Action == INSTALLSTATE_LOCAL)
|
||||
if (feature->Attributes == msidbFeatureAttributesFavorLocal)
|
||||
{
|
||||
component->Action = INSTALLSTATE_LOCAL;
|
||||
component->ActionRequest = INSTALLSTATE_LOCAL;
|
||||
if (!(component->Attributes & msidbComponentAttributesSourceOnly))
|
||||
{
|
||||
component->Action = INSTALLSTATE_LOCAL;
|
||||
component->ActionRequest = INSTALLSTATE_LOCAL;
|
||||
}
|
||||
}
|
||||
else if (feature->ActionRequest == INSTALLSTATE_SOURCE)
|
||||
else if (feature->Attributes == msidbFeatureAttributesFavorSource)
|
||||
{
|
||||
if ((component->Action == INSTALLSTATE_UNKNOWN) ||
|
||||
(component->Action == INSTALLSTATE_ABSENT) ||
|
||||
(component->Action == INSTALLSTATE_ADVERTISED))
|
||||
(component->Action == INSTALLSTATE_ADVERTISED) ||
|
||||
(component->Action == INSTALLSTATE_DEFAULT))
|
||||
|
||||
{
|
||||
component->Action = INSTALLSTATE_SOURCE;
|
||||
|
@ -1743,6 +1773,12 @@ UINT MSI_SetFeatureStates(MSIPACKAGE *package)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (component->ForceLocalState)
|
||||
{
|
||||
feature->Action = INSTALLSTATE_LOCAL;
|
||||
feature->ActionRequest = INSTALLSTATE_LOCAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2915,6 +2951,10 @@ static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
|
|||
Path = build_icon_path(package,buffer);
|
||||
index = MSI_RecordGetInteger(row,10);
|
||||
|
||||
/* no value means 0 */
|
||||
if (index == MSI_NULL_INTEGER)
|
||||
index = 0;
|
||||
|
||||
IShellLinkW_SetIconLocation(sl,Path,index);
|
||||
msi_free(Path);
|
||||
}
|
||||
|
@ -2927,7 +2967,8 @@ static UINT ITERATE_CreateShortcuts(MSIRECORD *row, LPVOID param)
|
|||
LPWSTR Path;
|
||||
buffer = MSI_RecordGetString(row,12);
|
||||
Path = resolve_folder(package, buffer, FALSE, FALSE, NULL);
|
||||
IShellLinkW_SetWorkingDirectory(sl,Path);
|
||||
if (Path)
|
||||
IShellLinkW_SetWorkingDirectory(sl,Path);
|
||||
msi_free(Path);
|
||||
}
|
||||
|
||||
|
@ -3106,6 +3147,10 @@ static UINT ACTION_PublishProduct(MSIPACKAGE *package)
|
|||
/* FIXME: Need to write more keys to the user registry */
|
||||
|
||||
hDb= alloc_msihandle( &package->db->hdr );
|
||||
if (!hDb) {
|
||||
rc = ERROR_NOT_ENOUGH_MEMORY;
|
||||
goto end;
|
||||
}
|
||||
rc = MsiGetSummaryInformationW(hDb, NULL, 0, &hSumInfo);
|
||||
MsiCloseHandle(hDb);
|
||||
if (rc == ERROR_SUCCESS)
|
||||
|
|
|
@ -59,6 +59,7 @@ typedef struct tagMSICOMPONENT
|
|||
INSTALLSTATE ActionRequest;
|
||||
INSTALLSTATE Action;
|
||||
|
||||
BOOL ForceLocalState;
|
||||
BOOL Enabled;
|
||||
INT Cost;
|
||||
INT RefCount;
|
||||
|
@ -119,6 +120,7 @@ typedef struct tagMSIFILE
|
|||
msi_file_state state;
|
||||
LPWSTR SourcePath;
|
||||
LPWSTR TargetPath;
|
||||
BOOL IsCompressed;
|
||||
} MSIFILE;
|
||||
|
||||
typedef struct tagMSITEMPFILE
|
||||
|
|
177
reactos/dll/win32/msi/alter.c
Normal file
177
reactos/dll/win32/msi/alter.c
Normal file
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* Implementation of the Microsoft Installer (msi.dll)
|
||||
*
|
||||
* Copyright 2006 Mike McCormack
|
||||
*
|
||||
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
#include "wine/debug.h"
|
||||
#include "msi.h"
|
||||
#include "msiquery.h"
|
||||
#include "objbase.h"
|
||||
#include "objidl.h"
|
||||
#include "msipriv.h"
|
||||
|
||||
#include "query.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msidb);
|
||||
|
||||
typedef struct tagMSIALTERVIEW
|
||||
{
|
||||
MSIVIEW view;
|
||||
MSIDATABASE *db;
|
||||
} MSIALTERVIEW;
|
||||
|
||||
static UINT ALTER_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
|
||||
{
|
||||
MSIALTERVIEW *av = (MSIALTERVIEW*)view;
|
||||
|
||||
TRACE("%p %d %d %p\n", av, row, col, val );
|
||||
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
static UINT ALTER_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm)
|
||||
{
|
||||
MSIALTERVIEW *av = (MSIALTERVIEW*)view;
|
||||
|
||||
TRACE("%p %d %d %p\n", av, row, col, stm );
|
||||
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
static UINT ALTER_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val )
|
||||
{
|
||||
MSIALTERVIEW *av = (MSIALTERVIEW*)view;
|
||||
|
||||
TRACE("%p %d %d %04x\n", av, row, col, val );
|
||||
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
static UINT ALTER_insert_row( struct tagMSIVIEW *view, MSIRECORD *record )
|
||||
{
|
||||
MSIALTERVIEW *av = (MSIALTERVIEW*)view;
|
||||
|
||||
TRACE("%p %p\n", av, record );
|
||||
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
static UINT ALTER_execute( struct tagMSIVIEW *view, MSIRECORD *record )
|
||||
{
|
||||
MSIALTERVIEW *av = (MSIALTERVIEW*)view;
|
||||
|
||||
FIXME("%p %p\n", av, record);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT ALTER_close( struct tagMSIVIEW *view )
|
||||
{
|
||||
MSIALTERVIEW *av = (MSIALTERVIEW*)view;
|
||||
|
||||
TRACE("%p\n", av );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT ALTER_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
|
||||
{
|
||||
MSIALTERVIEW *av = (MSIALTERVIEW*)view;
|
||||
|
||||
TRACE("%p %p %p\n", av, rows, cols );
|
||||
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
static UINT ALTER_get_column_info( struct tagMSIVIEW *view,
|
||||
UINT n, LPWSTR *name, UINT *type )
|
||||
{
|
||||
MSIALTERVIEW *av = (MSIALTERVIEW*)view;
|
||||
|
||||
TRACE("%p %d %p %p\n", av, n, name, type );
|
||||
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
static UINT ALTER_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode,
|
||||
MSIRECORD *rec )
|
||||
{
|
||||
MSIALTERVIEW *av = (MSIALTERVIEW*)view;
|
||||
|
||||
TRACE("%p %d %p\n", av, eModifyMode, rec );
|
||||
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
static UINT ALTER_delete( struct tagMSIVIEW *view )
|
||||
{
|
||||
MSIALTERVIEW *av = (MSIALTERVIEW*)view;
|
||||
|
||||
TRACE("%p\n", av );
|
||||
msi_free( av );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT ALTER_find_matching_rows( struct tagMSIVIEW *view, UINT col,
|
||||
UINT val, UINT *row, MSIITERHANDLE *handle )
|
||||
{
|
||||
TRACE("%p, %d, %u, %p\n", view, col, val, *handle);
|
||||
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
|
||||
static const MSIVIEWOPS alter_ops =
|
||||
{
|
||||
ALTER_fetch_int,
|
||||
ALTER_fetch_stream,
|
||||
ALTER_set_int,
|
||||
ALTER_insert_row,
|
||||
ALTER_execute,
|
||||
ALTER_close,
|
||||
ALTER_get_dimensions,
|
||||
ALTER_get_column_info,
|
||||
ALTER_modify,
|
||||
ALTER_delete,
|
||||
ALTER_find_matching_rows
|
||||
};
|
||||
|
||||
UINT ALTER_CreateView( MSIDATABASE *db, MSIVIEW **view, LPCWSTR name, int hold )
|
||||
{
|
||||
MSIALTERVIEW *av = NULL;
|
||||
|
||||
TRACE("%p\n", av );
|
||||
|
||||
av = msi_alloc_zero( sizeof *av );
|
||||
if( !av )
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
/* fill the structure */
|
||||
av->view.ops = &alter_ops;
|
||||
av->db = db;
|
||||
|
||||
*view = &av->view;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
|
@ -798,7 +798,6 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
|
|||
static const WCHAR szVIProgID[] = { 'V','e','r','s','i','o','n','I','n','d','e','p','e','n','d','e','n','t','P','r','o','g','I','D',0 };
|
||||
static const WCHAR szAppID[] = { 'A','p','p','I','D',0 };
|
||||
static const WCHAR szSpace[] = {' ',0};
|
||||
static const WCHAR szInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
|
||||
static const WCHAR szFileType_fmt[] = {'F','i','l','e','T','y','p','e','\\','%','s','\\','%','i',0};
|
||||
HKEY hkey,hkey2,hkey3;
|
||||
MSICLASS *cls;
|
||||
|
@ -808,16 +807,11 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
|
|||
if (rc != ERROR_SUCCESS)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
/* install_on_demand should be set if OLE supports install on demand OLE
|
||||
* servers. For now i am defaulting to FALSE because i do not know how to
|
||||
* check, and i am told our builtin OLE does not support it
|
||||
*/
|
||||
|
||||
LIST_FOR_EACH_ENTRY( cls, &package->classes, MSICLASS, entry )
|
||||
{
|
||||
MSICOMPONENT *comp;
|
||||
MSIFILE *file;
|
||||
DWORD size, sz;
|
||||
DWORD size;
|
||||
LPWSTR argument;
|
||||
MSIFEATURE *feature;
|
||||
|
||||
|
@ -827,17 +821,14 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
|
|||
|
||||
feature = cls->Feature;
|
||||
|
||||
/*
|
||||
* yes. MSDN says that these are based on _Feature_ not on
|
||||
* Component. So verify the feature is to be installed
|
||||
/*
|
||||
* MSDN says that these are based on Feature not on Component.
|
||||
*/
|
||||
if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ))
|
||||
/* && !(install_on_demand &&
|
||||
ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))) */
|
||||
if (!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_LOCAL ) &&
|
||||
!ACTION_VerifyFeatureForAction( feature, INSTALLSTATE_ADVERTISED ))
|
||||
{
|
||||
TRACE("Skipping class %s reg due to disabled feature %s\n",
|
||||
debugstr_w(cls->clsid),
|
||||
debugstr_w(feature->Feature));
|
||||
TRACE("Skipping class %s reg due to disabled feature %s\n",
|
||||
debugstr_w(cls->clsid), debugstr_w(feature->Feature));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
@ -855,63 +846,28 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
|
|||
RegCreateKeyW( hkey2, cls->Context, &hkey3 );
|
||||
file = get_loaded_file( package, comp->KeyPath );
|
||||
|
||||
|
||||
/* the context server is a short path name
|
||||
* except for if it is InprocServer32...
|
||||
/*
|
||||
* FIXME: Implement install on demand (advertised components).
|
||||
*
|
||||
* ole32.dll should call msi.MsiProvideComponentFromDescriptor()
|
||||
* when it needs an InProcServer that doesn't exist.
|
||||
* The component advertise string should be in the "InProcServer" value.
|
||||
*/
|
||||
if (strcmpiW( cls->Context, szInprocServer32 )!=0)
|
||||
size = lstrlenW( file->TargetPath )+1;
|
||||
if (cls->Argument)
|
||||
size += lstrlenW(cls->Argument)+1;
|
||||
|
||||
argument = msi_alloc( size * sizeof(WCHAR) );
|
||||
lstrcpyW( argument, file->TargetPath );
|
||||
|
||||
if (cls->Argument)
|
||||
{
|
||||
sz = GetShortPathNameW( file->TargetPath, NULL, 0 );
|
||||
if (sz == 0)
|
||||
{
|
||||
ERR("Unable to find short path for CLSID COM Server\n");
|
||||
argument = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
size = sz * sizeof(WCHAR);
|
||||
|
||||
if (cls->Argument)
|
||||
{
|
||||
size += strlenW(cls->Argument) * sizeof(WCHAR);
|
||||
size += sizeof(WCHAR);
|
||||
}
|
||||
|
||||
argument = msi_alloc( size + sizeof(WCHAR));
|
||||
GetShortPathNameW( file->TargetPath, argument, sz );
|
||||
|
||||
if (cls->Argument)
|
||||
{
|
||||
strcatW(argument,szSpace);
|
||||
strcatW( argument, cls->Argument );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size = lstrlenW( file->TargetPath ) * sizeof(WCHAR);
|
||||
|
||||
if (cls->Argument)
|
||||
{
|
||||
size += strlenW(cls->Argument) * sizeof(WCHAR);
|
||||
size += sizeof(WCHAR);
|
||||
}
|
||||
|
||||
argument = msi_alloc( size + sizeof(WCHAR));
|
||||
strcpyW( argument, file->TargetPath );
|
||||
|
||||
if (cls->Argument)
|
||||
{
|
||||
strcatW(argument,szSpace);
|
||||
strcatW( argument, cls->Argument );
|
||||
}
|
||||
lstrcatW( argument, szSpace );
|
||||
lstrcatW( argument, cls->Argument );
|
||||
}
|
||||
|
||||
if (argument)
|
||||
{
|
||||
msi_reg_set_val_str( hkey3, NULL, argument );
|
||||
msi_free(argument);
|
||||
}
|
||||
msi_reg_set_val_str( hkey3, NULL, argument );
|
||||
msi_free(argument);
|
||||
|
||||
RegCloseKey(hkey3);
|
||||
|
||||
|
@ -934,7 +890,7 @@ UINT ACTION_RegisterClassInfo(MSIPACKAGE *package)
|
|||
}
|
||||
|
||||
if (cls->AppID)
|
||||
{
|
||||
{
|
||||
MSIAPPID *appid = cls->AppID;
|
||||
|
||||
msi_reg_set_val_str( hkey2, szAppID, appid->AppID );
|
||||
|
|
|
@ -396,8 +396,61 @@ static WCHAR *strstriW( const WCHAR *str, const WCHAR *sub )
|
|||
return r;
|
||||
}
|
||||
|
||||
static BOOL str_is_number( LPCWSTR str )
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < lstrlenW( str ); i++)
|
||||
if (!isdigitW(str[i]))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static INT compare_substring( LPCWSTR a, INT operator, LPCWSTR b )
|
||||
{
|
||||
int lhs, rhs;
|
||||
|
||||
/* substring operators return 0 if LHS is missing */
|
||||
if (!a || !*a)
|
||||
return 0;
|
||||
|
||||
/* substring operators return 1 if RHS is missing */
|
||||
if (!b || !*b)
|
||||
return 1;
|
||||
|
||||
/* if both strings contain only numbers, use integer comparison */
|
||||
lhs = atoiW(a);
|
||||
rhs = atoiW(b);
|
||||
if (str_is_number(a) && str_is_number(b))
|
||||
return compare_int( lhs, operator, rhs );
|
||||
|
||||
switch (operator)
|
||||
{
|
||||
case COND_SS:
|
||||
return strstrW( a, b ) ? 1 : 0;
|
||||
case COND_ISS:
|
||||
return strstriW( a, b ) ? 1 : 0;
|
||||
case COND_LHS:
|
||||
return 0 == strncmpW( a, b, lstrlenW( b ) );
|
||||
case COND_RHS:
|
||||
return 0 == lstrcmpW( a + (lstrlenW( a ) - lstrlenW( b )), b );
|
||||
case COND_ILHS:
|
||||
return 0 == strncmpiW( a, b, lstrlenW( b ) );
|
||||
case COND_IRHS:
|
||||
return 0 == lstrcmpiW( a + (lstrlenW( a ) - lstrlenW( b )), b );
|
||||
default:
|
||||
ERR("invalid substring operator\n");
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b )
|
||||
{
|
||||
if (operator >= COND_SS && operator <= COND_RHS)
|
||||
return compare_substring( a, operator, b );
|
||||
|
||||
/* null and empty string are equivalent */
|
||||
if (!a) a = szEmpty;
|
||||
if (!b) b = szEmpty;
|
||||
|
@ -417,8 +470,6 @@ static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b )
|
|||
return -1 != lstrcmpW( a, b );
|
||||
case COND_LE:
|
||||
return 1 != lstrcmpW( a, b );
|
||||
case COND_SS: /* substring */
|
||||
return strstrW( a, b ) ? 1 : 0;
|
||||
case COND_ILT:
|
||||
return -1 == lstrcmpiW( a, b );
|
||||
case COND_IGT:
|
||||
|
@ -431,16 +482,8 @@ static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b )
|
|||
return -1 != lstrcmpiW( a, b );
|
||||
case COND_ILE:
|
||||
return 1 != lstrcmpiW( a, b );
|
||||
case COND_ISS:
|
||||
return strstriW( a, b ) ? 1 : 0;
|
||||
case COND_LHS:
|
||||
case COND_RHS:
|
||||
case COND_ILHS:
|
||||
case COND_IRHS:
|
||||
ERR("unimplemented string comparison\n");
|
||||
break;
|
||||
default:
|
||||
ERR("invalid integer operator\n");
|
||||
ERR("invalid string operator\n");
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
|
@ -508,10 +551,10 @@ static int COND_GetOperator( COND_input *cond )
|
|||
{ {'>','=',0}, COND_GE },
|
||||
{ {'>','<',0}, COND_SS },
|
||||
{ {'<','<',0}, COND_LHS },
|
||||
{ {'>',0}, COND_GT },
|
||||
{ {'<','>',0}, COND_NE },
|
||||
{ {'<','=',0}, COND_LE },
|
||||
{ {'>','>',0}, COND_RHS },
|
||||
{ {'>',0}, COND_GT },
|
||||
{ {'<',0}, COND_LT },
|
||||
{ {0}, 0 }
|
||||
};
|
||||
|
|
|
@ -93,8 +93,10 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
|
|||
r = StgOpenStorage( szDBPath, NULL,
|
||||
STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
|
||||
}
|
||||
else if( szPersist == MSIDBOPEN_CREATE )
|
||||
else if( szPersist == MSIDBOPEN_CREATE || szPersist == MSIDBOPEN_CREATEDIRECT )
|
||||
{
|
||||
/* FIXME: MSIDBOPEN_CREATE should case STGM_TRANSACTED flag to be
|
||||
* used here: */
|
||||
r = StgCreateDocfile( szDBPath,
|
||||
STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, 0, &stg);
|
||||
if( r == ERROR_SUCCESS )
|
||||
|
@ -104,6 +106,13 @@ UINT MSI_OpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIDATABASE **pdb)
|
|||
}
|
||||
}
|
||||
else if( szPersist == MSIDBOPEN_TRANSACT )
|
||||
{
|
||||
/* FIXME: MSIDBOPEN_TRANSACT should case STGM_TRANSACTED flag to be
|
||||
* used here: */
|
||||
r = StgOpenStorage( szDBPath, NULL,
|
||||
STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
|
||||
}
|
||||
else if( szPersist == MSIDBOPEN_DIRECT )
|
||||
{
|
||||
r = StgOpenStorage( szDBPath, NULL,
|
||||
STGM_DIRECT|STGM_READWRITE|STGM_SHARE_EXCLUSIVE, NULL, 0, &stg);
|
||||
|
@ -181,6 +190,8 @@ UINT WINAPI MsiOpenDatabaseW(LPCWSTR szDBPath, LPCWSTR szPersist, MSIHANDLE *phD
|
|||
if( ret == ERROR_SUCCESS )
|
||||
{
|
||||
*phDB = alloc_msihandle( &db->hdr );
|
||||
if (! *phDB)
|
||||
ret = ERROR_NOT_ENOUGH_MEMORY;
|
||||
msiobj_release( &db->hdr );
|
||||
}
|
||||
|
||||
|
|
|
@ -26,9 +26,9 @@
|
|||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "wingdi.h"
|
||||
#include "winuser.h"
|
||||
#include "winnls.h"
|
||||
#include "wingdi.h"
|
||||
#include "msi.h"
|
||||
#include "msipriv.h"
|
||||
#include "msidefs.h"
|
||||
|
@ -36,6 +36,8 @@
|
|||
#include "olectl.h"
|
||||
#include "richedit.h"
|
||||
#include "commctrl.h"
|
||||
#include "winreg.h"
|
||||
#include "shlwapi.h"
|
||||
|
||||
#include "wine/debug.h"
|
||||
#include "wine/unicode.h"
|
||||
|
@ -64,6 +66,7 @@ struct msi_control_tag
|
|||
HMODULE hDll;
|
||||
float progress_current;
|
||||
float progress_max;
|
||||
DWORD attributes;
|
||||
WCHAR name[1];
|
||||
};
|
||||
|
||||
|
@ -136,6 +139,9 @@ static const WCHAR szSelectionTree[] = {
|
|||
'S','e','l','e','c','t','i','o','n','T','r','e','e',0 };
|
||||
static const WCHAR szGroupBox[] = { 'G','r','o','u','p','B','o','x',0 };
|
||||
static const WCHAR szListBox[] = { 'L','i','s','t','B','o','x',0 };
|
||||
static const WCHAR szDirectoryCombo[] = { 'D','i','r','e','c','t','o','r','y','C','o','m','b','o',0 };
|
||||
static const WCHAR szDirectoryList[] = { 'D','i','r','e','c','t','o','r','y','L','i','s','t',0 };
|
||||
static const WCHAR szVolumeCostList[] = { 'V','o','l','u','m','e','C','o','s','t','L','i','s','t',0 };
|
||||
|
||||
static UINT msi_dialog_checkbox_handler( msi_dialog *, msi_control *, WPARAM );
|
||||
static void msi_dialog_checkbox_sync_state( msi_dialog *, msi_control * );
|
||||
|
@ -191,6 +197,17 @@ static LPWSTR msi_get_deformatted_field( MSIPACKAGE *package, MSIRECORD *rec, in
|
|||
return ret;
|
||||
}
|
||||
|
||||
static LPWSTR msi_dialog_dup_property( msi_dialog *dialog, LPCWSTR property, BOOL indirect )
|
||||
{
|
||||
if (!property)
|
||||
return NULL;
|
||||
|
||||
if (indirect)
|
||||
return msi_dup_property( dialog->package, property );
|
||||
|
||||
return strdupW( property );
|
||||
}
|
||||
|
||||
/*
|
||||
* msi_dialog_get_style
|
||||
*
|
||||
|
@ -750,6 +767,9 @@ static UINT msi_dialog_line_control( msi_dialog *dialog, MSIRECORD *rec )
|
|||
{
|
||||
TRACE("%p %p\n", dialog, rec);
|
||||
|
||||
/* line is exactly 2 units in height */
|
||||
MSI_RecordSetInteger( rec, 7, 2 );
|
||||
|
||||
msi_dialog_add_control( dialog, rec, szStatic, SS_ETCHEDHORZ | SS_SUNKEN );
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
@ -1354,10 +1374,83 @@ static UINT msi_dialog_progress_bar( msi_dialog *dialog, MSIRECORD *rec )
|
|||
|
||||
/******************** Path Edit ********************************************/
|
||||
|
||||
static LPWSTR msi_get_window_text( HWND hwnd )
|
||||
{
|
||||
UINT sz, r;
|
||||
LPWSTR buf;
|
||||
|
||||
sz = 0x20;
|
||||
buf = msi_alloc( sz*sizeof(WCHAR) );
|
||||
while ( buf )
|
||||
{
|
||||
r = GetWindowTextW( hwnd, buf, sz );
|
||||
if ( r < (sz - 1) )
|
||||
break;
|
||||
sz *= 2;
|
||||
buf = msi_realloc( buf, sz*sizeof(WCHAR) );
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static UINT msi_dialog_pathedit_handler( msi_dialog *dialog,
|
||||
msi_control *control, WPARAM param )
|
||||
{
|
||||
LPWSTR buf, prop;
|
||||
BOOL indirect;
|
||||
|
||||
if( HIWORD(param) != EN_KILLFOCUS )
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
indirect = control->attributes & msidbControlAttributesIndirect;
|
||||
prop = msi_dialog_dup_property( dialog, control->property, indirect );
|
||||
|
||||
/* FIXME: verify the new path */
|
||||
buf = msi_get_window_text( control->hwnd );
|
||||
MSI_SetPropertyW( dialog->package, prop, buf );
|
||||
|
||||
TRACE("edit %s contents changed, set %s\n", debugstr_w(control->name),
|
||||
debugstr_w(prop));
|
||||
|
||||
msi_free( buf );
|
||||
msi_free( prop );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static void msi_dialog_update_pathedit( msi_dialog *dialog )
|
||||
{
|
||||
msi_control *control;
|
||||
LPWSTR prop, path;
|
||||
BOOL indirect;
|
||||
|
||||
control = msi_dialog_find_control( dialog, szPathEdit );
|
||||
indirect = control->attributes & msidbControlAttributesIndirect;
|
||||
prop = msi_dialog_dup_property( dialog, control->property, indirect );
|
||||
|
||||
path = msi_dup_property( dialog->package, prop );
|
||||
SetWindowTextW( control->hwnd, path );
|
||||
SendMessageW( control->hwnd, EM_SETSEL, 0, -1 );
|
||||
|
||||
msi_free( path );
|
||||
msi_free( prop );
|
||||
}
|
||||
|
||||
static UINT msi_dialog_pathedit_control( msi_dialog *dialog, MSIRECORD *rec )
|
||||
{
|
||||
FIXME("not implemented properly\n");
|
||||
return msi_dialog_edit_control( dialog, rec );
|
||||
msi_control *control;
|
||||
LPCWSTR prop;
|
||||
|
||||
control = msi_dialog_add_control( dialog, rec, szEdit,
|
||||
WS_BORDER | WS_TABSTOP );
|
||||
control->handler = msi_dialog_pathedit_handler;
|
||||
control->attributes = MSI_RecordGetInteger( rec, 8 );
|
||||
prop = MSI_RecordGetString( rec, 9 );
|
||||
control->property = msi_dialog_dup_property( dialog, prop, FALSE );
|
||||
|
||||
msi_dialog_update_pathedit( dialog );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/* radio buttons are a bit different from normal controls */
|
||||
|
@ -1866,6 +1959,118 @@ static UINT msi_dialog_list_box( msi_dialog *dialog, MSIRECORD *rec )
|
|||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/******************** Directory Combo ***************************************/
|
||||
|
||||
static void msi_dialog_update_directory_combo( msi_dialog *dialog )
|
||||
{
|
||||
msi_control *control;
|
||||
LPWSTR prop, path;
|
||||
BOOL indirect;
|
||||
|
||||
control = msi_dialog_find_control( dialog, szDirectoryCombo );
|
||||
indirect = control->attributes & msidbControlAttributesIndirect;
|
||||
prop = msi_dialog_dup_property( dialog, control->property, indirect );
|
||||
path = msi_dup_property( dialog->package, prop );
|
||||
|
||||
PathStripPathW( path );
|
||||
PathRemoveBackslashW( path );
|
||||
|
||||
SendMessageW( control->hwnd, CB_INSERTSTRING, 0, (LPARAM)path );
|
||||
SendMessageW( control->hwnd, CB_SETCURSEL, 0, 0 );
|
||||
|
||||
msi_free( path );
|
||||
msi_free( prop );
|
||||
}
|
||||
|
||||
static UINT msi_dialog_directory_combo( msi_dialog *dialog, MSIRECORD *rec )
|
||||
{
|
||||
msi_control *control;
|
||||
LPCWSTR prop;
|
||||
DWORD style;
|
||||
|
||||
/* FIXME: use CBS_OWNERDRAWFIXED and add owner draw code */
|
||||
style = CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_CHILD |
|
||||
WS_GROUP | WS_TABSTOP | WS_VSCROLL;
|
||||
control = msi_dialog_add_control( dialog, rec, WC_COMBOBOXW, style );
|
||||
if (!control)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
control->attributes = MSI_RecordGetInteger( rec, 8 );
|
||||
prop = MSI_RecordGetString( rec, 9 );
|
||||
control->property = msi_dialog_dup_property( dialog, prop, FALSE );
|
||||
|
||||
msi_dialog_update_directory_combo( dialog );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/******************** Directory List ***************************************/
|
||||
|
||||
UINT msi_dialog_directorylist_up( msi_dialog *dialog )
|
||||
{
|
||||
msi_control *control;
|
||||
LPWSTR prop, path, ptr;
|
||||
BOOL indirect;
|
||||
|
||||
control = msi_dialog_find_control( dialog, szDirectoryList );
|
||||
indirect = control->attributes & msidbControlAttributesIndirect;
|
||||
prop = msi_dialog_dup_property( dialog, control->property, indirect );
|
||||
|
||||
path = msi_dup_property( dialog->package, prop );
|
||||
|
||||
/* strip off the last directory */
|
||||
ptr = PathFindFileNameW( path );
|
||||
if (ptr != path) *(ptr - 1) = '\0';
|
||||
PathAddBackslashW( path );
|
||||
|
||||
MSI_SetPropertyW( dialog->package, prop, path );
|
||||
|
||||
msi_dialog_update_directory_combo( dialog );
|
||||
msi_dialog_update_pathedit( dialog );
|
||||
|
||||
msi_free( path );
|
||||
msi_free( prop );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static UINT msi_dialog_directory_list( msi_dialog *dialog, MSIRECORD *rec )
|
||||
{
|
||||
msi_control *control;
|
||||
LPCWSTR prop;
|
||||
DWORD style;
|
||||
|
||||
style = LVS_LIST | LVS_EDITLABELS | WS_VSCROLL | LVS_SHAREIMAGELISTS |
|
||||
LVS_AUTOARRANGE | LVS_SINGLESEL | WS_BORDER |
|
||||
LVS_SORTASCENDING | WS_CHILD | WS_GROUP | WS_TABSTOP;
|
||||
control = msi_dialog_add_control( dialog, rec, WC_LISTVIEWW, style );
|
||||
if (!control)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
control->attributes = MSI_RecordGetInteger( rec, 8 );
|
||||
prop = MSI_RecordGetString( rec, 9 );
|
||||
control->property = msi_dialog_dup_property( dialog, prop, FALSE );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/******************** VolumeCost List ***************************************/
|
||||
|
||||
static UINT msi_dialog_volumecost_list( msi_dialog *dialog, MSIRECORD *rec )
|
||||
{
|
||||
msi_control *control;
|
||||
DWORD style;
|
||||
|
||||
style = LVS_REPORT | WS_VSCROLL | WS_HSCROLL | LVS_SHAREIMAGELISTS |
|
||||
LVS_AUTOARRANGE | LVS_SINGLESEL | WS_BORDER |
|
||||
WS_CHILD | WS_TABSTOP | WS_GROUP;
|
||||
control = msi_dialog_add_control( dialog, rec, WC_LISTVIEWW, style );
|
||||
if (!control)
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static const struct control_handler msi_dialog_handler[] =
|
||||
{
|
||||
{ szText, msi_dialog_text_control },
|
||||
|
@ -1884,6 +2089,9 @@ static const struct control_handler msi_dialog_handler[] =
|
|||
{ szSelectionTree, msi_dialog_selection_tree },
|
||||
{ szGroupBox, msi_dialog_group_box },
|
||||
{ szListBox, msi_dialog_list_box },
|
||||
{ szDirectoryCombo, msi_dialog_directory_combo },
|
||||
{ szDirectoryList, msi_dialog_directory_list },
|
||||
{ szVolumeCostList, msi_dialog_volumecost_list },
|
||||
};
|
||||
|
||||
#define NUM_CONTROL_TYPES (sizeof msi_dialog_handler/sizeof msi_dialog_handler[0])
|
||||
|
@ -2058,20 +2266,41 @@ static MSIRECORD *msi_get_dialog_record( msi_dialog *dialog )
|
|||
return rec;
|
||||
}
|
||||
|
||||
static void msi_dialog_adjust_dialog_size( msi_dialog *dialog, LPSIZE sz )
|
||||
static void msi_dialog_adjust_dialog_pos( msi_dialog *dialog, MSIRECORD *rec, LPRECT pos )
|
||||
{
|
||||
RECT rect;
|
||||
static const WCHAR szScreenX[] = {'S','c','r','e','e','n','X',0};
|
||||
static const WCHAR szScreenY[] = {'S','c','r','e','e','n','Y',0};
|
||||
|
||||
UINT xres, yres;
|
||||
POINT center;
|
||||
SIZE sz;
|
||||
LONG style;
|
||||
|
||||
/* turn the client size into the window rectangle */
|
||||
rect.left = 0;
|
||||
rect.top = 0;
|
||||
rect.right = msi_dialog_scale_unit( dialog, sz->cx );
|
||||
rect.bottom = msi_dialog_scale_unit( dialog, sz->cy );
|
||||
center.x = MSI_RecordGetInteger( rec, 2 );
|
||||
center.y = MSI_RecordGetInteger( rec, 3 );
|
||||
|
||||
sz.cx = MSI_RecordGetInteger( rec, 4 );
|
||||
sz.cy = MSI_RecordGetInteger( rec, 5 );
|
||||
|
||||
sz.cx = msi_dialog_scale_unit( dialog, sz.cx );
|
||||
sz.cy = msi_dialog_scale_unit( dialog, sz.cy );
|
||||
|
||||
xres = msi_get_property_int( dialog->package, szScreenX, 0 );
|
||||
yres = msi_get_property_int( dialog->package, szScreenY, 0 );
|
||||
|
||||
center.x = MulDiv( center.x, xres, 100 );
|
||||
center.y = MulDiv( center.y, yres, 100 );
|
||||
|
||||
/* turn the client pos into the window rectangle */
|
||||
pos->left = center.x - sz.cx/2;
|
||||
pos->right = pos->left + sz.cx;
|
||||
pos->top = center.y - sz.cy/2;
|
||||
pos->bottom = pos->top + sz.cy;
|
||||
|
||||
TRACE("%lu %lu %lu %lu\n", pos->left, pos->top, pos->right, pos->bottom);
|
||||
|
||||
style = GetWindowLongPtrW( dialog->hwnd, GWL_STYLE );
|
||||
AdjustWindowRect( &rect, style, FALSE );
|
||||
sz->cx = rect.right - rect.left;
|
||||
sz->cy = rect.bottom - rect.top;
|
||||
AdjustWindowRect( pos, style, FALSE );
|
||||
}
|
||||
|
||||
static BOOL msi_control_set_next( msi_control *control, msi_control *next )
|
||||
|
@ -2116,7 +2345,7 @@ static LRESULT msi_dialog_oncreate( HWND hwnd, LPCREATESTRUCTW cs )
|
|||
msi_dialog *dialog = (msi_dialog*) cs->lpCreateParams;
|
||||
MSIRECORD *rec = NULL;
|
||||
LPWSTR title = NULL;
|
||||
SIZE size;
|
||||
RECT pos;
|
||||
|
||||
TRACE("%p %p\n", dialog, dialog->package);
|
||||
|
||||
|
@ -2132,9 +2361,7 @@ static LRESULT msi_dialog_oncreate( HWND hwnd, LPCREATESTRUCTW cs )
|
|||
|
||||
dialog->scale = msi_dialog_get_sans_serif_height(dialog->hwnd);
|
||||
|
||||
size.cx = MSI_RecordGetInteger( rec, 4 );
|
||||
size.cy = MSI_RecordGetInteger( rec, 5 );
|
||||
msi_dialog_adjust_dialog_size( dialog, &size );
|
||||
msi_dialog_adjust_dialog_pos( dialog, rec, &pos );
|
||||
|
||||
dialog->attributes = MSI_RecordGetInteger( rec, 6 );
|
||||
|
||||
|
@ -2149,8 +2376,9 @@ static LRESULT msi_dialog_oncreate( HWND hwnd, LPCREATESTRUCTW cs )
|
|||
SetWindowTextW( hwnd, title );
|
||||
msi_free( title );
|
||||
|
||||
SetWindowPos( hwnd, 0, 0, 0, size.cx, size.cy,
|
||||
SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW );
|
||||
SetWindowPos( hwnd, 0, pos.left, pos.top,
|
||||
pos.right - pos.left, pos.bottom - pos.top,
|
||||
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW );
|
||||
|
||||
msi_dialog_build_font_list( dialog );
|
||||
msi_dialog_fill_controls( dialog );
|
||||
|
@ -2320,7 +2548,6 @@ static UINT msi_dialog_checkbox_handler( msi_dialog *dialog,
|
|||
static UINT msi_dialog_edit_handler( msi_dialog *dialog,
|
||||
msi_control *control, WPARAM param )
|
||||
{
|
||||
UINT sz, r;
|
||||
LPWSTR buf;
|
||||
|
||||
if( HIWORD(param) != EN_CHANGE )
|
||||
|
@ -2329,17 +2556,7 @@ static UINT msi_dialog_edit_handler( msi_dialog *dialog,
|
|||
TRACE("edit %s contents changed, set %s\n", debugstr_w(control->name),
|
||||
debugstr_w(control->property));
|
||||
|
||||
sz = 0x20;
|
||||
buf = msi_alloc( sz*sizeof(WCHAR) );
|
||||
while( buf )
|
||||
{
|
||||
r = GetWindowTextW( control->hwnd, buf, sz );
|
||||
if( r < (sz-1) )
|
||||
break;
|
||||
sz *= 2;
|
||||
buf = msi_realloc( buf, sz*sizeof(WCHAR) );
|
||||
}
|
||||
|
||||
buf = msi_get_window_text( control->hwnd );
|
||||
MSI_SetPropertyW( dialog->package, control->property, buf );
|
||||
|
||||
msi_free( buf );
|
||||
|
@ -2598,7 +2815,7 @@ UINT msi_dialog_run_message_loop( msi_dialog *dialog )
|
|||
{
|
||||
while( !dialog->finished )
|
||||
{
|
||||
MsgWaitForMultipleObjects( 0, NULL, 0, INFINITE, QS_ALLEVENTS );
|
||||
MsgWaitForMultipleObjects( 0, NULL, 0, INFINITE, QS_ALLINPUT );
|
||||
msi_process_pending_messages( dialog->hwnd );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -379,6 +379,12 @@ static UINT ControlEvent_SetInstallLevel(MSIPACKAGE* package, LPCWSTR argument,
|
|||
return MSI_SetInstallLevel( package, iInstallLevel );
|
||||
}
|
||||
|
||||
static UINT ControlEvent_DirectoryListUp(MSIPACKAGE *package, LPCWSTR argument,
|
||||
msi_dialog *dialog)
|
||||
{
|
||||
return msi_dialog_directorylist_up( dialog );
|
||||
}
|
||||
|
||||
static const struct _events Events[] = {
|
||||
{ "EndDialog",ControlEvent_EndDialog },
|
||||
{ "NewDialog",ControlEvent_NewDialog },
|
||||
|
@ -391,6 +397,7 @@ static const struct _events Events[] = {
|
|||
{ "SetTargetPath",ControlEvent_SetTargetPath },
|
||||
{ "Reset",ControlEvent_Reset },
|
||||
{ "SetInstallLevel",ControlEvent_SetInstallLevel },
|
||||
{ "DirectoryListUp",ControlEvent_DirectoryListUp },
|
||||
{ NULL,NULL },
|
||||
};
|
||||
|
||||
|
|
|
@ -42,6 +42,8 @@
|
|||
#include "msvcrt/fcntl.h"
|
||||
#include "msipriv.h"
|
||||
#include "winuser.h"
|
||||
#include "winreg.h"
|
||||
#include "shlwapi.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "action.h"
|
||||
|
||||
|
@ -56,6 +58,7 @@ extern const WCHAR szRemoveFiles[];
|
|||
|
||||
static const WCHAR cszTempFolder[]= {'T','e','m','p','F','o','l','d','e','r',0};
|
||||
|
||||
extern LPCWSTR msi_download_file( LPCWSTR szUrl, LPWSTR filename );
|
||||
|
||||
/*
|
||||
* This is a helper function for handling embedded cabinet media
|
||||
|
@ -218,7 +221,7 @@ static INT_PTR cabinet_notify(FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin)
|
|||
|
||||
if (!f)
|
||||
{
|
||||
ERR("Unknown File in Cabinet (%s)\n",debugstr_a(pfdin->psz1));
|
||||
WARN("unknown file in cabinet (%s)\n",debugstr_a(pfdin->psz1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -280,6 +283,7 @@ static BOOL extract_cabinet_file(MSIPACKAGE* package, LPCWSTR source,
|
|||
BOOL ret;
|
||||
char *cabinet;
|
||||
char *cab_path;
|
||||
static CHAR empty[] = "";
|
||||
CabData data;
|
||||
|
||||
TRACE("Extracting %s to %s\n",debugstr_w(source), debugstr_w(path));
|
||||
|
@ -314,7 +318,7 @@ static BOOL extract_cabinet_file(MSIPACKAGE* package, LPCWSTR source,
|
|||
data.package = package;
|
||||
data.cab_path = cab_path;
|
||||
|
||||
ret = FDICopy(hfdi, cabinet, "", 0, cabinet_notify, NULL, &data);
|
||||
ret = FDICopy(hfdi, cabinet, empty, 0, cabinet_notify, NULL, &data);
|
||||
|
||||
if (!ret)
|
||||
ERR("FDICopy failed\n");
|
||||
|
@ -330,7 +334,7 @@ static BOOL extract_cabinet_file(MSIPACKAGE* package, LPCWSTR source,
|
|||
static VOID set_file_source(MSIPACKAGE* package, MSIFILE* file, MSICOMPONENT*
|
||||
comp, LPCWSTR path)
|
||||
{
|
||||
if (file->Attributes & msidbFileAttributesNoncompressed)
|
||||
if (!file->IsCompressed)
|
||||
{
|
||||
LPWSTR p, path;
|
||||
p = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
|
||||
|
@ -378,6 +382,52 @@ static void free_media_info( struct media_info *mi )
|
|||
msi_free( mi );
|
||||
}
|
||||
|
||||
/* downloads a remote cabinet and extracts it if it exists */
|
||||
static UINT msi_extract_remote_cabinet( MSIPACKAGE *package, struct media_info *mi )
|
||||
{
|
||||
FDICABINETINFO cabinfo;
|
||||
WCHAR temppath[MAX_PATH];
|
||||
WCHAR src[MAX_PATH];
|
||||
LPSTR cabpath;
|
||||
LPCWSTR file;
|
||||
LPWSTR ptr;
|
||||
HFDI hfdi;
|
||||
ERF erf;
|
||||
int hf;
|
||||
|
||||
/* the URL is the path prefix of the package URL and the filename
|
||||
* of the file to download
|
||||
*/
|
||||
ptr = strrchrW(package->PackagePath, '/');
|
||||
lstrcpynW(src, package->PackagePath, ptr - package->PackagePath + 2);
|
||||
ptr = strrchrW(mi->source, '\\');
|
||||
lstrcatW(src, ptr + 1);
|
||||
|
||||
file = msi_download_file( src, temppath );
|
||||
lstrcpyW(mi->source, file);
|
||||
|
||||
/* check if the remote cabinet still exists, ignore if it doesn't */
|
||||
hfdi = FDICreate(cabinet_alloc, cabinet_free, cabinet_open, cabinet_read,
|
||||
cabinet_write, cabinet_close, cabinet_seek, 0, &erf);
|
||||
if (!hfdi)
|
||||
{
|
||||
ERR("FDICreate failed\n");
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
cabpath = strdupWtoA(mi->source);
|
||||
hf = cabinet_open(cabpath, _O_RDONLY, 0);
|
||||
if (!FDIIsCabinet(hfdi, hf, &cabinfo))
|
||||
{
|
||||
WARN("Remote cabinet %s does not exist.\n", debugstr_w(mi->source));
|
||||
msi_free(cabpath);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
msi_free(cabpath);
|
||||
return !extract_cabinet_file(package, mi->source, mi->last_path);
|
||||
}
|
||||
|
||||
static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi,
|
||||
MSIFILE *file )
|
||||
{
|
||||
|
@ -410,16 +460,13 @@ static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi,
|
|||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
seq = MSI_RecordGetInteger(row,2);
|
||||
mi->last_sequence = seq;
|
||||
|
||||
volume = MSI_RecordGetString(row, 5);
|
||||
prompt = MSI_RecordGetString(row, 3);
|
||||
|
||||
msi_free(mi->last_path);
|
||||
mi->last_path = NULL;
|
||||
|
||||
if (file->Attributes & msidbFileAttributesNoncompressed)
|
||||
if (!file->IsCompressed)
|
||||
{
|
||||
mi->last_path = resolve_folder(package, comp->Directory, TRUE, FALSE, NULL);
|
||||
set_file_source(package,file,comp,mi->last_path);
|
||||
|
@ -436,6 +483,9 @@ static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi,
|
|||
return rc;
|
||||
}
|
||||
|
||||
seq = MSI_RecordGetInteger(row,2);
|
||||
mi->last_sequence = seq;
|
||||
|
||||
cab = MSI_RecordGetString(row,4);
|
||||
if (cab)
|
||||
{
|
||||
|
@ -488,7 +538,17 @@ static UINT ready_media_for_file( MSIPACKAGE *package, struct media_info *mi,
|
|||
GetTempPathW(MAX_PATH,mi->last_path);
|
||||
}
|
||||
}
|
||||
rc = !extract_cabinet_file(package, mi->source, mi->last_path);
|
||||
|
||||
/* only download the remote cabinet file if a local copy does not exist */
|
||||
if (GetFileAttributesW(mi->source) == INVALID_FILE_ATTRIBUTES &&
|
||||
UrlIsW(package->PackagePath, URLIS_URL))
|
||||
{
|
||||
rc = msi_extract_remote_cabinet(package, mi);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = !extract_cabinet_file(package, mi->source, mi->last_path);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -605,7 +665,7 @@ UINT ACTION_InstallFiles(MSIPACKAGE *package)
|
|||
continue;
|
||||
|
||||
/* compressed files are extracted in ready_media_for_file */
|
||||
if (~file->Attributes & msidbFileAttributesNoncompressed)
|
||||
if (file->IsCompressed)
|
||||
{
|
||||
if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(file->TargetPath))
|
||||
ERR("compressed file wasn't extracted (%s)\n",
|
||||
|
@ -764,6 +824,24 @@ UINT ACTION_DuplicateFiles(MSIPACKAGE *package)
|
|||
return rc;
|
||||
}
|
||||
|
||||
/* compares the version of a file read from the filesystem and
|
||||
* the version specified in the File table
|
||||
*/
|
||||
static int msi_compare_file_version( MSIFILE *file )
|
||||
{
|
||||
WCHAR version[MAX_PATH];
|
||||
DWORD size;
|
||||
UINT r;
|
||||
|
||||
size = MAX_PATH;
|
||||
version[0] = '\0';
|
||||
r = MsiGetFileVersionW( file->TargetPath, version, &size, NULL, NULL );
|
||||
if ( r != ERROR_SUCCESS )
|
||||
return 0;
|
||||
|
||||
return lstrcmpW( version, file->Version );
|
||||
}
|
||||
|
||||
UINT ACTION_RemoveFiles( MSIPACKAGE *package )
|
||||
{
|
||||
MSIFILE *file;
|
||||
|
@ -784,6 +862,12 @@ UINT ACTION_RemoveFiles( MSIPACKAGE *package )
|
|||
if ( file->state != msifs_present )
|
||||
continue;
|
||||
|
||||
/* only remove a file if the version to be installed
|
||||
* is strictly newer than the old file
|
||||
*/
|
||||
if ( msi_compare_file_version( file ) >= 0 )
|
||||
continue;
|
||||
|
||||
TRACE("removing %s\n", debugstr_w(file->File) );
|
||||
if ( !DeleteFileW( file->TargetPath ) )
|
||||
ERR("failed to delete %s\n", debugstr_w(file->TargetPath) );
|
||||
|
|
|
@ -57,7 +57,15 @@ typedef struct msi_handle_info_t
|
|||
DWORD dwThreadId;
|
||||
} msi_handle_info;
|
||||
|
||||
static msi_handle_info msihandletable[MSIMAXHANDLES];
|
||||
static msi_handle_info *msihandletable = NULL;
|
||||
static int msihandletable_size = 0;
|
||||
|
||||
void msi_free_handle_table(void)
|
||||
{
|
||||
msi_free( msihandletable );
|
||||
msihandletable = NULL;
|
||||
msihandletable_size = 0;
|
||||
}
|
||||
|
||||
MSIHANDLE alloc_msihandle( MSIOBJECTHDR *obj )
|
||||
{
|
||||
|
@ -67,11 +75,29 @@ MSIHANDLE alloc_msihandle( MSIOBJECTHDR *obj )
|
|||
EnterCriticalSection( &MSI_handle_cs );
|
||||
|
||||
/* find a slot */
|
||||
for(i=0; i<MSIMAXHANDLES; i++)
|
||||
for(i=0; i<msihandletable_size; i++)
|
||||
if( !msihandletable[i].obj )
|
||||
break;
|
||||
if( (i>=MSIMAXHANDLES) || msihandletable[i].obj )
|
||||
goto out;
|
||||
if( i==msihandletable_size )
|
||||
{
|
||||
msi_handle_info *p;
|
||||
int newsize;
|
||||
if (msihandletable_size == 0)
|
||||
{
|
||||
newsize = 256;
|
||||
p = msi_alloc_zero(newsize*sizeof(msi_handle_info));
|
||||
}
|
||||
else
|
||||
{
|
||||
newsize = msihandletable_size * 2;
|
||||
p = msi_realloc_zero(msihandletable,
|
||||
newsize*sizeof(msi_handle_info));
|
||||
}
|
||||
if (!p)
|
||||
goto out;
|
||||
msihandletable = p;
|
||||
msihandletable_size = newsize;
|
||||
}
|
||||
|
||||
msiobj_addref( obj );
|
||||
msihandletable[i].obj = obj;
|
||||
|
@ -92,7 +118,7 @@ void *msihandle2msiinfo(MSIHANDLE handle, UINT type)
|
|||
handle--;
|
||||
if( handle<0 )
|
||||
goto out;
|
||||
if( handle>=MSIMAXHANDLES )
|
||||
if( handle>=msihandletable_size )
|
||||
goto out;
|
||||
if( !msihandletable[handle].obj )
|
||||
goto out;
|
||||
|
@ -230,14 +256,18 @@ UINT WINAPI MsiCloseAllHandles(void)
|
|||
|
||||
TRACE("\n");
|
||||
|
||||
for(i=0; i<MSIMAXHANDLES; i++)
|
||||
EnterCriticalSection( &MSI_handle_cs );
|
||||
for(i=0; i<msihandletable_size; i++)
|
||||
{
|
||||
if(msihandletable[i].dwThreadId == GetCurrentThreadId())
|
||||
{
|
||||
LeaveCriticalSection( &MSI_handle_cs );
|
||||
MsiCloseHandle( i+1 );
|
||||
EnterCriticalSection( &MSI_handle_cs );
|
||||
n++;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection( &MSI_handle_cs );
|
||||
|
||||
return n;
|
||||
}
|
||||
|
|
|
@ -72,35 +72,6 @@ LPWSTR msi_dup_record_field( MSIRECORD *row, INT index )
|
|||
return strdupW( MSI_RecordGetString(row,index) );
|
||||
}
|
||||
|
||||
LPWSTR msi_dup_property(MSIPACKAGE *package, LPCWSTR prop)
|
||||
{
|
||||
DWORD sz = 0;
|
||||
LPWSTR str;
|
||||
UINT r;
|
||||
|
||||
r = MSI_GetPropertyW(package, prop, NULL, &sz);
|
||||
if (r != ERROR_SUCCESS && r != ERROR_MORE_DATA)
|
||||
return NULL;
|
||||
|
||||
sz++;
|
||||
str = msi_alloc(sz*sizeof(WCHAR));
|
||||
r = MSI_GetPropertyW(package, prop, str, &sz);
|
||||
if (r != ERROR_SUCCESS)
|
||||
{
|
||||
msi_free(str);
|
||||
str = NULL;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
int msi_get_property_int( MSIPACKAGE *package, LPCWSTR prop, int def )
|
||||
{
|
||||
LPWSTR str = msi_dup_property( package, prop );
|
||||
int val = str ? atoiW( str ) : def;
|
||||
msi_free( str );
|
||||
return val;
|
||||
}
|
||||
|
||||
MSICOMPONENT* get_loaded_component( MSIPACKAGE* package, LPCWSTR Component )
|
||||
{
|
||||
MSICOMPONENT *comp;
|
||||
|
@ -1009,3 +980,18 @@ WCHAR* generate_error_string(MSIPACKAGE *package, UINT error, DWORD count, ... )
|
|||
data = NULL;
|
||||
return data;
|
||||
}
|
||||
|
||||
void msi_ui_error( DWORD msg_id, DWORD type )
|
||||
{
|
||||
WCHAR text[2048];
|
||||
|
||||
static const WCHAR title[] = {
|
||||
'W','i','n','d','o','w','s',' ','I','n','s','t','a','l','l','e','r',0
|
||||
};
|
||||
|
||||
if (!MsiLoadStringW( -1, msg_id, text, sizeof(text) / sizeof(text[0]),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) ))
|
||||
return;
|
||||
|
||||
MessageBoxW( NULL, text, title, type );
|
||||
}
|
||||
|
|
|
@ -634,6 +634,30 @@ UINT WINAPI MsiGetFeatureStateW(MSIHANDLE hInstall, LPCWSTR szFeature,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiGetFeatureCostA (MSI.@)
|
||||
*/
|
||||
UINT WINAPI MsiGetFeatureCostA(MSIHANDLE hInstall, LPCSTR szFeature,
|
||||
MSICOSTTREE iCostTree, INSTALLSTATE iState, INT *piCost)
|
||||
{
|
||||
FIXME("(%ld %s %i %i %p): stub\n", hInstall, debugstr_a(szFeature),
|
||||
iCostTree, iState, piCost);
|
||||
if (piCost) *piCost = 0;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiGetFeatureCostW (MSI.@)
|
||||
*/
|
||||
UINT WINAPI MsiGetFeatureCostW(MSIHANDLE hInstall, LPCWSTR szFeature,
|
||||
MSICOSTTREE iCostTree, INSTALLSTATE iState, INT *piCost)
|
||||
{
|
||||
FIXME("(%ld %s %i %i %p): stub\n", hInstall, debugstr_w(szFeature),
|
||||
iCostTree, iState, piCost);
|
||||
if (piCost) *piCost = 0;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MsiSetComponentStateA (MSI.@)
|
||||
*/
|
||||
|
|
|
@ -326,6 +326,8 @@ static UINT JOIN_delete( struct tagMSIVIEW *view )
|
|||
msi_free( jv->pairs );
|
||||
jv->pairs = NULL;
|
||||
|
||||
msi_free( jv );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -125,6 +125,8 @@ UINT WINAPI MsiOpenProductW( LPCWSTR szProduct, MSIHANDLE *phProduct )
|
|||
if( r == ERROR_SUCCESS )
|
||||
{
|
||||
*phProduct = alloc_msihandle( &package->hdr );
|
||||
if (! *phProduct)
|
||||
r = ERROR_NOT_ENOUGH_MEMORY;
|
||||
msiobj_release( &package->hdr );
|
||||
}
|
||||
return r;
|
||||
|
@ -1092,7 +1094,7 @@ end:
|
|||
* INSTALLSTATE_LOCAL Feature is installed and useable
|
||||
* INSTALLSTATE_ABSENT Feature is absent
|
||||
* INSTALLSTATE_ADVERTISED Feature should be installed on demand
|
||||
* INSTALLSTATE_UNKNOWN An error occured
|
||||
* INSTALLSTATE_UNKNOWN An error occurred
|
||||
* INSTALLSTATE_INVALIDARG One of the GUIDs was invalid
|
||||
*
|
||||
*/
|
||||
|
@ -1441,6 +1443,7 @@ UINT WINAPI MSI_ProvideQualifiedComponentEx(LPCWSTR szComponent,
|
|||
else
|
||||
rc = MSI_GetComponentPath(szProduct, component, lpPathBuf, pcchPathBuf);
|
||||
|
||||
msi_free( info );
|
||||
|
||||
if (rc != INSTALLSTATE_LOCAL)
|
||||
return ERROR_FILE_NOT_FOUND;
|
||||
|
|
|
@ -4,29 +4,29 @@
|
|||
<include base="msi">.</include>
|
||||
<include base="ReactOS">include/reactos/wine</include>
|
||||
<define name="__REACTOS__" />
|
||||
<define name="__USE_W32API" />
|
||||
<define name="__WINESRC__" />
|
||||
<define name="__USE_W32API" />
|
||||
<define name="_WIN32_IE">0x600</define>
|
||||
<define name="_WIN32_WINNT">0x501</define>
|
||||
<define name="WINVER">0x501</define>
|
||||
<library>wine</library>
|
||||
<library>uuid</library>
|
||||
<library>ntdll</library>
|
||||
<library>kernel32</library>
|
||||
<library>urlmon</library>
|
||||
<library>wininet</library>
|
||||
<library>comctl32</library>
|
||||
<library>shell32</library>
|
||||
<library>shlwapi</library>
|
||||
<library>cabinet</library>
|
||||
<library>oleaut32</library>
|
||||
<library>ole32</library>
|
||||
<library>version</library>
|
||||
<library>user32</library>
|
||||
<library>gdi32</library>
|
||||
<library>advapi32</library>
|
||||
<library>shell32</library>
|
||||
<library>shlwapi</library>
|
||||
<library>winmm</library>
|
||||
<library>cabinet</library>
|
||||
<library>comctl32</library>
|
||||
<library>ole32</library>
|
||||
<library>oleaut32</library>
|
||||
<library>version</library>
|
||||
<library>wininet</library>
|
||||
<library>urlmon</library>
|
||||
<library>kernel32</library>
|
||||
<library>uuid</library>
|
||||
<library>ntdll</library>
|
||||
<file>action.c</file>
|
||||
<file>alter.c</file>
|
||||
<file>appsearch.c</file>
|
||||
<file>classes.c</file>
|
||||
<file>cond.tab.c</file>
|
||||
|
@ -63,6 +63,6 @@
|
|||
<file>update.c</file>
|
||||
<file>upgrade.c</file>
|
||||
<file>where.c</file>
|
||||
<file>msi.spec</file>
|
||||
<file>msi.rc</file>
|
||||
<file>msi.spec</file>
|
||||
</module>
|
||||
|
|
|
@ -46,8 +46,8 @@
|
|||
50 stdcall MsiGetComponentStateA(long str ptr ptr)
|
||||
51 stdcall MsiGetComponentStateW(long wstr ptr ptr)
|
||||
52 stdcall MsiGetDatabaseState(long)
|
||||
53 stub MsiGetFeatureCostA
|
||||
54 stub MsiGetFeatureCostW
|
||||
53 stdcall MsiGetFeatureCostA(long str long long ptr)
|
||||
54 stdcall MsiGetFeatureCostW(long wstr long long ptr)
|
||||
55 stub MsiGetFeatureInfoA
|
||||
56 stub MsiGetFeatureInfoW
|
||||
57 stdcall MsiGetFeatureStateA(long str ptr ptr)
|
||||
|
|
|
@ -22,6 +22,7 @@ LANGUAGE LANG_BULGARIAN, SUBLANG_DEFAULT
|
|||
|
||||
STRINGTABLE DISCARDABLE
|
||||
{
|
||||
4 "The specified installation package could not be opened. Please check the file path and try again."
|
||||
5 "пътят %s не е намерен"
|
||||
9 "поставете диск %s"
|
||||
10 "некоректни параметри"
|
||||
|
|
|
@ -22,6 +22,7 @@ LANGUAGE LANG_GERMAN, SUBLANG_DEFAULT
|
|||
|
||||
STRINGTABLE DISCARDABLE
|
||||
{
|
||||
4 "The specified installation package could not be opened. Please check the file path and try again."
|
||||
5 "Der Pfad %s wurde nicht gefunden."
|
||||
9 "Bitte Disk %s einlegen."
|
||||
10 "schlechte Parameter"
|
||||
|
|
|
@ -22,6 +22,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
|
|||
|
||||
STRINGTABLE DISCARDABLE
|
||||
{
|
||||
4 "The specified installation package could not be opened. Please check the file path and try again."
|
||||
5 "path %s not found"
|
||||
9 "insert disk %s"
|
||||
10 "bad parameters"
|
||||
|
|
|
@ -22,6 +22,7 @@ LANGUAGE LANG_ESPERANTO, SUBLANG_DEFAULT
|
|||
|
||||
STRINGTABLE DISCARDABLE
|
||||
{
|
||||
4 "The specified installation package could not be opened. Please check the file path and try again."
|
||||
5 "Mi ne trovis la vojon %s"
|
||||
9 "enþovu la diskon %s"
|
||||
10 "nekorektaj parametroj"
|
||||
|
|
|
@ -22,6 +22,7 @@ LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL
|
|||
|
||||
STRINGTABLE DISCARDABLE
|
||||
{
|
||||
4 "The specified installation package could not be opened. Please check the file path and try again."
|
||||
5 "ruta %s no encontrada"
|
||||
9 "inserte el disco %s"
|
||||
10 "parámetros incorrectos"
|
||||
|
|
|
@ -22,6 +22,7 @@ LANGUAGE LANG_FINNISH, SUBLANG_DEFAULT
|
|||
|
||||
STRINGTABLE DISCARDABLE
|
||||
{
|
||||
4 "The specified installation package could not be opened. Please check the file path and try again."
|
||||
5 "Polkua %s ei löydy."
|
||||
9 "Anna levy %s"
|
||||
10 "Virheelliset parametrit."
|
||||
|
|
|
@ -22,6 +22,7 @@ LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
|
|||
|
||||
STRINGTABLE DISCARDABLE
|
||||
{
|
||||
4 "The specified installation package could not be opened. Please check the file path and try again."
|
||||
5 "Le chemin %s est introuvable"
|
||||
9 "insérez le disque %s"
|
||||
10 "mauvais paramètres"
|
||||
|
|
|
@ -22,6 +22,7 @@ LANGUAGE LANG_HUNGARIAN, SUBLANG_DEFAULT
|
|||
|
||||
STRINGTABLE DISCARDABLE
|
||||
{
|
||||
4 "The specified installation package could not be opened. Please check the file path and try again."
|
||||
5 "%s útvonal nem található"
|
||||
9 "helyezze be a lemezt: %s"
|
||||
10 "rossz paraméterek"
|
||||
|
|
|
@ -22,6 +22,7 @@ LANGUAGE LANG_ITALIAN, SUBLANG_DEFAULT
|
|||
|
||||
STRINGTABLE DISCARDABLE
|
||||
{
|
||||
4 "The specified installation package could not be opened. Please check the file path and try again."
|
||||
5 "percorso %s non trovato"
|
||||
9 "inserire disco %s"
|
||||
10 "parametri incorretti"
|
||||
|
|
|
@ -22,6 +22,7 @@ LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT
|
|||
|
||||
STRINGTABLE DISCARDABLE
|
||||
{
|
||||
4 " 지정한 설치 패키지를 열 수 없습니다. 파일 경로를 확인하고 다시 시도하십시오."
|
||||
5 "%s 경로를 찾을수 없습니다"
|
||||
9 "디스크 %s 삽입"
|
||||
10 "절못된 매개변수"
|
||||
|
|
|
@ -22,6 +22,7 @@ LANGUAGE LANG_DUTCH, SUBLANG_DEFAULT
|
|||
|
||||
STRINGTABLE DISCARDABLE
|
||||
{
|
||||
4 "The specified installation package could not be opened. Please check the file path and try again."
|
||||
5 "Pad %s niet gevonden"
|
||||
9 "Plaats disk %s"
|
||||
10 "Ongeldige parameters"
|
||||
|
|
|
@ -22,6 +22,7 @@ LANGUAGE LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL
|
|||
|
||||
STRINGTABLE DISCARDABLE
|
||||
{
|
||||
4 "The specified installation package could not be opened. Please check the file path and try again."
|
||||
5 "Fant ikke stien '%s'."
|
||||
9 "Sett i disk '%s'"
|
||||
10 "Gale parametere."
|
||||
|
|
|
@ -22,6 +22,7 @@ LANGUAGE LANG_PORTUGUESE, SUBLANG_DEFAULT
|
|||
|
||||
STRINGTABLE DISCARDABLE
|
||||
{
|
||||
4 "The specified installation package could not be opened. Please check the file path and try again."
|
||||
5 "caminho %s não encontrado"
|
||||
9 "insira disco %s"
|
||||
10 "parâmetros inválidos"
|
||||
|
|
|
@ -22,6 +22,7 @@ LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
|
|||
|
||||
STRINGTABLE DISCARDABLE
|
||||
{
|
||||
4 "The specified installation package could not be opened. Please check the file path and try again."
|
||||
5 "путь %s не найден"
|
||||
9 "вставьте диск %s"
|
||||
10 "неверные параметры"
|
||||
|
|
|
@ -22,6 +22,7 @@ LANGUAGE LANG_TURKISH, SUBLANG_DEFAULT
|
|||
|
||||
STRINGTABLE DISCARDABLE
|
||||
{
|
||||
4 "The specified installation package could not be opened. Please check the file path and try again."
|
||||
5 "%s yolu bulunamadı"
|
||||
9 "%s nolu diski yerleştirin"
|
||||
10 "bozuk parametreler"
|
||||
|
|
|
@ -1,180 +1,181 @@
|
|||
/*
|
||||
* Implementation of the Microsoft Installer (msi.dll)
|
||||
*
|
||||
* Copyright 2006 Mike McCormack 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#define COBJMACROS
|
||||
#define NONAMELESSUNION
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winreg.h"
|
||||
#include "shlwapi.h"
|
||||
#include "msipriv.h"
|
||||
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
|
||||
static LONG dll_count;
|
||||
|
||||
/* the UI level */
|
||||
INSTALLUILEVEL gUILevel = INSTALLUILEVEL_BASIC;
|
||||
HWND gUIhwnd = 0;
|
||||
INSTALLUI_HANDLERA gUIHandlerA = NULL;
|
||||
INSTALLUI_HANDLERW gUIHandlerW = NULL;
|
||||
DWORD gUIFilter = 0;
|
||||
LPVOID gUIContext = NULL;
|
||||
WCHAR gszLogFile[MAX_PATH];
|
||||
HINSTANCE msi_hInstance;
|
||||
|
||||
/*
|
||||
* Dll lifetime tracking declaration
|
||||
*/
|
||||
static void LockModule(void)
|
||||
{
|
||||
InterlockedIncrement(&dll_count);
|
||||
}
|
||||
|
||||
static void UnlockModule(void)
|
||||
{
|
||||
InterlockedDecrement(&dll_count);
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* DllMain
|
||||
*/
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
{
|
||||
switch (fdwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
msi_hInstance = hinstDLL;
|
||||
DisableThreadLibraryCalls(hinstDLL);
|
||||
msi_dialog_register_class();
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
msi_dialog_unregister_class();
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef struct tagIClassFactoryImpl
|
||||
{
|
||||
const IClassFactoryVtbl *lpVtbl;
|
||||
} IClassFactoryImpl;
|
||||
|
||||
static HRESULT WINAPI MsiCF_QueryInterface(LPCLASSFACTORY iface,
|
||||
REFIID riid,LPVOID *ppobj)
|
||||
{
|
||||
IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
|
||||
FIXME("%p %s %p\n",This,debugstr_guid(riid),ppobj);
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
static ULONG WINAPI MsiCF_AddRef(LPCLASSFACTORY iface)
|
||||
{
|
||||
LockModule();
|
||||
return 2;
|
||||
}
|
||||
|
||||
static ULONG WINAPI MsiCF_Release(LPCLASSFACTORY iface)
|
||||
{
|
||||
UnlockModule();
|
||||
return 1;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI MsiCF_CreateInstance(LPCLASSFACTORY iface,
|
||||
LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj)
|
||||
{
|
||||
IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
|
||||
|
||||
FIXME("%p %p %s %p\n", This, pOuter, debugstr_guid(riid), ppobj);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI MsiCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
|
||||
{
|
||||
TRACE("%p %d\n", iface, dolock);
|
||||
|
||||
if (dolock)
|
||||
LockModule();
|
||||
else
|
||||
UnlockModule();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const IClassFactoryVtbl MsiCF_Vtbl =
|
||||
{
|
||||
MsiCF_QueryInterface,
|
||||
MsiCF_AddRef,
|
||||
MsiCF_Release,
|
||||
MsiCF_CreateInstance,
|
||||
MsiCF_LockServer
|
||||
};
|
||||
|
||||
static IClassFactoryImpl Msi_CF = { &MsiCF_Vtbl };
|
||||
|
||||
/******************************************************************
|
||||
* DllGetClassObject [MSI.@]
|
||||
*/
|
||||
HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
|
||||
{
|
||||
TRACE("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
|
||||
|
||||
if( IsEqualCLSID (rclsid, &CLSID_IMsiServer) ||
|
||||
IsEqualCLSID (rclsid, &CLSID_IMsiServerMessage) ||
|
||||
IsEqualCLSID (rclsid, &CLSID_IMsiServerX1) ||
|
||||
IsEqualCLSID (rclsid, &CLSID_IMsiServerX2) ||
|
||||
IsEqualCLSID (rclsid, &CLSID_IMsiServerX3) )
|
||||
{
|
||||
*ppv = (LPVOID) &Msi_CF;
|
||||
return S_OK;
|
||||
}
|
||||
return CLASS_E_CLASSNOTAVAILABLE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* DllGetVersion [MSI.@]
|
||||
*/
|
||||
HRESULT WINAPI DllGetVersion(DLLVERSIONINFO *pdvi)
|
||||
{
|
||||
TRACE("%p\n",pdvi);
|
||||
|
||||
if (pdvi->cbSize != sizeof(DLLVERSIONINFO))
|
||||
return E_INVALIDARG;
|
||||
|
||||
pdvi->dwMajorVersion = MSI_MAJORVERSION;
|
||||
pdvi->dwMinorVersion = MSI_MINORVERSION;
|
||||
pdvi->dwBuildNumber = MSI_BUILDNUMBER;
|
||||
pdvi->dwPlatformID = 1;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* DllCanUnloadNow [MSI.@]
|
||||
*/
|
||||
HRESULT WINAPI DllCanUnloadNow(void)
|
||||
{
|
||||
return dll_count == 0 ? S_OK : S_FALSE;
|
||||
}
|
||||
/*
|
||||
* Implementation of the Microsoft Installer (msi.dll)
|
||||
*
|
||||
* Copyright 2006 Mike McCormack 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#define COBJMACROS
|
||||
#define NONAMELESSUNION
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winreg.h"
|
||||
#include "shlwapi.h"
|
||||
#include "msipriv.h"
|
||||
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
|
||||
static LONG dll_count;
|
||||
|
||||
/* the UI level */
|
||||
INSTALLUILEVEL gUILevel = INSTALLUILEVEL_BASIC;
|
||||
HWND gUIhwnd = 0;
|
||||
INSTALLUI_HANDLERA gUIHandlerA = NULL;
|
||||
INSTALLUI_HANDLERW gUIHandlerW = NULL;
|
||||
DWORD gUIFilter = 0;
|
||||
LPVOID gUIContext = NULL;
|
||||
WCHAR gszLogFile[MAX_PATH];
|
||||
HINSTANCE msi_hInstance;
|
||||
|
||||
/*
|
||||
* Dll lifetime tracking declaration
|
||||
*/
|
||||
static void LockModule(void)
|
||||
{
|
||||
InterlockedIncrement(&dll_count);
|
||||
}
|
||||
|
||||
static void UnlockModule(void)
|
||||
{
|
||||
InterlockedDecrement(&dll_count);
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* DllMain
|
||||
*/
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
{
|
||||
switch (fdwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
msi_hInstance = hinstDLL;
|
||||
DisableThreadLibraryCalls(hinstDLL);
|
||||
msi_dialog_register_class();
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
msi_dialog_unregister_class();
|
||||
msi_free_handle_table();
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef struct tagIClassFactoryImpl
|
||||
{
|
||||
const IClassFactoryVtbl *lpVtbl;
|
||||
} IClassFactoryImpl;
|
||||
|
||||
static HRESULT WINAPI MsiCF_QueryInterface(LPCLASSFACTORY iface,
|
||||
REFIID riid,LPVOID *ppobj)
|
||||
{
|
||||
IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
|
||||
FIXME("%p %s %p\n",This,debugstr_guid(riid),ppobj);
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
static ULONG WINAPI MsiCF_AddRef(LPCLASSFACTORY iface)
|
||||
{
|
||||
LockModule();
|
||||
return 2;
|
||||
}
|
||||
|
||||
static ULONG WINAPI MsiCF_Release(LPCLASSFACTORY iface)
|
||||
{
|
||||
UnlockModule();
|
||||
return 1;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI MsiCF_CreateInstance(LPCLASSFACTORY iface,
|
||||
LPUNKNOWN pOuter, REFIID riid, LPVOID *ppobj)
|
||||
{
|
||||
IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
|
||||
|
||||
FIXME("%p %p %s %p\n", This, pOuter, debugstr_guid(riid), ppobj);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI MsiCF_LockServer(LPCLASSFACTORY iface, BOOL dolock)
|
||||
{
|
||||
TRACE("%p %d\n", iface, dolock);
|
||||
|
||||
if (dolock)
|
||||
LockModule();
|
||||
else
|
||||
UnlockModule();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const IClassFactoryVtbl MsiCF_Vtbl =
|
||||
{
|
||||
MsiCF_QueryInterface,
|
||||
MsiCF_AddRef,
|
||||
MsiCF_Release,
|
||||
MsiCF_CreateInstance,
|
||||
MsiCF_LockServer
|
||||
};
|
||||
|
||||
static IClassFactoryImpl Msi_CF = { &MsiCF_Vtbl };
|
||||
|
||||
/******************************************************************
|
||||
* DllGetClassObject [MSI.@]
|
||||
*/
|
||||
HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
|
||||
{
|
||||
TRACE("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
|
||||
|
||||
if( IsEqualCLSID (rclsid, &CLSID_IMsiServer) ||
|
||||
IsEqualCLSID (rclsid, &CLSID_IMsiServerMessage) ||
|
||||
IsEqualCLSID (rclsid, &CLSID_IMsiServerX1) ||
|
||||
IsEqualCLSID (rclsid, &CLSID_IMsiServerX2) ||
|
||||
IsEqualCLSID (rclsid, &CLSID_IMsiServerX3) )
|
||||
{
|
||||
*ppv = (LPVOID) &Msi_CF;
|
||||
return S_OK;
|
||||
}
|
||||
return CLASS_E_CLASSNOTAVAILABLE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* DllGetVersion [MSI.@]
|
||||
*/
|
||||
HRESULT WINAPI DllGetVersion(DLLVERSIONINFO *pdvi)
|
||||
{
|
||||
TRACE("%p\n",pdvi);
|
||||
|
||||
if (pdvi->cbSize < sizeof(DLLVERSIONINFO))
|
||||
return E_INVALIDARG;
|
||||
|
||||
pdvi->dwMajorVersion = MSI_MAJORVERSION;
|
||||
pdvi->dwMinorVersion = MSI_MINORVERSION;
|
||||
pdvi->dwBuildNumber = MSI_BUILDNUMBER;
|
||||
pdvi->dwPlatformID = DLLVER_PLATFORM_WINDOWS;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
* DllCanUnloadNow [MSI.@]
|
||||
*/
|
||||
HRESULT WINAPI DllCanUnloadNow(void)
|
||||
{
|
||||
return dll_count == 0 ? S_OK : S_FALSE;
|
||||
}
|
||||
|
|
|
@ -39,6 +39,12 @@
|
|||
#define MSITYPE_NULLABLE 0x1000
|
||||
#define MSITYPE_KEY 0x2000
|
||||
|
||||
/* Word Count masks */
|
||||
#define MSIWORDCOUNT_SHORTFILENAMES 0x0001
|
||||
#define MSIWORDCOUNT_COMPRESSED 0x0002
|
||||
#define MSIWORDCOUNT_ADMINISTRATIVE 0x0004
|
||||
#define MSIWORDCOUNT_PRIVILEGES 0x0008
|
||||
|
||||
#define MSITYPE_IS_BINARY(type) (((type) & ~MSITYPE_NULLABLE) == (MSITYPE_STRING|MSITYPE_VALID))
|
||||
|
||||
struct tagMSITABLE;
|
||||
|
@ -195,6 +201,8 @@ struct tagMSIVIEW
|
|||
struct msi_dialog_tag;
|
||||
typedef struct msi_dialog_tag msi_dialog;
|
||||
|
||||
#define PROPERTY_HASH_SIZE 67
|
||||
|
||||
typedef struct tagMSIPACKAGE
|
||||
{
|
||||
MSIOBJECTHDR hdr;
|
||||
|
@ -212,7 +220,7 @@ typedef struct tagMSIPACKAGE
|
|||
struct list progids;
|
||||
struct list mimes;
|
||||
struct list appids;
|
||||
|
||||
|
||||
struct tagMSISCRIPT *script;
|
||||
|
||||
struct list RunningActions;
|
||||
|
@ -223,7 +231,11 @@ typedef struct tagMSIPACKAGE
|
|||
UINT CurrentInstallState;
|
||||
msi_dialog *dialog;
|
||||
LPWSTR next_dialog;
|
||||
|
||||
|
||||
UINT WordCount;
|
||||
|
||||
struct list props[PROPERTY_HASH_SIZE];
|
||||
|
||||
struct list subscriptions;
|
||||
} MSIPACKAGE;
|
||||
|
||||
|
@ -252,14 +264,13 @@ typedef struct tagMSISUMMARYINFO
|
|||
#define MSIHANDLETYPE_PACKAGE 5
|
||||
#define MSIHANDLETYPE_PREVIEW 6
|
||||
|
||||
#define MSI_MAJORVERSION 2
|
||||
#define MSI_MINORVERSION 0
|
||||
#define MSI_BUILDNUMBER 2600
|
||||
#define MSI_MAJORVERSION 3
|
||||
#define MSI_MINORVERSION 1
|
||||
#define MSI_BUILDNUMBER 4000
|
||||
|
||||
#define GUID_SIZE 39
|
||||
|
||||
#define MSIHANDLE_MAGIC 0x4d434923
|
||||
#define MSIMAXHANDLES 0xf0
|
||||
|
||||
DEFINE_GUID(CLSID_IMsiServer, 0x000C101C,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
|
||||
DEFINE_GUID(CLSID_IMsiServerX1, 0x000C103E,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
|
||||
|
@ -295,6 +306,7 @@ extern void msiobj_addref(MSIOBJECTHDR *);
|
|||
extern int msiobj_release(MSIOBJECTHDR *);
|
||||
extern void msiobj_lock(MSIOBJECTHDR *);
|
||||
extern void msiobj_unlock(MSIOBJECTHDR *);
|
||||
extern void msi_free_handle_table(void);
|
||||
|
||||
extern void free_cached_tables( MSIDATABASE *db );
|
||||
extern void msi_free_transforms( MSIDATABASE *db );
|
||||
|
@ -316,7 +328,7 @@ extern string_table *msi_init_stringtable( int entries, UINT codepage );
|
|||
extern VOID msi_destroy_stringtable( string_table *st );
|
||||
extern UINT msi_string_count( string_table *st );
|
||||
extern UINT msi_id_refcount( string_table *st, UINT i );
|
||||
extern UINT msi_string_totalsize( string_table *st, UINT *last );
|
||||
extern UINT msi_string_totalsize( string_table *st, UINT *datasize, UINT *poolsize );
|
||||
extern UINT msi_strcmp( string_table *st, UINT lval, UINT rval, UINT *res );
|
||||
extern const WCHAR *msi_string_lookup_id( string_table *st, UINT id );
|
||||
extern UINT msi_string_get_codepage( string_table *st );
|
||||
|
@ -442,6 +454,7 @@ extern BOOL msi_dialog_register_class( void );
|
|||
extern void msi_dialog_unregister_class( void );
|
||||
extern void msi_dialog_handle_event( msi_dialog*, LPCWSTR, LPCWSTR, MSIRECORD * );
|
||||
extern UINT msi_dialog_reset( msi_dialog *dialog );
|
||||
extern UINT msi_dialog_directorylist_up( msi_dialog *dialog );
|
||||
|
||||
/* preview */
|
||||
extern MSIPREVIEW *MSI_EnableUIPreview( MSIDATABASE * );
|
||||
|
|
|
@ -255,6 +255,8 @@ UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb,
|
|||
if( ret == ERROR_SUCCESS )
|
||||
{
|
||||
*phView = alloc_msihandle( &query->hdr );
|
||||
if (! *phView)
|
||||
ret = ERROR_NOT_ENOUGH_MEMORY;
|
||||
msiobj_release( &query->hdr );
|
||||
}
|
||||
msiobj_release( &db->hdr );
|
||||
|
@ -366,6 +368,8 @@ UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record)
|
|||
if( ret == ERROR_SUCCESS )
|
||||
{
|
||||
*record = alloc_msihandle( &rec->hdr );
|
||||
if (! *record)
|
||||
ret = ERROR_NOT_ENOUGH_MEMORY;
|
||||
msiobj_release( &rec->hdr );
|
||||
}
|
||||
msiobj_release( &query->hdr );
|
||||
|
@ -533,6 +537,8 @@ UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hR
|
|||
}
|
||||
|
||||
*hRec = alloc_msihandle( &rec->hdr );
|
||||
if (! *hRec)
|
||||
r = ERROR_NOT_ENOUGH_MEMORY;
|
||||
|
||||
out:
|
||||
msiobj_release( &query->hdr );
|
||||
|
@ -831,6 +837,8 @@ UINT WINAPI MsiDatabaseGetPrimaryKeysW( MSIHANDLE hdb,
|
|||
if( r == ERROR_SUCCESS )
|
||||
{
|
||||
*phRec = alloc_msihandle( &rec->hdr );
|
||||
if (! *phRec)
|
||||
r = ERROR_NOT_ENOUGH_MEMORY;
|
||||
msiobj_release( &rec->hdr );
|
||||
}
|
||||
msiobj_release( &db->hdr );
|
||||
|
|
|
@ -40,12 +40,17 @@
|
|||
#include "shlobj.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "objbase.h"
|
||||
#include "msidefs.h"
|
||||
|
||||
#include "msipriv.h"
|
||||
#include "action.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
|
||||
extern void msi_ui_error( DWORD msg_id, DWORD type );
|
||||
|
||||
static void msi_free_properties( MSIPACKAGE *package );
|
||||
|
||||
static void MSI_FreePackage( MSIOBJECTHDR *arg)
|
||||
{
|
||||
MSIPACKAGE *package= (MSIPACKAGE*) arg;
|
||||
|
@ -54,42 +59,21 @@ static void MSI_FreePackage( MSIOBJECTHDR *arg)
|
|||
msi_dialog_destroy( package->dialog );
|
||||
ACTION_free_package_structures(package);
|
||||
|
||||
msi_free_properties( package );
|
||||
|
||||
msiobj_release( &package->db->hdr );
|
||||
}
|
||||
|
||||
static UINT clone_properties(MSIDATABASE *db)
|
||||
static UINT clone_properties( MSIPACKAGE *package )
|
||||
{
|
||||
MSIQUERY * view = NULL;
|
||||
UINT rc;
|
||||
static const WCHAR CreateSql[] = {
|
||||
'C','R','E','A','T','E',' ','T','A','B','L','E',' ','`','_','P','r','o',
|
||||
'p','e','r','t','y','`',' ','(',' ','`','_','P','r','o','p','e','r','t',
|
||||
'y','`',' ','C','H','A','R','(','5','6',')',' ','N','O','T',' ','N','U',
|
||||
'L','L',',',' ','`','V','a','l','u','e','`',' ','C','H','A','R','(','9',
|
||||
'8',')',' ','N','O','T',' ','N','U','L','L',' ','P','R','I','M','A','R',
|
||||
'Y',' ','K','E','Y',' ','`','_','P','r','o','p','e','r','t','y','`',')',0};
|
||||
static const WCHAR Query[] = {
|
||||
'S','E','L','E','C','T',' ','*',' ',
|
||||
'F','R','O','M',' ','`','P','r','o','p','e','r','t','y','`',0};
|
||||
static const WCHAR Insert[] = {
|
||||
'I','N','S','E','R','T',' ','i','n','t','o',' ',
|
||||
'`','_','P','r','o','p','e','r','t','y','`',' ',
|
||||
'(','`','_','P','r','o','p','e','r','t','y','`',',',
|
||||
'`','V','a','l','u','e','`',')',' ',
|
||||
'V','A','L','U','E','S',' ','(','?',',','?',')',0};
|
||||
|
||||
/* create the temporary properties table */
|
||||
rc = MSI_DatabaseOpenViewW(db, CreateSql, &view);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
return rc;
|
||||
rc = MSI_ViewExecute(view,0);
|
||||
MSI_ViewClose(view);
|
||||
msiobj_release(&view->hdr);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
return rc;
|
||||
|
||||
/* clone the existing properties */
|
||||
rc = MSI_DatabaseOpenViewW(db, Query, &view);
|
||||
rc = MSI_DatabaseOpenViewW( package->db, Query, &view );
|
||||
if (rc != ERROR_SUCCESS)
|
||||
return rc;
|
||||
|
||||
|
@ -97,31 +81,27 @@ static UINT clone_properties(MSIDATABASE *db)
|
|||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
MSI_ViewClose(view);
|
||||
msiobj_release(&view->hdr);
|
||||
msiobj_release(&view->hdr);
|
||||
return rc;
|
||||
}
|
||||
while (1)
|
||||
{
|
||||
MSIRECORD * row;
|
||||
MSIQUERY * view2;
|
||||
LPCWSTR name, value;
|
||||
|
||||
rc = MSI_ViewFetch(view,&row);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
break;
|
||||
|
||||
rc = MSI_DatabaseOpenViewW(db,Insert,&view2);
|
||||
if (rc!= ERROR_SUCCESS)
|
||||
continue;
|
||||
rc = MSI_ViewExecute(view2,row);
|
||||
MSI_ViewClose(view2);
|
||||
msiobj_release(&view2->hdr);
|
||||
|
||||
if (rc == ERROR_SUCCESS)
|
||||
msiobj_release(&row->hdr);
|
||||
name = MSI_RecordGetString( row, 1 );
|
||||
value = MSI_RecordGetString( row, 2 );
|
||||
MSI_SetPropertyW( package, name, value );
|
||||
|
||||
msiobj_release( &row->hdr );
|
||||
}
|
||||
MSI_ViewClose(view);
|
||||
msiobj_release(&view->hdr);
|
||||
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -232,6 +212,7 @@ static VOID set_installer_properties(MSIPACKAGE *package)
|
|||
static const WCHAR szColorBits[] = {'C','o','l','o','r','B','i','t','s',0};
|
||||
static const WCHAR szScreenFormat[] = {'%','d',0};
|
||||
static const WCHAR szIntel[] = { 'I','n','t','e','l',0 };
|
||||
static const WCHAR szAllUsers[] = { 'A','L','L','U','S','E','R','S',0 };
|
||||
SYSTEM_INFO sys_info;
|
||||
|
||||
/*
|
||||
|
@ -335,6 +316,7 @@ static VOID set_installer_properties(MSIPACKAGE *package)
|
|||
/* in a wine environment the user is always admin and privileged */
|
||||
MSI_SetPropertyW(package,szAdminUser,szOne);
|
||||
MSI_SetPropertyW(package,szPriv,szOne);
|
||||
MSI_SetPropertyW(package, szAllUsers, szOne);
|
||||
|
||||
/* set the os things */
|
||||
OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
|
||||
|
@ -376,6 +358,38 @@ static VOID set_installer_properties(MSIPACKAGE *package)
|
|||
ReleaseDC(0, dc);
|
||||
}
|
||||
|
||||
static UINT msi_get_word_count( MSIPACKAGE *package )
|
||||
{
|
||||
UINT rc;
|
||||
INT word_count;
|
||||
MSIHANDLE suminfo;
|
||||
MSIHANDLE hdb = alloc_msihandle( &package->db->hdr );
|
||||
|
||||
if (!hdb) {
|
||||
ERR("Unable to allocate handle\n");
|
||||
return 0;
|
||||
}
|
||||
rc = MsiGetSummaryInformationW( hdb, NULL, 0, &suminfo );
|
||||
MsiCloseHandle(hdb);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
ERR("Unable to open Summary Information\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = MsiSummaryInfoGetPropertyW( suminfo, PID_WORDCOUNT, NULL,
|
||||
&word_count, NULL, NULL, NULL );
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
ERR("Unable to query word count\n");
|
||||
MsiCloseHandle(suminfo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MsiCloseHandle(suminfo);
|
||||
return word_count;
|
||||
}
|
||||
|
||||
MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db )
|
||||
{
|
||||
static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 };
|
||||
|
@ -384,6 +398,7 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db )
|
|||
'P','r','o','d','u','c','t','C','o','d','e',0};
|
||||
MSIPACKAGE *package = NULL;
|
||||
WCHAR uilevel[10];
|
||||
int i;
|
||||
|
||||
TRACE("%p\n", db);
|
||||
|
||||
|
@ -411,10 +426,15 @@ MSIPACKAGE *MSI_CreatePackage( MSIDATABASE *db )
|
|||
list_init( &package->progids );
|
||||
list_init( &package->RunningActions );
|
||||
|
||||
package->WordCount = msi_get_word_count( package );
|
||||
|
||||
/* OK, here is where we do a slew of things to the database to
|
||||
* prep for all that is to come as a package */
|
||||
|
||||
clone_properties(db);
|
||||
for (i=0; i<PROPERTY_HASH_SIZE; i++)
|
||||
list_init( &package->props[i] );
|
||||
|
||||
clone_properties( package );
|
||||
set_installer_properties(package);
|
||||
sprintfW(uilevel,szpi,gUILevel);
|
||||
MSI_SetPropertyW(package, szLevel, uilevel);
|
||||
|
@ -454,7 +474,7 @@ static LPCWSTR copy_package_to_temp( LPCWSTR szPackage, LPWSTR filename )
|
|||
return filename;
|
||||
}
|
||||
|
||||
static LPCWSTR msi_download_package( LPCWSTR szUrl, LPWSTR filename )
|
||||
LPCWSTR msi_download_file( LPCWSTR szUrl, LPWSTR filename )
|
||||
{
|
||||
LPINTERNET_CACHE_ENTRY_INFOW cache_entry;
|
||||
DWORD size = 0;
|
||||
|
@ -508,7 +528,7 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
|
|||
LPCWSTR file;
|
||||
|
||||
if ( UrlIsW( szPackage, URLIS_URL ) )
|
||||
file = msi_download_package( szPackage, temppath );
|
||||
file = msi_download_file( szPackage, temppath );
|
||||
else
|
||||
file = copy_package_to_temp( szPackage, temppath );
|
||||
|
||||
|
@ -518,7 +538,12 @@ UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
|
|||
DeleteFileW( file );
|
||||
|
||||
if( r != ERROR_SUCCESS )
|
||||
{
|
||||
if (GetLastError() == ERROR_FILE_NOT_FOUND)
|
||||
msi_ui_error( 4, MB_OK | MB_ICONWARNING );
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
package = MSI_CreatePackage( db );
|
||||
|
@ -563,6 +588,8 @@ UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phP
|
|||
if( ret == ERROR_SUCCESS )
|
||||
{
|
||||
*phPackage = alloc_msihandle( &package->hdr );
|
||||
if (! *phPackage)
|
||||
ret = ERROR_NOT_ENOUGH_MEMORY;
|
||||
msiobj_release( &package->hdr );
|
||||
}
|
||||
|
||||
|
@ -668,6 +695,10 @@ INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
|
|||
|
||||
action = MSI_RecordGetString(record, 1);
|
||||
action_text = MSI_RecordGetString(record, 2);
|
||||
|
||||
if (!action || !action_text)
|
||||
return IDOK;
|
||||
|
||||
deformat_string(package, action_text, &deformatted);
|
||||
|
||||
len = strlenW(timet) + strlenW(action) + strlenW(template_s);
|
||||
|
@ -805,6 +836,79 @@ out:
|
|||
}
|
||||
|
||||
/* property code */
|
||||
|
||||
typedef struct msi_property {
|
||||
struct list entry;
|
||||
LPWSTR key;
|
||||
LPWSTR value;
|
||||
} msi_property;
|
||||
|
||||
static UINT msi_prop_makehash( const WCHAR *str )
|
||||
{
|
||||
UINT hash = 0;
|
||||
|
||||
if (str==NULL)
|
||||
return hash;
|
||||
|
||||
while( *str )
|
||||
{
|
||||
hash ^= *str++;
|
||||
hash *= 53;
|
||||
hash = (hash<<5) | (hash>>27);
|
||||
}
|
||||
return hash % PROPERTY_HASH_SIZE;
|
||||
}
|
||||
|
||||
static msi_property *msi_prop_find( MSIPACKAGE *package, LPCWSTR key )
|
||||
{
|
||||
UINT hash = msi_prop_makehash( key );
|
||||
msi_property *prop;
|
||||
|
||||
LIST_FOR_EACH_ENTRY( prop, &package->props[hash], msi_property, entry )
|
||||
if (!lstrcmpW( prop->key, key ))
|
||||
return prop;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static msi_property *msi_prop_add( MSIPACKAGE *package, LPCWSTR key )
|
||||
{
|
||||
UINT hash = msi_prop_makehash( key );
|
||||
msi_property *prop;
|
||||
|
||||
prop = msi_alloc( sizeof *prop );
|
||||
if (prop)
|
||||
{
|
||||
prop->key = strdupW( key );
|
||||
prop->value = NULL;
|
||||
list_add_head( &package->props[hash], &prop->entry );
|
||||
}
|
||||
return prop;
|
||||
}
|
||||
|
||||
static void msi_delete_property( msi_property *prop )
|
||||
{
|
||||
list_remove( &prop->entry );
|
||||
msi_free( prop->key );
|
||||
msi_free( prop->value );
|
||||
msi_free( prop );
|
||||
}
|
||||
|
||||
static void msi_free_properties( MSIPACKAGE *package )
|
||||
{
|
||||
int i;
|
||||
|
||||
for ( i=0; i<PROPERTY_HASH_SIZE; i++ )
|
||||
{
|
||||
while ( !list_empty(&package->props[i]) )
|
||||
{
|
||||
msi_property *prop;
|
||||
prop = LIST_ENTRY( list_head( &package->props[i] ),
|
||||
msi_property, entry );
|
||||
msi_delete_property( prop );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue )
|
||||
{
|
||||
LPWSTR szwName = NULL, szwValue = NULL;
|
||||
|
@ -829,21 +933,7 @@ end:
|
|||
|
||||
UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
|
||||
{
|
||||
MSIQUERY *view;
|
||||
MSIRECORD *row;
|
||||
UINT rc;
|
||||
DWORD sz = 0;
|
||||
static const WCHAR Insert[]=
|
||||
{'I','N','S','E','R','T',' ','i','n','t','o',' ','`','_','P','r','o','p'
|
||||
,'e','r','t','y','`',' ','(','`','_','P','r','o','p','e','r','t','y','`'
|
||||
,',','`','V','a','l','u','e','`',')',' ','V','A','L','U','E','S'
|
||||
,' ','(','?',',','?',')',0};
|
||||
static const WCHAR Update[]=
|
||||
{'U','P','D','A','T','E',' ','_','P','r','o','p','e'
|
||||
,'r','t','y',' ','s','e','t',' ','`','V','a','l','u','e','`',' ','='
|
||||
,' ','?',' ','w','h','e','r','e',' ','`','_','P','r','o','p'
|
||||
,'e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
|
||||
WCHAR Query[1024];
|
||||
msi_property *prop;
|
||||
|
||||
TRACE("%p %s %s\n", package, debugstr_w(szName), debugstr_w(szValue));
|
||||
|
||||
|
@ -854,35 +944,22 @@ UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
|
|||
if (!szName[0])
|
||||
return szValue ? ERROR_FUNCTION_FAILED : ERROR_SUCCESS;
|
||||
|
||||
rc = MSI_GetPropertyW(package,szName,0,&sz);
|
||||
if (rc==ERROR_MORE_DATA || rc == ERROR_SUCCESS)
|
||||
prop = msi_prop_find( package, szName );
|
||||
if (!prop)
|
||||
prop = msi_prop_add( package, szName );
|
||||
|
||||
if (!prop)
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
if (szValue)
|
||||
{
|
||||
sprintfW(Query,Update,szName);
|
||||
|
||||
row = MSI_CreateRecord(1);
|
||||
MSI_RecordSetStringW(row,1,szValue);
|
||||
|
||||
msi_free( prop->value );
|
||||
prop->value = strdupW( szValue );
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpyW(Query,Insert);
|
||||
msi_delete_property( prop );
|
||||
|
||||
row = MSI_CreateRecord(2);
|
||||
MSI_RecordSetStringW(row,1,szName);
|
||||
MSI_RecordSetStringW(row,2,szValue);
|
||||
}
|
||||
|
||||
rc = MSI_DatabaseOpenViewW(package->db,Query,&view);
|
||||
if (rc == ERROR_SUCCESS)
|
||||
{
|
||||
rc = MSI_ViewExecute(view,row);
|
||||
|
||||
MSI_ViewClose(view);
|
||||
msiobj_release(&view->hdr);
|
||||
}
|
||||
msiobj_release(&row->hdr);
|
||||
|
||||
return rc;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
|
||||
|
@ -898,59 +975,79 @@ UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue
|
|||
return ret;
|
||||
}
|
||||
|
||||
static MSIRECORD *MSI_GetPropertyRow( MSIPACKAGE *package, LPCWSTR name )
|
||||
{
|
||||
static const WCHAR query[]=
|
||||
{'S','E','L','E','C','T',' ','`','V','a','l','u','e','`',' ',
|
||||
'F','R','O','M',' ' ,'`','_','P','r','o','p','e','r','t','y','`',
|
||||
' ','W','H','E','R','E',' ' ,'`','_','P','r','o','p','e','r','t','y','`',
|
||||
'=','\'','%','s','\'',0};
|
||||
|
||||
if (!name || !name[0])
|
||||
return NULL;
|
||||
|
||||
return MSI_QueryGetRecord( package->db, query, name );
|
||||
}
|
||||
|
||||
/* internal function, not compatible with MsiGetPropertyW */
|
||||
UINT MSI_GetPropertyW( MSIPACKAGE *package, LPCWSTR szName,
|
||||
LPWSTR szValueBuf, DWORD* pchValueBuf )
|
||||
{
|
||||
MSIRECORD *row;
|
||||
UINT rc = ERROR_FUNCTION_FAILED;
|
||||
|
||||
row = MSI_GetPropertyRow( package, szName );
|
||||
msi_property *prop;
|
||||
UINT r, len;
|
||||
|
||||
if (*pchValueBuf > 0)
|
||||
szValueBuf[0] = 0;
|
||||
|
||||
if (row)
|
||||
{
|
||||
rc = MSI_RecordGetStringW(row,1,szValueBuf,pchValueBuf);
|
||||
msiobj_release(&row->hdr);
|
||||
}
|
||||
|
||||
if (rc == ERROR_SUCCESS)
|
||||
TRACE("returning %s for property %s\n", debugstr_w(szValueBuf),
|
||||
debugstr_w(szName));
|
||||
else if (rc == ERROR_MORE_DATA)
|
||||
TRACE("need %li sized buffer for %s\n", *pchValueBuf,
|
||||
debugstr_w(szName));
|
||||
else
|
||||
prop = msi_prop_find( package, szName );
|
||||
if (!prop)
|
||||
{
|
||||
*pchValueBuf = 0;
|
||||
TRACE("property %s not found\n", debugstr_w(szName));
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
return rc;
|
||||
if (prop->value)
|
||||
{
|
||||
len = lstrlenW( prop->value );
|
||||
lstrcpynW(szValueBuf, prop->value, *pchValueBuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
len = 1;
|
||||
if( *pchValueBuf > 0 )
|
||||
szValueBuf[0] = 0;
|
||||
}
|
||||
|
||||
TRACE("%s -> %s\n", debugstr_w(szName), debugstr_w(szValueBuf));
|
||||
|
||||
if ( *pchValueBuf <= len )
|
||||
{
|
||||
TRACE("have %lu, need %u -> ERROR_MORE_DATA\n", *pchValueBuf, len);
|
||||
r = ERROR_MORE_DATA;
|
||||
}
|
||||
else
|
||||
r = ERROR_SUCCESS;
|
||||
|
||||
*pchValueBuf = len;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static UINT MSI_GetProperty( MSIHANDLE handle, LPCWSTR name,
|
||||
LPWSTR msi_dup_property( MSIPACKAGE *package, LPCWSTR szName )
|
||||
{
|
||||
msi_property *prop;
|
||||
LPWSTR value = NULL;
|
||||
|
||||
prop = msi_prop_find( package, szName );
|
||||
if (prop)
|
||||
value = strdupW( prop->value );
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
int msi_get_property_int( MSIPACKAGE *package, LPCWSTR name, int value )
|
||||
{
|
||||
msi_property *prop;
|
||||
|
||||
prop = msi_prop_find( package, name );
|
||||
if (prop)
|
||||
value = atoiW( prop->value );
|
||||
return value;
|
||||
}
|
||||
|
||||
static UINT MSI_GetProperty( MSIHANDLE handle, LPCWSTR name,
|
||||
awstring *szValueBuf, DWORD* pchValueBuf )
|
||||
{
|
||||
static const WCHAR empty[] = {0};
|
||||
msi_property *prop;
|
||||
MSIPACKAGE *package;
|
||||
MSIRECORD *row = NULL;
|
||||
UINT r;
|
||||
LPCWSTR val = NULL;
|
||||
|
||||
|
@ -964,17 +1061,15 @@ static UINT MSI_GetProperty( MSIHANDLE handle, LPCWSTR name,
|
|||
if (!package)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
row = MSI_GetPropertyRow( package, name );
|
||||
if (row)
|
||||
val = MSI_RecordGetString( row, 1 );
|
||||
prop = msi_prop_find( package, name );
|
||||
if (prop)
|
||||
val = prop->value;
|
||||
|
||||
if (!val)
|
||||
val = empty;
|
||||
|
||||
r = msi_strcpy_to_awstring( val, szValueBuf, pchValueBuf );
|
||||
|
||||
if (row)
|
||||
msiobj_release( &row->hdr );
|
||||
msiobj_release( &package->hdr );
|
||||
|
||||
return r;
|
||||
|
@ -998,7 +1093,7 @@ UINT WINAPI MsiGetPropertyA( MSIHANDLE hInstall, LPCSTR szName,
|
|||
msi_free( name );
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
UINT WINAPI MsiGetPropertyW( MSIHANDLE hInstall, LPCWSTR szName,
|
||||
LPWSTR szValueBuf, DWORD* pchValueBuf )
|
||||
{
|
||||
|
|
|
@ -76,6 +76,8 @@ UINT WINAPI MsiEnableUIPreview( MSIHANDLE hdb, MSIHANDLE* phPreview )
|
|||
*phPreview = alloc_msihandle( &preview->hdr );
|
||||
msiobj_release( &preview->hdr );
|
||||
r = ERROR_SUCCESS;
|
||||
if (! *phPreview)
|
||||
r = ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
msiobj_release( &db->hdr );
|
||||
|
||||
|
|
|
@ -121,6 +121,8 @@ UINT JOIN_CreateView( MSIDATABASE *db, MSIVIEW **view,
|
|||
LPCWSTR left, LPCWSTR right,
|
||||
struct expr *cond );
|
||||
|
||||
UINT ALTER_CreateView( MSIDATABASE *db, MSIVIEW **view, LPCWSTR name, int hold );
|
||||
|
||||
int sqliteGetToken(const WCHAR *z, int *tokenType);
|
||||
|
||||
#endif /* __WINE_MSI_QUERY_H */
|
||||
|
|
|
@ -307,7 +307,7 @@ UINT MSI_RecordGetStringA(MSIRECORD *rec, unsigned int iField,
|
|||
NULL, 0 , NULL, NULL);
|
||||
WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1,
|
||||
szValue, *pcchValue, NULL, NULL);
|
||||
if( *pcchValue && len>*pcchValue )
|
||||
if( szValue && *pcchValue && len>*pcchValue )
|
||||
szValue[*pcchValue-1] = 0;
|
||||
if( len )
|
||||
len--;
|
||||
|
@ -321,7 +321,7 @@ UINT MSI_RecordGetStringA(MSIRECORD *rec, unsigned int iField,
|
|||
break;
|
||||
}
|
||||
|
||||
if( *pcchValue <= len )
|
||||
if( szValue && *pcchValue <= len )
|
||||
ret = ERROR_MORE_DATA;
|
||||
*pcchValue = len;
|
||||
|
||||
|
@ -383,13 +383,13 @@ UINT MSI_RecordGetStringW(MSIRECORD *rec, unsigned int iField,
|
|||
break;
|
||||
case MSIFIELD_NULL:
|
||||
len = 1;
|
||||
if( *pcchValue > 0 )
|
||||
if( szValue && *pcchValue > 0 )
|
||||
szValue[0] = 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if( *pcchValue <= len )
|
||||
if( szValue && *pcchValue <= len )
|
||||
ret = ERROR_MORE_DATA;
|
||||
*pcchValue = len;
|
||||
|
||||
|
|
|
@ -919,6 +919,7 @@ UINT WINAPI MSI_EnumComponentQualifiers( LPCWSTR szComponent, DWORD iIndex,
|
|||
if (val_sz > val_max)
|
||||
{
|
||||
val_max = val_sz + sizeof (WCHAR);
|
||||
msi_free( val );
|
||||
val = msi_alloc( val_max * sizeof (WCHAR) );
|
||||
if (!val)
|
||||
goto end;
|
||||
|
|
|
@ -72,11 +72,15 @@ struct regsvr_coclass {
|
|||
LPCSTR ips; /* can be NULL to omit */
|
||||
LPCSTR ips32; /* can be NULL to omit */
|
||||
LPCSTR ips32_tmodel; /* can be NULL to omit, if apartment, iph32 must be set */
|
||||
DWORD flags;
|
||||
LPCSTR progid; /* can be NULL to omit */
|
||||
LPCSTR viprogid; /* can be NULL to omit */
|
||||
LPCSTR progid_extra; /* can be NULL to omit */
|
||||
};
|
||||
|
||||
/* flags for regsvr_coclass.flags */
|
||||
#define PROGID_CLSID 0x00000010
|
||||
|
||||
static HRESULT register_coclasses(struct regsvr_coclass const *list);
|
||||
static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
|
||||
|
||||
|
@ -296,7 +300,8 @@ static HRESULT register_coclasses(struct regsvr_coclass const *list) {
|
|||
list->progid);
|
||||
if (res != ERROR_SUCCESS) goto error_close_clsid_key;
|
||||
|
||||
res = register_progid(buf, list->progid, NULL,
|
||||
res = register_progid(list->flags & PROGID_CLSID ? buf : NULL,
|
||||
list->progid, NULL,
|
||||
list->name, list->progid_extra);
|
||||
if (res != ERROR_SUCCESS) goto error_close_clsid_key;
|
||||
}
|
||||
|
@ -306,7 +311,8 @@ static HRESULT register_coclasses(struct regsvr_coclass const *list) {
|
|||
list->viprogid);
|
||||
if (res != ERROR_SUCCESS) goto error_close_clsid_key;
|
||||
|
||||
res = register_progid(buf, list->viprogid, list->progid,
|
||||
res = register_progid(list->flags & PROGID_CLSID ? buf : NULL,
|
||||
list->viprogid, list->progid,
|
||||
list->name, list->progid_extra);
|
||||
if (res != ERROR_SUCCESS) goto error_close_clsid_key;
|
||||
}
|
||||
|
@ -526,7 +532,8 @@ static struct regsvr_coclass const coclass_list[] = {
|
|||
NULL,
|
||||
"msi.dll",
|
||||
"Apartment",
|
||||
"WindowsInstaller.Installer",
|
||||
PROGID_CLSID,
|
||||
"IMsiServer",
|
||||
NULL
|
||||
},
|
||||
{
|
||||
|
@ -536,6 +543,7 @@ static struct regsvr_coclass const coclass_list[] = {
|
|||
NULL,
|
||||
"msi.dll",
|
||||
NULL,
|
||||
PROGID_CLSID,
|
||||
"WindowsInstaller.Message",
|
||||
NULL
|
||||
},
|
||||
|
@ -546,6 +554,7 @@ static struct regsvr_coclass const coclass_list[] = {
|
|||
NULL,
|
||||
"msi.dll",
|
||||
"Apartment",
|
||||
0,
|
||||
"WindowsInstaller.Installer",
|
||||
NULL
|
||||
},
|
||||
|
@ -556,6 +565,7 @@ static struct regsvr_coclass const coclass_list[] = {
|
|||
NULL,
|
||||
"msi.dll",
|
||||
"Apartment",
|
||||
PROGID_CLSID,
|
||||
"WindowsInstaller.Installer",
|
||||
NULL
|
||||
},
|
||||
|
@ -566,6 +576,7 @@ static struct regsvr_coclass const coclass_list[] = {
|
|||
NULL,
|
||||
"msi.dll",
|
||||
"Apartment",
|
||||
0,
|
||||
"WindowsInstaller.Installer",
|
||||
NULL
|
||||
},
|
||||
|
|
|
@ -408,14 +408,15 @@ UINT WINAPI MsiSourceListAddSourceW( LPCWSTR szProduct, LPCWSTR szUserName,
|
|||
INT ret;
|
||||
LPWSTR sidstr = NULL;
|
||||
DWORD sidsize = 0;
|
||||
DWORD domsize = 0;
|
||||
|
||||
TRACE("%s %s %s\n", debugstr_w(szProduct), debugstr_w(szUserName), debugstr_w(szSource));
|
||||
|
||||
if (LookupAccountNameW(NULL, szUserName, NULL, &sidsize, NULL, NULL, NULL))
|
||||
if (LookupAccountNameW(NULL, szUserName, NULL, &sidsize, NULL, &domsize, NULL))
|
||||
{
|
||||
PSID psid = msi_alloc(sidsize);
|
||||
|
||||
if (LookupAccountNameW(NULL, szUserName, psid, &sidsize, NULL, NULL, NULL))
|
||||
if (LookupAccountNameW(NULL, szUserName, psid, &sidsize, NULL, &domsize, NULL))
|
||||
ConvertSidToStringSidW(psid, &sidstr);
|
||||
|
||||
msi_free(psid);
|
||||
|
|
|
@ -79,15 +79,15 @@ static struct expr * EXPR_wildcard( void *info );
|
|||
int integer;
|
||||
}
|
||||
|
||||
%token TK_ABORT TK_AFTER TK_AGG_FUNCTION TK_ALL TK_AND TK_AS TK_ASC
|
||||
%token TK_ABORT TK_AFTER TK_AGG_FUNCTION TK_ALL TK_ALTER TK_AND TK_AS TK_ASC
|
||||
%token TK_BEFORE TK_BEGIN TK_BETWEEN TK_BITAND TK_BITNOT TK_BITOR TK_BY
|
||||
%token TK_CASCADE TK_CASE TK_CHAR TK_CHECK TK_CLUSTER TK_COLLATE TK_COLUMN
|
||||
%token TK_COMMA TK_COMMENT TK_COMMIT TK_CONCAT TK_CONFLICT
|
||||
%token TK_COMMA TK_COMMENT TK_COMMIT TK_CONCAT TK_CONFLICT
|
||||
%token TK_CONSTRAINT TK_COPY TK_CREATE
|
||||
%token TK_DEFAULT TK_DEFERRABLE TK_DEFERRED TK_DELETE TK_DELIMITERS TK_DESC
|
||||
%token TK_DISTINCT TK_DOT TK_DROP TK_EACH
|
||||
%token TK_ELSE TK_END TK_END_OF_FILE TK_EQ TK_EXCEPT TK_EXPLAIN
|
||||
%token TK_FAIL TK_FLOAT TK_FOR TK_FOREIGN TK_FROM TK_FUNCTION
|
||||
%token TK_FAIL TK_FLOAT TK_FOR TK_FOREIGN TK_FREE TK_FROM TK_FUNCTION
|
||||
%token TK_GE TK_GLOB TK_GROUP TK_GT
|
||||
%token TK_HAVING TK_HOLD
|
||||
%token TK_IGNORE TK_ILLEGAL TK_IMMEDIATE TK_IN TK_INDEX TK_INITIALLY
|
||||
|
@ -127,10 +127,10 @@ static struct expr * EXPR_wildcard( void *info );
|
|||
%type <column_list> selcollist column column_and_type column_def table_def
|
||||
%type <column_list> column_assignment update_assign_list constlist
|
||||
%type <query> query multifrom from fromtable selectfrom unorderedsel
|
||||
%type <query> oneupdate onedelete oneselect onequery onecreate oneinsert
|
||||
%type <query> oneupdate onedelete oneselect onequery onecreate oneinsert onealter
|
||||
%type <expr> expr val column_val const_val
|
||||
%type <column_type> column_type data_type data_type_l data_count
|
||||
%type <integer> number
|
||||
%type <integer> number alterop
|
||||
|
||||
/* Reference: http://mates.ms.mff.cuni.cz/oracle/doc/ora815nt/server.815/a67779/operator.htm */
|
||||
%left TK_OR
|
||||
|
@ -156,6 +156,7 @@ onequery:
|
|||
| oneinsert
|
||||
| oneupdate
|
||||
| onedelete
|
||||
| onealter
|
||||
;
|
||||
|
||||
oneinsert:
|
||||
|
@ -235,6 +236,30 @@ onedelete:
|
|||
}
|
||||
;
|
||||
|
||||
onealter:
|
||||
TK_ALTER TK_TABLE table alterop
|
||||
{
|
||||
SQL_input* sql = (SQL_input*) info;
|
||||
MSIVIEW *alter = NULL;
|
||||
|
||||
ALTER_CreateView( sql->db, &alter, $3, $4 );
|
||||
if( !alter )
|
||||
YYABORT;
|
||||
$$ = alter;
|
||||
}
|
||||
;
|
||||
|
||||
alterop:
|
||||
TK_HOLD
|
||||
{
|
||||
$$ = 1;
|
||||
}
|
||||
| TK_FREE
|
||||
{
|
||||
$$ = -1;
|
||||
}
|
||||
;
|
||||
|
||||
table_def:
|
||||
column_def TK_PRIMARY TK_KEY selcollist
|
||||
{
|
||||
|
|
|
@ -435,13 +435,17 @@ UINT msi_id_refcount( string_table *st, UINT i )
|
|||
return st->strings[i].refcount;
|
||||
}
|
||||
|
||||
UINT msi_string_totalsize( string_table *st, UINT *total )
|
||||
UINT msi_string_totalsize( string_table *st, UINT *datasize, UINT *poolsize )
|
||||
{
|
||||
UINT size = 0, i, len;
|
||||
UINT i, len, max, holesize;
|
||||
|
||||
if( st->strings[0].str || st->strings[0].refcount )
|
||||
ERR("oops. element 0 has a string\n");
|
||||
*total = 0;
|
||||
|
||||
*poolsize = 4;
|
||||
*datasize = 0;
|
||||
max = 1;
|
||||
holesize = 0;
|
||||
for( i=1; i<st->maxcount; i++ )
|
||||
{
|
||||
if( st->strings[i].str )
|
||||
|
@ -451,12 +455,18 @@ UINT msi_string_totalsize( string_table *st, UINT *total )
|
|||
st->strings[i].str, -1, NULL, 0, NULL, NULL);
|
||||
if( len )
|
||||
len--;
|
||||
size += len;
|
||||
*total = (i+1);
|
||||
(*datasize) += len;
|
||||
if (len>0xffff)
|
||||
(*poolsize) += 4;
|
||||
max = i + 1;
|
||||
(*poolsize) += holesize + 4;
|
||||
holesize = 0;
|
||||
}
|
||||
else
|
||||
holesize += 4;
|
||||
}
|
||||
TRACE("%u/%u strings %u bytes codepage %x\n", *total, st->maxcount, size, st->codepage );
|
||||
return size;
|
||||
TRACE("data %u pool %u codepage %x\n", *datasize, *poolsize, st->codepage );
|
||||
return max;
|
||||
}
|
||||
|
||||
UINT msi_string_get_codepage( string_table *st )
|
||||
|
|
|
@ -468,6 +468,8 @@ UINT WINAPI MsiGetSummaryInformationW( MSIHANDLE hDatabase,
|
|||
*pHandle = alloc_msihandle( &si->hdr );
|
||||
if( *pHandle )
|
||||
ret = ERROR_SUCCESS;
|
||||
else
|
||||
ret = ERROR_NOT_ENOUGH_MEMORY;
|
||||
msiobj_release( &si->hdr );
|
||||
}
|
||||
|
||||
|
|
|
@ -686,7 +686,7 @@ string_table *load_string_table( IStorage *stg )
|
|||
CHAR *data = NULL;
|
||||
USHORT *pool = NULL;
|
||||
UINT r, datasize = 0, poolsize = 0, codepage;
|
||||
DWORD i, count, offset, len, n;
|
||||
DWORD i, count, offset, len, n, refs;
|
||||
static const WCHAR szStringData[] = {
|
||||
'_','S','t','r','i','n','g','D','a','t','a',0 };
|
||||
static const WCHAR szStringPool[] = {
|
||||
|
@ -708,38 +708,51 @@ string_table *load_string_table( IStorage *stg )
|
|||
|
||||
offset = 0;
|
||||
n = 1;
|
||||
for( i=1; i<count; i++ )
|
||||
i = 1;
|
||||
while( i<count )
|
||||
{
|
||||
len = pool[i*2];
|
||||
/* the string reference count is always the second word */
|
||||
refs = pool[i*2+1];
|
||||
|
||||
/* empty entries have two zeros, still have a string id */
|
||||
if (pool[i*2] == 0 && refs == 0)
|
||||
{
|
||||
i++;
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* If a string is over 64k, the previous string entry is made null
|
||||
* and its the high word of the length is inserted in the null string's
|
||||
* reference count field.
|
||||
*/
|
||||
if( pool[i*2-2] == 0 && pool[i*2-1] )
|
||||
len += pool[i*2+1] * 0x10000;
|
||||
if( pool[i*2] == 0)
|
||||
{
|
||||
len = (pool[i*2+3] << 16) + pool[i*2+2];
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
len = pool[i*2];
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if( (offset + len) > datasize )
|
||||
if ( (offset + len) > datasize )
|
||||
{
|
||||
ERR("string table corrupt?\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* don't add the high word of a string's length as a string */
|
||||
if ( len || !pool[i*2+1] )
|
||||
{
|
||||
r = msi_addstring( st, n, data+offset, len, pool[i*2+1] );
|
||||
if( r != n )
|
||||
ERR("Failed to add string %ld\n", n );
|
||||
n++;
|
||||
}
|
||||
|
||||
r = msi_addstring( st, n, data+offset, len, refs );
|
||||
if( r != n )
|
||||
ERR("Failed to add string %ld\n", n );
|
||||
n++;
|
||||
offset += len;
|
||||
}
|
||||
|
||||
if ( datasize != offset )
|
||||
ERR("string table load failed! (%08x != %08lx)\n", datasize, offset );
|
||||
ERR("string table load failed! (%08x != %08lx), please report\n", datasize, offset );
|
||||
|
||||
TRACE("Loaded %ld strings\n", count);
|
||||
|
||||
|
@ -752,7 +765,7 @@ end:
|
|||
|
||||
static UINT save_string_table( MSIDATABASE *db )
|
||||
{
|
||||
UINT i, count, datasize, poolsize, sz, used, r, codepage;
|
||||
UINT i, count, datasize = 0, poolsize = 0, sz, used, r, codepage, n;
|
||||
UINT ret = ERROR_FUNCTION_FAILED;
|
||||
static const WCHAR szStringData[] = {
|
||||
'_','S','t','r','i','n','g','D','a','t','a',0 };
|
||||
|
@ -764,8 +777,9 @@ static UINT save_string_table( MSIDATABASE *db )
|
|||
TRACE("\n");
|
||||
|
||||
/* construct the new table in memory first */
|
||||
datasize = msi_string_totalsize( db->strings, &count );
|
||||
poolsize = (count + 1)*2*sizeof(USHORT);
|
||||
count = msi_string_totalsize( db->strings, &datasize, &poolsize );
|
||||
|
||||
TRACE("%u %u %u\n", count, datasize, poolsize );
|
||||
|
||||
pool = msi_alloc( poolsize );
|
||||
if( ! pool )
|
||||
|
@ -784,6 +798,7 @@ static UINT save_string_table( MSIDATABASE *db )
|
|||
codepage = msi_string_get_codepage( db->strings );
|
||||
pool[0]=codepage&0xffff;
|
||||
pool[1]=(codepage>>16);
|
||||
n = 1;
|
||||
for( i=1; i<count; i++ )
|
||||
{
|
||||
sz = datasize - used;
|
||||
|
@ -795,9 +810,20 @@ static UINT save_string_table( MSIDATABASE *db )
|
|||
}
|
||||
if( sz && (sz < (datasize - used ) ) )
|
||||
sz--;
|
||||
TRACE("adding %u bytes %s\n", sz, debugstr_a(data+used) );
|
||||
pool[ i*2 ] = sz;
|
||||
pool[ i*2 + 1 ] = msi_id_refcount( db->strings, i );
|
||||
|
||||
pool[ n*2 + 1 ] = msi_id_refcount( db->strings, i );
|
||||
if (sz < 0x10000)
|
||||
{
|
||||
pool[ n*2 ] = sz;
|
||||
n++;
|
||||
}
|
||||
else
|
||||
{
|
||||
pool[ n*2 ] = 0;
|
||||
pool[ n*2 + 2 ] = sz&0xffff;
|
||||
pool[ n*2 + 3 ] = (sz>>16);
|
||||
n += 2;
|
||||
}
|
||||
used += sz;
|
||||
if( used > datasize )
|
||||
{
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "wine/debug.h"
|
||||
#include "winnls.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "query.h"
|
||||
#include "sql.tab.h"
|
||||
|
||||
|
@ -35,120 +35,230 @@ WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
|||
*/
|
||||
typedef struct Keyword Keyword;
|
||||
struct Keyword {
|
||||
const char *zName; /* The keyword name */
|
||||
const WCHAR *zName; /* The keyword name */
|
||||
int tokenType; /* The token value for this keyword */
|
||||
};
|
||||
|
||||
static const WCHAR ABORT_W[] = { 'A','B','O','R','T',0 };
|
||||
static const WCHAR AFTER_W[] = { 'A','F','T','E','R',0 };
|
||||
static const WCHAR ALTER_W[] = { 'A','L','T','E','R',0 };
|
||||
static const WCHAR ALL_W[] = { 'A','L','L',0 };
|
||||
static const WCHAR AND_W[] = { 'A','N','D',0 };
|
||||
static const WCHAR AS_W[] = { 'A','S',0 };
|
||||
static const WCHAR ASC_W[] = { 'A','S','C',0 };
|
||||
static const WCHAR BEFORE_W[] = { 'B','E','F','O','R','E',0 };
|
||||
static const WCHAR BEGIN_W[] = { 'B','E','G','I','N','W',0 };
|
||||
static const WCHAR BETWEEN_W[] = { 'B','E','T','W','E','E','N',0 };
|
||||
static const WCHAR BY_W[] = { 'B','Y',0 };
|
||||
static const WCHAR CASCADE_W[] = { 'C','A','S','C','A','D','E',0 };
|
||||
static const WCHAR CASE_W[] = { 'C','A','S','E',0 };
|
||||
static const WCHAR CHAR_W[] = { 'C','H','A','R',0 };
|
||||
static const WCHAR CHARACTER_W[] = { 'C','H','A','R','A','C','T','E','R',0 };
|
||||
static const WCHAR CHECK_W[] = { 'C','H','E','C','K',0 };
|
||||
static const WCHAR CLUSTER_W[] = { 'C','L','U','S','T','E','R',0 };
|
||||
static const WCHAR COLLATE_W[] = { 'C','O','L','L','A','T','E',0 };
|
||||
static const WCHAR COMMIT_W[] = { 'C','O','M','M','I','T',0 };
|
||||
static const WCHAR CONFLICT_W[] = { 'C','O','N','F','L','I','C','T',0 };
|
||||
static const WCHAR CONSTRAINT_W[] = { 'C','O','N','S','T','R','A','I','N','T',0 };
|
||||
static const WCHAR COPY_W[] = { 'C','O','P','Y',0 };
|
||||
static const WCHAR CREATE_W[] = { 'C','R','E','A','T','E',0 };
|
||||
static const WCHAR CROSS_W[] = { 'C','R','O','S','S',0 };
|
||||
static const WCHAR DEFAULT_W[] = { 'D','E','F','A','U','L','T',0 };
|
||||
static const WCHAR DEFERRED_W[] = { 'D','E','F','E','R','R','E','D',0 };
|
||||
static const WCHAR DEFERRABLE_W[] = { 'D','E','F','E','R','R','A','B','L','E',0 };
|
||||
static const WCHAR DELETE_W[] = { 'D','E','L','E','T','E',0 };
|
||||
static const WCHAR DELIMITERS_W[] = { 'D','E','L','I','M','I','T','E','R','S',0 };
|
||||
static const WCHAR DESC_W[] = { 'D','E','S','C',0 };
|
||||
static const WCHAR DISTINCT_W[] = { 'D','I','S','T','I','N','C','T',0 };
|
||||
static const WCHAR DROP_W[] = { 'D','R','O','P',0 };
|
||||
static const WCHAR END_W[] = { 'E','N','D',0 };
|
||||
static const WCHAR EACH_W[] = { 'E','A','C','H',0 };
|
||||
static const WCHAR ELSE_W[] = { 'E','L','S','E',0 };
|
||||
static const WCHAR EXCEPT_W[] = { 'E','X','C','E','P','T',0 };
|
||||
static const WCHAR EXPLAIN_W[] = { 'E','X','P','L','A','I','N',0 };
|
||||
static const WCHAR FAIL_W[] = { 'F','A','I','L',0 };
|
||||
static const WCHAR FOR_W[] = { 'F','O','R',0 };
|
||||
static const WCHAR FOREIGN_W[] = { 'F','O','R','E','I','G','N',0 };
|
||||
static const WCHAR FREE_W[] = { 'F','R','E','E',0 };
|
||||
static const WCHAR FROM_W[] = { 'F','R','O','M',0 };
|
||||
static const WCHAR FULL_W[] = { 'F','U','L','L',0 };
|
||||
static const WCHAR GLOB_W[] = { 'G','L','O','B',0 };
|
||||
static const WCHAR GROUP_W[] = { 'G','R','O','U','P',0 };
|
||||
static const WCHAR HAVING_W[] = { 'H','A','V','I','N','G',0 };
|
||||
static const WCHAR HOLD_W[] = { 'H','O','L','D',0 };
|
||||
static const WCHAR IGNORE_W[] = { 'I','G','N','O','R','E',0 };
|
||||
static const WCHAR IMMEDIATE_W[] = { 'I','M','M','E','D','I','A','T','E',0 };
|
||||
static const WCHAR IN_W[] = { 'I','N',0 };
|
||||
static const WCHAR INDEX_W[] = { 'I','N','D','E','X',0 };
|
||||
static const WCHAR INITIALLY_W[] = { 'I','N','I','T','I','A','L','L','Y',0 };
|
||||
static const WCHAR INNER_W[] = { 'I','N','N','E','R',0 };
|
||||
static const WCHAR INSERT_W[] = { 'I','N','S','E','R','T',0 };
|
||||
static const WCHAR INSTEAD_W[] = { 'I','N','S','T','E','A','D',0 };
|
||||
static const WCHAR INT_W[] = { 'I','N','T',0 };
|
||||
static const WCHAR INTERSECT_W[] = { 'I','N','T','E','R','S','E','C','T',0 };
|
||||
static const WCHAR INTO_W[] = { 'I','N','T','O',0 };
|
||||
static const WCHAR IS_W[] = { 'I','S',0 };
|
||||
static const WCHAR ISNULL_W[] = { 'I','S','N','U','L','L',0 };
|
||||
static const WCHAR JOIN_W[] = { 'J','O','I','N',0 };
|
||||
static const WCHAR KEY_W[] = { 'K','E','Y',0 };
|
||||
static const WCHAR LEFT_W[] = { 'L','E','F','T',0 };
|
||||
static const WCHAR LIKE_W[] = { 'L','I','K','E',0 };
|
||||
static const WCHAR LIMIT_W[] = { 'L','I','M','I','T',0 };
|
||||
static const WCHAR LOCALIZABLE_W[] = { 'L','O','C','A','L','I','Z','A','B','L','E',0 };
|
||||
static const WCHAR LONG_W[] = { 'L','O','N','G',0 };
|
||||
static const WCHAR LONGCHAR_W[] = { 'L','O','N','G','C','H','A','R',0 };
|
||||
static const WCHAR MATCH_W[] = { 'M','A','T','C','H',0 };
|
||||
static const WCHAR NATURAL_W[] = { 'N','A','T','U','R','A','L',0 };
|
||||
static const WCHAR NOT_W[] = { 'N','O','T',0 };
|
||||
static const WCHAR NOTNULL_W[] = { 'N','O','T','N','U','L','L',0 };
|
||||
static const WCHAR NULL_W[] = { 'N','U','L','L',0 };
|
||||
static const WCHAR OBJECT_W[] = { 'O','B','J','E','C','T',0 };
|
||||
static const WCHAR OF_W[] = { 'O','F',0 };
|
||||
static const WCHAR OFFSET_W[] = { 'O','F','F','S','E','T',0 };
|
||||
static const WCHAR ON_W[] = { 'O','N',0 };
|
||||
static const WCHAR OR_W[] = { 'O','R',0 };
|
||||
static const WCHAR ORDER_W[] = { 'O','R','D','E','R',0 };
|
||||
static const WCHAR OUTER_W[] = { 'O','U','T','E','R',0 };
|
||||
static const WCHAR PRAGMA_W[] = { 'P','R','A','G','M','A',0 };
|
||||
static const WCHAR PRIMARY_W[] = { 'P','R','I','M','A','R','Y',0 };
|
||||
static const WCHAR RAISE_W[] = { 'R','A','I','S','E',0 };
|
||||
static const WCHAR REFERENCES_W[] = { 'R','E','F','E','R','E','N','C','E','S',0 };
|
||||
static const WCHAR REPLACE_W[] = { 'R','E','P','L','A','C','E',0 };
|
||||
static const WCHAR RESTRICT_W[] = { 'R','E','S','T','R','I','C','T',0 };
|
||||
static const WCHAR RIGHT_W[] = { 'R','I','G','H','T',0 };
|
||||
static const WCHAR ROLLBACK_W[] = { 'R','O','L','L','B','A','C','K',0 };
|
||||
static const WCHAR ROW_W[] = { 'R','O','W',0 };
|
||||
static const WCHAR SELECT_W[] = { 'S','E','L','E','C','T',0 };
|
||||
static const WCHAR SET_W[] = { 'S','E','T',0 };
|
||||
static const WCHAR SHORT_W[] = { 'S','H','O','R','T',0 };
|
||||
static const WCHAR STATEMENT_W[] = { 'S','T','A','T','E','M','E','N','T',0 };
|
||||
static const WCHAR TABLE_W[] = { 'T','A','B','L','E',0 };
|
||||
static const WCHAR TEMP_W[] = { 'T','E','M','P',0 };
|
||||
static const WCHAR TEMPORARY_W[] = { 'T','E','M','P','O','R','A','R','Y',0 };
|
||||
static const WCHAR THEN_W[] = { 'T','H','E','N',0 };
|
||||
static const WCHAR TRANSACTION_W[] = { 'T','R','A','N','S','A','C','T','I','O','N',0 };
|
||||
static const WCHAR TRIGGER_W[] = { 'T','R','I','G','G','E','R',0 };
|
||||
static const WCHAR UNION_W[] = { 'U','N','I','O','N',0 };
|
||||
static const WCHAR UNIQUE_W[] = { 'U','N','I','Q','U','E',0 };
|
||||
static const WCHAR UPDATE_W[] = { 'U','P','D','A','T','E',0 };
|
||||
static const WCHAR USING_W[] = { 'U','S','I','N','G',0 };
|
||||
static const WCHAR VACUUM_W[] = { 'V','A','C','U','U','M',0 };
|
||||
static const WCHAR VALUES_W[] = { 'V','A','L','U','E','S',0 };
|
||||
static const WCHAR VIEW_W[] = { 'V','I','E','W',0 };
|
||||
static const WCHAR WHEN_W[] = { 'W','H','E','N',0 };
|
||||
static const WCHAR WHERE_W[] = { 'W','H','E','R','E',0 };
|
||||
|
||||
/*
|
||||
** These are the keywords
|
||||
*/
|
||||
static const Keyword aKeywordTable[] = {
|
||||
{ "ABORT", TK_ABORT },
|
||||
{ "AFTER", TK_AFTER },
|
||||
{ "ALL", TK_ALL },
|
||||
{ "AND", TK_AND },
|
||||
{ "AS", TK_AS },
|
||||
{ "ASC", TK_ASC },
|
||||
{ "BEFORE", TK_BEFORE },
|
||||
{ "BEGIN", TK_BEGIN },
|
||||
{ "BETWEEN", TK_BETWEEN },
|
||||
{ "BY", TK_BY },
|
||||
{ "CASCADE", TK_CASCADE },
|
||||
{ "CASE", TK_CASE },
|
||||
{ "CHAR", TK_CHAR },
|
||||
{ "CHARACTER", TK_CHAR },
|
||||
{ "CHECK", TK_CHECK },
|
||||
{ "CLUSTER", TK_CLUSTER },
|
||||
{ "COLLATE", TK_COLLATE },
|
||||
{ "COMMIT", TK_COMMIT },
|
||||
{ "CONFLICT", TK_CONFLICT },
|
||||
{ "CONSTRAINT", TK_CONSTRAINT },
|
||||
{ "COPY", TK_COPY },
|
||||
{ "CREATE", TK_CREATE },
|
||||
{ "CROSS", TK_JOIN_KW },
|
||||
{ "DEFAULT", TK_DEFAULT },
|
||||
{ "DEFERRED", TK_DEFERRED },
|
||||
{ "DEFERRABLE", TK_DEFERRABLE },
|
||||
{ "DELETE", TK_DELETE },
|
||||
{ "DELIMITERS", TK_DELIMITERS },
|
||||
{ "DESC", TK_DESC },
|
||||
{ "DISTINCT", TK_DISTINCT },
|
||||
{ "DROP", TK_DROP },
|
||||
{ "END", TK_END },
|
||||
{ "EACH", TK_EACH },
|
||||
{ "ELSE", TK_ELSE },
|
||||
{ "EXCEPT", TK_EXCEPT },
|
||||
{ "EXPLAIN", TK_EXPLAIN },
|
||||
{ "FAIL", TK_FAIL },
|
||||
{ "FOR", TK_FOR },
|
||||
{ "FOREIGN", TK_FOREIGN },
|
||||
{ "FROM", TK_FROM },
|
||||
{ "FULL", TK_JOIN_KW },
|
||||
{ "GLOB", TK_GLOB },
|
||||
{ "GROUP", TK_GROUP },
|
||||
{ "HAVING", TK_HAVING },
|
||||
{ "HOLD", TK_HOLD },
|
||||
{ "IGNORE", TK_IGNORE },
|
||||
{ "IMMEDIATE", TK_IMMEDIATE },
|
||||
{ "IN", TK_IN },
|
||||
{ "INDEX", TK_INDEX },
|
||||
{ "INITIALLY", TK_INITIALLY },
|
||||
{ "INNER", TK_JOIN_KW },
|
||||
{ "INSERT", TK_INSERT },
|
||||
{ "INSTEAD", TK_INSTEAD },
|
||||
{ "INT", TK_INT },
|
||||
{ "INTERSECT", TK_INTERSECT },
|
||||
{ "INTO", TK_INTO },
|
||||
{ "IS", TK_IS },
|
||||
{ "ISNULL", TK_ISNULL },
|
||||
{ "JOIN", TK_JOIN },
|
||||
{ "KEY", TK_KEY },
|
||||
{ "LEFT", TK_JOIN_KW },
|
||||
{ "LIKE", TK_LIKE },
|
||||
{ "LIMIT", TK_LIMIT },
|
||||
{ "LOCALIZABLE", TK_LOCALIZABLE },
|
||||
{ "LONG", TK_LONG },
|
||||
{ "LONGCHAR", TK_LONGCHAR },
|
||||
{ "MATCH", TK_MATCH },
|
||||
{ "NATURAL", TK_JOIN_KW },
|
||||
{ "NOT", TK_NOT },
|
||||
{ "NOTNULL", TK_NOTNULL },
|
||||
{ "NULL", TK_NULL },
|
||||
{ "OBJECT", TK_OBJECT },
|
||||
{ "OF", TK_OF },
|
||||
{ "OFFSET", TK_OFFSET },
|
||||
{ "ON", TK_ON },
|
||||
{ "OR", TK_OR },
|
||||
{ "ORDER", TK_ORDER },
|
||||
{ "OUTER", TK_JOIN_KW },
|
||||
{ "PRAGMA", TK_PRAGMA },
|
||||
{ "PRIMARY", TK_PRIMARY },
|
||||
{ "RAISE", TK_RAISE },
|
||||
{ "REFERENCES", TK_REFERENCES },
|
||||
{ "REPLACE", TK_REPLACE },
|
||||
{ "RESTRICT", TK_RESTRICT },
|
||||
{ "RIGHT", TK_JOIN_KW },
|
||||
{ "ROLLBACK", TK_ROLLBACK },
|
||||
{ "ROW", TK_ROW },
|
||||
{ "SELECT", TK_SELECT },
|
||||
{ "SET", TK_SET },
|
||||
{ "SHORT", TK_SHORT },
|
||||
{ "STATEMENT", TK_STATEMENT },
|
||||
{ "TABLE", TK_TABLE },
|
||||
{ "TEMP", TK_TEMP },
|
||||
{ "TEMPORARY", TK_TEMP },
|
||||
{ "THEN", TK_THEN },
|
||||
{ "TRANSACTION", TK_TRANSACTION },
|
||||
{ "TRIGGER", TK_TRIGGER },
|
||||
{ "UNION", TK_UNION },
|
||||
{ "UNIQUE", TK_UNIQUE },
|
||||
{ "UPDATE", TK_UPDATE },
|
||||
{ "USING", TK_USING },
|
||||
{ "VACUUM", TK_VACUUM },
|
||||
{ "VALUES", TK_VALUES },
|
||||
{ "VIEW", TK_VIEW },
|
||||
{ "WHEN", TK_WHEN },
|
||||
{ "WHERE", TK_WHERE },
|
||||
{ ABORT_W, TK_ABORT },
|
||||
{ AFTER_W, TK_AFTER },
|
||||
/*{ ALTER_W, TK_ALTER },*/
|
||||
{ ALL_W, TK_ALL },
|
||||
{ AND_W, TK_AND },
|
||||
{ AS_W, TK_AS },
|
||||
{ ASC_W, TK_ASC },
|
||||
{ BEFORE_W, TK_BEFORE },
|
||||
{ BEGIN_W, TK_BEGIN },
|
||||
{ BETWEEN_W, TK_BETWEEN },
|
||||
{ BY_W, TK_BY },
|
||||
{ CASCADE_W, TK_CASCADE },
|
||||
{ CASE_W, TK_CASE },
|
||||
{ CHAR_W, TK_CHAR },
|
||||
{ CHARACTER_W, TK_CHAR },
|
||||
{ CHECK_W, TK_CHECK },
|
||||
{ CLUSTER_W, TK_CLUSTER },
|
||||
{ COLLATE_W, TK_COLLATE },
|
||||
{ COMMIT_W, TK_COMMIT },
|
||||
{ CONFLICT_W, TK_CONFLICT },
|
||||
{ CONSTRAINT_W, TK_CONSTRAINT },
|
||||
{ COPY_W, TK_COPY },
|
||||
{ CREATE_W, TK_CREATE },
|
||||
{ CROSS_W, TK_JOIN_KW },
|
||||
{ DEFAULT_W, TK_DEFAULT },
|
||||
{ DEFERRED_W, TK_DEFERRED },
|
||||
{ DEFERRABLE_W, TK_DEFERRABLE },
|
||||
{ DELETE_W, TK_DELETE },
|
||||
{ DELIMITERS_W, TK_DELIMITERS },
|
||||
{ DESC_W, TK_DESC },
|
||||
{ DISTINCT_W, TK_DISTINCT },
|
||||
{ DROP_W, TK_DROP },
|
||||
{ END_W, TK_END },
|
||||
{ EACH_W, TK_EACH },
|
||||
{ ELSE_W, TK_ELSE },
|
||||
{ EXCEPT_W, TK_EXCEPT },
|
||||
{ EXPLAIN_W, TK_EXPLAIN },
|
||||
{ FAIL_W, TK_FAIL },
|
||||
{ FOR_W, TK_FOR },
|
||||
{ FOREIGN_W, TK_FOREIGN },
|
||||
{ FROM_W, TK_FROM },
|
||||
{ FULL_W, TK_JOIN_KW },
|
||||
{ GLOB_W, TK_GLOB },
|
||||
{ GROUP_W, TK_GROUP },
|
||||
{ HAVING_W, TK_HAVING },
|
||||
{ HOLD_W, TK_HOLD },
|
||||
{ IGNORE_W, TK_IGNORE },
|
||||
{ IMMEDIATE_W, TK_IMMEDIATE },
|
||||
{ IN_W, TK_IN },
|
||||
{ INDEX_W, TK_INDEX },
|
||||
{ INITIALLY_W, TK_INITIALLY },
|
||||
{ INNER_W, TK_JOIN_KW },
|
||||
{ INSERT_W, TK_INSERT },
|
||||
{ INSTEAD_W, TK_INSTEAD },
|
||||
{ INT_W, TK_INT },
|
||||
{ INTERSECT_W, TK_INTERSECT },
|
||||
{ INTO_W, TK_INTO },
|
||||
{ IS_W, TK_IS },
|
||||
{ ISNULL_W, TK_ISNULL },
|
||||
{ JOIN_W, TK_JOIN },
|
||||
{ KEY_W, TK_KEY },
|
||||
{ LEFT_W, TK_JOIN_KW },
|
||||
{ LIKE_W, TK_LIKE },
|
||||
{ LIMIT_W, TK_LIMIT },
|
||||
{ LOCALIZABLE_W, TK_LOCALIZABLE },
|
||||
{ LONG_W, TK_LONG },
|
||||
{ LONGCHAR_W, TK_LONGCHAR },
|
||||
{ MATCH_W, TK_MATCH },
|
||||
{ NATURAL_W, TK_JOIN_KW },
|
||||
{ NOT_W, TK_NOT },
|
||||
{ NOTNULL_W, TK_NOTNULL },
|
||||
{ NULL_W, TK_NULL },
|
||||
{ OBJECT_W, TK_OBJECT },
|
||||
{ OF_W, TK_OF },
|
||||
{ OFFSET_W, TK_OFFSET },
|
||||
{ ON_W, TK_ON },
|
||||
{ OR_W, TK_OR },
|
||||
{ ORDER_W, TK_ORDER },
|
||||
{ OUTER_W, TK_JOIN_KW },
|
||||
{ PRAGMA_W, TK_PRAGMA },
|
||||
{ PRIMARY_W, TK_PRIMARY },
|
||||
{ RAISE_W, TK_RAISE },
|
||||
{ REFERENCES_W, TK_REFERENCES },
|
||||
{ REPLACE_W, TK_REPLACE },
|
||||
{ RESTRICT_W, TK_RESTRICT },
|
||||
{ RIGHT_W, TK_JOIN_KW },
|
||||
{ ROLLBACK_W, TK_ROLLBACK },
|
||||
{ ROW_W, TK_ROW },
|
||||
{ SELECT_W, TK_SELECT },
|
||||
{ SET_W, TK_SET },
|
||||
{ SHORT_W, TK_SHORT },
|
||||
{ STATEMENT_W, TK_STATEMENT },
|
||||
{ TABLE_W, TK_TABLE },
|
||||
{ TEMP_W, TK_TEMP },
|
||||
{ TEMPORARY_W, TK_TEMP },
|
||||
{ THEN_W, TK_THEN },
|
||||
{ TRANSACTION_W, TK_TRANSACTION },
|
||||
{ TRIGGER_W, TK_TRIGGER },
|
||||
{ UNION_W, TK_UNION },
|
||||
{ UNIQUE_W, TK_UNIQUE },
|
||||
{ UPDATE_W, TK_UPDATE },
|
||||
{ USING_W, TK_USING },
|
||||
{ VACUUM_W, TK_VACUUM },
|
||||
{ VALUES_W, TK_VALUES },
|
||||
{ VIEW_W, TK_VIEW },
|
||||
{ WHEN_W, TK_WHEN },
|
||||
{ WHERE_W, TK_WHERE },
|
||||
};
|
||||
|
||||
#define KEYWORD_COUNT ( sizeof aKeywordTable/sizeof (Keyword) )
|
||||
|
@ -159,17 +269,13 @@ static const Keyword aKeywordTable[] = {
|
|||
** returned. If the input is not a keyword, TK_ID is returned.
|
||||
*/
|
||||
static int sqliteKeywordCode(const WCHAR *z, int n){
|
||||
UINT i, len;
|
||||
char buffer[0x10];
|
||||
UINT i;
|
||||
|
||||
len = WideCharToMultiByte( CP_ACP, 0, z, n, buffer, sizeof buffer, NULL, NULL );
|
||||
for(i=0; i<len; i++)
|
||||
buffer[i] = toupper(buffer[i]);
|
||||
for(i=0; i<KEYWORD_COUNT; i++)
|
||||
{
|
||||
if(memcmp(buffer, aKeywordTable[i].zName, len))
|
||||
if(strncmpiW(z, aKeywordTable[i].zName, n))
|
||||
continue;
|
||||
if(strlen(aKeywordTable[i].zName) == len )
|
||||
if(lstrlenW(aKeywordTable[i].zName) == n )
|
||||
return aKeywordTable[i].tokenType;
|
||||
}
|
||||
return TK_ID;
|
||||
|
|
|
@ -37,6 +37,14 @@ typedef enum tagMSICOLINFO
|
|||
MSICOLINFO_TYPES = 1
|
||||
} MSICOLINFO;
|
||||
|
||||
typedef enum tagMSICOSTTREE
|
||||
{
|
||||
MSICOSTTREE_SELFONLY = 0,
|
||||
MSICOSTTREE_CHILDREN = 1,
|
||||
MSICOSTTREE_PARENTS = 2,
|
||||
MSICOSTTREE_PRODUCT = 3,
|
||||
} MSICOSTTREE;
|
||||
|
||||
typedef enum tagMSIMODIFY
|
||||
{
|
||||
MSIMODIFY_REFRESH = 0,
|
||||
|
|
Loading…
Reference in a new issue