Partial implementation of the Microsoft Installer (msi.dll).

This commit is contained in:
Mike McCormack 2003-08-13 01:27:48 +00:00 committed by Alexandre Julliard
parent f6fab8c730
commit 6386edc5d8
23 changed files with 5535 additions and 1 deletions

3
configure vendored

File diff suppressed because one or more lines are too long

View File

@ -1452,6 +1452,7 @@ dlls/msacm/msadp32/Makefile
dlls/msacm/msg711/Makefile
dlls/msacm/winemp3/Makefile
dlls/msdmo/Makefile
dlls/msi/Makefile
dlls/msimg32/Makefile
dlls/msisys/Makefile
dlls/msnet32/Makefile

View File

@ -58,6 +58,7 @@ BASEDIRS = \
msacm/msg711 \
msacm/winemp3 \
msdmo \
msi \
msimg32 \
msisys \
msnet32 \
@ -247,6 +248,7 @@ SYMLINKS = \
msadp32.acm$(DLLEXT) \
msdmo.dll$(DLLEXT) \
msg711.acm$(DLLEXT) \
msi.dll$(DLLEXT) \
msimg32.dll$(DLLEXT) \
msisys.ocx$(DLLEXT) \
msnet32.dll$(DLLEXT) \
@ -482,6 +484,9 @@ msdmo.dll$(DLLEXT): msdmo/msdmo.dll$(DLLEXT)
msg711.acm$(DLLEXT): msacm/msg711/msg711.acm$(DLLEXT)
$(RM) $@ && $(LN_S) msacm/msg711/msg711.acm$(DLLEXT) $@
msi.dll$(DLLEXT): msi/msi.dll$(DLLEXT)
$(RM) $@ && $(LN_S) msi/msi.dll$(DLLEXT) $@
msimg32.dll$(DLLEXT): msimg32/msimg32.dll$(DLLEXT)
$(RM) $@ && $(LN_S) msimg32/msimg32.dll$(DLLEXT) $@
@ -719,6 +724,7 @@ IMPORT_LIBS = \
libmpr \
libmsacm32 \
libmsdmo \
libmsi \
libmsimg32 \
libmsnet32 \
libmsrle32 \
@ -994,6 +1000,11 @@ libmsdmo.def: msdmo/msdmo.spec.def
libmsdmo.a: msdmo/msdmo.spec.def
$(DLLTOOL) -k -l $@ -d msdmo/msdmo.spec.def
libmsi.def: msi/msi.spec.def
$(RM) $@ && $(LN_S) msi/msi.spec.def $@
libmsi.a: msi/msi.spec.def
$(DLLTOOL) -k -l $@ -d msi/msi.spec.def
libmsimg32.def: msimg32/msimg32.spec.def
$(RM) $@ && $(LN_S) msimg32/msimg32.spec.def $@
libmsimg32.a: msimg32/msimg32.spec.def
@ -1308,6 +1319,7 @@ mapi32/mapi32.spec.def: $(WINEBUILD)
mpr/mpr.spec.def: $(WINEBUILD)
msacm/msacm32.spec.def: $(WINEBUILD)
msdmo/msdmo.spec.def: $(WINEBUILD)
msi/msi.spec.def: $(WINEBUILD)
msimg32/msimg32.spec.def: $(WINEBUILD)
msnet32/msnet32.spec.def: $(WINEBUILD)
msvideo/msrle32/msrle32.spec.def: $(WINEBUILD)
@ -1424,6 +1436,7 @@ msacm/msacm32.dll$(DLLEXT): msacm
msacm/msadp32/msadp32.acm$(DLLEXT): msacm/msadp32
msdmo/msdmo.dll$(DLLEXT): msdmo
msacm/msg711/msg711.acm$(DLLEXT): msacm/msg711
msi/msi.dll$(DLLEXT): msi
msimg32/msimg32.dll$(DLLEXT): msimg32
msisys/msisys.ocx$(DLLEXT): msisys
msnet32/msnet32.dll$(DLLEXT): msnet32

6
dlls/msi/.cvsignore Normal file
View File

@ -0,0 +1,6 @@
Makefile
msi.dll.dbg.c
msi.spec.c
msi.spec.def
y.tab.c
y.tab.h

39
dlls/msi/Makefile.in Normal file
View File

@ -0,0 +1,39 @@
TOPSRCDIR = @top_srcdir@
TOPOBJDIR = ../..
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = msi.dll
IMPORTS = ole32 user32 advapi32 kernel32
EXTRALIBS = $(LIBUUID) $(LIBUNICODE)
LDDLLFLAGS = @LDDLLFLAGS@
SYMBOLFILE = $(MODULE).tmp.o
C_SRCS = \
distinct.c \
handle.c \
msi.c \
msiquery.c \
order.c \
record.c \
select.c \
suminfo.c \
table.c \
tokenize.c \
where.c
#RC_SRCS= msi_rc.rc
EXTRA_SRCS = sql.y
EXTRA_OBJS = y.tab.o
@MAKE_DLL_RULES@
y.tab.c y.tab.h: sql.y
$(YACC) -d -t $(SRCDIR)/sql.y
# hack to allow parallel make
y.tab.h: y.tab.c
y.tab.o: y.tab.h
### Dependencies:

286
dlls/msi/distinct.c Normal file
View File

@ -0,0 +1,286 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#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 "winnls.h"
#include "query.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
typedef struct tagDISTINCTSET
{
UINT val;
UINT count;
UINT row;
struct tagDISTINCTSET *nextrow;
struct tagDISTINCTSET *nextcol;
} DISTINCTSET;
typedef struct tagMSIDISTINCTVIEW
{
MSIVIEW view;
MSIDATABASE *db;
MSIVIEW *table;
UINT row_count;
UINT *translation;
} MSIDISTINCTVIEW;
static DISTINCTSET ** distinct_insert( DISTINCTSET **x, UINT val, UINT row )
{
/* horrible O(n) find */
while( *x )
{
if( (*x)->val == val )
{
(*x)->count++;
return x;
}
x = &(*x)->nextrow;
}
/* nothing found, so add one */
*x = HeapAlloc( GetProcessHeap(), 0, sizeof (DISTINCTSET) );
if( *x )
{
(*x)->val = val;
(*x)->count = 1;
(*x)->row = row;
(*x)->nextrow = NULL;
(*x)->nextcol = NULL;
}
return x;
}
static void distinct_free( DISTINCTSET *x )
{
while( x )
{
DISTINCTSET *next = x->nextrow;
distinct_free( x->nextcol );
HeapFree( GetProcessHeap(), 0, x );
x = next;
}
}
static UINT DISTINCT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
{
MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
TRACE("%p %d %d %p\n", dv, row, col, val );
if( !dv->table )
return ERROR_FUNCTION_FAILED;
if( row >= dv->row_count )
return ERROR_INVALID_PARAMETER;
row = dv->translation[ row ];
return dv->table->ops->fetch_int( dv->table, row, col, val );
}
static UINT DISTINCT_execute( struct tagMSIVIEW *view, MSIHANDLE record )
{
MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
UINT r, i, j, r_count, c_count;
DISTINCTSET *rowset = NULL;
TRACE("%p %ld\n", dv, record);
if( !dv->table )
return ERROR_FUNCTION_FAILED;
r = dv->table->ops->execute( dv->table, record );
if( r != ERROR_SUCCESS )
return r;
r = dv->table->ops->get_dimensions( dv->table, &r_count, &c_count );
if( r != ERROR_SUCCESS )
return r;
dv->translation = HeapAlloc( GetProcessHeap(), 0, r_count*sizeof(UINT) );
if( !dv->translation )
return ERROR_FUNCTION_FAILED;
/* build it */
for( i=0; i<r_count; i++ )
{
DISTINCTSET **x = &rowset;
for( j=1; j<=c_count; j++ )
{
UINT val = 0;
r = dv->table->ops->fetch_int( dv->table, i, j, &val );
if( r != ERROR_SUCCESS )
{
ERR("Failed to fetch int at %d %d\n", i, j );
distinct_free( rowset );
return r;
}
x = distinct_insert( x, val, i );
if( !*x )
{
ERR("Failed to insert at %d %d\n", i, j );
distinct_free( rowset );
return ERROR_FUNCTION_FAILED;
}
if( j != c_count )
x = &(*x)->nextcol;
}
/* check if it was distinct and if so, include it */
if( (*x)->row == i )
{
TRACE("Row %d -> %d\n", dv->row_count, i);
dv->translation[dv->row_count++] = i;
}
}
distinct_free( rowset );
return ERROR_SUCCESS;
}
static UINT DISTINCT_close( struct tagMSIVIEW *view )
{
MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
TRACE("%p\n", dv );
if( !dv->table )
return ERROR_FUNCTION_FAILED;
if( dv->translation )
HeapFree( GetProcessHeap(), 0, dv->translation );
dv->translation = NULL;
dv->row_count = 0;
return dv->table->ops->close( dv->table );
}
static UINT DISTINCT_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
{
MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
TRACE("%p %p %p\n", dv, rows, cols );
if( !dv->table )
return ERROR_FUNCTION_FAILED;
if( rows )
{
if( !dv->translation )
return ERROR_FUNCTION_FAILED;
*rows = dv->row_count;
}
return dv->table->ops->get_dimensions( dv->table, NULL, cols );
}
static UINT DISTINCT_get_column_info( struct tagMSIVIEW *view,
UINT n, LPWSTR *name, UINT *type )
{
MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
TRACE("%p %d %p %p\n", dv, n, name, type );
if( !dv->table )
return ERROR_FUNCTION_FAILED;
return dv->table->ops->get_column_info( dv->table, n, name, type );
}
static UINT DISTINCT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
{
MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
TRACE("%p %d %ld\n", dv, eModifyMode, hrec );
if( !dv->table )
return ERROR_FUNCTION_FAILED;
return dv->table->ops->modify( dv->table, eModifyMode, hrec );
}
static UINT DISTINCT_delete( struct tagMSIVIEW *view )
{
MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
TRACE("%p\n", dv );
if( dv->table )
dv->table->ops->delete( dv->table );
if( dv->translation )
HeapFree( GetProcessHeap(), 0, dv->translation );
HeapFree( GetProcessHeap(), 0, dv );
return ERROR_SUCCESS;
}
MSIVIEWOPS distinct_ops =
{
DISTINCT_fetch_int,
DISTINCT_execute,
DISTINCT_close,
DISTINCT_get_dimensions,
DISTINCT_get_column_info,
DISTINCT_modify,
DISTINCT_delete
};
UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )
{
MSIDISTINCTVIEW *dv = NULL;
UINT count = 0, r;
TRACE("%p\n", dv );
r = table->ops->get_dimensions( table, NULL, &count );
if( r != ERROR_SUCCESS )
{
ERR("can't get table dimensions\n");
return r;
}
dv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *dv );
if( !dv )
return ERROR_FUNCTION_FAILED;
/* fill the structure */
dv->view.ops = &distinct_ops;
dv->db = db;
dv->table = table;
dv->translation = NULL;
dv->row_count = 0;
*view = (MSIVIEW*) dv;
return ERROR_SUCCESS;
}

115
dlls/msi/handle.c Normal file
View File

@ -0,0 +1,115 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "shlwapi.h"
#include "wine/debug.h"
#include "msi.h"
#include "msiquery.h"
#include "msipriv.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
MSIHANDLEINFO *msihandletable[MSIMAXHANDLES];
MSIHANDLE alloc_msihandle(UINT type, UINT size, msihandledestructor destroy)
{
MSIHANDLEINFO *info;
UINT i;
/* find a slot */
for(i=0; i<MSIMAXHANDLES; i++)
if( !msihandletable[i] )
break;
if( (i>=MSIMAXHANDLES) || msihandletable[i] )
return 0;
size += sizeof (MSIHANDLEINFO);
info = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
if( !info )
return 0;
info->magic = MSIHANDLE_MAGIC;
info->type = type;
info->destructor = destroy;
msihandletable[i] = info;
return (MSIHANDLE) (i+1);
}
void *msihandle2msiinfo(MSIHANDLE handle, UINT type)
{
handle--;
if( handle<0 )
return NULL;
if( handle>=MSIMAXHANDLES )
return NULL;
if( !msihandletable[handle] )
return NULL;
if( msihandletable[handle]->magic != MSIHANDLE_MAGIC )
return NULL;
if( type && (msihandletable[handle]->type != type) )
return NULL;
return &msihandletable[handle][1];
}
UINT WINAPI MsiCloseHandle(MSIHANDLE handle)
{
MSIHANDLEINFO *info = msihandle2msiinfo(handle, 0);
TRACE("%lx\n",handle);
if( !info )
return ERROR_INVALID_HANDLE;
info--;
if( info->magic != MSIHANDLE_MAGIC )
{
ERR("Invalid handle!\n");
return ERROR_INVALID_HANDLE;
}
if( info->destructor )
info->destructor( &info[1] );
HeapFree( GetProcessHeap(), 0, info );
msihandletable[handle-1] = NULL;
TRACE("Destroyed\n");
return 0;
}
UINT WINAPI MsiCloseAllHandles(void)
{
UINT i;
TRACE("\n");
for(i=0; i<MSIMAXHANDLES; i++)
MsiCloseHandle( i+1 );
return 0;
}

640
dlls/msi/msi.c Normal file
View File

@ -0,0 +1,640 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define NONAMELESSUNION
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "shlwapi.h"
#include "wine/debug.h"
#include "msi.h"
#include "msiquery.h"
#include "msipriv.h"
#include "objidl.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
const WCHAR szInstaller[] = {
'S','o','f','t','w','a','r','e','\\',
'M','i','c','r','o','s','o','f','t','\\',
'W','i','n','d','o','w','s','\\',
'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
'I','n','s','t','a','l','l','e','r',0 };
const WCHAR szFeatures[] = {
'F','e','a','t','u','r','e','s',0 };
const WCHAR szComponents[] = {
'C','o','m','p','o','n','e','n','t','s',0 };
/*
* .MSI file format
*
* A .msi file is a structured storage file.
* It should contain a number of streams.
*/
BOOL unsquash_guid(LPCWSTR in, LPWSTR out)
{
DWORD i,n=0;
out[n++]='{';
for(i=0; i<8; i++)
out[n++] = in[7-i];
out[n++]='-';
for(i=0; i<4; i++)
out[n++] = in[11-i];
out[n++]='-';
for(i=0; i<4; i++)
out[n++] = in[15-i];
out[n++]='-';
for(i=0; i<2; i++)
{
out[n++] = in[17+i*2];
out[n++] = in[16+i*2];
}
out[n++]='-';
for( ; i<8; i++)
{
out[n++] = in[17+i*2];
out[n++] = in[16+i*2];
}
out[n++]='}';
out[n]=0;
return TRUE;
}
BOOL squash_guid(LPCWSTR in, LPWSTR out)
{
DWORD i,n=0;
if(in[n++] != '{')
return FALSE;
for(i=0; i<8; i++)
out[7-i] = in[n++];
if(in[n++] != '-')
return FALSE;
for(i=0; i<4; i++)
out[11-i] = in[n++];
if(in[n++] != '-')
return FALSE;
for(i=0; i<4; i++)
out[15-i] = in[n++];
if(in[n++] != '-')
return FALSE;
for(i=0; i<2; i++)
{
out[17+i*2] = in[n++];
out[16+i*2] = in[n++];
}
if(in[n++] != '-')
return FALSE;
for( ; i<8; i++)
{
out[17+i*2] = in[n++];
out[16+i*2] = in[n++];
}
out[32]=0;
if(in[n++] != '}')
return FALSE;
if(in[n])
return FALSE;
return TRUE;
}
VOID MSI_CloseDatabase( VOID *arg )
{
MSIDATABASE *db = (MSIDATABASE *) arg;
free_cached_tables( db );
IStorage_Release( db->storage );
}
UINT WINAPI MsiOpenDatabaseA(
LPCSTR szDBPath, LPCSTR szPersist, MSIHANDLE *phDB)
{
HRESULT r = ERROR_FUNCTION_FAILED;
LPWSTR szwDBPath = NULL, szwPersist = NULL;
TRACE("%s %s %p\n", debugstr_a(szDBPath), debugstr_a(szPersist), phDB);
if( szDBPath )
{
szwDBPath = HEAP_strdupAtoW( GetProcessHeap(), 0, szDBPath );
if( !szwDBPath )
goto end;
}
if( szPersist )
{
szwPersist = HEAP_strdupAtoW( GetProcessHeap(), 0, szPersist );
if( !szwPersist )
goto end;
}
r = MsiOpenDatabaseW( szwDBPath, szwPersist, phDB );
end:
if( szwPersist )
HeapFree( GetProcessHeap(), 0, szwPersist );
if( szwDBPath )
HeapFree( GetProcessHeap(), 0, szwDBPath );
return r;
}
UINT WINAPI MsiOpenDatabaseW(
LPCWSTR szDBPath, LPCWSTR szPersist, MSIHANDLE *phDB)
{
IStorage *stg = NULL;
HRESULT r;
MSIHANDLE handle;
MSIDATABASE *db;
UINT ret;
TRACE("%s %s %p\n",debugstr_w(szDBPath),debugstr_w(szPersist), phDB);
if( !phDB )
return ERROR_INVALID_PARAMETER;
r = StgOpenStorage( szDBPath, NULL, STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg);
if( FAILED( r ) )
{
FIXME("open failed r = %08lx!\n",r);
return ERROR_FUNCTION_FAILED;
}
handle = alloc_msihandle(MSIHANDLETYPE_DATABASE, sizeof (MSIDATABASE), MSI_CloseDatabase );
if( !handle )
{
FIXME("Failed to allocate a handle\n");
ret = ERROR_FUNCTION_FAILED;
goto end;
}
db = msihandle2msiinfo( handle, MSIHANDLETYPE_DATABASE );
if( !db )
{
FIXME("Failed to get handle pointer \n");
ret = ERROR_FUNCTION_FAILED;
goto end;
}
db->storage = stg;
ret = load_string_table( db, &db->strings);
if( ret != ERROR_SUCCESS )
goto end;
*phDB = handle;
IStorage_AddRef( stg );
end:
if( stg )
IStorage_Release( stg );
return ret;
}
UINT WINAPI MsiOpenProductA(LPCSTR szProduct, MSIHANDLE *phProduct)
{
FIXME("%s %p\n",debugstr_a(szProduct), phProduct);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiOpenProductW(LPCWSTR szProduct, MSIHANDLE *phProduct)
{
FIXME("%s %p\n",debugstr_w(szProduct), phProduct);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
{
FIXME("%s %p\n",debugstr_a(szPackage), phPackage);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
{
FIXME("%s %p\n",debugstr_w(szPackage), phPackage);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiInstallProductA(LPCSTR szPackagePath, LPCSTR szCommandLine)
{
LPWSTR szwPath = NULL, szwCommand = NULL;
UINT r = ERROR_FUNCTION_FAILED; /* FIXME: check return code */
TRACE("%s %s\n",debugstr_a(szPackagePath), debugstr_a(szCommandLine));
if( szPackagePath )
{
szwPath = HEAP_strdupAtoW(GetProcessHeap(),0,szPackagePath);
if( szwPath == NULL )
goto end;
}
if( szCommandLine )
{
szwCommand = HEAP_strdupAtoW(GetProcessHeap(),0,szCommandLine);
if( szwCommand == NULL )
goto end;
}
r = MsiInstallProductW( szwPath, szwCommand );
end:
if( szwPath )
HeapFree( GetProcessHeap(), 0, szwPath );
if( szwCommand )
HeapFree( GetProcessHeap(), 0, szwCommand );
return r;
}
UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine)
{
FIXME("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine));
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiConfigureProductA(
LPCSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState)
{
FIXME("%s %d %d\n",debugstr_a(szProduct), iInstallLevel, eInstallState);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiConfigureProductW(
LPCWSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState)
{
FIXME("%s %d %d\n",debugstr_w(szProduct), iInstallLevel, eInstallState);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiGetProductCodeA(LPCSTR szComponent, LPSTR szBuffer)
{
FIXME("%s %s\n",debugstr_a(szComponent), debugstr_a(szBuffer));
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer)
{
FIXME("%s %s\n",debugstr_w(szComponent), debugstr_w(szBuffer));
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute, LPSTR szBuffer, DWORD *pcchValueBuf)
{
FIXME("%s %s %p %p\n",debugstr_a(szProduct), debugstr_a(szAttribute), szBuffer, pcchValueBuf);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiGetProductInfoW(LPCWSTR szProduct, LPCWSTR szAttribute, LPWSTR szBuffer, DWORD *pcchValueBuf)
{
FIXME("%s %s %p %p\n",debugstr_w(szProduct), debugstr_w(szAttribute), szBuffer, pcchValueBuf);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiDatabaseImportA(LPCSTR szFolderPath, LPCSTR szFilename)
{
FIXME("%s %s\n",debugstr_a(szFolderPath), debugstr_a(szFilename));
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiDatabaseImportW(LPCWSTR szFolderPath, LPCWSTR szFilename)
{
FIXME("%s %s\n",debugstr_w(szFolderPath), debugstr_w(szFilename));
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiEnableLogA(DWORD dwLogMode, LPCSTR szLogFile, BOOL fAppend)
{
FIXME("%08lx %s %d\n", dwLogMode, debugstr_a(szLogFile), fAppend);
return ERROR_SUCCESS;
/* return ERROR_CALL_NOT_IMPLEMENTED; */
}
UINT WINAPI MsiEnableLogW(DWORD dwLogMode, LPCWSTR szLogFile, BOOL fAppend)
{
FIXME("%08lx %s %d\n", dwLogMode, debugstr_w(szLogFile), fAppend);
return ERROR_CALL_NOT_IMPLEMENTED;
}
INSTALLSTATE WINAPI MsiQueryProductStateA(LPCSTR szProduct)
{
FIXME("%s\n", debugstr_a(szProduct));
return 0;
}
INSTALLSTATE WINAPI MsiQueryProductStateW(LPCWSTR szProduct)
{
FIXME("%s\n", debugstr_w(szProduct));
return 0;
}
INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd)
{
FIXME("%08x %p\n", dwUILevel, phWnd);
return dwUILevel;
}
UINT WINAPI MsiLoadStringA(DWORD a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f)
{
FIXME("%08lx %08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e,f);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiLoadStringW(DWORD a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f)
{
FIXME("%08lx %08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e,f);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiMessageBoxA(DWORD a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f)
{
FIXME("%08lx %08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e,f);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiMessageBoxW(DWORD a, DWORD b, DWORD c, DWORD d, DWORD e, DWORD f)
{
FIXME("%08lx %08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e,f);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid)
{
DWORD r;
WCHAR szwGuid[GUID_SIZE];
TRACE("%ld %p\n",index,lpguid);
r = MsiEnumProductsW(index, szwGuid);
if( r == ERROR_SUCCESS )
WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
return r;
}
UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid)
{
HKEY hkey = 0, hkeyFeatures = 0;
DWORD r;
WCHAR szKeyName[33];
TRACE("%ld %p\n",index,lpguid);
r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey);
if( r != ERROR_SUCCESS )
goto end;
r = RegOpenKeyW(hkey, szFeatures, &hkeyFeatures);
if( r != ERROR_SUCCESS )
goto end;
r = RegEnumKeyW(hkeyFeatures, index, szKeyName, GUID_SIZE);
unsquash_guid(szKeyName, lpguid);
end:
if( hkeyFeatures )
RegCloseKey(hkeyFeatures);
if( hkey )
RegCloseKey(hkey);
return r;
}
UINT WINAPI MsiEnumFeaturesA(LPCSTR szProduct, DWORD index,
LPSTR szFeature, LPSTR szParent)
{
DWORD r;
WCHAR szwFeature[GUID_SIZE], szwParent[GUID_SIZE];
LPWSTR szwProduct = NULL;
TRACE("%s %ld %p %p\n",debugstr_a(szProduct),index,szFeature,szParent);
if( szProduct )
{
szwProduct = HEAP_strdupAtoW(GetProcessHeap(),0,szProduct);
if( !szwProduct )
return ERROR_FUNCTION_FAILED;
}
r = MsiEnumFeaturesW(szProduct?szwProduct:NULL,
index, szwFeature, szwParent);
if( r == ERROR_SUCCESS )
{
WideCharToMultiByte(CP_ACP, 0, szwFeature, -1,
szFeature, GUID_SIZE, NULL, NULL);
WideCharToMultiByte(CP_ACP, 0, szwParent, -1,
szParent, GUID_SIZE, NULL, NULL);
}
if( szwProduct )
HeapFree( GetProcessHeap(), 0, szwProduct);
return r;
}
UINT WINAPI MsiEnumFeaturesW(LPCWSTR szProduct, DWORD index,
LPWSTR szFeature, LPWSTR szParent)
{
HKEY hkey = 0, hkeyFeatures = 0, hkeyProduct = 0;
DWORD r, sz;
WCHAR szRegName[GUID_SIZE];
TRACE("%s %ld %p %p\n",debugstr_w(szProduct),index,szFeature,szParent);
if( !squash_guid(szProduct, szRegName) )
return ERROR_INVALID_PARAMETER;
r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey);
if( r != ERROR_SUCCESS )
goto end;
r = RegOpenKeyW(hkey, szFeatures, &hkeyFeatures);
if( r != ERROR_SUCCESS )
goto end;
r = RegOpenKeyW(hkeyFeatures, szRegName, &hkeyProduct);
if( r != ERROR_SUCCESS )
goto end;
sz = GUID_SIZE;
r = RegEnumValueW(hkeyProduct, index, szFeature, &sz, NULL, NULL, NULL, NULL);
end:
if( hkeyProduct )
RegCloseKey(hkeyProduct);
if( hkeyFeatures )
RegCloseKey(hkeyFeatures);
if( hkey )
RegCloseKey(hkey);
return r;
}
UINT WINAPI MsiEnumComponentsA(DWORD index, LPSTR lpguid)
{
DWORD r;
WCHAR szwGuid[GUID_SIZE];
TRACE("%ld %p\n",index,lpguid);
r = MsiEnumComponentsW(index, szwGuid);
if( r == ERROR_SUCCESS )
WideCharToMultiByte(CP_ACP, 0, szwGuid, -1, lpguid, GUID_SIZE, NULL, NULL);
return r;
}
UINT WINAPI MsiEnumComponentsW(DWORD index, LPWSTR lpguid)
{
HKEY hkey = 0, hkeyComponents = 0;
DWORD r;
WCHAR szKeyName[33];
TRACE("%ld %p\n",index,lpguid);
r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey);
if( r != ERROR_SUCCESS )
goto end;
r = RegOpenKeyW(hkey, szComponents, &hkeyComponents);
if( r != ERROR_SUCCESS )
goto end;
r = RegEnumKeyW(hkeyComponents, index, szKeyName, GUID_SIZE);
unsquash_guid(szKeyName, lpguid);
end:
if( hkeyComponents )
RegCloseKey(hkeyComponents);
if( hkey )
RegCloseKey(hkey);
return r;
}
UINT WINAPI MsiEnumClientsA(LPCSTR szComponent, DWORD index, LPSTR szProduct)
{
DWORD r;
WCHAR szwProduct[GUID_SIZE];
LPWSTR szwComponent = NULL;
TRACE("%s %ld %p\n",debugstr_a(szComponent),index,szProduct);
if( szComponent )
{
szwComponent = HEAP_strdupAtoW(GetProcessHeap(),0,szComponent);
if( !szwComponent )
return ERROR_FUNCTION_FAILED;
}
r = MsiEnumClientsW(szComponent?szwComponent:NULL, index, szwProduct);
if( r == ERROR_SUCCESS )
{
WideCharToMultiByte(CP_ACP, 0, szwProduct, -1,
szProduct, GUID_SIZE, NULL, NULL);
}
if( szwComponent )
HeapFree( GetProcessHeap(), 0, szwComponent);
return r;
}
UINT WINAPI MsiEnumClientsW(LPCWSTR szComponent, DWORD index, LPWSTR szProduct)
{
HKEY hkey = 0, hkeyComponents = 0, hkeyComp = 0;
DWORD r, sz;
WCHAR szRegName[GUID_SIZE], szValName[GUID_SIZE];
TRACE("%s %ld %p\n",debugstr_w(szComponent),index,szProduct);
if( !squash_guid(szComponent, szRegName) )
return ERROR_INVALID_PARAMETER;
r = RegOpenKeyW(HKEY_LOCAL_MACHINE, szInstaller, &hkey);
if( r != ERROR_SUCCESS )
goto end;
r = RegOpenKeyW(hkey, szComponents, &hkeyComponents);
if( r != ERROR_SUCCESS )
goto end;
r = RegOpenKeyW(hkeyComponents, szRegName, &hkeyComp);
if( r != ERROR_SUCCESS )
goto end;
sz = GUID_SIZE;
r = RegEnumValueW(hkeyComp, index, szValName, &sz, NULL, NULL, NULL, NULL);
if( r != ERROR_SUCCESS )
goto end;
unsquash_guid(szValName, szProduct);
end:
if( hkeyComp )
RegCloseKey(hkeyComp);
if( hkeyComponents )
RegCloseKey(hkeyComponents);
if( hkey )
RegCloseKey(hkey);
return r;
}
UINT WINAPI MsiProvideComponentFromDescriptorA( LPCSTR szDescriptor, LPSTR szPath, DWORD *pcchPath, DWORD *pcchArgs )
{
FIXME("%s %p %p %p\n", debugstr_a(szDescriptor), szPath, pcchPath, pcchArgs );
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiProvideComponentFromDescriptorW( LPCWSTR szDescriptor, LPWSTR szPath, DWORD *pcchPath, DWORD *pcchArgs )
{
FIXME("%s %p %p %p\n", debugstr_w(szDescriptor), szPath, pcchPath, pcchArgs );
return ERROR_CALL_NOT_IMPLEMENTED;
}
HRESULT WINAPI MSI_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;
}
BOOL WINAPI MSI_DllCanUnloadNow(void)
{
return FALSE;
}

218
dlls/msi/msi.spec Normal file
View File

@ -0,0 +1,218 @@
1 stdcall DllCanUnloadNow() MSI_DllCanUnloadNow
2 stub DllGetClassObject
3 stub DllRegisterServer
4 stub DllUnregisterServer
5 stub MsiAdvertiseProductA
6 stub MsiAdvertiseProductW
7 stdcall MsiCloseAllHandles() MsiCloseAllHandles
8 stdcall MsiCloseHandle(long) MsiCloseHandle
9 stub MsiCollectUserInfoA
10 stub MsiCollectUserInfoW
11 stub MsiConfigureFeatureA
12 stub MsiConfigureFeatureFromDescriptorA
13 stub MsiConfigureFeatureFromDescriptorW
14 stub MsiConfigureFeatureW
15 stdcall MsiConfigureProductA(str long long) MsiConfigureProductA
16 stdcall MsiConfigureProductW(wstr long long) MsiConfigureProductW
17 stdcall MsiCreateRecord(long) MsiCreateRecord
18 stdcall MsiDatabaseApplyTransformA(long str long) MsiDatabaseApplyTransformA
19 stdcall MsiDatabaseApplyTransformW(long wstr long) MsiDatabaseApplyTransformW
20 stdcall MsiDatabaseCommit(long) MsiDatabaseCommit
21 stub MsiDatabaseExportA
22 stub MsiDatabaseExportW
23 stdcall MsiDatabaseGenerateTransformA(long long str long long) MsiDatabaseGenerateTransformA
24 stdcall MsiDatabaseGenerateTransformW(long long wstr long long) MsiDatabaseGenerateTransformW
25 stdcall MsiDatabaseGetPrimaryKeysA(long str ptr) MsiDatabaseGetPrimaryKeysA
26 stdcall MsiDatabaseGetPrimaryKeysW(long wstr ptr) MsiDatabaseGetPrimaryKeysW
27 stdcall MsiDatabaseImportA(str str) MsiDatabaseImportA
28 stdcall MsiDatabaseImportW(wstr wstr) MsiDatabaseImportW
29 stub MsiDatabaseMergeA
30 stub MsiDatabaseMergeW
31 stdcall MsiDatabaseOpenViewA(str ptr) MsiDatabaseOpenViewA
32 stdcall MsiDatabaseOpenViewW(wstr ptr) MsiDatabaseOpenViewW
33 stdcall MsiDoActionA(long str) MsiDoActionA
34 stdcall MsiDoActionW(long wstr) MsiDoActionW
35 stub MsiEnableUIPreview
36 stdcall MsiEnumClientsA(long ptr) MsiEnumClientsA
37 stdcall MsiEnumClientsW(long ptr) MsiEnumClientsW
38 stub MsiEnumComponentQualifiersA
39 stub MsiEnumComponentQualifiersW
40 stdcall MsiEnumComponentsA(long ptr) MsiEnumComponentsA
41 stdcall MsiEnumComponentsW(long ptr) MsiEnumComponentsW
42 stdcall MsiEnumFeaturesA(str long ptr ptr) MsiEnumFeaturesA
43 stdcall MsiEnumFeaturesW(wstr long ptr ptr) MsiEnumFeaturesW
44 stdcall MsiEnumProductsA(long ptr) MsiEnumProductsA
45 stdcall MsiEnumProductsW(long ptr) MsiEnumProductsW
46 stub MsiEvaluateConditionA
47 stub MsiEvaluateConditionW
48 stub MsiGetLastErrorRecord
49 stub MsiGetActiveDatabase
50 stub MsiGetComponentStateA
51 stub MsiGetComponentStateW
52 stub MsiGetDatabaseState
53 stub MsiGetFeatureCostA
54 stub MsiGetFeatureCostW
55 stub MsiGetFeatureInfoA
56 stub MsiGetFeatureInfoW
57 stub MsiGetFeatureStateA
58 stub MsiGetFeatureStateW
59 stub MsiGetFeatureUsageA
60 stub MsiGetFeatureUsageW
61 stub MsiGetFeatureValidStatesA
62 stub MsiGetFeatureValidStatesW
63 stub MsiGetLanguage
64 stub MsiGetMode
65 stdcall MsiGetProductCodeA(str str) MsiGetProductCodeA
66 stdcall MsiGetProductCodeW(wstr wstr) MsiGetProductCodeW
67 stdcall MsiGetProductInfoA(str str str long) MsiGetProductInfoA
68 stub MsiGetProductInfoFromScriptA
69 stub MsiGetProductInfoFromScriptW
70 stdcall MsiGetProductInfoW(wstr wstr wstr long) MsiGetProductInfoW
71 stub MsiGetProductPropertyA
72 stub MsiGetProductPropertyW
73 stub MsiGetPropertyA
74 stub MsiGetPropertyW
75 stub MsiGetSourcePathA
76 stub MsiGetSourcePathW
77 stdcall MsiGetSummaryInformationA(str long ptr) MsiGetSummaryInformationA
78 stdcall MsiGetSummaryInformationW(wstr long ptr) MsiGetSummaryInformationW
79 stub MsiGetTargetPathA
80 stub MsiGetTargetPathW
81 stub MsiGetUserInfoA
82 stub MsiGetUserInfoW
83 stub MsiInstallMissingComponentA
84 stub MsiInstallMissingComponentW
85 stub MsiInstallMissingFileA
86 stub MsiInstallMissingFileW
87 stdcall MsiInstallProductA(str str) MsiInstallProductA
88 stdcall MsiInstallProductW(wstr wstr) MsiInstallProductW
89 stub MsiLocateComponentA
90 stub MsiLocateComponentW
91 stdcall MsiOpenDatabaseA(str str ptr) MsiOpenDatabaseA
92 stdcall MsiOpenDatabaseW(wstr wstr ptr) MsiOpenDatabaseW
93 stdcall MsiOpenPackageA(str ptr) MsiOpenPackageA
94 stdcall MsiOpenPackageW(wstr ptr) MsiOpenPackageW
95 stdcall MsiOpenProductA(str ptr) MsiOpenProductA
96 stdcall MsiOpenProductW(wstr ptr) MsiOpenProductW
97 stub MsiPreviewBillboardA
98 stub MsiPreviewBillboardW
99 stub MsiPreviewDialogA
100 stub MsiPreviewDialogW
101 stub MsiProcessAdvertiseScriptA
102 stub MsiProcessAdvertiseScriptW
103 stub MsiProcessMessage
104 stub MsiProvideComponentA
105 stdcall MsiProvideComponentFromDescriptorA(str ptr ptr ptr) MsiProvideComponentFromDescriptorA
106 stdcall MsiProvideComponentFromDescriptorW(wstr ptr ptr ptr) MsiProvideComponentFromDescriptorW
107 stub MsiProvideComponentW
108 stub MsiProvideQualifiedComponentA
109 stub MsiProvideQualifiedComponentW
110 stub MsiQueryFeatureStateA
111 stub MsiQueryFeatureStateW
112 stdcall MsiQueryProductStateA(str) MsiQueryProductStateA
113 stdcall MsiQueryProductStateW(wstr) MsiQueryProductStateW
114 stdcall MsiRecordDataSize(long long) MsiRecordDataSize
115 stdcall MsiRecordGetFieldCount(long) MsiRecordGetFieldCount
116 stdcall MsiRecordGetInteger(long long) MsiRecordGetInteger
117 stdcall MsiRecordGetStringA(long long ptr ptr) MsiRecordGetStringA
118 stdcall MsiRecordGetStringW(long long ptr ptr) MsiRecordGetStringW
119 stdcall MsiRecordIsNull(long long) MsiRecordIsNull
120 stdcall MsiRecordReadStream(long long ptr ptr) MsiRecordReadStream
121 stdcall MsiRecordSetInteger(long long long) MsiRecordSetInteger
122 stdcall MsiRecordSetStreamA(long long str) MsiRecordSetStreamA
123 stdcall MsiRecordSetStreamW(long long wstr) MsiRecordSetStreamW
124 stdcall MsiRecordSetStringA(long long str) MsiRecordSetStringA
125 stdcall MsiRecordSetStringW(long long wstr) MsiRecordSetStringW
126 stub MsiReinstallFeatureA
127 stub MsiReinstallFeatureFromDescriptorA
128 stub MsiReinstallFeatureFromDescriptorW
129 stub MsiReinstallFeatureW
130 stub MsiReinstallProductA
131 stub MsiReinstallProductW
132 stub MsiSequenceA
133 stub MsiSequenceW
134 stub MsiSetComponentStateA
135 stub MsiSetComponentStateW
136 stub MsiSetExternalUIA
137 stub MsiSetExternalUIW
138 stub MsiSetFeatureStateA
139 stub MsiSetFeatureStateW
140 stub MsiSetInstallLevel
141 stdcall MsiSetInternalUI(long ptr) MsiSetInternalUI
142 stub MsiVerifyDiskSpace
143 stub MsiSetMode
144 stub MsiSetPropertyA
145 stub MsiSetPropertyW
146 stub MsiSetTargetPathA
147 stub MsiSetTargetPathW
148 stdcall MsiSummaryInfoGetPropertyA(long long ptr ptr ptr ptr ptr) MsiSummaryInfoGetPropertyA
149 stdcall MsiSummaryInfoGetPropertyCount(long ptr) MsiSummaryInfoGetPropertyCount
150 stdcall MsiSummaryInfoGetPropertyW(long long ptr ptr ptr ptr ptr) MsiSummaryInfoGetPropertyW
151 stub MsiSummaryInfoPersist
152 stub MsiSummaryInfoSetPropertyA
153 stub MsiSummaryInfoSetPropertyW
154 stub MsiUseFeatureA
155 stub MsiUseFeatureW
156 stub MsiVerifyPackageA
157 stub MsiVerifyPackageW
158 stdcall MsiViewClose(long) MsiViewClose
159 stdcall MsiViewExecute(long long) MsiViewExecute
160 stdcall MsiViewFetch(long ptr) MsiViewFetch
161 stub MsiViewGetErrorA
162 stub MsiViewGetErrorW
163 stub MsiViewModify
164 stdcall MsiDatabaseIsTablePersistentA(long str) MsiDatabaseIsTablePersistentA
165 stdcall MsiDatabaseIsTablePersistentW(long wstr) MsiDatabaseIsTablePersistentW
166 stdcall MsiViewGetColumnInfo(long long ptr) MsiViewGetColumnInfo
167 stdcall MsiRecordClearData(long) MsiRecordClearData
168 stdcall MsiEnableLogA(long str long) MsiEnableLogA
169 stdcall MsiEnableLogW(long wstr long) MsiEnableLogW
170 stdcall MsiFormatRecordA(long long ptr ptr) MsiFormatRecordA
171 stdcall MsiFormatRecordW(long long ptr ptr) MsiFormatRecordW
172 stub MsiGetComponentPathA
173 stub MsiGetComponentPathW
174 stub MsiApplyPatchA
175 stub MsiApplyPatchW
176 stub MsiAdvertiseScriptA
177 stub MsiAdvertiseScriptW
178 stub MsiGetPatchInfoA
179 stub MsiGetPatchInfoW
180 stub MsiEnumPatchesA
181 stub MsiEnumPatchesW
182 stdcall DllGetVersion(ptr) MSI_DllGetVersion
183 stub MsiGetProductCodeFromPackageCodeA
184 stub MsiGetProductCodeFromPackageCodeW
185 stub MsiCreateTransformSummaryInfoA
186 stub MsiCreateTransformSummaryInfoW
187 stub MsiQueryFeatureStateFromDescriptorA
188 stub MsiQueryFeatureStateFromDescriptorW
189 stub MsiConfigureProductExA
190 stub MsiConfigureProductExW
191 stub MsiInvalidateFeatureCache
192 stub MsiUseFeatureExA
193 stub MsiUseFeatureExW
194 stub MsiGetFileVersionA
195 stub MsiGetFileVersionW
196 stdcall MsiLoadStringA(long long long long long long) MsiLoadStringA
197 stdcall MsiLoadStringW(long long long long long long) MsiLoadStringW
198 stdcall MsiMessageBoxA(long long long long long long) MsiMessageBoxA
199 stdcall MsiMessageBoxW(long long long long long long) MsiMessageBoxW
200 stub MsiDecomposeDescriptorA
201 stub MsiDecomposeDescriptorW
202 stub MsiProvideQualifiedComponentExA
203 stub MsiProvideQualifiedComponentExW
204 stub MsiEnumRelatedProductsA
205 stub MsiEnumRelatedProductsW
206 stub MsiSetFeatureAttributesA
207 stub MsiSetFeatureAttributesW
208 stub MsiSourceListClearAllA
209 stub MsiSourceListClearAllW
210 stub MsiSourceListAddSourceA
211 stub MsiSourceListAddSourceW
212 stub MsiSourceListForceResolutionA
213 stub MsiSourceListForceResolutionW
214 stub MsiIsProductElevatedA
215 stub MsiIsProductElevatedW
216 stub MsiGetShortcutTargetA
217 stub MsiGetShortcutTargetW

186
dlls/msi/msipriv.h Normal file
View File

@ -0,0 +1,186 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __WINE_MSI_PRIVATE__
#define __WINE_MSI_PRIVATE__
#include "msi.h"
#include "msiquery.h"
#include "objidl.h"
#define MSI_DATASIZEMASK 0x00ff
#define MSITYPE_VALID 0x0100
#define MSITYPE_STRING 0x0800
#define MSITYPE_NULLABLE 0x1000
#define MSITYPE_KEY 0x2000
struct tagMSITABLE;
typedef struct tagMSITABLE MSITABLE;
typedef struct pool_data_tag
{
USHORT *data;
UINT size;
} pool_data;
typedef struct string_data_tag
{
CHAR *data;
UINT size;
} string_data;
typedef struct string_table_tag
{
pool_data pool;
string_data info;
} string_table;
typedef struct tagMSIDATABASE
{
IStorage *storage;
string_table strings;
MSITABLE *first_table, *last_table;
} MSIDATABASE;
struct tagMSIVIEW;
typedef struct tagMSIVIEWOPS
{
/*
* fetch_int - reads one integer from {row,col} in the table
*
* This function should be called after the execute method.
* Data returned by the function should not change until
* close or delete is called.
* To get a string value, query the database's string table with
* the integer value returned from this function.
*/
UINT (*fetch_int)( struct tagMSIVIEW *, UINT row, UINT col, UINT *val );
/*
* execute - loads the underlying data into memory so it can be read
*/
UINT (*execute)( struct tagMSIVIEW *, MSIHANDLE );
/*
* close - clears the data read by execute from memory
*/
UINT (*close)( struct tagMSIVIEW * );
/*
* get_dimensions - returns the number of rows or columns in a table.
*
* The number of rows can only be queried after the execute method
* is called. The number of columns can be queried at any time.
*/
UINT (*get_dimensions)( struct tagMSIVIEW *, UINT *rows, UINT *cols );
/*
* get_column_info - returns the name and type of a specific column
*
* The name is HeapAlloc'ed by this function and should be freed by
* the caller.
* The column information can be queried at any time.
*/
UINT (*get_column_info)( struct tagMSIVIEW *, UINT n, LPWSTR *name, UINT *type );
/*
* modify - not yet implemented properly
*/
UINT (*modify)( struct tagMSIVIEW *, MSIMODIFY, MSIHANDLE );
/*
* delete - destroys the structure completely
*/
UINT (*delete)( struct tagMSIVIEW * );
} MSIVIEWOPS;
typedef struct tagMSIVIEW
{
MSIVIEWOPS *ops;
} MSIVIEW;
typedef struct tagMSISUMMARYINFO
{
IPropertyStorage *propstg;
} MSISUMMARYINFO;
typedef VOID (*msihandledestructor)( VOID * );
typedef struct tagMSIHANDLEINFO
{
UINT magic;
UINT type;
msihandledestructor destructor;
struct tagMSIHANDLEINFO *next;
struct tagMSIHANDLEINFO *prev;
} MSIHANDLEINFO;
#define MSIHANDLETYPE_ANY 0
#define MSIHANDLETYPE_DATABASE 1
#define MSIHANDLETYPE_SUMMARYINFO 2
#define MSIHANDLETYPE_VIEW 3
#define MSIHANDLETYPE_RECORD 4
#define MSI_MAJORVERSION 1
#define MSI_MINORVERSION 10
#define MSI_BUILDNUMBER 1029
#define GUID_SIZE 39
#define MSIHANDLE_MAGIC 0x4d434923
#define MSIMAXHANDLES 0x80
#define MSISUMINFO_OFFSET 0x30LL
extern void *msihandle2msiinfo(MSIHANDLE handle, UINT type);
MSIHANDLE alloc_msihandle(UINT type, UINT extra, msihandledestructor destroy);
/* add this table to the list of cached tables in the database */
extern void add_table(MSIDATABASE *db, MSITABLE *table);
extern void remove_table( MSIDATABASE *db, MSITABLE *table );
extern void free_table( MSIDATABASE *db, MSITABLE *table );
extern void free_cached_tables( MSIDATABASE *db );
extern UINT find_cached_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **table);
extern UINT get_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **table);
extern UINT dump_string_table(MSIDATABASE *db);
extern UINT load_string_table( MSIDATABASE *db, string_table *pst);
extern UINT msi_id2string( string_table *st, UINT string_no, LPWSTR buffer, UINT *sz );
extern LPWSTR MSI_makestring( MSIDATABASE *db, UINT stringid);
UINT VIEW_find_column( MSIVIEW *view, LPWSTR name, UINT *n );
/* FIXME! should get rid of that */
#include "winnls.h"
inline static LPWSTR HEAP_strdupAtoW( HANDLE heap, DWORD flags, LPCSTR str )
{
LPWSTR ret;
INT len;
if (!str) return NULL;
len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
ret = HeapAlloc( heap, flags, len * sizeof(WCHAR) );
if (ret) MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
return ret;
}
#endif /* __WINE_MSI_PRIVATE__ */

376
dlls/msi/msiquery.c Normal file
View File

@ -0,0 +1,376 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#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 "winnls.h"
#include "query.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
typedef struct tagMSIQUERY
{
MSIVIEW *view;
UINT row;
MSIDATABASE *db;
} MSIQUERY;
UINT WINAPI MsiDatabaseIsTablePersistentA(
MSIHANDLE hDatabase, LPSTR szTableName)
{
FIXME("%lx %s\n", hDatabase, debugstr_a(szTableName));
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiDatabaseIsTablePersistentW(
MSIHANDLE hDatabase, LPWSTR szTableName)
{
FIXME("%lx %s\n", hDatabase, debugstr_w(szTableName));
return ERROR_CALL_NOT_IMPLEMENTED;
}
void MSI_CloseView( VOID *arg )
{
MSIQUERY *query = arg;
if( query->view && query->view->ops->delete )
query->view->ops->delete( query->view );
}
UINT VIEW_find_column( MSIVIEW *table, LPWSTR name, UINT *n )
{
LPWSTR col_name;
UINT i, count, r;
r = table->ops->get_dimensions( table, NULL, &count );
if( r != ERROR_SUCCESS )
return r;
for( i=1; i<=count; i++ )
{
INT x;
col_name = NULL;
r = table->ops->get_column_info( table, i, &col_name, NULL );
if( r != ERROR_SUCCESS )
return r;
x = lstrcmpW( name, col_name );
HeapFree( GetProcessHeap(), 0, col_name );
if( !x )
{
*n = i;
return ERROR_SUCCESS;
}
}
return ERROR_INVALID_PARAMETER;
}
UINT WINAPI MsiDatabaseOpenViewA(MSIHANDLE hdb,
LPCSTR szQuery, MSIHANDLE *phView)
{
UINT r;
LPCWSTR szwQuery;
TRACE("%ld %s %p\n", hdb, debugstr_a(szQuery), phView);
if( szQuery )
{
szwQuery = HEAP_strdupAtoW( GetProcessHeap(), 0, szQuery );
if( !szwQuery )
return ERROR_FUNCTION_FAILED;
}
else
szwQuery = NULL;
r = MsiDatabaseOpenViewW( hdb, szwQuery, phView);
return r;
}
UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb,
LPCWSTR szQuery, MSIHANDLE *phView)
{
MSIDATABASE *db;
MSIHANDLE handle;
MSIQUERY *query;
UINT r;
TRACE("%s %p\n", debugstr_w(szQuery), phView);
if( !szQuery)
return ERROR_INVALID_PARAMETER;
db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
if( !db )
return ERROR_INVALID_HANDLE;
/* pre allocate a handle to hold a pointer to the view */
handle = alloc_msihandle( MSIHANDLETYPE_VIEW, sizeof (MSIQUERY), MSI_CloseView );
if( !handle )
return ERROR_FUNCTION_FAILED;
query = msihandle2msiinfo( handle, MSIHANDLETYPE_VIEW );
if( !query )
return ERROR_FUNCTION_FAILED;
query->row = 0;
query->db = db;
query->view = NULL;
r = MSI_ParseSQL( db, szQuery, &query->view );
if( r != ERROR_SUCCESS )
{
MsiCloseHandle( handle );
return r;
}
*phView = handle;
return ERROR_SUCCESS;
}
UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record)
{
MSIQUERY *query;
MSIVIEW *view;
MSIHANDLE handle;
UINT row_count = 0, col_count = 0, i, ival, ret, type;
TRACE("%ld %p\n", hView, record);
query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
if( !query )
return ERROR_INVALID_HANDLE;
view = query->view;
if( !view )
return ERROR_FUNCTION_FAILED;
ret = view->ops->get_dimensions( view, &row_count, &col_count );
if( ret )
return ret;
if( !col_count )
return ERROR_INVALID_PARAMETER;
if( query->row >= row_count )
return ERROR_NO_MORE_ITEMS;
handle = MsiCreateRecord( col_count );
if( !handle )
return ERROR_FUNCTION_FAILED;
for( i=1; i<=col_count; i++ )
{
ret = view->ops->get_column_info( view, i, NULL, &type );
if( ret )
{
ERR("Error getting column type for %d\n", i );
continue;
}
ret = view->ops->fetch_int( view, query->row, i, &ival );
if( ret )
{
ERR("Error fetching data for %d\n", i );
continue;
}
if( ! (type & MSITYPE_VALID ) )
ERR("Invalid type!\n");
/* check if it's nul (0) - if so, don't set anything */
if( !ival )
continue;
if( type & MSITYPE_STRING )
{
LPWSTR sval = MSI_makestring( query->db, ival );
MsiRecordSetStringW( handle, i, sval );
HeapFree( GetProcessHeap(), 0, sval );
}
else
{
if( (type & MSI_DATASIZEMASK) == 2 )
MsiRecordSetInteger( handle, i, ival - (1<<15) );
else
MsiRecordSetInteger( handle, i, ival - (1<<31) );
}
}
query->row ++;
*record = handle;
return ERROR_SUCCESS;
}
UINT WINAPI MsiViewClose(MSIHANDLE hView)
{
MSIQUERY *query;
MSIVIEW *view;
TRACE("%ld\n", hView );
query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
if( !query )
return ERROR_INVALID_HANDLE;
view = query->view;
if( !view )
return ERROR_FUNCTION_FAILED;
if( !view->ops->close )
return ERROR_FUNCTION_FAILED;
return view->ops->close( view );
}
UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec)
{
MSIQUERY *query;
MSIVIEW *view;
TRACE("%ld %ld\n", hView, hRec);
query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
if( !query )
return ERROR_INVALID_HANDLE;
view = query->view;
if( !view )
return ERROR_FUNCTION_FAILED;
if( !view->ops->execute )
return ERROR_FUNCTION_FAILED;
query->row = 0;
return view->ops->execute( view, hRec );
}
UINT WINAPI MsiViewGetColumnInfo(MSIHANDLE hView, MSICOLINFO info, MSIHANDLE *hRec)
{
MSIVIEW *view;
MSIQUERY *query;
MSIHANDLE handle;
UINT ret, i, count = 0, type;
LPWSTR name;
TRACE("%ld %d %p\n", hView, info, hRec);
query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
if( !query )
return ERROR_INVALID_HANDLE;
view = query->view;
if( !view )
return ERROR_FUNCTION_FAILED;
if( !view->ops->get_dimensions )
return ERROR_FUNCTION_FAILED;
ret = view->ops->get_dimensions( view, NULL, &count );
if( ret )
return ret;
if( !count )
return ERROR_INVALID_PARAMETER;
handle = MsiCreateRecord( count );
if( !handle )
return ERROR_FUNCTION_FAILED;
for( i=0; i<count; i++ )
{
name = NULL;
ret = view->ops->get_column_info( view, i+1, &name, &type );
if( ret != ERROR_SUCCESS )
continue;
MsiRecordSetStringW( handle, i+1, name );
HeapFree( GetProcessHeap(), 0, name );
}
*hRec = handle;
return ERROR_SUCCESS;
}
UINT WINAPI MsiDoActionA( MSIHANDLE hInstall, LPCSTR szAction )
{
FIXME("%ld %s\n", hInstall, debugstr_a(szAction) );
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiDoActionW( MSIHANDLE hInstall, LPCWSTR szAction )
{
FIXME("%ld %s\n", hInstall, debugstr_w(szAction) );
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiDatabaseApplyTransformA( MSIHANDLE hdb,
LPCSTR szTransformFile, int iErrorCond)
{
FIXME("%ld %s %d\n", hdb, debugstr_a(szTransformFile), iErrorCond);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiDatabaseApplyTransformW( MSIHANDLE hdb,
LPCWSTR szTransformFile, int iErrorCond)
{
FIXME("%ld %s %d\n", hdb, debugstr_w(szTransformFile), iErrorCond);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiDatabaseGenerateTransformA( MSIHANDLE hdb, MSIHANDLE hdbref,
LPCSTR szTransformFile, int iReserved1, int iReserved2 )
{
FIXME("%ld %ld %s %d %d\n", hdb, hdbref,
debugstr_a(szTransformFile), iReserved1, iReserved2);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiDatabaseGenerateTransformW( MSIHANDLE hdb, MSIHANDLE hdbref,
LPCWSTR szTransformFile, int iReserved1, int iReserved2 )
{
FIXME("%ld %ld %s %d %d\n", hdb, hdbref,
debugstr_w(szTransformFile), iReserved1, iReserved2);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiDatabaseCommit( MSIHANDLE hdb )
{
FIXME("%ld\n", hdb);
return ERROR_SUCCESS;
}
UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE hdb,
LPCSTR table, MSIHANDLE* rec)
{
FIXME("%ld %s %p\n", hdb, debugstr_a(table), rec);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiDatabaseGetPrimaryKeysW(MSIHANDLE hdb,
LPCWSTR table, MSIHANDLE* rec)
{
FIXME("%ld %s %p\n", hdb, debugstr_w(table), rec);
return ERROR_CALL_NOT_IMPLEMENTED;
}

328
dlls/msi/order.c Normal file
View File

@ -0,0 +1,328 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#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 "winnls.h"
#include "query.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
/* below is the query interface to a table */
typedef struct tagMSIORDERVIEW
{
MSIVIEW view;
MSIDATABASE *db;
MSIVIEW *table;
UINT *reorder;
UINT num_cols;
UINT cols[1];
} MSIORDERVIEW;
static UINT ORDER_compare( MSIORDERVIEW *ov, UINT a, UINT b, UINT *swap )
{
UINT r, i, a_val = 0, b_val = 0;
*swap = 0;
for( i=0; i<ov->num_cols; i++ )
{
r = ov->table->ops->fetch_int( ov->table, a, ov->cols[i], &a_val );
if( r != ERROR_SUCCESS )
return r;
r = ov->table->ops->fetch_int( ov->table, b, ov->cols[i], &b_val );
if( r != ERROR_SUCCESS )
return r;
if( a_val != b_val )
{
if( a_val > b_val )
*swap = 1;
break;
}
}
return ERROR_SUCCESS;
}
static UINT ORDER_mergesort( MSIORDERVIEW *ov, UINT left, UINT right )
{
UINT r, centre = (left + right)/2, temp, swap = 0, i, j;
UINT *array = ov->reorder;
if( left == right )
return ERROR_SUCCESS;
/* sort the left half */
r = ORDER_mergesort( ov, left, centre );
if( r != ERROR_SUCCESS )
return r;
/* sort the right half */
r = ORDER_mergesort( ov, centre+1, right );
if( r != ERROR_SUCCESS )
return r;
for( i=left, j=centre+1; (i<=centre) && (j<=right); i++ )
{
r = ORDER_compare( ov, array[i], array[j], &swap );
if( r != ERROR_SUCCESS )
return r;
if( swap )
{
temp = array[j];
memmove( &array[i+1], &array[i], (j-i)*sizeof (UINT) );
array[i] = temp;
j++;
centre++;
}
}
return ERROR_SUCCESS;
}
static UINT ORDER_verify( MSIORDERVIEW *ov, UINT num_rows )
{
UINT i, swap, r;
for( i=1; i<num_rows; i++ )
{
r = ORDER_compare( ov, ov->reorder[i-1], ov->reorder[i], &swap );
if( r != ERROR_SUCCESS )
return r;
if( !swap )
continue;
ERR("Bad order! %d\n", i);
return ERROR_FUNCTION_FAILED;
}
return ERROR_SUCCESS;
}
static UINT ORDER_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
{
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
TRACE("%p %d %d %p\n", ov, row, col, val );
if( !ov->table )
return ERROR_FUNCTION_FAILED;
row = ov->reorder[ row ];
return ov->table->ops->fetch_int( ov->table, row, col, val );
}
static UINT ORDER_execute( struct tagMSIVIEW *view, MSIHANDLE record )
{
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
UINT r, num_rows = 0, i;
TRACE("%p %ld\n", ov, record);
if( !ov->table )
return ERROR_FUNCTION_FAILED;
r = ov->table->ops->execute( ov->table, record );
if( r != ERROR_SUCCESS )
return r;
r = ov->table->ops->get_dimensions( ov->table, &num_rows, NULL );
if( r != ERROR_SUCCESS )
return r;
ov->reorder = HeapAlloc( GetProcessHeap(), 0, num_rows*sizeof(UINT) );
if( !ov->reorder )
return ERROR_FUNCTION_FAILED;
for( i=0; i<num_rows; i++ )
ov->reorder[i] = i;
r = ORDER_mergesort( ov, 0, num_rows - 1 );
if( r != ERROR_SUCCESS )
return r;
r = ORDER_verify( ov, num_rows );
if( r != ERROR_SUCCESS )
return r;
return ERROR_SUCCESS;
}
static UINT ORDER_close( struct tagMSIVIEW *view )
{
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
TRACE("%p\n", ov );
if( !ov->table )
return ERROR_FUNCTION_FAILED;
if( ov->reorder )
HeapFree( GetProcessHeap(), 0, ov->reorder );
ov->reorder = NULL;
return ov->table->ops->close( ov->table );
}
static UINT ORDER_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
{
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
TRACE("%p %p %p\n", ov, rows, cols );
if( !ov->table )
return ERROR_FUNCTION_FAILED;
return ov->table->ops->get_dimensions( ov->table, rows, cols );
}
static UINT ORDER_get_column_info( struct tagMSIVIEW *view,
UINT n, LPWSTR *name, UINT *type )
{
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
TRACE("%p %d %p %p\n", ov, n, name, type );
if( !ov->table )
return ERROR_FUNCTION_FAILED;
return ov->table->ops->get_column_info( ov->table, n, name, type );
}
static UINT ORDER_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
{
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
TRACE("%p %d %ld\n", ov, eModifyMode, hrec );
if( !ov->table )
return ERROR_FUNCTION_FAILED;
return ov->table->ops->modify( ov->table, eModifyMode, hrec );
}
static UINT ORDER_delete( struct tagMSIVIEW *view )
{
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
TRACE("%p\n", ov );
if( ov->table )
ov->table->ops->delete( ov->table );
if( ov->reorder )
HeapFree( GetProcessHeap(), 0, ov->reorder );
ov->reorder = NULL;
HeapFree( GetProcessHeap(), 0, ov );
return ERROR_SUCCESS;
}
MSIVIEWOPS order_ops =
{
ORDER_fetch_int,
ORDER_execute,
ORDER_close,
ORDER_get_dimensions,
ORDER_get_column_info,
ORDER_modify,
ORDER_delete
};
UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )
{
MSIORDERVIEW *ov = NULL;
UINT count = 0, r;
TRACE("%p\n", ov );
r = table->ops->get_dimensions( table, NULL, &count );
if( r != ERROR_SUCCESS )
{
ERR("can't get table dimensions\n");
return r;
}
ov = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof *ov + sizeof (UINT) * count );
if( !ov )
return ERROR_FUNCTION_FAILED;
/* fill the structure */
ov->view.ops = &order_ops;
ov->db = db;
ov->table = table;
ov->reorder = NULL;
ov->num_cols = 0;
*view = (MSIVIEW*) ov;
return ERROR_SUCCESS;
}
UINT ORDER_AddColumn( MSIVIEW *view, LPWSTR name )
{
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
UINT n, count, r;
MSIVIEW *table;
TRACE("%p adding %s\n", ov, debugstr_w( name ) );
if( ov->view.ops != &order_ops )
return ERROR_FUNCTION_FAILED;
table = ov->table;
if( !table )
return ERROR_FUNCTION_FAILED;
if( !table->ops->get_dimensions )
return ERROR_FUNCTION_FAILED;
if( !table->ops->get_column_info )
return ERROR_FUNCTION_FAILED;
r = table->ops->get_dimensions( table, NULL, &count );
if( r != ERROR_SUCCESS )
return r;
if( ov->num_cols >= count )
return ERROR_FUNCTION_FAILED;
r = VIEW_find_column( table, name, &n );
if( r != ERROR_SUCCESS )
return r;
ov->cols[ov->num_cols] = n;
TRACE("Ordering by column %s (%d)\n", debugstr_w( name ), n);
ov->num_cols++;
return ERROR_SUCCESS;
}

88
dlls/msi/query.h Normal file
View File

@ -0,0 +1,88 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __WINE_MSI_QUERY_H
#define __WINE_MSI_QUERY_H
#include "winbase.h"
#include "objidl.h"
#include "msi.h"
#include "msiquery.h"
#include "msipriv.h"
#define OP_EQ 1
#define OP_AND 2
#define OP_OR 3
#define OP_GT 4
#define OP_LT 5
#define OP_LE 6
#define OP_GE 7
#define OP_NE 8
#define OP_ISNULL 9
#define OP_NOTNULL 10
#define EXPR_COMPLEX 1
#define EXPR_COLUMN 2
#define EXPR_COL_NUMBER 3
#define EXPR_IVAL 4
#define EXPR_SVAL 5
#define EXPR_UVAL 6
struct complex_expr
{
UINT op;
struct expr *left;
struct expr *right;
};
struct expr
{
int type;
union
{
struct complex_expr expr;
INT ival;
UINT uval;
LPWSTR sval;
LPWSTR column;
UINT col_number;
} u;
};
UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phView);
UINT TABLE_CreateView( MSIDATABASE *db, LPWSTR name, MSIVIEW **view );
UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table );
UINT SELECT_AddColumn( MSIVIEW *select, LPWSTR name );
UINT DISTINCT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table );
UINT ORDER_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table );
UINT ORDER_AddColumn( MSIVIEW *group, LPWSTR name );
UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table );
UINT WHERE_AddCondition( MSIVIEW *view, struct expr *condition );
int sqliteGetToken(const WCHAR *z, int *tokenType);
#endif /* __WINE_MSI_QUERY_H */

442
dlls/msi/record.c Normal file
View File

@ -0,0 +1,442 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "winerror.h"
#include "wine/debug.h"
#include "msi.h"
#include "msiquery.h"
#include "msipriv.h"
#include "objidl.h"
#include "winnls.h"
#include "query.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
#define MSIFIELD_NULL 0
#define MSIFIELD_INT 1
#define MSIFIELD_STR 2
#define MSIFIELD_WSTR 3
#define MSIFIELD_STREAM 4
/* maybe we can use a Variant instead of doing it ourselves? */
typedef struct tagMSIFIELD
{
UINT type;
union
{
INT iVal;
LPSTR szVal;
LPWSTR szwVal;
IStream *stream;
} u;
} MSIFIELD;
typedef struct tagMSIRECORD
{
UINT count; /* as passed to MsiCreateRecord */
MSIFIELD fields[1]; /* nb. array size is count+1 */
} MSIRECORD;
void MSI_FreeField( MSIFIELD *field )
{
switch( field->type )
{
case MSIFIELD_NULL:
case MSIFIELD_INT:
break;
case MSIFIELD_STR:
HeapFree( GetProcessHeap(), 0, field->u.szVal);
break;
case MSIFIELD_WSTR:
HeapFree( GetProcessHeap(), 0, field->u.szwVal);
break;
case MSIFIELD_STREAM:
IStream_Release( field->u.stream );
break;
default:
ERR("Invalid field type %d\n", field->type);
}
}
void MSI_CloseRecord( VOID *arg )
{
MSIRECORD *rec = (MSIRECORD *) arg;
UINT i;
for( i=0; i<rec->count; i++ )
MSI_FreeField( &rec->fields[i] );
}
MSIHANDLE WINAPI MsiCreateRecord( unsigned int cParams )
{
MSIHANDLE handle = 0;
UINT sz;
MSIRECORD *rec;
TRACE("%d\n", cParams);
sz = sizeof (MSIRECORD) + sizeof(MSIFIELD)*(cParams+1) ;
handle = alloc_msihandle( MSIHANDLETYPE_RECORD, sz, MSI_CloseRecord );
if( !handle )
return 0;
rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
if( !rec )
return 0;
rec->count = cParams;
return handle;
}
unsigned int WINAPI MsiRecordGetFieldCount( MSIHANDLE handle )
{
MSIRECORD *rec;
TRACE("%ld\n", handle );
rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
if( !rec )
{
ERR("Record not found!\n");
return 0;
}
return rec->count;
}
static BOOL string2intA( LPCSTR str, int *out )
{
int x = 0;
LPCSTR p = str;
if( *p == '-' ) /* skip the minus sign */
p++;
while ( *p )
{
if( (*p < '0') || (*p > '9') )
return FALSE;
x *= 10;
x += (*p - '0');
p++;
}
if( str[0] == '-' ) /* check if it's negative */
x = -x;
*out = x;
return TRUE;
}
static BOOL string2intW( LPCWSTR str, int *out )
{
int x = 0;
LPCWSTR p = str;
if( *p == '-' ) /* skip the minus sign */
p++;
while ( *p )
{
if( (*p < '0') || (*p > '9') )
return FALSE;
x *= 10;
x += (*p - '0');
p++;
}
if( str[0] == '-' ) /* check if it's negative */
x = -x;
*out = x;
return TRUE;
}
int WINAPI MsiRecordGetInteger( MSIHANDLE handle, unsigned int iField)
{
MSIRECORD *rec;
int ret = 0;
TRACE("%ld %d\n", handle, iField );
rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
if( !rec )
return MSI_NULL_INTEGER;
if( iField > rec->count )
return MSI_NULL_INTEGER;
switch( rec->fields[iField].type )
{
case MSIFIELD_INT:
return rec->fields[iField].u.iVal;
case MSIFIELD_STR:
if( string2intA( rec->fields[iField].u.szVal, &ret ) )
return ret;
return MSI_NULL_INTEGER;
case MSIFIELD_WSTR:
if( string2intW( rec->fields[iField].u.szwVal, &ret ) )
return ret;
return MSI_NULL_INTEGER;
default:
break;
}
return MSI_NULL_INTEGER;
}
UINT WINAPI MsiRecordClearData( MSIHANDLE handle )
{
MSIRECORD *rec;
UINT i;
TRACE("%ld\n", handle );
rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
if( !rec )
return ERROR_INVALID_HANDLE;
for( i=0; i<=rec->count; i++)
{
MSI_FreeField( &rec->fields[i] );
rec->fields[i].type = MSIFIELD_NULL;
rec->fields[i].u.iVal = 0;
}
return ERROR_SUCCESS;
}
UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, unsigned int iField, int iVal )
{
MSIRECORD *rec;
TRACE("%ld %u %d\n", handle,iField, iVal);
rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
if( !rec )
return ERROR_INVALID_HANDLE;
if( iField > rec->count )
return ERROR_INVALID_FIELD;
MSI_FreeField( &rec->fields[iField] );
rec->fields[iField].type = MSIFIELD_INT;
rec->fields[iField].u.iVal = iVal;
return ERROR_SUCCESS;
}
BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, unsigned int iField )
{
MSIRECORD *rec;
TRACE("%ld %d\n", handle,iField );
rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
if( !rec )
return ERROR_INVALID_HANDLE;
if( iField > rec->count )
return TRUE;
if( rec->fields[iField].type == MSIFIELD_NULL )
return TRUE;
return FALSE;
}
UINT WINAPI MsiRecordGetStringA(MSIHANDLE handle, unsigned int iField,
LPSTR szValue, DWORD *pcchValue)
{
MSIRECORD *rec;
UINT len=0, ret;
CHAR buffer[16];
TRACE("%ld %d %p %p\n", handle, iField, szValue, pcchValue);
rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
if( !rec )
return ERROR_INVALID_HANDLE;
if( iField > rec->count )
return ERROR_INVALID_PARAMETER;
ret = ERROR_SUCCESS;
switch( rec->fields[iField].type )
{
case MSIFIELD_INT:
wsprintfA(buffer, "%d", rec->fields[iField].u.iVal);
len = lstrlenA( buffer );
lstrcpynA(szValue, buffer, *pcchValue);
break;
case MSIFIELD_STR:
len = lstrlenA( rec->fields[iField].u.szVal );
lstrcpynA(szValue, rec->fields[iField].u.szVal, *pcchValue);
break;
case MSIFIELD_WSTR:
len = WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1,
NULL, 0 , NULL, NULL);
WideCharToMultiByte( CP_ACP, 0, rec->fields[iField].u.szwVal, -1,
szValue, *pcchValue, NULL, NULL);
break;
default:
ret = ERROR_INVALID_PARAMETER;
break;
}
if( *pcchValue < len )
ret = ERROR_MORE_DATA;
*pcchValue = len;
return ret;
}
UINT WINAPI MsiRecordGetStringW(MSIHANDLE handle, unsigned int iField,
LPWSTR szValue, DWORD *pcchValue)
{
MSIRECORD *rec;
UINT len=0, ret;
WCHAR buffer[16];
const WCHAR szFormat[] = { '%','d',0 };
TRACE("%ld %d %p %p\n", handle, iField, szValue, pcchValue);
rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
if( !rec )
return ERROR_INVALID_HANDLE;
if( iField > rec->count )
return ERROR_INVALID_PARAMETER;
ret = ERROR_SUCCESS;
switch( rec->fields[iField].type )
{
case MSIFIELD_INT:
wsprintfW(buffer, szFormat, rec->fields[iField].u.iVal);
len = lstrlenW( buffer );
lstrcpynW(szValue, buffer, *pcchValue);
break;
case MSIFIELD_WSTR:
len = lstrlenW( rec->fields[iField].u.szwVal );
lstrcpynW(szValue, rec->fields[iField].u.szwVal, *pcchValue);
break;
case MSIFIELD_STR:
len = MultiByteToWideChar( CP_ACP, 0, rec->fields[iField].u.szVal, -1,
NULL, 0 );
MultiByteToWideChar( CP_ACP, 0, rec->fields[iField].u.szVal, -1,
szValue, *pcchValue);
break;
default:
break;
}
if( *pcchValue < len )
ret = ERROR_MORE_DATA;
*pcchValue = len;
return ret;
}
UINT WINAPI MsiRecordDataSize(MSIHANDLE hRecord, unsigned int iField)
{
FIXME("%ld %d\n", hRecord, iField);
return 0;
}
UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, unsigned int iField, LPCSTR szValue )
{
MSIRECORD *rec;
LPSTR str;
TRACE("%ld %d %s\n", handle, iField, debugstr_a(szValue));
rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
if( !rec )
return ERROR_INVALID_HANDLE;
if( iField > rec->count )
return ERROR_INVALID_FIELD;
str = HeapAlloc( GetProcessHeap(), 0, (lstrlenA(szValue) + 1)*sizeof str[0]);
lstrcpyA( str, szValue );
MSI_FreeField( &rec->fields[iField] );
rec->fields[iField].type = MSIFIELD_STR;
rec->fields[iField].u.szVal = str;
return 0;
}
UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, unsigned int iField, LPCWSTR szValue )
{
MSIRECORD *rec;
LPWSTR str;
TRACE("%ld %d %s\n", handle, iField, debugstr_w(szValue));
rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
if( !rec )
return ERROR_INVALID_HANDLE;
if( iField > rec->count )
return ERROR_INVALID_FIELD;
str = HeapAlloc( GetProcessHeap(), 0, (lstrlenW(szValue) + 1)*sizeof str[0]);
lstrcpyW( str, szValue );
MSI_FreeField( &rec->fields[iField] );
rec->fields[iField].type = MSIFIELD_WSTR;
rec->fields[iField].u.szwVal = str;
return 0;
}
UINT WINAPI MsiFormatRecordA(MSIHANDLE hInstall, MSIHANDLE hRecord, LPSTR szResult, DWORD *sz)
{
FIXME("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiFormatRecordW(MSIHANDLE hInstall, MSIHANDLE hRecord, LPWSTR szResult, DWORD *sz)
{
FIXME("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiRecordSetStreamA(MSIHANDLE hRecord, unsigned int iField, LPCSTR szFilename)
{
FIXME("%ld %d %s\n", hRecord, iField, debugstr_a(szFilename));
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiRecordSetStreamW(MSIHANDLE hRecord, unsigned int iField, LPCWSTR szFilename)
{
FIXME("%ld %d %s\n", hRecord, iField, debugstr_w(szFilename));
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, unsigned int iField, char *buf, DWORD *sz)
{
FIXME("%ld %d %p %p\n",handle,iField,buf,sz);
return ERROR_CALL_NOT_IMPLEMENTED;
}

224
dlls/msi/select.c Normal file
View File

@ -0,0 +1,224 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#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 "winnls.h"
#include "query.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
/* below is the query interface to a table */
typedef struct tagMSISELECTVIEW
{
MSIVIEW view;
MSIDATABASE *db;
MSIVIEW *table;
UINT num_cols;
UINT max_cols;
UINT cols[1];
} MSISELECTVIEW;
static UINT SELECT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
{
MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
TRACE("%p %d %d %p\n", sv, row, col, val );
if( !sv->table )
return ERROR_FUNCTION_FAILED;
if( (col==0) || (col>sv->num_cols) )
return ERROR_FUNCTION_FAILED;
col = sv->cols[ col - 1 ];
return sv->table->ops->fetch_int( sv->table, row, col, val );
}
static UINT SELECT_execute( struct tagMSIVIEW *view, MSIHANDLE record )
{
MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
TRACE("%p %ld\n", sv, record);
if( !sv->table )
return ERROR_FUNCTION_FAILED;
return sv->table->ops->execute( sv->table, record );
}
static UINT SELECT_close( struct tagMSIVIEW *view )
{
MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
TRACE("%p\n", sv );
if( !sv->table )
return ERROR_FUNCTION_FAILED;
return sv->table->ops->close( sv->table );
}
static UINT SELECT_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
{
MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
TRACE("%p %p %p\n", sv, rows, cols );
if( !sv->table )
return ERROR_FUNCTION_FAILED;
if( cols )
*cols = sv->num_cols;
return sv->table->ops->get_dimensions( sv->table, rows, NULL );
}
static UINT SELECT_get_column_info( struct tagMSIVIEW *view,
UINT n, LPWSTR *name, UINT *type )
{
MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
TRACE("%p %d %p %p\n", sv, n, name, type );
if( !sv->table )
return ERROR_FUNCTION_FAILED;
if( (n==0) || (n>sv->num_cols) )
return ERROR_FUNCTION_FAILED;
n = sv->cols[ n - 1 ];
return sv->table->ops->get_column_info( sv->table, n, name, type );
}
static UINT SELECT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
{
MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
TRACE("%p %d %ld\n", sv, eModifyMode, hrec );
if( !sv->table )
return ERROR_FUNCTION_FAILED;
return sv->table->ops->modify( sv->table, eModifyMode, hrec );
}
static UINT SELECT_delete( struct tagMSIVIEW *view )
{
MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
TRACE("%p\n", sv );
if( sv->table )
sv->table->ops->delete( sv->table );
HeapFree( GetProcessHeap(), 0, sv );
return ERROR_SUCCESS;
}
MSIVIEWOPS select_ops =
{
SELECT_fetch_int,
SELECT_execute,
SELECT_close,
SELECT_get_dimensions,
SELECT_get_column_info,
SELECT_modify,
SELECT_delete
};
UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )
{
MSISELECTVIEW *sv = NULL;
UINT count = 0, r;
TRACE("%p\n", sv );
r = table->ops->get_dimensions( table, NULL, &count );
if( r != ERROR_SUCCESS )
{
ERR("can't get table dimensions\n");
return r;
}
sv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof *sv + count*sizeof (UINT) );
if( !sv )
return ERROR_FUNCTION_FAILED;
/* fill the structure */
sv->view.ops = &select_ops;
sv->db = db;
sv->table = table;
sv->num_cols = 0;
sv->max_cols = count;
*view = (MSIVIEW*) sv;
return ERROR_SUCCESS;
}
UINT SELECT_AddColumn( MSIVIEW *view, LPWSTR name )
{
MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
UINT r, n=0;
MSIVIEW *table;
TRACE("%p adding %s\n", sv, debugstr_w( name ) );
if( sv->view.ops != &select_ops )
return ERROR_FUNCTION_FAILED;
table = sv->table;
if( !table )
return ERROR_FUNCTION_FAILED;
if( !table->ops->get_dimensions )
return ERROR_FUNCTION_FAILED;
if( !table->ops->get_column_info )
return ERROR_FUNCTION_FAILED;
if( sv->num_cols >= sv->max_cols )
return ERROR_FUNCTION_FAILED;
r = VIEW_find_column( table, name, &n );
if( r != ERROR_SUCCESS )
return r;
sv->cols[sv->num_cols] = n;
TRACE("Translating column %s from %d -> %d\n",
debugstr_w( name ), sv->num_cols, n);
sv->num_cols++;
return ERROR_SUCCESS;
}

513
dlls/msi/sql.y Normal file
View File

@ -0,0 +1,513 @@
%{
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "winbase.h"
#include <stdio.h>
#include <stdlib.h>
#include "query.h"
#include "wine/debug.h"
#include "wine/unicode.h"
#define YYLEX_PARAM info
#define YYPARSE_PARAM info
extern int yyerror(char *str);
WINE_DEFAULT_DEBUG_CHANNEL(msi);
typedef struct tag_yyinput
{
MSIDATABASE *db;
LPCWSTR command;
DWORD n, len;
MSIVIEW **view; /* view structure for the resulting query */
} yyinput;
struct string_list
{
LPWSTR string;
struct string_list *next;
};
static LPWSTR yygetstring( yyinput *info );
static INT yygetint( yyinput *sql );
static int yylex( void *yylval, yyinput *info);
static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in,
struct string_list *columns );
static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in,
struct string_list *columns );
static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r );
static struct expr * EXPR_column( LPWSTR column );
static struct expr * EXPR_ival( INT ival );
static struct expr * EXPR_sval( LPWSTR string );
%}
%pure-parser
%union
{
LPWSTR string;
struct string_list *column_list;
MSIVIEW *table;
struct expr *expr;
}
%token TK_ABORT TK_AFTER TK_AGG_FUNCTION TK_ALL 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_CHECK TK_CLUSTER TK_COLLATE TK_COLUMN TK_COMMA
%token 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_GE TK_GLOB TK_GROUP TK_GT
%token TK_HAVING
%token TK_IGNORE TK_ILLEGAL TK_IMMEDIATE TK_IN TK_INDEX TK_INITIALLY
%token <string> TK_ID
%token TK_INSERT TK_INSTEAD TK_INTEGER TK_INTERSECT TK_INTO TK_IS TK_ISNULL
%token TK_JOIN TK_JOIN_KW
%token TK_KEY
%token TK_LE TK_LIKE TK_LIMIT TK_LP TK_LSHIFT TK_LT
%token TK_MATCH TK_MINUS
%token TK_NE TK_NOT TK_NOTNULL TK_NULL
%token TK_OF TK_OFFSET TK_ON TK_OR TK_ORACLE_OUTER_JOIN TK_ORDER
%token TK_PLUS TK_PRAGMA TK_PRIMARY
%token TK_RAISE TK_REFERENCES TK_REM TK_REPLACE TK_RESTRICT TK_ROLLBACK
%token TK_ROW TK_RP TK_RSHIFT
%token TK_SELECT TK_SEMI TK_SET TK_SLASH TK_SPACE TK_STAR TK_STATEMENT
%token <string> TK_STRING
%token TK_TABLE TK_TEMP TK_THEN TK_TRANSACTION TK_TRIGGER
%token TK_UMINUS TK_UNCLOSED_STRING TK_UNION TK_UNIQUE
%token TK_UPDATE TK_UPLUS TK_USING
%token TK_VACUUM TK_VALUES TK_VIEW
%token TK_WHEN TK_WHERE
// These are extra tokens used by the lexer but never seen by the
// parser. We put them in a rule so that the parser generator will
// add them to the parse.h output file.
//
%nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
COLUMN AGG_FUNCTION.
%type <query> oneselect
%type <string> column table string_or_id
%type <column_list> selcollist
%type <table> from unorderedsel
%type <expr> expr val column_val
%%
oneselect:
unorderedsel TK_ORDER TK_BY selcollist
{
yyinput* sql = (yyinput*) info;
if( !$1 )
YYABORT;
if( $4 )
*sql->view = do_order_by( sql->db, $1, $4 );
else
*sql->view = $1;
}
| unorderedsel
{
yyinput* sql = (yyinput*) info;
*sql->view = $1;
}
;
unorderedsel:
TK_SELECT selcollist from
{
yyinput* sql = (yyinput*) info;
if( !$3 )
YYABORT;
if( $2 )
$$ = do_one_select( sql->db, $3, $2 );
else
$$ = $3;
}
| TK_SELECT TK_DISTINCT selcollist from
{
yyinput* sql = (yyinput*) info;
MSIVIEW *view = $4;
if( !view )
YYABORT;
if( $3 )
view = do_one_select( sql->db, view, $3 );
DISTINCT_CreateView( sql->db, & $$, view );
}
;
selcollist:
column
{
struct string_list *list;
list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
if( !list )
YYABORT;
list->string = $1;
list->next = NULL;
$$ = list;
TRACE("Collist %s\n",debugstr_w($$->string));
}
| column TK_COMMA selcollist
{
struct string_list *list;
list = HeapAlloc( GetProcessHeap(), 0, sizeof *list );
if( !list )
YYABORT;
list->string = $1;
list->next = $3;
$$ = list;
TRACE("From table: %s\n",debugstr_w($$->string));
}
| TK_STAR
{
$$ = NULL;
}
;
from:
TK_FROM table
{
yyinput* sql = (yyinput*) info;
$$ = NULL;
TRACE("From table: %s\n",debugstr_w($2));
TABLE_CreateView( sql->db, $2, & $$ );
}
| TK_FROM table TK_WHERE expr
{
yyinput* sql = (yyinput*) info;
MSIVIEW *view = NULL;
UINT r;
$$ = NULL;
TRACE("From table: %s\n",debugstr_w($2));
r = TABLE_CreateView( sql->db, $2, &view );
if( r != ERROR_SUCCESS )
YYABORT;
r = WHERE_CreateView( sql->db, &view, view );
if( r != ERROR_SUCCESS )
YYABORT;
r = WHERE_AddCondition( view, $4 );
if( r != ERROR_SUCCESS )
YYABORT;
$$ = view;
}
;
expr:
TK_LP expr TK_RP
{
$$ = $2;
}
| column_val TK_EQ column_val
{
$$ = EXPR_complex( $1, OP_EQ, $3 );
}
| expr TK_AND expr
{
$$ = EXPR_complex( $1, OP_AND, $3 );
}
| expr TK_OR expr
{
$$ = EXPR_complex( $1, OP_OR, $3 );
}
| column_val TK_EQ val
{
$$ = EXPR_complex( $1, OP_EQ, $3 );
}
| column_val TK_GT val
{
$$ = EXPR_complex( $1, OP_GT, $3 );
}
| column_val TK_LT val
{
$$ = EXPR_complex( $1, OP_LT, $3 );
}
| column_val TK_LE val
{
$$ = EXPR_complex( $1, OP_LE, $3 );
}
| column_val TK_GE val
{
$$ = EXPR_complex( $1, OP_GE, $3 );
}
| column_val TK_NE val
{
$$ = EXPR_complex( $1, OP_NE, $3 );
}
| column_val TK_IS TK_NULL
{
$$ = EXPR_complex( $1, OP_ISNULL, NULL );
}
| column_val TK_IS TK_NOT TK_NULL
{
$$ = EXPR_complex( $1, OP_NOTNULL, NULL );
}
;
val:
column_val
{
$$ = $1;
}
| TK_INTEGER
{
yyinput* sql = (yyinput*) info;
$$ = EXPR_ival( yygetint(sql) );
}
| TK_STRING
{
$$ = EXPR_sval( $1 );
}
;
column_val:
column
{
$$ = EXPR_column( $1 );
}
;
column:
table TK_DOT string_or_id
{
$$ = $3; /* FIXME */
}
| string_or_id
{
$$ = $1;
}
;
table:
string_or_id
{
$$ = $1;
}
;
string_or_id:
TK_ID
{
yyinput* sql = (yyinput*) info;
$$ = yygetstring(sql);
}
| TK_STRING
{
yyinput* sql = (yyinput*) info;
$$ = yygetstring(sql);
}
;
%%
int yylex( void *yylval, yyinput *sql)
{
int token;
do
{
sql->n += sql->len;
if( ! sql->command[sql->n] )
return 0; /* end of input */
TRACE("string : %s\n", debugstr_w(&sql->command[sql->n]));
sql->len = sqliteGetToken( &sql->command[sql->n], &token );
if( sql->len==0 )
break;
}
while( token == TK_SPACE );
TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len));
return token;
}
LPWSTR yygetstring( yyinput *sql )
{
LPCWSTR p = &sql->command[sql->n];
LPWSTR str;
UINT len = sql->len;
/* if there's quotes, remove them */
if( (p[0]=='`') && (p[len-1]=='`') )
{
p++;
len -= 2;
}
str = HeapAlloc( GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR));
if(!str )
return str;
memcpy(str, p, len*sizeof(WCHAR) );
str[len]=0;
return str;
}
INT yygetint( yyinput *sql )
{
LPCWSTR p = &sql->command[sql->n];
return atoiW( p );
}
int yyerror(char *str)
{
return 0;
}
static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in,
struct string_list *columns )
{
MSIVIEW *view = NULL;
SELECT_CreateView( db, &view, in );
if( view )
{
struct string_list *x = columns;
while( x )
{
struct string_list *t = x->next;
SELECT_AddColumn( view, x->string );
HeapFree( GetProcessHeap(), 0, x->string );
HeapFree( GetProcessHeap(), 0, x );
x = t;
}
}
else
ERR("Error creating select query\n");
return view;
}
static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in,
struct string_list *columns )
{
MSIVIEW *view = NULL;
ORDER_CreateView( db, &view, in );
if( view )
{
struct string_list *x = columns;
while( x )
{
struct string_list *t = x->next;
ORDER_AddColumn( view, x->string );
HeapFree( GetProcessHeap(), 0, x->string );
HeapFree( GetProcessHeap(), 0, x );
x = t;
}
}
else
ERR("Error creating select query\n");
return view;
}
static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r )
{
struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
if( e )
{
e->type = EXPR_COMPLEX;
e->u.expr.left = l;
e->u.expr.op = op;
e->u.expr.right = r;
}
return e;
}
static struct expr * EXPR_column( LPWSTR column )
{
struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
if( e )
{
e->type = EXPR_COLUMN;
e->u.column = column;
}
return e;
}
static struct expr * EXPR_ival( INT ival )
{
struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
if( e )
{
e->type = EXPR_IVAL;
e->u.ival = ival;
}
return e;
}
static struct expr * EXPR_sval( LPWSTR string )
{
struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
if( e )
{
e->type = EXPR_SVAL;
e->u.sval = string;
}
return e;
}
UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview )
{
yyinput sql;
int r;
*phview = NULL;
sql.db = db;
sql.command = command;
sql.n = 0;
sql.len = 0;
sql.view = phview;
r = yyparse(&sql);
TRACE("Parse returned %d\n", r);
if( r )
{
if( *sql.view )
(*sql.view)->ops->delete( *sql.view );
return ERROR_BAD_QUERY_SYNTAX;
}
return ERROR_SUCCESS;
}

223
dlls/msi/suminfo.c Normal file
View File

@ -0,0 +1,223 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define NONAMELESSUNION
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "shlwapi.h"
#include "wine/debug.h"
#include "msi.h"
#include "msiquery.h"
#include "msipriv.h"
#include "objidl.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
const WCHAR szSumInfo[] = { 5 ,'S','u','m','m','a','r','y',
'I','n','f','o','r','m','a','t','i','o','n',0 };
static void MSI_CloseSummaryInfo( VOID *arg )
{
MSISUMMARYINFO *suminfo = (MSISUMMARYINFO *) arg;
IPropertyStorage_Release( suminfo->propstg );
}
UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE hDatabase,
LPCSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *phSummaryInfo)
{
LPWSTR szwDatabase = NULL;
UINT ret;
TRACE("%ld %s %d %p\n", hDatabase, debugstr_a(szDatabase),
uiUpdateCount, phSummaryInfo);
if( szDatabase )
{
szwDatabase = HEAP_strdupAtoW( GetProcessHeap(), 0, szDatabase );
if( !szwDatabase )
return ERROR_FUNCTION_FAILED;
}
ret = MsiGetSummaryInformationW(hDatabase, szwDatabase, uiUpdateCount, phSummaryInfo);
if( szwDatabase )
HeapFree( GetProcessHeap(), 0, szwDatabase );
return ret;
}
UINT WINAPI MsiGetSummaryInformationW(MSIHANDLE hDatabase,
LPCWSTR szDatabase, UINT uiUpdateCount, MSIHANDLE *phSummaryInfo)
{
HRESULT r;
MSIHANDLE handle, hdb = hDatabase;
MSISUMMARYINFO *suminfo;
MSIDATABASE *db;
UINT ret = ERROR_SUCCESS;
IPropertySetStorage *psstg = NULL;
IPropertyStorage *ps = NULL;
DWORD grfMode;
TRACE("%ld %s %d %p\n", hDatabase, debugstr_w(szDatabase),
uiUpdateCount, phSummaryInfo);
if( !phSummaryInfo )
return ERROR_INVALID_PARAMETER;
if( szDatabase )
{
UINT res;
res = MsiOpenDatabaseW(szDatabase, NULL, &hdb);
if( res != ERROR_SUCCESS )
return res;
}
db = msihandle2msiinfo(hdb, MSIHANDLETYPE_DATABASE);
if( !db )
return ERROR_INVALID_PARAMETER;
r = IStorage_QueryInterface( db->storage,
&IID_IPropertySetStorage, (LPVOID)&psstg);
if( FAILED( r ) )
{
ERR("IStorage -> IPropertySetStorage failed\n");
return ERROR_FUNCTION_FAILED;
}
ERR("storage = %p propertysetstorage = %p\n", db->storage, psstg);
grfMode = STGM_READ | STGM_SHARE_EXCLUSIVE;
r = IPropertySetStorage_Open( psstg, &FMTID_SummaryInformation, grfMode, &ps );
if( FAILED( r ) )
{
ERR("failed to get IPropertyStorage r=%08lx\n",r);
ret = ERROR_FUNCTION_FAILED;
goto end;
}
handle = alloc_msihandle( MSIHANDLETYPE_SUMMARYINFO,
sizeof (MSISUMMARYINFO), MSI_CloseSummaryInfo );
if( !handle )
{
ret = ERROR_FUNCTION_FAILED;
goto end;
}
suminfo = msihandle2msiinfo( handle, MSIHANDLETYPE_SUMMARYINFO );
if( !suminfo )
{
ret = ERROR_FUNCTION_FAILED;
goto end;
}
IPropertyStorage_AddRef(ps);
suminfo->propstg = ps;
*phSummaryInfo = handle;
end:
if( ps )
IPropertyStorage_Release(ps);
if( psstg )
IPropertySetStorage_Release(psstg);
if( !hDatabase )
MsiCloseHandle( hdb );
return ret;
}
UINT WINAPI MsiSummaryInfoGetPropertyCount(MSIHANDLE hSummaryInfo, UINT *pCount)
{
MSISUMMARYINFO *suminfo;
FIXME("%ld %p\n",hSummaryInfo, pCount);
suminfo = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO );
if( !suminfo )
return ERROR_INVALID_HANDLE;
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiSummaryInfoGetPropertyA(
MSIHANDLE hSummaryInfo, UINT uiProperty, UINT *puiDataType, INT *piValue,
FILETIME *pftValue, LPSTR szValueBuf, DWORD *pcchValueBuf)
{
MSISUMMARYINFO *suminfo;
HRESULT r;
PROPSPEC spec;
PROPVARIANT var;
TRACE("%ld %d %p %p %p %p %p\n",
hSummaryInfo, uiProperty, puiDataType, piValue,
pftValue, szValueBuf, pcchValueBuf);
suminfo = msihandle2msiinfo( hSummaryInfo, MSIHANDLETYPE_SUMMARYINFO );
if( !suminfo )
return ERROR_INVALID_HANDLE;
spec.ulKind = PRSPEC_PROPID;
spec.DUMMYUNIONNAME.propid = uiProperty;
r = IPropertyStorage_ReadMultiple( suminfo->propstg, 1, &spec, &var);
if( FAILED(r) )
return ERROR_FUNCTION_FAILED;
if( puiDataType )
*puiDataType = var.vt;
switch( var.vt )
{
case VT_I4:
if( piValue )
*piValue = var.DUMMYUNIONNAME.lVal;
break;
case VT_LPSTR:
if( pcchValueBuf && szValueBuf )
{
lstrcpynA(szValueBuf, var.DUMMYUNIONNAME.pszVal, *pcchValueBuf );
*pcchValueBuf = lstrlenA( var.DUMMYUNIONNAME.pszVal );
}
break;
case VT_FILETIME:
if( pftValue )
memcpy(pftValue, &var.DUMMYUNIONNAME.filetime, sizeof (FILETIME) );
break;
case VT_EMPTY:
break;
default:
FIXME("Unknown property variant type\n");
break;
}
return ERROR_SUCCESS;
}
UINT WINAPI MsiSummaryInfoGetPropertyW(
MSIHANDLE hSummaryInfo, UINT uiProperty, UINT *puiDataType, INT *piValue,
FILETIME *pftValue, LPWSTR szValueBuf, DWORD *pcchValueBuf)
{
FIXME("%ld %d %p %p %p %p %p\n",
hSummaryInfo, uiProperty, puiDataType, piValue,
pftValue, szValueBuf, pcchValueBuf);
return ERROR_CALL_NOT_IMPLEMENTED;
}

887
dlls/msi/table.c Normal file
View File

@ -0,0 +1,887 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#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 "winnls.h"
#include "query.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
typedef struct tagMSICOLUMNINFO
{
LPWSTR tablename;
UINT number;
LPWSTR colname;
UINT type;
UINT offset;
} MSICOLUMNINFO;
struct tagMSITABLE
{
USHORT *data;
UINT size;
UINT ref_count;
/* MSICOLUMNINFO *columns; */
/* UINT num_cols; */
struct tagMSITABLE *next;
struct tagMSITABLE *prev;
WCHAR name[1];
} ;
#define MAX_STREAM_NAME 0x1f
static int utf2mime(int x)
{
if( (x>='0') && (x<='9') )
return x-'0';
if( (x>='A') && (x<='Z') )
return x-'A'+10;
if( (x>='a') && (x<='z') )
return x-'a'+10+26;
if( x=='.' )
return 10+26+26;
if( x=='_' )
return 10+26+26+1;
return -1;
}
static BOOL encode_streamname(BOOL bTable, LPCWSTR in, LPWSTR out)
{
DWORD count = MAX_STREAM_NAME;
DWORD ch, next;
if( bTable )
{
*out++ = 0x4840;
count --;
}
while( count -- )
{
ch = *in++;
if( !ch )
{
*out = ch;
return TRUE;
}
if( ( ch < 0x80 ) && ( utf2mime(ch) >= 0 ) )
{
ch = utf2mime(ch) + 0x4800;
next = *in;
if( next && (next<0x80) )
{
next = utf2mime(next);
if( next >= 0 )
{
next += 0x3ffffc0;
ch += (next<<6);
in++;
}
}
}
*out++ = ch;
}
return FALSE;
}
#if 0
static int mime2utf(int x)
{
if( x<10 )
return x + '0';
if( x<(10+26))
return x - 10 + 'A';
if( x<(10+26+26))
return x - 10 - 26 + 'a';
if( x == (10+26+26) )
return '.';
return '_';
}
static BOOL decode_streamname(LPWSTR in, LPWSTR out)
{
WCHAR ch;
DWORD count = 0;
while ( (ch = *in++) )
{
if( (ch >= 0x3800 ) && (ch < 0x4840 ) )
{
if( ch >= 0x4800 )
ch = mime2utf(ch-0x4800);
else
{
ch -= 0x3800;
*out++ = mime2utf(ch&0x3f);
count++;
ch = mime2utf((ch>>6)&0x3f);
}
}
*out++ = ch;
count++;
}
*out = 0;
return count;
}
#endif
UINT read_table_from_storage(IStorage *stg, LPCWSTR name, MSITABLE **ptable)
{
WCHAR buffer[0x20];
HRESULT r;
IStream *stm = NULL;
STATSTG stat;
UINT ret = ERROR_FUNCTION_FAILED;
VOID *data;
ULONG sz, count;
MSITABLE *t;
encode_streamname(TRUE, name, buffer);
TRACE("%s -> %s\n",debugstr_w(name),debugstr_w(buffer));
r = IStorage_OpenStream(stg, buffer, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
if( FAILED( r ) )
{
ERR("open stream failed r = %08lx!\n",r);
return r;
}
r = IStream_Stat(stm, &stat, STATFLAG_NONAME );
if( FAILED( r ) )
{
ERR("open stream failed r = %08lx!\n",r);
goto end;
}
if( stat.cbSize.QuadPart >> 32 )
{
ERR("Too big!\n");
goto end;
}
sz = stat.cbSize.QuadPart;
data = HeapAlloc( GetProcessHeap(), 0, sz );
if( !data )
{
ERR("couldn't allocate memory r=%08lx!\n",r);
goto end;
}
r = IStream_Read(stm, data, sz, &count );
if( FAILED( r ) )
{
HeapFree( GetProcessHeap(), 0, data );
ERR("read stream failed r = %08lx!\n",r);
goto end;
}
t = HeapAlloc( GetProcessHeap(), 0, sizeof (MSITABLE) + lstrlenW(name)*sizeof (WCHAR) );
if( !t )
{
HeapFree( GetProcessHeap(), 0, data );
ERR("malloc failed!\n");
goto end;
}
if( count == sz )
{
ret = ERROR_SUCCESS;
t->size = sz;
t->data = data;
lstrcpyW( t->name, name );
t->ref_count = 1;
*ptable = t;
}
else
{
HeapFree( GetProcessHeap(), 0, data );
ERR("Count != sz\n");
}
end:
if( stm )
IStream_Release( stm );
return ret;
}
/* add this table to the list of cached tables in the database */
void add_table(MSIDATABASE *db, MSITABLE *table)
{
table->next = db->first_table;
table->prev = NULL;
if( db->first_table )
db->first_table->prev = table;
else
db->last_table = table;
db->first_table = table;
}
/* remove from the list of cached tables */
void remove_table( MSIDATABASE *db, MSITABLE *table )
{
if( table->next )
table->next->prev = table->prev;
else
db->last_table = table->prev;
if( table->prev )
table->prev->next = table->next;
else
db->first_table = table->next;
table->next = NULL;
table->prev = NULL;
}
void release_table( MSIDATABASE *db, MSITABLE *table )
{
if( !table->ref_count )
ERR("Trying to destroy table with refcount 0\n");
table->ref_count --;
if( !table->ref_count )
{
remove_table( db, table );
HeapFree( GetProcessHeap(), 0, table->data );
HeapFree( GetProcessHeap(), 0, table );
TRACE("Destroyed table %s\n", debugstr_w(table->name));
}
}
void free_cached_tables( MSIDATABASE *db )
{
while( db->first_table )
{
MSITABLE *t = db->first_table;
if ( --t->ref_count )
ERR("table ref count not zero for %s\n", debugstr_w(t->name));
remove_table( db, t );
HeapFree( GetProcessHeap(), 0, t->data );
HeapFree( GetProcessHeap(), 0, t );
}
}
UINT find_cached_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable)
{
MSITABLE *t;
for( t = db->first_table; t; t=t->next )
{
if( !lstrcmpW( name, t->name ) )
{
*ptable = t;
return ERROR_SUCCESS;
}
}
return ERROR_FUNCTION_FAILED;
}
UINT get_table(MSIDATABASE *db, LPCWSTR name, MSITABLE **ptable)
{
UINT r;
*ptable = NULL;
/* first, see if the table is cached */
r = find_cached_table( db, name, ptable );
if( r == ERROR_SUCCESS )
{
(*ptable)->ref_count++;
return r;
}
r = read_table_from_storage( db->storage, name, ptable );
if( r != ERROR_SUCCESS )
return r;
/* add the table to the list */
add_table( db, *ptable );
(*ptable)->ref_count++;
return ERROR_SUCCESS;
}
UINT dump_string_table(MSIDATABASE *db)
{
DWORD i, count, offset, len;
string_table *st = &db->strings;
MESSAGE("%d,%d bytes\n",st->pool.size,st->info.size);
count = st->pool.size/4;
offset = 0;
for(i=0; i<count; i++)
{
len = st->pool.data[i*2];
MESSAGE("[%2ld] = %s\n",i, debugstr_an(st->info.data+offset,len));
offset += len;
}
return ERROR_SUCCESS;
}
UINT load_string_table( MSIDATABASE *db, string_table *pst)
{
MSITABLE *pool = NULL, *info = NULL;
UINT r, ret = ERROR_FUNCTION_FAILED;
const WCHAR szStringData[] = {
'_','S','t','r','i','n','g','D','a','t','a',0 };
const WCHAR szStringPool[] = {
'_','S','t','r','i','n','g','P','o','o','l',0 };
r = get_table( db, szStringPool, &pool );
if( r != ERROR_SUCCESS)
goto end;
r = get_table( db, szStringData, &info );
if( r != ERROR_SUCCESS)
goto end;
pst->pool.size = pool->size;
pst->pool.data = pool->data;
pst->info.size = info->size;
pst->info.data = (CHAR *)info->data;
TRACE("Loaded %d,%d bytes\n",pst->pool.size,pst->info.size);
ret = ERROR_SUCCESS;
end:
if( info )
release_table( db, info );
if( pool )
release_table( db, pool );
return ret;
}
UINT msi_id2string( string_table *st, UINT string_no, LPWSTR buffer, UINT *sz )
{
DWORD i, count, offset, len;
count = st->pool.size/4;
TRACE("Finding string %d of %ld\n", string_no, count);
if(string_no >= count)
return ERROR_FUNCTION_FAILED;
offset = 0;
for(i=0; i<string_no; i++)
{
len = st->pool.data[i*2];
offset += len;
}
len = st->pool.data[i*2];
if( !buffer )
{
*sz = len;
return ERROR_SUCCESS;
}
if( (offset+len) > st->info.size )
return ERROR_FUNCTION_FAILED;
len = MultiByteToWideChar(CP_ACP,0,&st->info.data[offset],len,buffer,*sz-1);
buffer[len] = 0;
*sz = len+1;
return ERROR_SUCCESS;
}
static UINT msi_string2id( string_table *st, LPCWSTR buffer, UINT *id )
{
DWORD i, count, offset, len, sz;
UINT r = ERROR_INVALID_PARAMETER;
LPSTR str;
count = st->pool.size/4;
TRACE("Finding string %s in %ld strings\n", debugstr_w(buffer), count);
sz = WideCharToMultiByte( CP_ACP, 0, buffer, -1, NULL, 0, NULL, NULL );
str = HeapAlloc( GetProcessHeap(), 0, sz );
WideCharToMultiByte( CP_ACP, 0, buffer, -1, str, sz, NULL, NULL );
offset = 0;
for(i=0; i<count; i++)
{
len = st->pool.data[i*2];
if ( ( sz == len ) && !memcmp( str, st->info.data+offset, sz ) )
{
*id = i;
r = ERROR_SUCCESS;
break;
}
offset += len;
}
if( str )
HeapFree( GetProcessHeap(), 0, str );
return r;
}
static LPWSTR strdupW( LPCWSTR str )
{
UINT len = lstrlenW( str );
LPWSTR ret = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
if( ret )
lstrcpyW( ret, str );
return ret;
}
static inline UINT bytes_per_column( MSICOLUMNINFO *col )
{
if( col->type & MSITYPE_STRING )
return 2;
if( (col->type & 0xff) > 4 )
ERR("Invalid column size!\n");
return col->type & 0xff;
}
/* information for default tables */
const WCHAR szTables[] = { '_','T','a','b','l','e','s',0 };
const WCHAR szTable[] = { 'T','a','b','l','e',0 };
const WCHAR szName[] = { 'N','a','m','e',0 };
const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 };
const WCHAR szColumn[] = { 'C','o','l','u','m','n',0 };
const WCHAR szNumber[] = { 'N','u','m','b','e','r',0 };
const WCHAR szType[] = { 'T','y','p','e',0 };
struct standard_table {
LPCWSTR tablename;
LPCWSTR columnname;
UINT number;
UINT type;
} MSI_standard_tables[] =
{
{ szTables, szName, 1, MSITYPE_VALID | MSITYPE_STRING | 32},
{ szColumns, szTable, 1, MSITYPE_VALID | MSITYPE_STRING | 32},
{ szColumns, szNumber, 2, MSITYPE_VALID | 2},
{ szColumns, szName, 3, MSITYPE_VALID | MSITYPE_STRING | 32},
{ szColumns, szType, 4, MSITYPE_VALID | 2},
};
#define STANDARD_TABLE_COUNT \
(sizeof(MSI_standard_tables)/sizeof(struct standard_table))
UINT get_defaulttablecolumns( LPCWSTR szTable, MSICOLUMNINFO *colinfo, UINT *sz)
{
DWORD i, n=0;
for(i=0; i<STANDARD_TABLE_COUNT; i++)
{
if( lstrcmpW( szTable, MSI_standard_tables[i].tablename ) )
continue;
if(colinfo && (n < *sz) )
{
colinfo[n].tablename = strdupW(MSI_standard_tables[i].tablename);
colinfo[n].colname = strdupW(MSI_standard_tables[i].columnname);
colinfo[n].number = MSI_standard_tables[i].number;
colinfo[n].type = MSI_standard_tables[i].type;
/* ERR("Table %s has column %s\n",debugstr_w(colinfo[n].tablename),
debugstr_w(colinfo[n].colname)); */
if( n )
colinfo[n].offset = colinfo[n-1].offset
+ bytes_per_column( &colinfo[n-1] );
else
colinfo[n].offset = 0;
}
n++;
if( colinfo && (n >= *sz) )
break;
}
*sz = n;
return ERROR_SUCCESS;
}
LPWSTR MSI_makestring( MSIDATABASE *db, UINT stringid)
{
UINT sz=0, r;
LPWSTR str;
r = msi_id2string( &db->strings, stringid, NULL, &sz );
if( r != ERROR_SUCCESS )
return NULL;
sz ++; /* space for NUL char */
str = HeapAlloc( GetProcessHeap(), 0, sz*sizeof (WCHAR));
if( !str )
return str;
r = msi_id2string( &db->strings, stringid, str, &sz );
if( r == ERROR_SUCCESS )
return str;
HeapFree( GetProcessHeap(), 0, str );
return NULL;
}
UINT get_tablecolumns( MSIDATABASE *db,
LPCWSTR szTableName, MSICOLUMNINFO *colinfo, UINT *sz)
{
UINT r, i, n=0, table_id, count, maxcount = *sz;
MSITABLE *table = NULL;
const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 };
/* first check if there is a default table with that name */
r = get_defaulttablecolumns( szTableName, colinfo, sz );
if( ( r == ERROR_SUCCESS ) && *sz )
return r;
r = get_table( db, szColumns, &table);
if( r != ERROR_SUCCESS )
{
ERR("table %s not available\n", debugstr_w(szColumns));
return r;
}
/* convert table and column names to IDs from the string table */
r = msi_string2id( &db->strings, szTableName, &table_id );
if( r != ERROR_SUCCESS )
{
release_table( db, table );
ERR("Couldn't find id for %s\n", debugstr_w(szTableName));
return r;
}
TRACE("Table id is %d\n", table_id);
count = table->size/8;
for( i=0; i<count; i++ )
{
if( table->data[ i ] != table_id )
continue;
if( colinfo )
{
UINT id = table->data[ i + count*2 ];
colinfo[n].tablename = MSI_makestring( db, table_id );
colinfo[n].number = table->data[ i + count ] - (1<<15);
colinfo[n].colname = MSI_makestring( db, id );
colinfo[n].type = table->data[ i + count*3 ];
/* this assumes that columns are in order in the table */
if( n )
colinfo[n].offset = colinfo[n-1].offset
+ bytes_per_column( &colinfo[n-1] );
else
colinfo[n].offset = 0;
TRACE("table %s column %d is [%s] (%d) with type %08x "
"offset %d at row %d\n", debugstr_w(szTableName),
colinfo[n].number, debugstr_w(colinfo[n].colname),
id, colinfo[n].type, colinfo[n].offset, i);
if( n != (colinfo[n].number-1) )
{
ERR("oops. data in the _Columns table isn't in the right "
"order for table %s\n", debugstr_w(szTableName));
return ERROR_FUNCTION_FAILED;
}
}
n++;
if( colinfo && ( n >= maxcount ) )
break;
}
*sz = n;
release_table( db, table );
return ERROR_SUCCESS;
}
/* try to find the table name in the _Tables table */
BOOL TABLE_Exists( MSIDATABASE *db, LPWSTR name )
{
const WCHAR szTables[] = { '_','T','a','b','l','e','s',0 };
const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 };
UINT r, table_id = 0, i, count;
MSITABLE *table = NULL;
if( !lstrcmpW( name, szTables ) )
return TRUE;
if( !lstrcmpW( name, szColumns ) )
return TRUE;
r = msi_string2id( &db->strings, name, &table_id );
if( r != ERROR_SUCCESS )
{
ERR("Couldn't find id for %s\n", debugstr_w(name));
return FALSE;
}
r = get_table( db, szTables, &table);
if( r != ERROR_SUCCESS )
{
ERR("table %s not available\n", debugstr_w(szTables));
return FALSE;
}
count = table->size/2;
for( i=0; i<count; i++ )
if( table->data[ i ] == table_id )
break;
release_table( db, table );
if (i!=count)
return TRUE;
return FALSE;
}
/* below is the query interface to a table */
typedef struct tagMSITABLEVIEW
{
MSIVIEW view;
MSIDATABASE *db;
MSITABLE *table;
MSICOLUMNINFO *columns;
UINT num_cols;
UINT row_size;
WCHAR name[1];
} MSITABLEVIEW;
static UINT TABLE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
UINT offset, num_rows, n;
if( !tv->table )
return ERROR_INVALID_PARAMETER;
if( (col==0) || (col>tv->num_cols) )
return ERROR_INVALID_PARAMETER;
/* how many rows are there ? */
num_rows = tv->table->size / tv->row_size;
if( row >= num_rows )
return ERROR_NO_MORE_ITEMS;
if( tv->columns[col-1].offset >= tv->row_size )
{
ERR("Stuffed up %d >= %d\n", tv->columns[col-1].offset, tv->row_size );
ERR("%p %p\n", tv, tv->columns );
return ERROR_FUNCTION_FAILED;
}
offset = row + (tv->columns[col-1].offset/2) * num_rows;
n = bytes_per_column( &tv->columns[col-1] );
switch( n )
{
case 4:
offset = row*2 + (tv->columns[col-1].offset/2) * num_rows;
*val = tv->table->data[offset] + (tv->table->data[offset + 1] << 16);
break;
case 2:
offset = row + (tv->columns[col-1].offset/2) * num_rows;
*val = tv->table->data[offset];
break;
default:
ERR("oops! what is %d bytes per column?\n", n );
return ERROR_FUNCTION_FAILED;
}
TRACE("Data [%d][%d] = %d \n", row, col, *val );
return ERROR_SUCCESS;
}
static UINT TABLE_execute( struct tagMSIVIEW *view, MSIHANDLE record )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
UINT r;
TRACE("%p %ld\n", tv, record);
if( tv->table )
return ERROR_FUNCTION_FAILED;
r = get_table( tv->db, tv->name, &tv->table );
if( r != ERROR_SUCCESS )
return r;
return ERROR_SUCCESS;
}
static UINT TABLE_close( struct tagMSIVIEW *view )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
TRACE("%p\n", view );
if( !tv->table )
return ERROR_FUNCTION_FAILED;
release_table( tv->db, tv->table );
tv->table = NULL;
return ERROR_SUCCESS;
}
static UINT TABLE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols)
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
TRACE("%p %p %p\n", view, rows, cols );
if( cols )
*cols = tv->num_cols;
if( rows )
{
if( !tv->table )
return ERROR_INVALID_PARAMETER;
*rows = tv->table->size / tv->row_size;
}
return ERROR_SUCCESS;
}
static UINT TABLE_get_column_info( struct tagMSIVIEW *view,
UINT n, LPWSTR *name, UINT *type )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
TRACE("%p %d %p %p\n", tv, n, name, type );
if( ( n == 0 ) || ( n > tv->num_cols ) )
return ERROR_INVALID_PARAMETER;
if( name )
{
*name = strdupW( tv->columns[n-1].colname );
if( !*name )
return ERROR_FUNCTION_FAILED;
}
if( type )
*type = tv->columns[n-1].type;
return ERROR_SUCCESS;
}
static UINT TABLE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
{
FIXME("%p %d %ld\n", view, eModifyMode, hrec );
return ERROR_CALL_NOT_IMPLEMENTED;
}
static UINT TABLE_delete( struct tagMSIVIEW *view )
{
MSITABLEVIEW *tv = (MSITABLEVIEW*)view;
TRACE("%p\n", view );
if( tv->table )
release_table( tv->db, tv->table );
tv->table = NULL;
if( tv->columns )
{
UINT i;
for( i=0; i<tv->num_cols; i++)
{
HeapFree( GetProcessHeap(), 0, tv->columns[i].colname );
HeapFree( GetProcessHeap(), 0, tv->columns[i].tablename );
}
HeapFree( GetProcessHeap(), 0, tv->columns );
}
tv->columns = NULL;
HeapFree( GetProcessHeap(), 0, tv );
return ERROR_SUCCESS;
}
MSIVIEWOPS table_ops =
{
TABLE_fetch_int,
TABLE_execute,
TABLE_close,
TABLE_get_dimensions,
TABLE_get_column_info,
TABLE_modify,
TABLE_delete
};
UINT TABLE_CreateView( MSIDATABASE *db, LPWSTR name, MSIVIEW **view )
{
MSITABLEVIEW *tv ;
UINT r, sz, column_count;
MSICOLUMNINFO *columns, *last_col;
TRACE("%p %s %p\n", db, debugstr_w(name), view );
/* get the number of columns in this table */
column_count = 0;
r = get_tablecolumns( db, name, NULL, &column_count );
if( r != ERROR_SUCCESS )
return r;
/* if there's no columns, there's no table */
if( column_count == 0 )
return ERROR_INVALID_PARAMETER;
TRACE("Table found\n");
sz = sizeof *tv + lstrlenW(name)*sizeof name[0] ;
tv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
if( !tv )
return ERROR_FUNCTION_FAILED;
columns = HeapAlloc( GetProcessHeap(), 0, column_count*sizeof (MSICOLUMNINFO));
if( !columns )
{
HeapFree( GetProcessHeap(), 0, tv );
return ERROR_FUNCTION_FAILED;
}
r = get_tablecolumns( db, name, columns, &column_count );
if( r != ERROR_SUCCESS )
{
HeapFree( GetProcessHeap(), 0, columns );
HeapFree( GetProcessHeap(), 0, tv );
return ERROR_FUNCTION_FAILED;
}
TRACE("Table has %d columns\n", column_count);
last_col = &columns[column_count-1];
/* fill the structure */
tv->view.ops = &table_ops;
tv->db = db;
tv->columns = columns;
tv->num_cols = column_count;
tv->table = NULL;
tv->row_size = last_col->offset + bytes_per_column( last_col );
TRACE("one row is %d bytes\n", tv->row_size );
*view = (MSIVIEW*) tv;
lstrcpyW( tv->name, name );
return ERROR_SUCCESS;
}

379
dlls/msi/tokenize.c Normal file
View File

@ -0,0 +1,379 @@
/*
** 2001 September 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** An tokenizer for SQL
**
** This file contains C code that splits an SQL input string up into
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
*/
#include "winbase.h"
#include <ctype.h>
#include <stdlib.h>
#include "wine/debug.h"
#include "winnls.h"
#include "query.h"
#include "y.tab.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
/*
** All the keywords of the SQL language are stored as in a hash
** table composed of instances of the following structure.
*/
typedef struct Keyword Keyword;
struct Keyword {
const char *zName; /* The keyword name */
int tokenType; /* The token value for this keyword */
};
/*
** 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 },
{ "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 },
{ "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 },
{ "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 },
{ "MATCH", TK_MATCH },
{ "NATURAL", TK_JOIN_KW },
{ "NOT", TK_NOT },
{ "NOTNULL", TK_NOTNULL },
{ "NULL", TK_NULL },
{ "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 },
{ "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 },
};
#define KEYWORD_COUNT ( sizeof aKeywordTable/sizeof (Keyword) )
/*
** This function looks up an identifier to determine if it is a
** keyword. If it is a keyword, the token code of that keyword is
** returned. If the input is not a keyword, TK_ID is returned.
*/
int sqliteKeywordCode(const WCHAR *z, int n){
int i, len;
char buffer[0x10];
len = WideCharToMultiByte( CP_ACP, 0, z, n, buffer, sizeof buffer, NULL, NULL );
for(i=0; i<KEYWORD_COUNT; i++)
{
if(memcmp(buffer, aKeywordTable[i].zName, len))
continue;
if(strlen(aKeywordTable[i].zName) == len )
return aKeywordTable[i].tokenType;
}
return TK_ID;
}
/*
** If X is a character that can be used in an identifier then
** isIdChar[X] will be 1. Otherwise isIdChar[X] will be 0.
**
** In this implementation, an identifier can be a string of
** alphabetic characters, digits, and "_" plus any character
** with the high-order bit set. The latter rule means that
** any sequence of UTF-8 characters or characters taken from
** an extended ISO8859 character set can form an identifier.
*/
static const char isIdChar[] = {
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 4x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 9x */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Ax */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Bx */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Cx */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Dx */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Ex */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Fx */
};
/*
** Return the length of the token that begins at z[0]. Return
** -1 if the token is (or might be) incomplete. Store the token
** type in *tokenType before returning.
*/
int sqliteGetToken(const WCHAR *z, int *tokenType){
int i;
switch( *z ){
case ' ': case '\t': case '\n': case '\f': case '\r': {
for(i=1; isspace(z[i]); i++){}
*tokenType = TK_SPACE;
return i;
}
case '-': {
if( z[1]==0 ) return -1;
if( z[1]=='-' ){
for(i=2; z[i] && z[i]!='\n'; i++){}
*tokenType = TK_COMMENT;
return i;
}
*tokenType = TK_MINUS;
return 1;
}
case '(': {
if( z[1]=='+' && z[2]==')' ){
*tokenType = TK_ORACLE_OUTER_JOIN;
return 3;
}else{
*tokenType = TK_LP;
return 1;
}
}
case ')': {
*tokenType = TK_RP;
return 1;
}
case ';': {
*tokenType = TK_SEMI;
return 1;
}
case '+': {
*tokenType = TK_PLUS;
return 1;
}
case '*': {
*tokenType = TK_STAR;
return 1;
}
case '/': {
if( z[1]!='*' || z[2]==0 ){
*tokenType = TK_SLASH;
return 1;
}
for(i=3; z[i] && (z[i]!='/' || z[i-1]!='*'); i++){}
if( z[i] ) i++;
*tokenType = TK_COMMENT;
return i;
}
case '%': {
*tokenType = TK_REM;
return 1;
}
case '=': {
*tokenType = TK_EQ;
return 1 + (z[1]=='=');
}
case '<': {
if( z[1]=='=' ){
*tokenType = TK_LE;
return 2;
}else if( z[1]=='>' ){
*tokenType = TK_NE;
return 2;
}else if( z[1]=='<' ){
*tokenType = TK_LSHIFT;
return 2;
}else{
*tokenType = TK_LT;
return 1;
}
}
case '>': {
if( z[1]=='=' ){
*tokenType = TK_GE;
return 2;
}else if( z[1]=='>' ){
*tokenType = TK_RSHIFT;
return 2;
}else{
*tokenType = TK_GT;
return 1;
}
}
case '!': {
if( z[1]!='=' ){
*tokenType = TK_ILLEGAL;
return 2;
}else{
*tokenType = TK_NE;
return 2;
}
}
case '|': {
if( z[1]!='|' ){
*tokenType = TK_BITOR;
return 1;
}else{
*tokenType = TK_CONCAT;
return 2;
}
}
case ',': {
*tokenType = TK_COMMA;
return 1;
}
case '&': {
*tokenType = TK_BITAND;
return 1;
}
case '~': {
*tokenType = TK_BITNOT;
return 1;
}
case '`': case '\'': case '"': {
int delim = z[0];
for(i=1; z[i]; i++){
if( z[i]==delim ){
if( z[i+1]==delim ){
i++;
}else{
break;
}
}
}
if( z[i] ) i++;
*tokenType = TK_STRING;
return i;
}
case '.': {
if( !isdigit(z[1]) ){
*tokenType = TK_DOT;
return 1;
}
/* Fall thru into the next case */
}
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': {
*tokenType = TK_INTEGER;
for(i=1; isdigit(z[i]); i++){}
if( z[i]=='.' ){
i++;
while( isdigit(z[i]) ){ i++; }
*tokenType = TK_FLOAT;
}
if( (z[i]=='e' || z[i]=='E') &&
( isdigit(z[i+1])
|| ((z[i+1]=='+' || z[i+1]=='-') && isdigit(z[i+2]))
)
){
i += 2;
while( isdigit(z[i]) ){ i++; }
*tokenType = TK_FLOAT;
}else if( z[0]=='.' ){
*tokenType = TK_FLOAT;
}
return i;
}
case '[': {
for(i=1; z[i] && z[i-1]!=']'; i++){}
*tokenType = TK_ID;
return i;
}
default: {
if( !isIdChar[*z] ){
break;
}
for(i=1; isIdChar[z[i]]; i++){}
*tokenType = sqliteKeywordCode(z, i);
return i;
}
}
*tokenType = TK_ILLEGAL;
return 1;
}

384
dlls/msi/where.c Normal file
View File

@ -0,0 +1,384 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#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 "winnls.h"
#include "query.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
/* below is the query interface to a table */
typedef struct tagMSIWHEREVIEW
{
MSIVIEW view;
MSIDATABASE *db;
MSIVIEW *table;
UINT row_count;
UINT *reorder;
struct expr *cond;
} MSIWHEREVIEW;
static UINT WHERE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
{
MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
TRACE("%p %d %d %p\n", wv, row, col, val );
if( !wv->table )
return ERROR_FUNCTION_FAILED;
if( row > wv->row_count )
return ERROR_NO_MORE_ITEMS;
row = wv->reorder[ row ];
return wv->table->ops->fetch_int( wv->table, row, col, val );
}
static UINT INT_evaluate( UINT lval, UINT op, UINT rval )
{
switch( op )
{
case OP_EQ:
return ( lval == rval );
case OP_AND:
return ( lval && rval );
case OP_OR:
return ( lval || rval );
case OP_GT:
return ( lval > rval );
case OP_LT:
return ( lval < rval );
case OP_LE:
return ( lval <= rval );
case OP_GE:
return ( lval >= rval );
case OP_NE:
return ( lval != rval );
case OP_ISNULL:
return ( !lval );
case OP_NOTNULL:
return ( lval );
default:
ERR("Unknown operator %d\n", op );
}
return 0;
}
static UINT WHERE_evaluate( MSIVIEW *table, UINT row,
struct expr *cond, UINT *val )
{
UINT r, lval, rval;
if( !cond )
return ERROR_SUCCESS;
switch( cond->type )
{
case EXPR_COL_NUMBER:
return table->ops->fetch_int( table, row, cond->u.col_number, val );
/* case EXPR_IVAL:
*val = cond->u.ival;
return ERROR_SUCCESS; */
case EXPR_UVAL:
*val = cond->u.uval;
return ERROR_SUCCESS;
case EXPR_COMPLEX:
r = WHERE_evaluate( table, row, cond->u.expr.left, &lval );
if( r != ERROR_SUCCESS )
return r;
r = WHERE_evaluate( table, row, cond->u.expr.right, &rval );
if( r != ERROR_SUCCESS )
return r;
*val = INT_evaluate( lval, cond->u.expr.op, rval );
return ERROR_SUCCESS;
default:
ERR("Invalid expression type\n");
break;
}
return ERROR_SUCCESS;
}
static UINT WHERE_execute( struct tagMSIVIEW *view, MSIHANDLE record )
{
MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
UINT count = 0, r, val, i;
MSIVIEW *table = wv->table;
TRACE("%p %ld\n", wv, record);
if( !table )
return ERROR_FUNCTION_FAILED;
r = table->ops->execute( table, record );
if( r != ERROR_SUCCESS )
return r;
r = table->ops->get_dimensions( table, &count, NULL );
if( r != ERROR_SUCCESS )
return r;
wv->reorder = HeapAlloc( GetProcessHeap(), 0, count*sizeof(UINT) );
if( !wv->reorder )
return ERROR_FUNCTION_FAILED;
for( i=0; i<count; i++ )
{
val = 0;
r = WHERE_evaluate( table, i, wv->cond, &val );
if( r != ERROR_SUCCESS )
return r;
if( val )
wv->reorder[ wv->row_count ++ ] = i;
}
return ERROR_SUCCESS;
}
static UINT WHERE_close( struct tagMSIVIEW *view )
{
MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
TRACE("%p\n", wv );
if( !wv->table )
return ERROR_FUNCTION_FAILED;
if( wv->reorder )
HeapFree( GetProcessHeap(), 0, wv->reorder );
wv->reorder = NULL;
return wv->table->ops->close( wv->table );
}
static UINT WHERE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
{
MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
TRACE("%p %p %p\n", wv, rows, cols );
if( !wv->table )
return ERROR_FUNCTION_FAILED;
if( rows )
{
if( !wv->reorder )
return ERROR_FUNCTION_FAILED;
*rows = wv->row_count;
}
return wv->table->ops->get_dimensions( wv->table, NULL, cols );
}
static UINT WHERE_get_column_info( struct tagMSIVIEW *view,
UINT n, LPWSTR *name, UINT *type )
{
MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
TRACE("%p %d %p %p\n", wv, n, name, type );
if( !wv->table )
return ERROR_FUNCTION_FAILED;
return wv->table->ops->get_column_info( wv->table, n, name, type );
}
static UINT WHERE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
{
MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
TRACE("%p %d %ld\n", wv, eModifyMode, hrec );
if( !wv->table )
return ERROR_FUNCTION_FAILED;
return wv->table->ops->modify( wv->table, eModifyMode, hrec );
}
static void WHERE_delete_expr( struct expr *e )
{
if( !e )
return;
if( e->type == EXPR_COMPLEX )
{
WHERE_delete_expr( e->u.expr.left );
WHERE_delete_expr( e->u.expr.right );
}
HeapFree( GetProcessHeap(), 0, e );
}
static UINT WHERE_delete( struct tagMSIVIEW *view )
{
MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
TRACE("%p\n", wv );
if( wv->table )
wv->table->ops->delete( wv->table );
if( wv->reorder )
HeapFree( GetProcessHeap(), 0, wv->reorder );
wv->reorder = NULL;
wv->row_count = 0;
WHERE_delete_expr( wv->cond );
HeapFree( GetProcessHeap(), 0, wv );
return ERROR_SUCCESS;
}
MSIVIEWOPS where_ops =
{
WHERE_fetch_int,
WHERE_execute,
WHERE_close,
WHERE_get_dimensions,
WHERE_get_column_info,
WHERE_modify,
WHERE_delete
};
UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table )
{
MSIWHEREVIEW *wv = NULL;
UINT count = 0, r;
TRACE("%p\n", wv );
r = table->ops->get_dimensions( table, NULL, &count );
if( r != ERROR_SUCCESS )
{
ERR("can't get table dimensions\n");
return r;
}
wv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *wv );
if( !wv )
return ERROR_FUNCTION_FAILED;
/* fill the structure */
wv->view.ops = &where_ops;
wv->db = db;
wv->table = table;
wv->row_count = 0;
wv->reorder = NULL;
*view = (MSIVIEW*) wv;
return ERROR_SUCCESS;
}
static UINT WHERE_VerifyCondition( MSIVIEW *table, struct expr *cond,
UINT *valid )
{
UINT r, col = 0;
switch( cond->type )
{
case EXPR_COLUMN:
r = VIEW_find_column( table, cond->u.column, &col );
if( r == ERROR_SUCCESS )
{
*valid = 1;
cond->type = EXPR_COL_NUMBER;
cond->u.col_number = col;
}
else
{
*valid = 0;
ERR("Couldn't find column %s\n", debugstr_w( cond->u.column ) );
}
break;
case EXPR_COMPLEX:
r = WHERE_VerifyCondition( table, cond->u.expr.left, valid );
if( r != ERROR_SUCCESS )
return r;
if( !*valid )
return ERROR_SUCCESS;
r = WHERE_VerifyCondition( table, cond->u.expr.right, valid );
if( r != ERROR_SUCCESS )
return r;
break;
case EXPR_IVAL:
*valid = 1;
cond->type = EXPR_UVAL;
cond->u.uval = cond->u.ival + (1<<15);
break;
case EXPR_SVAL:
*valid = 0;
FIXME("can't deal with string values yet\n");
break;
default:
ERR("Invalid expression type\n");
*valid = 0;
break;
}
return ERROR_SUCCESS;
}
UINT WHERE_AddCondition( MSIVIEW *view, struct expr *cond )
{
MSIWHEREVIEW *wv = (MSIWHEREVIEW *) view;
UINT r, valid = 0;
if( wv->view.ops != &where_ops )
return ERROR_FUNCTION_FAILED;
if( !wv->table )
return ERROR_INVALID_PARAMETER;
if( !cond )
return ERROR_SUCCESS;
TRACE("Adding condition\n");
r = WHERE_VerifyCondition( wv->table, cond, &valid );
if( r != ERROR_SUCCESS )
ERR("condition evaluation failed\n");
TRACE("condition is %s\n", valid ? "valid" : "invalid" );
if( !valid )
{
WHERE_delete_expr( cond );
return ERROR_FUNCTION_FAILED;
}
wv->cond = cond;
return ERROR_SUCCESS;
}

View File

@ -107,6 +107,8 @@ WINDOWS_INCLUDES = \
mmsystem.h \
msacm.h \
msacmdlg.h \
msi.h \
msiquery.h \
mssip.h \
mswsock.h \
nb30.h \

85
include/msi.h Normal file
View File

@ -0,0 +1,85 @@
/*
* Copyright (C) 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __WINE_MSI_H
#define __WINE_MSI_H
typedef unsigned long MSIHANDLE;
typedef enum tagINSTALLSTATE
{
INSTALLSTATE_BADCONFIG = -6,
INSTALLSTATE_INCOMPLETE = -5,
INSTALLSTATE_SOURCEABSENT = -4,
INSTALLSTATE_MOREDATA = -3,
INSTALLSTATE_INVALIDARG = -2,
INSTALLSTATE_UNKNOWN = -1,
INSTALLSTATE_BROKEN = 0,
INSTALLSTATE_ADVERTISED = 1,
INSTALLSTATE_ABSENT = 2,
INSTALLSTATE_LOCAL = 3,
INSTALLSTATE_SOURCE = 4,
INSTALLSTATE_DEFAULT = 5
} INSTALLSTATE;
typedef enum tagINSTALLUILEVEL
{
INSTALLUILEVEL_NOCHANGE = 0,
INSTALLUILEVEL_DEFAULT = 1,
INSTALLUILEVEL_NONE = 2,
INSTALLUILEVEL_BASIC = 3,
INSTALLUILEVEL_REDUCED = 4,
INSTALLUILEVEL_FULL = 5
} INSTALLUILEVEL;
#define MSIDBOPEN_READONLY 0
#define MSIDBOPEN_TRANSACT 1
#define MSIDBOPEN_DIRECT 2
#define MSIDBOPEN_CREATE 3
UINT WINAPI MsiInstallProductA(LPCSTR, LPCSTR);
UINT WINAPI MsiInstallProductW(LPCWSTR, LPCWSTR);
UINT WINAPI MsiEnumProductsA(DWORD index, LPSTR lpguid);
UINT WINAPI MsiEnumProductsW(DWORD index, LPWSTR lpguid);
UINT WINAPI MsiEnumFeaturesA(LPCSTR, DWORD, LPSTR, LPSTR);
UINT WINAPI MsiEnumFeaturesW(LPCWSTR, DWORD, LPWSTR, LPWSTR);
UINT WINAPI MsiEnumComponentsA(DWORD, LPSTR);
UINT WINAPI MsiEnumComponentsW(DWORD, LPWSTR);
UINT WINAPI MsiEnumClientsA(LPCSTR, DWORD, LPSTR);
UINT WINAPI MsiEnumClientsW(LPCWSTR, DWORD, LPWSTR);
UINT WINAPI MsiOpenDatabaseA(LPCSTR, LPCSTR, MSIHANDLE *);
UINT WINAPI MsiOpenDatabaseW(LPCWSTR, LPCWSTR, MSIHANDLE *);
UINT WINAPI MsiGetSummaryInformationA(MSIHANDLE, LPCSTR, UINT, MSIHANDLE *);
UINT WINAPI MsiGetSummaryInformationW(MSIHANDLE, LPCWSTR, UINT, MSIHANDLE *);
UINT WINAPI MsiSummaryInfoGetPropertyA(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPSTR,DWORD*);
UINT WINAPI MsiSummaryInfoGetPropertyW(MSIHANDLE,UINT,UINT*,INT*,FILETIME*,LPWSTR,DWORD*);
UINT WINAPI MsiCloseHandle(MSIHANDLE);
UINT WINAPI MsiCloseAllHandles();
UINT WINAPI MsiProvideComponentFromDescriptorA(LPCSTR,LPSTR,DWORD*,DWORD*);
UINT WINAPI MsiProvideComponentFromDescriptorW(LPCWSTR,LPWSTR,DWORD*,DWORD*);
#endif /* __WINE_MSI_H */

98
include/msiquery.h Normal file
View File

@ -0,0 +1,98 @@
/*
* Copyright (C) 2002 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __WINE_MSIQUERY_H
#define __WINE_MSIQUERY_H
#include "msi.h"
typedef enum tagMSICONDITION
{
MSICONDITION_FALSE = 0,
MSICONDITION_TRUE = 1,
MSICONDITION_NONE = 2,
MSICONDITION_ERROR = 3,
} MSICONDITION;
#define MSI_NULL_INTEGER 0x80000000
typedef enum tagMSICOLINFO
{
MSICOLINFO_NAMES = 0,
MSICOLINFO_TYPES = 1
} MSICOLINFO;
typedef enum tagMSIMODIFY
{
MSIMODIFY_REFRESH = 0,
MSIMODIFY_INSERT = 1,
MSIMODIFY_UPDATE = 2,
MSIMODIFY_ASSIGN = 3,
MSIMODIFY_REPLACE = 4,
MSIMODIFY_MERGE = 5,
MSIMODIFY_DELETE = 6,
MSIMODIFY_INSERT_TEMPORARY = 7,
MSIMODIFY_VALIDATE = 8,
MSIMODIFY_VALIDATE_NEW = 9,
MSIMODIFY_VALIDATE_FIELD = 10,
MSIMODIFY_VALIDATE_DELETE = 11
} MSIMODIFY;
#define MSI_NULL_INTEGER 0x80000000
/* view manipulation */
UINT WINAPI MsiViewFetch(MSIHANDLE,MSIHANDLE*);
UINT WINAPI MsiViewExecute(MSIHANDLE,MSIHANDLE);
UINT WINAPI MsiViewClose(MSIHANDLE);
UINT WINAPI MsiDatabaseOpenViewA(MSIHANDLE,LPCSTR,MSIHANDLE*);
UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE,LPCWSTR,MSIHANDLE*);
/* record manipulation */
MSIHANDLE WINAPI MsiCreateRecord(unsigned int);
UINT WINAPI MsiRecordClearData(MSIHANDLE);
UINT WINAPI MsiRecordSetInteger(MSIHANDLE,unsigned int,int);
UINT WINAPI MsiRecordSetStringA(MSIHANDLE,unsigned int,LPCSTR);
UINT WINAPI MsiRecordSetStringW(MSIHANDLE,unsigned int,LPCWSTR);
UINT WINAPI MsiRecordGetStringA(MSIHANDLE,unsigned int,LPSTR,DWORD*);
UINT WINAPI MsiRecordGetStringW(MSIHANDLE,unsigned int,LPWSTR,DWORD*);
UINT WINAPI MsiRecordGetFieldCount(MSIHANDLE);
int WINAPI MsiRecordGetInteger(MSIHANDLE,unsigned int);
UINT WINAPI MsiRecordDataSize(MSIHANDLE,unsigned int);
BOOL WINAPI MsiRecordIsNull(MSIHANDLE,unsigned int);
UINT WINAPI MsiFormatRecordA(MSIHANDLE,MSIHANDLE,LPSTR,DWORD*);
UINT WINAPI MsiFormatRecordW(MSIHANDLE,MSIHANDLE,LPWSTR,DWORD*);
UINT WINAPI MsiRecordSetStreamA(MSIHANDLE,unsigned int,LPCSTR);
UINT WINAPI MsiRecordSetStreamW(MSIHANDLE,unsigned int,LPCWSTR);
UINT WINAPI MsiRecordReadStream(MSIHANDLE,unsigned int,char*,DWORD *);
UINT WINAPI MsiDatabaseGetPrimaryKeysA(MSIHANDLE,LPCSTR,MSIHANDLE*);
UINT WINAPI MsiDatabaseGetPrimaryKeysW(MSIHANDLE,LPCWSTR,MSIHANDLE*);
/* installing */
UINT WINAPI MsiDoActionA(MSIHANDLE,LPCSTR );
UINT WINAPI MsiDoActionW(MSIHANDLE,LPCWSTR );
/* database transforms */
UINT WINAPI MsiDatabaseApplyTransformA(MSIHANDLE,LPCSTR,int);
UINT WINAPI MsiDatabaseApplyTransformW(MSIHANDLE,LPCWSTR,int);
UINT WINAPI MsiDatabaseGenerateTransformA(MSIHANDLE,MSIHANDLE,LPCSTR,int,int);
UINT WINAPI MsiDatabaseGenerateTransformW(MSIHANDLE,MSIHANDLE,LPCWSTR,int,int);
UINT WINAPI MsiDatabaseCommit(MSIHANDLE);
#endif /* __WINE_MSIQUERY_H */