First port of Wine projects msi.dll

svn path=/trunk/; revision=11877
This commit is contained in:
James Tabor 2004-11-30 19:10:50 +00:00
parent 6b4f09638b
commit 34151c8b26
29 changed files with 16192 additions and 0 deletions

View file

@ -0,0 +1,8 @@
*.coff
*.dll
*.d
*.a
*.o
*.sym
*.map
*.tmp

9
reactos/lib/msi/Makefile Normal file
View file

@ -0,0 +1,9 @@
# $Id: Makefile,v 1.1 2004/11/30 19:10:50 jimtabor Exp $
PATH_TO_TOP = ../..
TARGET_TYPE = winedll
include $(PATH_TO_TOP)/rules.mak
include $(TOOLS_PATH)/helper.mk

View file

@ -0,0 +1,50 @@
TOPSRCDIR = @top_srcdir@
TOPOBJDIR = ../..
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = msi.dll
IMPORTS = shell32 cabinet oleaut32 ole32 version user32 advapi32 kernel32
EXTRALIBS = -luuid $(LIBUNICODE)
C_SRCS = \
action.c \
create.c \
distinct.c \
handle.c \
insert.c \
msi.c \
msiquery.c \
order.c \
package.c \
record.c \
regsvr.c \
select.c \
string.c \
suminfo.c \
table.c \
tokenize.c \
update.c \
where.c
RC_SRCS = version.rc
EXTRA_SRCS = sql.y cond.y
EXTRA_OBJS = sql.tab.o cond.tab.o
@MAKE_DLL_RULES@
sql.tab.c sql.tab.h: sql.y
$(BISON) -p SQL_ -d $(SRCDIR)/sql.y -o sql.tab.c
cond.tab.c cond.tab.h: cond.y
$(BISON) -p COND_ -d $(SRCDIR)/cond.y -o cond.tab.c
# hack to allow parallel make
sql.tab.h: sql.tab.c
sql.tab.o: sql.tab.h
cond.tab.h: cond.tab.c
cond.tab.o: cond.tab.h
tokenize.o: sql.tab.h
### Dependencies:

View file

@ -0,0 +1,35 @@
# $Id: Makefile.ros-template
TARGET_NAME = msi
TARGET_OBJECTS = @C_SRCS@ @EXTRA_OBJS@
TARGET_CFLAGS = -D__REACTOS__ @EXTRADEFS@
TARGET_SDKLIBS = @IMPORTS@ libwine.a wine_uuid.a ntdll.a
TARGET_BASE = $(TARGET_BASE_LIB_WINMM)
TARGET_RC_SRCS = @RC_SRCS@
TARGET_RC_BINSRC = @RC_BINSRC@
TARGET_RC_BINARIES = @RC_BINARIES@
TARGET_CLEAN = *.tab.c *.tab.h
default: all
DEP_OBJECTS = $(TARGET_OBJECTS)
include $(TOOLS_PATH)/depend.mk
#
# Bison is requiered for building msi.dll. If MingW32 for windows,
# download bison from http://gnuwin32.sourceforge.net/
# Make sure bison.exe is placed in your command path for execution.
#
#
sql.tab.c sql.tab.h: sql.y
bison -p SQL_ -d ./sql.y -o sql.tab.c
cond.tab.c cond.tab.h: cond.y
bison -p COND_ -d ./cond.y -o cond.tab.c

4733
reactos/lib/msi/action.c Normal file

File diff suppressed because it is too large Load diff

774
reactos/lib/msi/cond.y Normal file
View file

@ -0,0 +1,774 @@
%{
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2003 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 <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include "windef.h"
#include "winbase.h"
#include "wine/debug.h"
#include "wine/unicode.h"
#include "msi.h"
#include "msiquery.h"
#include "msipriv.h"
#define YYLEX_PARAM info
#define YYPARSE_PARAM info
static int COND_error(char *str);
WINE_DEFAULT_DEBUG_CHANNEL(msi);
typedef struct tag_yyinput
{
MSIPACKAGE *package;
LPCWSTR str;
INT n;
MSICONDITION result;
} COND_input;
struct cond_str {
LPCWSTR data;
INT len;
};
static LPWSTR COND_GetString( struct cond_str *str );
static LPWSTR COND_GetLiteral( struct cond_str *str );
static int COND_lex( void *COND_lval, COND_input *info);
typedef INT (*comp_int)(INT a, INT b);
typedef INT (*comp_str)(LPWSTR a, LPWSTR b, BOOL caseless);
typedef INT (*comp_m1)(LPWSTR a,int b);
typedef INT (*comp_m2)(int a,LPWSTR b);
static INT comp_lt_i(INT a, INT b);
static INT comp_gt_i(INT a, INT b);
static INT comp_le_i(INT a, INT b);
static INT comp_ge_i(INT a, INT b);
static INT comp_eq_i(INT a, INT b);
static INT comp_ne_i(INT a, INT b);
static INT comp_bitand(INT a, INT b);
static INT comp_highcomp(INT a, INT b);
static INT comp_lowcomp(INT a, INT b);
static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless);
static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless);
static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless);
static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless);
static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless);
static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless);
static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless);
static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless);
static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless);
static INT comp_eq_m1(LPWSTR a, INT b);
static INT comp_ne_m1(LPWSTR a, INT b);
static INT comp_lt_m1(LPWSTR a, INT b);
static INT comp_gt_m1(LPWSTR a, INT b);
static INT comp_le_m1(LPWSTR a, INT b);
static INT comp_ge_m1(LPWSTR a, INT b);
static INT comp_eq_m2(INT a, LPWSTR b);
static INT comp_ne_m2(INT a, LPWSTR b);
static INT comp_lt_m2(INT a, LPWSTR b);
static INT comp_gt_m2(INT a, LPWSTR b);
static INT comp_le_m2(INT a, LPWSTR b);
static INT comp_ge_m2(INT a, LPWSTR b);
%}
%pure-parser
%union
{
struct cond_str str;
LPWSTR string;
INT value;
comp_int fn_comp_int;
comp_str fn_comp_str;
comp_m1 fn_comp_m1;
comp_m2 fn_comp_m2;
}
%token COND_SPACE COND_EOF COND_SPACE
%token COND_OR COND_AND COND_NOT
%token COND_LT COND_GT COND_EQ
%token COND_LPAR COND_RPAR COND_TILDA
%token COND_PERCENT COND_DOLLARS COND_QUESTION COND_AMPER COND_EXCLAM
%token <str> COND_IDENT <str> COND_NUMBER <str> COND_LITER
%nonassoc COND_EOF COND_ERROR
%type <value> expression boolean_term boolean_factor
%type <value> term value_i symbol_i integer
%type <string> identifier value_s symbol_s literal
%type <fn_comp_int> comp_op_i
%type <fn_comp_str> comp_op_s
%type <fn_comp_m1> comp_op_m1
%type <fn_comp_m2> comp_op_m2
%%
condition:
expression
{
COND_input* cond = (COND_input*) info;
cond->result = $1;
}
;
expression:
boolean_term
{
$$ = $1;
}
| boolean_term COND_OR expression
{
$$ = $1 || $3;
}
;
boolean_term:
boolean_factor
{
$$ = $1;
}
| boolean_term COND_AND boolean_factor
{
$$ = $1 && $3;
}
;
boolean_factor:
term
{
$$ = $1;
}
| COND_NOT term
{
$$ = ! $2;
}
;
term:
value_i
{
$$ = $1;
}
| value_s
{
$$ = atoiW($1);
}
| value_i comp_op_i value_i
{
$$ = $2( $1, $3 );
}
| value_s comp_op_s value_s
{
$$ = $2( $1, $3, FALSE );
}
| value_s COND_TILDA comp_op_s value_s
{
$$ = $3( $1, $4, TRUE );
}
| value_s comp_op_m1 value_i
{
$$ = $2( $1, $3 );
}
| value_i comp_op_m2 value_s
{
$$ = $2( $1, $3 );
}
| COND_LPAR expression COND_RPAR
{
$$ = $2;
}
;
comp_op_i:
/* common functions */
COND_EQ
{
$$ = comp_eq_i;
}
| COND_LT COND_GT
{
$$ = comp_ne_i;
}
| COND_LT
{
$$ = comp_lt_i;
}
| COND_GT
{
$$ = comp_gt_i;
}
| COND_LT COND_EQ
{
$$ = comp_le_i;
}
| COND_GT COND_EQ
{
$$ = comp_ge_i;
}
/*Int only*/
| COND_GT COND_LT
{
$$ = comp_bitand;
}
| COND_LT COND_LT
{
$$ = comp_highcomp;
}
| COND_GT COND_GT
{
$$ = comp_lowcomp;
}
;
comp_op_s:
/* common functions */
COND_EQ
{
$$ = comp_eq_s;
}
| COND_LT COND_GT
{
$$ = comp_ne_s;
}
| COND_LT
{
$$ = comp_lt_s;
}
| COND_GT
{
$$ = comp_gt_s;
}
| COND_LT COND_EQ
{
$$ = comp_le_s;
}
| COND_GT COND_EQ
{
$$ = comp_ge_s;
}
/*string only*/
| COND_GT COND_LT
{
$$ = comp_substring;
}
| COND_LT COND_LT
{
$$ = comp_start;
}
| COND_GT COND_GT
{
$$ = comp_end;
}
;
comp_op_m1:
/* common functions */
COND_EQ
{
$$ = comp_eq_m1;
}
| COND_LT COND_GT
{
$$ = comp_ne_m1;
}
| COND_LT
{
$$ = comp_lt_m1;
}
| COND_GT
{
$$ = comp_gt_m1;
}
| COND_LT COND_EQ
{
$$ = comp_le_m1;
}
| COND_GT COND_EQ
{
$$ = comp_ge_m1;
}
/*Not valid for mixed compares*/
| COND_GT COND_LT
{
$$ = 0;
}
| COND_LT COND_LT
{
$$ = 0;
}
| COND_GT COND_GT
{
$$ = 0;
}
;
comp_op_m2:
/* common functions */
COND_EQ
{
$$ = comp_eq_m2;
}
| COND_LT COND_GT
{
$$ = comp_ne_m2;
}
| COND_LT
{
$$ = comp_lt_m2;
}
| COND_GT
{
$$ = comp_gt_m2;
}
| COND_LT COND_EQ
{
$$ = comp_le_m2;
}
| COND_GT COND_EQ
{
$$ = comp_ge_m2;
}
/*Not valid for mixed compares*/
| COND_GT COND_LT
{
$$ = 0;
}
| COND_LT COND_LT
{
$$ = 0;
}
| COND_GT COND_GT
{
$$ = 0;
}
;
value_i:
symbol_i
{
$$ = $1;
}
| integer
{
$$ = $1;
}
;
value_s:
symbol_s
{
$$ = $1;
}
| literal
{
$$ = $1;
}
;
literal:
COND_LITER
{
$$ = COND_GetLiteral(&$1);
if( !$$ )
YYABORT;
}
;
symbol_i:
COND_DOLLARS identifier
{
COND_input* cond = (COND_input*) info;
INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
MSI_GetComponentStateW(cond->package, $2, &install, &action );
$$ = action;
HeapFree( GetProcessHeap(), 0, $2 );
}
| COND_QUESTION identifier
{
COND_input* cond = (COND_input*) info;
INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
MSI_GetComponentStateW(cond->package, $2, &install, &action );
$$ = install;
HeapFree( GetProcessHeap(), 0, $2 );
}
| COND_AMPER identifier
{
COND_input* cond = (COND_input*) info;
INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
MSI_GetFeatureStateW(cond->package, $2, &install, &action );
$$ = action;
HeapFree( GetProcessHeap(), 0, $2 );
}
| COND_EXCLAM identifier
{
COND_input* cond = (COND_input*) info;
INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
MSI_GetFeatureStateW(cond->package, $2, &install, &action );
$$ = install;
HeapFree( GetProcessHeap(), 0, $2 );
}
;
symbol_s:
identifier
{
DWORD sz;
COND_input* cond = (COND_input*) info;
$$ = HeapAlloc( GetProcessHeap(), 0, 0x100*sizeof (WCHAR) );
/* Lookup the identifier */
sz=0x100;
if (MSI_GetPropertyW(cond->package,$1,$$,&sz) != ERROR_SUCCESS)
{
$$[0]=0;
}
HeapFree( GetProcessHeap(), 0, $1 );
}
| COND_PERCENT identifier
{
UINT len = GetEnvironmentVariableW( $2, NULL, 0 );
if( len++ )
{
$$ = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
if( $$ )
GetEnvironmentVariableW( $2, $$, len );
}
HeapFree( GetProcessHeap(), 0, $2 );
}
;
identifier:
COND_IDENT
{
$$ = COND_GetString(&$1);
if( !$$ )
YYABORT;
}
;
integer:
COND_NUMBER
{
LPWSTR szNum = COND_GetString(&$1);
if( !szNum )
YYABORT;
$$ = atoiW( szNum );
HeapFree( GetProcessHeap(), 0, szNum );
}
;
%%
static int COND_IsAlpha( WCHAR x )
{
return( ( ( x >= 'A' ) && ( x <= 'Z' ) ) ||
( ( x >= 'a' ) && ( x <= 'z' ) ) ||
( ( x == '_' ) ) );
}
static int COND_IsNumber( WCHAR x )
{
return( (( x >= '0' ) && ( x <= '9' )) || (x =='-') || (x =='.') );
}
/* the mess of comparison functions */
static INT comp_lt_i(INT a, INT b)
{ return (a < b); }
static INT comp_gt_i(INT a, INT b)
{ return (a > b); }
static INT comp_le_i(INT a, INT b)
{ return (a <= b); }
static INT comp_ge_i(INT a, INT b)
{ return (a >= b); }
static INT comp_eq_i(INT a, INT b)
{ return (a == b); }
static INT comp_ne_i(INT a, INT b)
{ return (a != b); }
static INT comp_bitand(INT a, INT b)
{ return a & b;}
static INT comp_highcomp(INT a, INT b)
{ return HIWORD(a)==b; }
static INT comp_lowcomp(INT a, INT b)
{ return LOWORD(a)==b; }
static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless)
{ if (casless) return !strcmpiW(a,b); else return !strcmpW(a,b);}
static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless)
{ if (casless) return strcmpiW(a,b); else return strcmpW(a,b);}
static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless)
{ if (casless) return strcmpiW(a,b)<0; else return strcmpW(a,b)<0;}
static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless)
{ if (casless) return strcmpiW(a,b)>0; else return strcmpW(a,b)>0;}
static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless)
{ if (casless) return strcmpiW(a,b)<=0; else return strcmpW(a,b)<=0;}
static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless)
{ if (casless) return strcmpiW(a,b)>=0; else return strcmpW(a,b)>=0;}
static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless)
/* ERROR NOT WORKING REWRITE */
{ if (casless) return strstrW(a,b)!=NULL; else return strstrW(a,b)!=NULL;}
static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless)
{ if (casless) return strncmpiW(a,b,strlenW(b))==0;
else return strncmpW(a,b,strlenW(b))==0;}
static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless)
{
int i = strlenW(a);
int j = strlenW(b);
if (j>i)
return 0;
if (casless) return (!strcmpiW(&a[i-j-1],b));
else return (!strcmpW(&a[i-j-1],b));
}
static INT comp_eq_m1(LPWSTR a, INT b)
{ if (COND_IsNumber(a[0])) return atoiW(a)==b; else return 0;}
static INT comp_ne_m1(LPWSTR a, INT b)
{ if (COND_IsNumber(a[0])) return atoiW(a)!=b; else return 1;}
static INT comp_lt_m1(LPWSTR a, INT b)
{ if (COND_IsNumber(a[0])) return atoiW(a)<b; else return 0;}
static INT comp_gt_m1(LPWSTR a, INT b)
{ if (COND_IsNumber(a[0])) return atoiW(a)>b; else return 0;}
static INT comp_le_m1(LPWSTR a, INT b)
{ if (COND_IsNumber(a[0])) return atoiW(a)<=b; else return 0;}
static INT comp_ge_m1(LPWSTR a, INT b)
{ if (COND_IsNumber(a[0])) return atoiW(a)>=b; else return 0;}
static INT comp_eq_m2(INT a, LPWSTR b)
{ if (COND_IsNumber(b[0])) return a == atoiW(b); else return 0;}
static INT comp_ne_m2(INT a, LPWSTR b)
{ if (COND_IsNumber(b[0])) return a != atoiW(b); else return 1;}
static INT comp_lt_m2(INT a, LPWSTR b)
{ if (COND_IsNumber(b[0])) return a < atoiW(b); else return 0;}
static INT comp_gt_m2(INT a, LPWSTR b)
{ if (COND_IsNumber(b[0])) return a > atoiW(b); else return 0;}
static INT comp_le_m2(INT a, LPWSTR b)
{ if (COND_IsNumber(b[0])) return a <= atoiW(b); else return 0;}
static INT comp_ge_m2(INT a, LPWSTR b)
{ if (COND_IsNumber(b[0])) return a >= atoiW(b); else return 0;}
static int COND_IsIdent( WCHAR x )
{
return( COND_IsAlpha( x ) || COND_IsNumber( x ) || ( x == '_' )
|| ( x == '#' ) || (x == '.') );
}
static int COND_GetOne( struct cond_str *str, COND_input *cond )
{
static const WCHAR szNot[] = {'N','O','T',0};
static const WCHAR szAnd[] = {'A','N','D',0};
static const WCHAR szOr[] = {'O','R',0};
WCHAR ch;
int rc, len = 1;
str->data = &cond->str[cond->n];
ch = str->data[0];
switch( ch )
{
case 0: return 0;
case '(': rc = COND_LPAR; break;
case ')': rc = COND_RPAR; break;
case '&': rc = COND_AMPER; break;
case '!': rc = COND_EXCLAM; break;
case '$': rc = COND_DOLLARS; break;
case '?': rc = COND_QUESTION; break;
case '%': rc = COND_PERCENT; break;
case ' ': rc = COND_SPACE; break;
case '=': rc = COND_EQ; break;
case '~': rc = COND_TILDA; break;
case '<': rc = COND_LT; break;
case '>': rc = COND_GT; break;
case '"':
{
const WCHAR *ch2 = str->data + 1;
while ( *ch2 && *ch2 != '"' )
++ch2;
if (*ch2 == '"')
{
len = ch2 - str->data + 1;
rc = COND_LITER;
break;
}
}
ERR("Unterminated string\n");
rc = COND_ERROR;
break;
default:
if( COND_IsAlpha( ch ) )
{
while( COND_IsIdent( str->data[len] ) )
len++;
rc = COND_IDENT;
break;
}
if( COND_IsNumber( ch ) )
{
while( COND_IsNumber( str->data[len] ) )
len++;
rc = COND_NUMBER;
break;
}
ERR("Got unknown character %c(%x)\n",ch,ch);
rc = COND_ERROR;
break;
}
/* keyword identifiers */
if( rc == COND_IDENT )
{
if( (len==3) && (strncmpiW(str->data,szNot,len)==0) )
rc = COND_NOT;
else if( (len==3) && (strncmpiW(str->data,szAnd,len)==0) )
rc = COND_AND;
else if( (len==2) && (strncmpiW(str->data,szOr,len)==0) )
rc = COND_OR;
}
cond->n += len;
str->len = len;
return rc;
}
static int COND_lex( void *COND_lval, COND_input *cond )
{
int rc;
struct cond_str *str = COND_lval;
do {
rc = COND_GetOne( str, cond );
} while (rc == COND_SPACE);
return rc;
}
static LPWSTR COND_GetString( struct cond_str *str )
{
LPWSTR ret;
ret = HeapAlloc( GetProcessHeap(), 0, (str->len+1) * sizeof (WCHAR) );
if( ret )
{
strncpyW( ret, str->data, str->len );
ret[str->len]=0;
}
TRACE("Got identifier %s\n",debugstr_w(ret));
return ret;
}
static LPWSTR COND_GetLiteral( struct cond_str *str )
{
LPWSTR ret;
ret = HeapAlloc( GetProcessHeap(), 0, (str->len-1) * sizeof (WCHAR) );
if( ret )
{
memcpy( ret, str->data+1, (str->len-2) * sizeof(WCHAR) );
ret[str->len - 2]=0;
}
TRACE("Got literal %s\n",debugstr_w(ret));
return ret;
}
static int COND_error(char *str)
{
return 0;
}
MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition )
{
COND_input cond;
MSICONDITION r;
cond.package = package;
cond.str = szCondition;
cond.n = 0;
cond.result = -1;
TRACE("Evaluating %s\n",debugstr_w(szCondition));
if( !COND_parse( &cond ) )
r = cond.result;
else
r = MSICONDITION_ERROR;
TRACE("Evaluates to %i\n",r);
return r;
}
MSICONDITION WINAPI MsiEvaluateConditionW( MSIHANDLE hInstall, LPCWSTR szCondition )
{
MSIPACKAGE *package;
UINT ret;
package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
if( !package)
return ERROR_INVALID_HANDLE;
ret = MSI_EvaluateConditionW( package, szCondition );
msiobj_release( &package->hdr );
return ret;
}
MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szCondition )
{
LPWSTR szwCond = NULL;
MSICONDITION r;
if( szCondition )
{
UINT len = MultiByteToWideChar( CP_ACP, 0, szCondition, -1, NULL, 0 );
szwCond = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
MultiByteToWideChar( CP_ACP, 0, szCondition, -1, szwCond, len );
}
r = MsiEvaluateConditionW( hInstall, szwCond );
if( szwCond )
HeapFree( GetProcessHeap(), 0, szwCond );
return r;
}

258
reactos/lib/msi/create.c Normal file
View file

@ -0,0 +1,258 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002-2004 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 <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "wine/debug.h"
#include "msi.h"
#include "msiquery.h"
#include "objbase.h"
#include "objidl.h"
#include "msipriv.h"
#include "winnls.h"
#include "query.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
/* below is the query interface to a table */
typedef struct tagMSICREATEVIEW
{
MSIVIEW view;
MSIDATABASE *db;
LPWSTR name;
BOOL bIsTemp;
create_col_info *col_info;
} MSICREATEVIEW;
static UINT CREATE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
{
MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
TRACE("%p %d %d %p\n", cv, row, col, val );
return ERROR_FUNCTION_FAILED;
}
static UINT CREATE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
{
MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
create_col_info *col;
UINT r, nField, row, table_val, column_val;
static const WCHAR szTables[] = { '_','T','a','b','l','e','s',0 };
static const WCHAR szColumns[] = { '_','C','o','l','u','m','n','s',0 };
MSIVIEW *tv = NULL;
TRACE("%p Table %s (%s)\n", cv, debugstr_w(cv->name),
cv->bIsTemp?"temporary":"permanent");
/* only add tables that don't exist already */
if( TABLE_Exists(cv->db, cv->name ) )
return ERROR_BAD_QUERY_SYNTAX;
/* add the name to the _Tables table */
table_val = msi_addstringW( cv->db->strings, 0, cv->name, -1, 1 );
TRACE("New string %s -> %d\n", debugstr_w( cv->name ), table_val );
if( table_val < 0 )
return ERROR_FUNCTION_FAILED;
r = TABLE_CreateView( cv->db, szTables, &tv );
TRACE("CreateView returned %x\n", r);
if( r )
return r;
r = tv->ops->execute( tv, 0 );
TRACE("tv execute returned %x\n", r);
if( r )
return r;
row = -1;
r = tv->ops->insert_row( tv, &row );
TRACE("insert_row returned %x\n", r);
if( r )
goto err;
r = tv->ops->set_int( tv, row, 1, table_val );
if( r )
goto err;
tv->ops->delete( tv );
tv = NULL;
/* add each column to the _Columns table */
r = TABLE_CreateView( cv->db, szColumns, &tv );
if( r )
return r;
r = tv->ops->execute( tv, 0 );
TRACE("tv execute returned %x\n", r);
if( r )
return r;
/*
* need to set the table, column number, col name and type
* for each column we enter in the table
*/
nField = 1;
for( col = cv->col_info; col; col = col->next )
{
row = -1;
r = tv->ops->insert_row( tv, &row );
if( r )
goto err;
column_val = msi_addstringW( cv->db->strings, 0, col->colname, -1, 1 );
TRACE("New string %s -> %d\n", debugstr_w( col->colname ), column_val );
if( column_val < 0 )
break;
/* add the string again here so we increase the reference count */
table_val = msi_addstringW( cv->db->strings, 0, cv->name, -1, 1 );
if( table_val < 0 )
break;
r = tv->ops->set_int( tv, row, 1, table_val );
if( r )
break;
r = tv->ops->set_int( tv, row, 2, 0x8000|nField );
if( r )
break;
r = tv->ops->set_int( tv, row, 3, column_val );
if( r )
break;
r = tv->ops->set_int( tv, row, 4, 0x8000|col->type );
if( r )
break;
nField++;
}
if( !col )
r = ERROR_SUCCESS;
err:
/* FIXME: remove values from the string table on error */
if( tv )
tv->ops->delete( tv );
return r;
}
static UINT CREATE_close( struct tagMSIVIEW *view )
{
MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
TRACE("%p\n", cv);
return ERROR_SUCCESS;
}
static UINT CREATE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
{
MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
TRACE("%p %p %p\n", cv, rows, cols );
return ERROR_FUNCTION_FAILED;
}
static UINT CREATE_get_column_info( struct tagMSIVIEW *view,
UINT n, LPWSTR *name, UINT *type )
{
MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
TRACE("%p %d %p %p\n", cv, n, name, type );
return ERROR_FUNCTION_FAILED;
}
static UINT CREATE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
{
MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
TRACE("%p %d %ld\n", cv, eModifyMode, hrec );
return ERROR_FUNCTION_FAILED;
}
static UINT CREATE_delete( struct tagMSIVIEW *view )
{
MSICREATEVIEW *cv = (MSICREATEVIEW*)view;
create_col_info *col;
TRACE("%p\n", cv );
col = cv->col_info;
while( col )
{
create_col_info *t = col;
col = col->next;
HeapFree( GetProcessHeap(), 0, t->colname );
HeapFree( GetProcessHeap(), 0, t );
}
msiobj_release( &cv->db->hdr );
HeapFree( GetProcessHeap(), 0, cv->name );
HeapFree( GetProcessHeap(), 0, cv );
return ERROR_SUCCESS;
}
MSIVIEWOPS create_ops =
{
CREATE_fetch_int,
NULL,
NULL,
NULL,
CREATE_execute,
CREATE_close,
CREATE_get_dimensions,
CREATE_get_column_info,
CREATE_modify,
CREATE_delete
};
UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
create_col_info *col_info, BOOL temp )
{
MSICREATEVIEW *cv = NULL;
TRACE("%p\n", cv );
cv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *cv );
if( !cv )
return ERROR_FUNCTION_FAILED;
/* fill the structure */
cv->view.ops = &create_ops;
msiobj_addref( &db->hdr );
cv->db = db;
cv->name = table; /* FIXME: strdupW it? */
cv->col_info = col_info;
cv->bIsTemp = temp;
*view = (MSIVIEW*) cv;
return ERROR_SUCCESS;
}

293
reactos/lib/msi/distinct.c Normal file
View file

@ -0,0 +1,293 @@
/*
* 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 <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "wine/debug.h"
#include "msi.h"
#include "msiquery.h"
#include "objbase.h"
#include "objidl.h"
#include "msipriv.h"
#include "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, MSIRECORD *record )
{
MSIDISTINCTVIEW *dv = (MSIDISTINCTVIEW*)view;
UINT r, i, j, r_count, c_count;
DISTINCTSET *rowset = NULL;
TRACE("%p %p\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 );
msiobj_release( &dv->db->hdr );
HeapFree( GetProcessHeap(), 0, dv );
return ERROR_SUCCESS;
}
MSIVIEWOPS distinct_ops =
{
DISTINCT_fetch_int,
NULL,
NULL,
NULL,
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;
msiobj_addref( &db->hdr );
dv->db = db;
dv->table = table;
dv->translation = NULL;
dv->row_count = 0;
*view = (MSIVIEW*) dv;
return ERROR_SUCCESS;
}

215
reactos/lib/msi/handle.c Normal file
View file

@ -0,0 +1,215 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002-2004 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 <stdarg.h>
#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);
static CRITICAL_SECTION MSI_handle_cs;
static CRITICAL_SECTION_DEBUG MSI_handle_cs_debug =
{
0, 0, &MSI_handle_cs,
{ &MSI_handle_cs_debug.ProcessLocksList,
&MSI_handle_cs_debug.ProcessLocksList },
0, 0, { 0, (DWORD)(__FILE__ ": MSI_handle_cs") }
};
static CRITICAL_SECTION MSI_handle_cs = { &MSI_handle_cs_debug, -1, 0, 0, 0, 0 };
MSIOBJECTHDR *msihandletable[MSIMAXHANDLES];
MSIHANDLE alloc_msihandle( MSIOBJECTHDR *obj )
{
MSIHANDLE ret = 0;
UINT i;
EnterCriticalSection( &MSI_handle_cs );
/* find a slot */
for(i=0; i<MSIMAXHANDLES; i++)
if( !msihandletable[i] )
break;
if( (i>=MSIMAXHANDLES) || msihandletable[i] )
goto out;
msiobj_addref( obj );
msihandletable[i] = obj;
ret = (MSIHANDLE) (i+1);
out:
TRACE("%p -> %ld\n", obj, ret );
LeaveCriticalSection( &MSI_handle_cs );
return ret;
}
void *msihandle2msiinfo(MSIHANDLE handle, UINT type)
{
MSIOBJECTHDR *ret = NULL;
EnterCriticalSection( &MSI_handle_cs );
handle--;
if( handle<0 )
goto out;
if( handle>=MSIMAXHANDLES )
goto out;
if( !msihandletable[handle] )
goto out;
if( msihandletable[handle]->magic != MSIHANDLE_MAGIC )
goto out;
if( type && (msihandletable[handle]->type != type) )
goto out;
ret = msihandletable[handle];
msiobj_addref( ret );
out:
LeaveCriticalSection( &MSI_handle_cs );
return (void*) ret;
}
MSIHANDLE msiobj_findhandle( MSIOBJECTHDR *hdr )
{
MSIHANDLE ret = 0;
UINT i;
TRACE("%p\n", hdr);
EnterCriticalSection( &MSI_handle_cs );
for(i=0; (i<MSIMAXHANDLES) && !ret; i++)
if( msihandletable[i] == hdr )
ret = i+1;
LeaveCriticalSection( &MSI_handle_cs );
TRACE("%p -> %ld\n", hdr, ret);
msiobj_addref( hdr );
return ret;
}
void *alloc_msiobject(UINT type, UINT size, msihandledestructor destroy )
{
MSIOBJECTHDR *info;
info = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
if( info )
{
info->magic = MSIHANDLE_MAGIC;
info->type = type;
info->refcount = 1;
info->destructor = destroy;
}
return info;
}
void msiobj_addref( MSIOBJECTHDR *info )
{
TRACE("%p\n", info);
if( !info )
return;
if( info->magic != MSIHANDLE_MAGIC )
{
ERR("Invalid handle!\n");
return;
}
info->refcount++;
}
int msiobj_release( MSIOBJECTHDR *info )
{
int ret;
TRACE("%p\n",info);
if( !info )
return -1;
if( info->magic != MSIHANDLE_MAGIC )
{
ERR("Invalid handle!\n");
return -1;
}
ret = info->refcount--;
if (info->refcount == 0)
{
if( info->destructor )
info->destructor( info );
HeapFree( GetProcessHeap(), 0, info );
TRACE("object %p destroyed\n", info);
}
return ret;
}
UINT WINAPI MsiCloseHandle(MSIHANDLE handle)
{
MSIOBJECTHDR *info;
UINT ret = ERROR_INVALID_HANDLE;
TRACE("%lx\n",handle);
EnterCriticalSection( &MSI_handle_cs );
info = msihandle2msiinfo(handle, 0);
if( !info )
goto out;
if( info->magic != MSIHANDLE_MAGIC )
{
ERR("Invalid handle!\n");
goto out;
}
msiobj_release( info );
msihandletable[handle-1] = NULL;
ret = ERROR_SUCCESS;
TRACE("handle %lx Destroyed\n", handle);
out:
LeaveCriticalSection( &MSI_handle_cs );
if( info )
msiobj_release( info );
return ret;
}
UINT WINAPI MsiCloseAllHandles(void)
{
UINT i;
TRACE("\n");
for(i=0; i<MSIMAXHANDLES; i++)
MsiCloseHandle( i+1 );
return 0;
}

238
reactos/lib/msi/insert.c Normal file
View file

@ -0,0 +1,238 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2004 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 <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "wine/debug.h"
#include "msi.h"
#include "msiquery.h"
#include "objbase.h"
#include "objidl.h"
#include "msipriv.h"
#include "winnls.h"
#include "query.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
/* below is the query interface to a table */
typedef struct tagMSIINSERTVIEW
{
MSIVIEW view;
MSIDATABASE *db;
BOOL bIsTemp;
MSIVIEW *sv;
value_list *vals; /* looks like these may be ignored... */
} MSIINSERTVIEW;
static UINT INSERT_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
{
MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view;
TRACE("%p %d %d %p\n", iv, row, col, val );
return ERROR_FUNCTION_FAILED;
}
static UINT INSERT_execute( struct tagMSIVIEW *view, MSIRECORD *record )
{
MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view;
UINT n, type, val, r, row, col_count = 0;
MSIVIEW *sv;
TRACE("%p %p\n", iv, record );
sv = iv->sv;
if( !sv )
return ERROR_FUNCTION_FAILED;
r = sv->ops->execute( sv, 0 );
TRACE("tv execute returned %x\n", r);
if( r )
return r;
r = sv->ops->get_dimensions( sv, NULL, &col_count );
if( r )
goto err;
n = MSI_RecordGetFieldCount( record );
if( n != col_count )
{
ERR("Number of fields do not match\n");
goto err;
}
row = -1;
r = sv->ops->insert_row( sv, &row );
TRACE("insert_row returned %x\n", r);
if( r )
goto err;
for( n = 1; n <= col_count; n++ )
{
r = sv->ops->get_column_info( sv, n, NULL, &type );
if( r )
break;
if( type & MSITYPE_STRING )
{
const WCHAR *str = MSI_RecordGetString( record, n );
val = msi_addstringW( iv->db->strings, 0, str, -1, 1 );
}
else
{
val = MSI_RecordGetInteger( record, n );
val |= 0x8000;
}
r = sv->ops->set_int( sv, row, n, val );
if( r )
break;
}
err:
return ERROR_SUCCESS;
}
static UINT INSERT_close( struct tagMSIVIEW *view )
{
MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view;
MSIVIEW *sv;
TRACE("%p\n", iv);
sv = iv->sv;
if( !sv )
return ERROR_FUNCTION_FAILED;
return sv->ops->close( sv );
}
static UINT INSERT_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
{
MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view;
MSIVIEW *sv;
TRACE("%p %p %p\n", iv, rows, cols );
sv = iv->sv;
if( !sv )
return ERROR_FUNCTION_FAILED;
return sv->ops->get_dimensions( sv, rows, cols );
}
static UINT INSERT_get_column_info( struct tagMSIVIEW *view,
UINT n, LPWSTR *name, UINT *type )
{
MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view;
MSIVIEW *sv;
TRACE("%p %d %p %p\n", iv, n, name, type );
sv = iv->sv;
if( !sv )
return ERROR_FUNCTION_FAILED;
return sv->ops->get_column_info( sv, n, name, type );
}
static UINT INSERT_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
{
MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view;
TRACE("%p %d %ld\n", iv, eModifyMode, hrec );
return ERROR_FUNCTION_FAILED;
}
static UINT INSERT_delete( struct tagMSIVIEW *view )
{
MSIINSERTVIEW *iv = (MSIINSERTVIEW*)view;
MSIVIEW *sv;
TRACE("%p\n", iv );
sv = iv->sv;
if( sv )
sv->ops->delete( sv );
delete_value_list( iv->vals );
msiobj_release( &iv->db->hdr );
HeapFree( GetProcessHeap(), 0, iv );
return ERROR_SUCCESS;
}
MSIVIEWOPS insert_ops =
{
INSERT_fetch_int,
NULL,
NULL,
NULL,
INSERT_execute,
INSERT_close,
INSERT_get_dimensions,
INSERT_get_column_info,
INSERT_modify,
INSERT_delete
};
UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
string_list *columns, value_list *values, BOOL temp )
{
MSIINSERTVIEW *iv = NULL;
UINT r;
MSIVIEW *tv = NULL, *sv = NULL;
TRACE("%p\n", iv );
r = TABLE_CreateView( db, table, &tv );
if( r != ERROR_SUCCESS )
return r;
r = SELECT_CreateView( db, &sv, tv, columns );
if( r != ERROR_SUCCESS )
{
if( tv )
tv->ops->delete( tv );
return r;
}
iv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *iv );
if( !iv )
return ERROR_FUNCTION_FAILED;
/* fill the structure */
iv->view.ops = &insert_ops;
msiobj_addref( &db->hdr );
iv->db = db;
iv->vals = values;
iv->bIsTemp = temp;
iv->sv = sv;
*view = (MSIVIEW*) iv;
return ERROR_SUCCESS;
}

1584
reactos/lib/msi/msi.c Normal file

File diff suppressed because it is too large Load diff

236
reactos/lib/msi/msi.spec Normal file
View file

@ -0,0 +1,236 @@
1 stdcall -private DllCanUnloadNow() MSI_DllCanUnloadNow
2 stdcall -private DllGetClassObject(ptr ptr ptr) MSI_DllGetClassObject
3 stdcall -private DllRegisterServer() MSI_DllRegisterServer
4 stdcall -private DllUnregisterServer() MSI_DllUnregisterServer
5 stdcall MsiAdvertiseProductA(str str str long)
6 stdcall MsiAdvertiseProductW(wstr wstr wstr long)
7 stdcall MsiCloseAllHandles()
8 stdcall MsiCloseHandle(long)
9 stub MsiCollectUserInfoA
10 stub MsiCollectUserInfoW
11 stub MsiConfigureFeatureA
12 stub MsiConfigureFeatureFromDescriptorA
13 stub MsiConfigureFeatureFromDescriptorW
14 stub MsiConfigureFeatureW
15 stdcall MsiConfigureProductA(str long long)
16 stdcall MsiConfigureProductW(wstr long long)
17 stdcall MsiCreateRecord(long)
18 stdcall MsiDatabaseApplyTransformA(long str long)
19 stdcall MsiDatabaseApplyTransformW(long wstr long)
20 stdcall MsiDatabaseCommit(long)
21 stub MsiDatabaseExportA
22 stub MsiDatabaseExportW
23 stdcall MsiDatabaseGenerateTransformA(long long str long long)
24 stdcall MsiDatabaseGenerateTransformW(long long wstr long long)
25 stdcall MsiDatabaseGetPrimaryKeysA(long str ptr)
26 stdcall MsiDatabaseGetPrimaryKeysW(long wstr ptr)
27 stdcall MsiDatabaseImportA(str str)
28 stdcall MsiDatabaseImportW(wstr wstr)
29 stub MsiDatabaseMergeA
30 stub MsiDatabaseMergeW
31 stdcall MsiDatabaseOpenViewA(long str ptr)
32 stdcall MsiDatabaseOpenViewW(long wstr ptr)
33 stdcall MsiDoActionA(long str)
34 stdcall MsiDoActionW(long wstr)
35 stub MsiEnableUIPreview
36 stdcall MsiEnumClientsA(str long ptr)
37 stdcall MsiEnumClientsW(wstr long ptr)
38 stdcall MsiEnumComponentQualifiersA(str long str ptr str ptr)
39 stdcall MsiEnumComponentQualifiersW(wstr long wstr ptr wstr ptr)
40 stdcall MsiEnumComponentsA(long ptr)
41 stdcall MsiEnumComponentsW(long ptr)
42 stdcall MsiEnumFeaturesA(str long ptr ptr)
43 stdcall MsiEnumFeaturesW(wstr long ptr ptr)
44 stdcall MsiEnumProductsA(long ptr)
45 stdcall MsiEnumProductsW(long ptr)
46 stdcall MsiEvaluateConditionA(long str)
47 stdcall MsiEvaluateConditionW(long wstr)
48 stub MsiGetLastErrorRecord
49 stdcall MsiGetActiveDatabase(long)
50 stdcall MsiGetComponentStateA(long str ptr ptr)
51 stdcall MsiGetComponentStateW(long wstr ptr ptr)
52 stub MsiGetDatabaseState
53 stub MsiGetFeatureCostA
54 stub MsiGetFeatureCostW
55 stub MsiGetFeatureInfoA
56 stub MsiGetFeatureInfoW
57 stdcall MsiGetFeatureStateA(long str ptr ptr)
58 stdcall MsiGetFeatureStateW(long wstr ptr ptr)
59 stub MsiGetFeatureUsageA
60 stub MsiGetFeatureUsageW
61 stub MsiGetFeatureValidStatesA
62 stub MsiGetFeatureValidStatesW
63 stub MsiGetLanguage
64 stdcall MsiGetMode(long long)
65 stdcall MsiGetProductCodeA(str str)
66 stdcall MsiGetProductCodeW(wstr wstr)
67 stdcall MsiGetProductInfoA(str str str long)
68 stub MsiGetProductInfoFromScriptA
69 stub MsiGetProductInfoFromScriptW
70 stdcall MsiGetProductInfoW(wstr wstr wstr long)
71 stdcall MsiGetProductPropertyA(long str ptr ptr)
72 stdcall MsiGetProductPropertyW(long wstr ptr ptr)
73 stdcall MsiGetPropertyA(ptr str str ptr)
74 stdcall MsiGetPropertyW(ptr wstr wstr ptr)
75 stdcall MsiGetSourcePathA(long str ptr ptr)
76 stdcall MsiGetSourcePathW(long wstr ptr ptr)
77 stdcall MsiGetSummaryInformationA(long str long ptr)
78 stdcall MsiGetSummaryInformationW(long wstr long ptr)
79 stdcall MsiGetTargetPathA(long str ptr ptr)
80 stdcall MsiGetTargetPathW(long wstr ptr ptr)
81 stub MsiGetUserInfoA
82 stub MsiGetUserInfoW
83 stub MsiInstallMissingComponentA
84 stub MsiInstallMissingComponentW
85 stub MsiInstallMissingFileA
86 stub MsiInstallMissingFileW
87 stdcall MsiInstallProductA(str str)
88 stdcall MsiInstallProductW(wstr wstr)
89 stdcall MsiLocateComponentA(str ptr long)
90 stdcall MsiLocateComponentW(wstr ptr long)
91 stdcall MsiOpenDatabaseA(str str ptr)
92 stdcall MsiOpenDatabaseW(wstr wstr ptr)
93 stdcall MsiOpenPackageA(str ptr)
94 stdcall MsiOpenPackageW(wstr ptr)
95 stdcall MsiOpenProductA(str ptr)
96 stdcall MsiOpenProductW(wstr ptr)
97 stub MsiPreviewBillboardA
98 stub MsiPreviewBillboardW
99 stub MsiPreviewDialogA
100 stub MsiPreviewDialogW
101 stub MsiProcessAdvertiseScriptA
102 stub MsiProcessAdvertiseScriptW
103 stdcall MsiProcessMessage(long long long)
104 stub MsiProvideComponentA
105 stdcall MsiProvideComponentFromDescriptorA(str ptr ptr ptr)
106 stdcall MsiProvideComponentFromDescriptorW(wstr ptr ptr ptr)
107 stub MsiProvideComponentW
108 stub MsiProvideQualifiedComponentA
109 stub MsiProvideQualifiedComponentW
110 stdcall MsiQueryFeatureStateA(str str)
111 stdcall MsiQueryFeatureStateW(wstr wstr)
112 stdcall MsiQueryProductStateA(str)
113 stdcall MsiQueryProductStateW(wstr)
114 stdcall MsiRecordDataSize(long long)
115 stdcall MsiRecordGetFieldCount(long)
116 stdcall MsiRecordGetInteger(long long)
117 stdcall MsiRecordGetStringA(long long ptr ptr)
118 stdcall MsiRecordGetStringW(long long ptr ptr)
119 stdcall MsiRecordIsNull(long long)
120 stdcall MsiRecordReadStream(long long ptr ptr)
121 stdcall MsiRecordSetInteger(long long long)
122 stdcall MsiRecordSetStreamA(long long str)
123 stdcall MsiRecordSetStreamW(long long wstr)
124 stdcall MsiRecordSetStringA(long long str)
125 stdcall MsiRecordSetStringW(long long wstr)
126 stub MsiReinstallFeatureA
127 stub MsiReinstallFeatureFromDescriptorA
128 stub MsiReinstallFeatureFromDescriptorW
129 stub MsiReinstallFeatureW
130 stdcall MsiReinstallProductA(str long)
131 stdcall MsiReinstallProductW(wstr long)
132 stub MsiSequenceA
133 stub MsiSequenceW
134 stub MsiSetComponentStateA
135 stub MsiSetComponentStateW
136 stdcall MsiSetExternalUIA(ptr long ptr)
137 stub MsiSetExternalUIW
138 stdcall MsiSetFeatureStateA(long str long)
139 stdcall MsiSetFeatureStateW(long wstr long)
140 stub MsiSetInstallLevel
141 stdcall MsiSetInternalUI(long ptr)
142 stub MsiVerifyDiskSpace
143 stub MsiSetMode
144 stdcall MsiSetPropertyA(long str str)
145 stdcall MsiSetPropertyW(long wstr wstr)
146 stdcall MsiSetTargetPathA(long str str)
147 stdcall MsiSetTargetPathW(long wstr wstr)
148 stdcall MsiSummaryInfoGetPropertyA(long long ptr ptr ptr ptr ptr)
149 stdcall MsiSummaryInfoGetPropertyCount(long ptr)
150 stdcall MsiSummaryInfoGetPropertyW(long long ptr ptr ptr ptr ptr)
151 stub MsiSummaryInfoPersist
152 stub MsiSummaryInfoSetPropertyA
153 stub MsiSummaryInfoSetPropertyW
154 stub MsiUseFeatureA
155 stub MsiUseFeatureW
156 stdcall MsiVerifyPackageA(str)
157 stdcall MsiVerifyPackageW(wstr)
158 stdcall MsiViewClose(long)
159 stdcall MsiViewExecute(long long)
160 stdcall MsiViewFetch(long ptr)
161 stub MsiViewGetErrorA
162 stub MsiViewGetErrorW
163 stdcall MsiViewModify(long long long)
164 stdcall MsiDatabaseIsTablePersistentA(long str)
165 stdcall MsiDatabaseIsTablePersistentW(long wstr)
166 stdcall MsiViewGetColumnInfo(long long ptr)
167 stdcall MsiRecordClearData(long)
168 stdcall MsiEnableLogA(long str long)
169 stdcall MsiEnableLogW(long wstr long)
170 stdcall MsiFormatRecordA(long long ptr ptr)
171 stdcall MsiFormatRecordW(long long ptr ptr)
172 stdcall MsiGetComponentPathA(str str ptr ptr)
173 stdcall MsiGetComponentPathW(wstr wstr ptr ptr)
174 stdcall MsiApplyPatchA(str str long str)
175 stdcall MsiApplyPatchW(wstr wstr long wstr)
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 stdcall MsiGetFileVersionA(str str ptr str ptr)
195 stdcall MsiGetFileVersionW(wstr wstr ptr wstr ptr)
196 stdcall MsiLoadStringA(long long long long long)
197 stdcall MsiLoadStringW(long long long long long)
198 stdcall MsiMessageBoxA(long long long long long long)
199 stdcall MsiMessageBoxW(long long long long long long)
200 stub MsiDecomposeDescriptorA
201 stub MsiDecomposeDescriptorW
202 stub MsiProvideQualifiedComponentExA
203 stub MsiProvideQualifiedComponentExW
204 stdcall MsiEnumRelatedProductsA(str long long str)
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
218 stub MsiGetFileHashA
219 stub MsiGetFileHashW
220 stub MsiEnumComponentCostsA
221 stub MsiEnumComponentCostsW
222 stub MsiCreateAndVerifyInstallerDirectory
223 stdcall MsiGetFileSignatureInformationA(str long ptr ptr ptr)
224 stdcall MsiGetFileSignatureInformationW(wstr long ptr ptr ptr)
225 stdcall MsiProvideAssemblyA(str str long long str ptr)
226 stdcall MsiProvideAssemblyW(wstr wstr long long wstr ptr)
227 stdcall MsiAdvertiseProductExA(str str str long long long)
228 stdcall MsiAdvertiseProductExW(wstr wstr wstr long long long)
229 stub MsiNotifySidChangeA
230 stub MsiNotifySidChangeW
231 stdcall MsiOpenPackageExA(str long ptr)
232 stdcall MsiOpenPackageExW(wstr long ptr)
233 stub MsiDeleteUserDataA
234 stub MsiDeleteUserDataW
235 stub Migrate10CachedPackagesA
236 stub Migrate10CachedPackagesW

325
reactos/lib/msi/msipriv.h Normal file
View file

@ -0,0 +1,325 @@
/*
* 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 <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "msi.h"
#include "msiquery.h"
#include "objbase.h"
#include "objidl.h"
#define MSI_DATASIZEMASK 0x00ff
#define MSITYPE_VALID 0x0100
#define MSITYPE_STRING 0x0800
#define MSITYPE_NULLABLE 0x1000
#define MSITYPE_KEY 0x2000
#define MSITYPE_BINARY 0x8900
struct tagMSITABLE;
typedef struct tagMSITABLE MSITABLE;
struct string_table;
typedef struct string_table string_table;
struct tagMSIOBJECTHDR;
typedef struct tagMSIOBJECTHDR MSIOBJECTHDR;
typedef VOID (*msihandledestructor)( MSIOBJECTHDR * );
struct tagMSIOBJECTHDR
{
UINT magic;
UINT type;
UINT refcount;
msihandledestructor destructor;
struct tagMSIOBJECTHDR *next;
struct tagMSIOBJECTHDR *prev;
};
typedef struct tagMSIDATABASE
{
MSIOBJECTHDR hdr;
IStorage *storage;
string_table *strings;
LPWSTR mode;
MSITABLE *first_table, *last_table;
} MSIDATABASE;
typedef struct tagMSIVIEW MSIVIEW;
typedef struct tagMSIQUERY
{
MSIOBJECTHDR hdr;
MSIVIEW *view;
UINT row;
MSIDATABASE *db;
} MSIQUERY;
/* maybe we can use a Variant instead of doing it ourselves? */
typedef struct tagMSIFIELD
{
UINT type;
union
{
INT iVal;
LPWSTR szwVal;
IStream *stream;
} u;
} MSIFIELD;
typedef struct tagMSIRECORD
{
MSIOBJECTHDR hdr;
UINT count; /* as passed to MsiCreateRecord */
MSIFIELD fields[1]; /* nb. array size is count+1 */
} MSIRECORD;
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 );
/*
* fetch_int - reads one integer from {row,col} in the table
*
* This function is similar to fetch_int, except fetches a
* stream instead of an integer.
*/
UINT (*fetch_stream)( struct tagMSIVIEW *, UINT row, UINT col, IStream **stm );
/*
* get_int - sets one integer at {row,col} in the table
*
* Similar semantics to fetch_int
*/
UINT (*set_int)( struct tagMSIVIEW *, UINT row, UINT col, UINT val );
/*
* Inserts a new, blank row into the database
* *row receives the number of the new row
*/
UINT (*insert_row)( struct tagMSIVIEW *, UINT *row );
/*
* execute - loads the underlying data into memory so it can be read
*/
UINT (*execute)( struct tagMSIVIEW *, MSIRECORD * );
/*
* 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 tagMSISUMMARYINFO
{
MSIOBJECTHDR hdr;
IPropertyStorage *propstg;
} MSISUMMARYINFO;
struct tagMSIVIEW
{
MSIOBJECTHDR hdr;
MSIVIEWOPS *ops;
};
typedef struct tagMSIPACKAGE
{
MSIOBJECTHDR hdr;
MSIDATABASE *db;
struct tagMSIFEATURE *features;
UINT loaded_features;
struct tagMSIFOLDER *folders;
UINT loaded_folders;
struct tagMSICOMPONENT *components;
UINT loaded_components;
struct tagMSIFILE *files;
UINT loaded_files;
} MSIPACKAGE;
#define MSIHANDLETYPE_ANY 0
#define MSIHANDLETYPE_DATABASE 1
#define MSIHANDLETYPE_SUMMARYINFO 2
#define MSIHANDLETYPE_VIEW 3
#define MSIHANDLETYPE_RECORD 4
#define MSIHANDLETYPE_PACKAGE 5
#define MSI_MAJORVERSION 2
#define MSI_MINORVERSION 0
#define MSI_BUILDNUMBER 2600
#define GUID_SIZE 39
#define MSIHANDLE_MAGIC 0x4d434923
#define MSIMAXHANDLES 0x80
#define MSISUMINFO_OFFSET 0x30LL
DEFINE_GUID(CLSID_IMsiServer, 0x000C101C,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
DEFINE_GUID(CLSID_IMsiServerX1, 0x000C103E,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
DEFINE_GUID(CLSID_IMsiServerX2, 0x000C1090,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
DEFINE_GUID(CLSID_IMsiServerX3, 0x000C1094,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
DEFINE_GUID(CLSID_IMsiServerMessage, 0x000C101D,0x0000,0x0000,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46);
/* handle functions */
extern void *msihandle2msiinfo(MSIHANDLE handle, UINT type);
extern MSIHANDLE alloc_msihandle( MSIOBJECTHDR * );
extern void *alloc_msiobject(UINT type, UINT size, msihandledestructor destroy );
extern void msiobj_addref(MSIOBJECTHDR *);
extern int msiobj_release(MSIOBJECTHDR *);
extern MSIHANDLE msiobj_findhandle( MSIOBJECTHDR *hdr );
/* 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 load_string_table( MSIDATABASE *db );
extern UINT MSI_CommitTables( MSIDATABASE *db );
extern HRESULT init_string_table( IStorage *stg );
/* string table functions */
extern BOOL msi_addstring( string_table *st, int string_no, const CHAR *data, int len, UINT refcount );
extern BOOL msi_addstringW( string_table *st, int string_no, const WCHAR *data, int len, UINT refcount );
extern UINT msi_id2stringW( string_table *st, UINT string_no, LPWSTR buffer, UINT *sz );
extern UINT msi_id2stringA( string_table *st, UINT string_no, LPSTR buffer, UINT *sz );
extern LPWSTR MSI_makestring( MSIDATABASE *db, UINT stringid);
extern UINT msi_string2idW( string_table *st, LPCWSTR buffer, UINT *id );
extern UINT msi_string2idA( string_table *st, LPCSTR str, UINT *id );
extern string_table *msi_init_stringtable( int entries, UINT codepage );
extern VOID msi_destroy_stringtable( string_table *st );
extern UINT msi_string_count( string_table *st );
extern UINT msi_id_refcount( string_table *st, UINT i );
extern UINT msi_string_totalsize( string_table *st, UINT *last );
extern UINT msi_strcmp( string_table *st, UINT lval, UINT rval, UINT *res );
extern const WCHAR *msi_string_lookup_id( string_table *st, UINT id );
extern UINT msi_string_get_codepage( string_table *st );
extern UINT VIEW_find_column( MSIVIEW *view, LPWSTR name, UINT *n );
extern BOOL TABLE_Exists( MSIDATABASE *db, LPWSTR name );
extern UINT read_raw_stream_data( MSIDATABASE*, LPCWSTR stname,
USHORT **pdata, UINT *psz );
extern UINT ACTION_DoTopLevelINSTALL( MSIPACKAGE *, LPCWSTR, LPCWSTR );
extern void ACTION_remove_tracked_tempfiles( MSIPACKAGE* );
/* record internals */
extern UINT MSI_RecordSetIStream( MSIRECORD *, unsigned int, IStream *);
extern const WCHAR *MSI_RecordGetString( MSIRECORD *, unsigned int );
extern MSIRECORD *MSI_CreateRecord( unsigned int );
extern UINT MSI_RecordSetInteger( MSIRECORD *, unsigned int, int );
extern UINT MSI_RecordSetStringW( MSIRECORD *, unsigned int, LPCWSTR );
extern BOOL MSI_RecordIsNull( MSIRECORD *, unsigned int );
extern UINT MSI_RecordGetStringW( MSIRECORD * , unsigned int, LPWSTR, DWORD *);
extern UINT MSI_RecordGetStringA( MSIRECORD *, unsigned int, LPSTR, DWORD *);
extern int MSI_RecordGetInteger( MSIRECORD *, unsigned int );
extern UINT MSI_RecordReadStream( MSIRECORD *, unsigned int, char *, DWORD *);
extern unsigned int MSI_RecordGetFieldCount( MSIRECORD *rec );
/* stream internals */
extern UINT get_raw_stream( MSIHANDLE hdb, LPCWSTR stname, IStream **stm );
extern UINT db_get_raw_stream( MSIDATABASE *db, LPCWSTR stname, IStream **stm );
extern void enum_stream_names( IStorage *stg );
/* database internals */
extern UINT MSI_OpenDatabaseW( LPCWSTR, LPCWSTR, MSIDATABASE ** );
extern UINT MSI_DatabaseOpenViewW(MSIDATABASE *, LPCWSTR, MSIQUERY ** );
/* view internals */
extern UINT MSI_ViewExecute( MSIQUERY*, MSIRECORD * );
extern UINT MSI_ViewFetch( MSIQUERY*, MSIRECORD ** );
extern UINT MSI_ViewClose( MSIQUERY* );
/* package internals */
extern UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE ** );
extern UINT MSI_SetTargetPathW( MSIPACKAGE *, LPCWSTR, LPCWSTR);
extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
extern INT MSI_ProcessMessage( MSIPACKAGE *, INSTALLMESSAGE, MSIRECORD* );
extern UINT MSI_GetPropertyW( MSIPACKAGE *, LPCWSTR, LPWSTR, DWORD*);
extern MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *, LPCWSTR );
extern UINT MSI_SetPropertyW( MSIPACKAGE *, LPCWSTR, LPCWSTR );
extern UINT MSI_GetComponentStateW(MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE *);
extern UINT MSI_GetFeatureStateW(MSIPACKAGE *, LPWSTR, INSTALLSTATE *, INSTALLSTATE *);
/* registry data encoding/decoding functions */
BOOL unsquash_guid(LPCWSTR in, LPWSTR out);
BOOL squash_guid(LPCWSTR in, LPWSTR out);
BOOL encode_base85_guid(GUID *,LPWSTR);
BOOL decode_base85_guid(LPCWSTR,GUID*);
/* UI globals */
extern INSTALLUILEVEL gUILevel;
extern HWND gUIhwnd;
extern INSTALLUI_HANDLERA gUIHandler;
extern DWORD gUIFilter;
extern LPVOID gUIContext;
extern WCHAR gszLogFile[MAX_PATH];
#endif /* __WINE_MSI_PRIVATE__ */

485
reactos/lib/msi/msiquery.c Normal file
View file

@ -0,0 +1,485 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002-2004 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 <stdarg.h>
#define COBJMACROS
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "wine/debug.h"
#include "wine/unicode.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);
#if 0
typedef struct tagMSIQUERY
{
MSIOBJECTHDR hdr;
MSIVIEW *view;
UINT row;
MSIDATABASE *db;
} MSIQUERY;
#endif
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( MSIOBJECTHDR *arg )
{
MSIQUERY *query = (MSIQUERY*) arg;
if( query->view && query->view->ops->delete )
query->view->ops->delete( query->view );
msiobj_release( &query->db->hdr );
}
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;
LPWSTR szwQuery;
TRACE("%ld %s %p\n", hdb, debugstr_a(szQuery), phView);
if( szQuery )
{
UINT len = MultiByteToWideChar( CP_ACP, 0, szQuery, -1, NULL, 0 );
szwQuery = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
if( !szwQuery )
return ERROR_FUNCTION_FAILED;
MultiByteToWideChar( CP_ACP, 0, szQuery, -1, szwQuery, len );
}
else
szwQuery = NULL;
r = MsiDatabaseOpenViewW( hdb, szwQuery, phView);
return r;
}
UINT MSI_DatabaseOpenViewW(MSIDATABASE *db,
LPCWSTR szQuery, MSIQUERY **pView)
{
MSIQUERY *query;
UINT r;
TRACE("%s %p\n", debugstr_w(szQuery), pView);
if( !szQuery)
return ERROR_INVALID_PARAMETER;
/* pre allocate a handle to hold a pointer to the view */
query = alloc_msiobject( MSIHANDLETYPE_VIEW, sizeof (MSIQUERY),
MSI_CloseView );
if( !query )
return ERROR_FUNCTION_FAILED;
msiobj_addref( &db->hdr );
query->row = 0;
query->db = db;
query->view = NULL;
r = MSI_ParseSQL( db, szQuery, &query->view );
if( r == ERROR_SUCCESS )
{
msiobj_addref( &query->hdr );
*pView = query;
}
msiobj_release( &query->hdr );
return r;
}
UINT WINAPI MsiDatabaseOpenViewW(MSIHANDLE hdb,
LPCWSTR szQuery, MSIHANDLE *phView)
{
MSIDATABASE *db;
MSIQUERY *query = NULL;
UINT ret;
TRACE("%s %p\n", debugstr_w(szQuery), phView);
db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
if( !db )
return ERROR_INVALID_HANDLE;
ret = MSI_DatabaseOpenViewW( db, szQuery, &query );
if( ret == ERROR_SUCCESS )
{
*phView = alloc_msihandle( &query->hdr );
msiobj_release( &query->hdr );
}
msiobj_release( &db->hdr );
return ret;
}
UINT MSI_ViewFetch(MSIQUERY *query, MSIRECORD **prec)
{
MSIVIEW *view;
MSIRECORD *rec;
UINT row_count = 0, col_count = 0, i, ival, ret, type;
TRACE("%p %p\n", query, prec );
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;
rec = MSI_CreateRecord( col_count );
if( !rec )
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;
}
if (( type != MSITYPE_BINARY) && (type != (MSITYPE_BINARY |
MSITYPE_NULLABLE)))
{
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;
sval = MSI_makestring( query->db, ival );
MSI_RecordSetStringW( rec, i, sval );
HeapFree( GetProcessHeap(), 0, sval );
}
else
{
if( (type & MSI_DATASIZEMASK) == 2 )
MSI_RecordSetInteger( rec, i, ival - (1<<15) );
else
MSI_RecordSetInteger( rec, i, ival - (1<<31) );
}
}
else
{
IStream *stm = NULL;
ret = view->ops->fetch_stream( view, query->row, i, &stm );
if( ( ret == ERROR_SUCCESS ) && stm )
{
MSI_RecordSetIStream( rec, i, stm );
IStream_Release( stm );
}
else
ERR("failed to get stream\n");
}
}
query->row ++;
*prec = rec;
return ERROR_SUCCESS;
}
UINT WINAPI MsiViewFetch(MSIHANDLE hView, MSIHANDLE *record)
{
MSIQUERY *query;
MSIRECORD *rec = NULL;
UINT ret;
TRACE("%ld %p\n", hView, record);
query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
if( !query )
return ERROR_INVALID_HANDLE;
ret = MSI_ViewFetch( query, &rec );
if( ret == ERROR_SUCCESS )
{
*record = alloc_msihandle( &rec->hdr );
msiobj_release( &rec->hdr );
}
msiobj_release( &query->hdr );
return ret;
}
UINT MSI_ViewClose(MSIQUERY *query)
{
MSIVIEW *view;
TRACE("%p\n", query );
view = query->view;
if( !view )
return ERROR_FUNCTION_FAILED;
if( !view->ops->close )
return ERROR_FUNCTION_FAILED;
return view->ops->close( view );
}
UINT WINAPI MsiViewClose(MSIHANDLE hView)
{
MSIQUERY *query;
UINT ret;
TRACE("%ld\n", hView );
query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
if( !query )
return ERROR_INVALID_HANDLE;
ret = MSI_ViewClose( query );
msiobj_release( &query->hdr );
return ret;
}
UINT MSI_ViewExecute(MSIQUERY *query, MSIRECORD *rec )
{
MSIVIEW *view;
TRACE("%p %p\n", query, rec);
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, rec );
}
UINT WINAPI MsiViewExecute(MSIHANDLE hView, MSIHANDLE hRec)
{
MSIQUERY *query;
MSIRECORD *rec = NULL;
UINT ret;
TRACE("%ld %ld\n", hView, hRec);
query = msihandle2msiinfo( hView, MSIHANDLETYPE_VIEW );
if( !query )
return ERROR_INVALID_HANDLE;
if( hRec )
{
rec = msihandle2msiinfo( hRec, MSIHANDLETYPE_RECORD );
if( !rec )
{
ret = ERROR_INVALID_HANDLE;
goto out;
}
}
ret = MSI_ViewExecute( query, rec );
out:
if( query )
msiobj_release( &query->hdr );
if( rec )
msiobj_release( &rec->hdr );
return ret;
}
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 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 )
{
MSIDATABASE *db;
UINT r;
TRACE("%ld\n", hdb);
db = msihandle2msiinfo( hdb, MSIHANDLETYPE_DATABASE );
if( !db )
return ERROR_INVALID_HANDLE;
/* FIXME: lock the database */
r = MSI_CommitTables( db );
/* FIXME: unlock the database */
return r;
}
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;
}
UINT WINAPI MsiViewModify(MSIHANDLE hView, MSIMODIFY eModifyMode, MSIHANDLE
hRecord)
{
FIXME("%ld %x %ld\n",hView, eModifyMode, hRecord);
return ERROR_CALL_NOT_IMPLEMENTED;
}

335
reactos/lib/msi/order.c Normal file
View file

@ -0,0 +1,335 @@
/*
* 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 <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "wine/debug.h"
#include "msi.h"
#include "msiquery.h"
#include "objbase.h"
#include "objidl.h"
#include "msipriv.h"
#include "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, MSIRECORD *record )
{
MSIORDERVIEW *ov = (MSIORDERVIEW*)view;
UINT r, num_rows = 0, i;
TRACE("%p %p\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;
msiobj_release( &ov->db->hdr );
HeapFree( GetProcessHeap(), 0, ov );
return ERROR_SUCCESS;
}
MSIVIEWOPS order_ops =
{
ORDER_fetch_int,
NULL,
NULL,
NULL,
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;
msiobj_addref( &db->hdr );
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;
}

843
reactos/lib/msi/package.c Normal file
View file

@ -0,0 +1,843 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2004 Aric Stewart for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define NONAMELESSUNION
#include <stdarg.h>
#include <stdio.h>
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "winnls.h"
#include "shlwapi.h"
#include "wine/debug.h"
#include "msi.h"
#include "msiquery.h"
#include "msipriv.h"
#include "objidl.h"
#include "wincrypt.h"
#include "winuser.h"
#include "shlobj.h"
#include "wine/unicode.h"
#include "objbase.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
/*
* The MSVC headers define the MSIDBOPEN_* macros cast to LPCTSTR,
* which is a problem because LPCTSTR isn't defined when compiling wine.
* To work around this problem, we need to define LPCTSTR as LPCWSTR here,
* and make sure to only use it in W functions.
*/
#define LPCTSTR LPCWSTR
void MSI_FreePackage( MSIOBJECTHDR *arg)
{
MSIPACKAGE *package= (MSIPACKAGE*) arg;
ACTION_remove_tracked_tempfiles(package);
if (package->features && package->loaded_features > 0)
HeapFree(GetProcessHeap(),0,package->features);
if (package->folders && package->loaded_folders > 0)
HeapFree(GetProcessHeap(),0,package->folders);
if (package->components && package->loaded_components > 0)
HeapFree(GetProcessHeap(),0,package->components);
if (package->files && package->loaded_files > 0)
HeapFree(GetProcessHeap(),0,package->files);
msiobj_release( &package->db->hdr );
}
UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
{
LPWSTR szwPack = NULL;
UINT len, ret;
TRACE("%s %p\n",debugstr_a(szPackage), phPackage);
if( szPackage )
{
len = MultiByteToWideChar( CP_ACP, 0, szPackage, -1, NULL, 0 );
szwPack = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
if( szwPack )
MultiByteToWideChar( CP_ACP, 0, szPackage, -1, szwPack, len );
}
ret = MsiOpenPackageW( szwPack, phPackage );
if( szwPack )
HeapFree( GetProcessHeap(), 0, szwPack );
return ret;
}
static const UINT clone_properties(MSIDATABASE *db)
{
MSIQUERY * view = NULL;
UINT rc;
static const WCHAR CreateSql[] = {
'C','R','E','A','T','E',' ','T','A','B','L','E',' ','`','_','P','r','o',
'p','e','r','t','y','`',' ','(',' ','`','_','P','r','o','p','e','r','t',
'y','`',' ','C','H','A','R','(','5','6',')',' ','N','O','T',' ','N','U',
'L','L',',',' ','`','V','a','l','u','e','`',' ','C','H','A','R','(','9',
'8',')',' ','N','O','T',' ','N','U','L','L',' ','P','R','I','M','A','R',
'Y',' ','K','E','Y',' ','`','_','P','r','o','p','e','r','t','y','`',')',0};
static const WCHAR Query[] = {
'S','E','L','E','C','T',' ','*',' ',
'f','r','o','m',' ','P','r','o','p','e','r','t','y',0};
static const WCHAR Insert[] = {
'I','N','S','E','R','T',' ','i','n','t','o',' ',
'`','_','P','r','o','p','e','r','t','y','`',' ',
'(','`','_','P','r','o','p','e','r','t','y','`',',',
'`','V','a','l','u','e','`',')',' ',
'V','A','L','U','E','S',' ','(','?',')',0};
/* create the temporary properties table */
rc = MSI_DatabaseOpenViewW(db, CreateSql, &view);
if (rc != ERROR_SUCCESS)
return rc;
rc = MSI_ViewExecute(view,0);
MSI_ViewClose(view);
msiobj_release(&view->hdr);
if (rc != ERROR_SUCCESS)
return rc;
/* clone the existing properties */
rc = MSI_DatabaseOpenViewW(db, Query, &view);
if (rc != ERROR_SUCCESS)
return rc;
rc = MSI_ViewExecute(view, 0);
if (rc != ERROR_SUCCESS)
{
MSI_ViewClose(view);
msiobj_release(&view->hdr);
return rc;
}
while (1)
{
MSIRECORD * row;
MSIQUERY * view2;
rc = MSI_ViewFetch(view,&row);
if (rc != ERROR_SUCCESS)
break;
rc = MSI_DatabaseOpenViewW(db,Insert,&view2);
if (rc!= ERROR_SUCCESS)
continue;
rc = MSI_ViewExecute(view2,row);
MSI_ViewClose(view2);
msiobj_release(&view2->hdr);
if (rc == ERROR_SUCCESS)
msiobj_release(&row->hdr);
}
MSI_ViewClose(view);
msiobj_release(&view->hdr);
return rc;
}
/*
* There are a whole slew of these we need to set
*
*
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/properties.asp
*/
static VOID set_installer_properties(MSIPACKAGE *package)
{
WCHAR pth[MAX_PATH];
OSVERSIONINFOA OSVersion;
DWORD verval;
WCHAR verstr[10], msiver[10];
static const WCHAR cszbs[]={'\\',0};
static const WCHAR CFF[] =
{'C','o','m','m','o','n','F','i','l','e','s','F','o','l','d','e','r',0};
static const WCHAR PFF[] =
{'P','r','o','g','r','a','m','F','i','l','e','s','F','o','l','d','e','r',0};
static const WCHAR CADF[] =
{'C','o','m','m','o','n','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
static const WCHAR FaF[] =
{'F','a','v','o','r','i','t','e','s','F','o','l','d','e','r',0};
static const WCHAR FoF[] =
{'F','o','n','t','s','F','o','l','d','e','r',0};
static const WCHAR SendTF[] =
{'S','e','n','d','T','o','F','o','l','d','e','r',0};
static const WCHAR SMF[] =
{'S','t','a','r','t','M','e','n','u','F','o','l','d','e','r',0};
static const WCHAR StF[] =
{'S','t','a','r','t','u','p','F','o','l','d','e','r',0};
static const WCHAR TemplF[] =
{'T','e','m','p','l','a','t','e','F','o','l','d','e','r',0};
static const WCHAR DF[] =
{'D','e','s','k','t','o','p','F','o','l','d','e','r',0};
static const WCHAR PMF[] =
{'P','r','o','g','r','a','m','M','e','n','u','F','o','l','d','e','r',0};
static const WCHAR ATF[] =
{'A','d','m','i','n','T','o','o','l','s','F','o','l','d','e','r',0};
static const WCHAR ADF[] =
{'A','p','p','D','a','t','a','F','o','l','d','e','r',0};
static const WCHAR SF[] =
{'S','y','s','t','e','m','F','o','l','d','e','r',0};
static const WCHAR LADF[] =
{'L','o','c','a','l','A','p','p','D','a','t','a','F','o','l','d','e','r',0};
static const WCHAR MPF[] =
{'M','y','P','i','c','t','u','r','e','s','F','o','l','d','e','r',0};
static const WCHAR PF[] =
{'P','e','r','s','o','n','a','l','F','o','l','d','e','r',0};
static const WCHAR WF[] =
{'W','i','n','d','o','w','s','F','o','l','d','e','r',0};
static const WCHAR TF[]=
{'T','e','m','p','F','o','l','d','e','r',0};
static const WCHAR szAdminUser[] =
{'A','d','m','i','n','U','s','e','r',0};
static const WCHAR szPriv[] =
{'P','r','i','v','i','l','e','g','e','d',0};
static const WCHAR szOne[] =
{'1',0};
static const WCHAR v9x[] = { 'V','e','r','s','i','o','n','9','X',0 };
static const WCHAR vNT[] = { 'V','e','r','s','i','o','n','N','T',0 };
static const WCHAR szFormat[] = {'%','l','i',0};
static const WCHAR szWinBuild[] =
{'W','i','n','d','o','w','s','B','u','i','l','d', 0 };
static const WCHAR szSPL[] =
{'S','e','r','v','i','c','e','P','a','c','k','L','e','v','e','l',0 };
static const WCHAR szSix[] = {'6',0 };
static const WCHAR szVersionMsi[] = { 'V','e','r','s','i','o','n','M','s','i',0 };
static const WCHAR szFormat2[] = {'%','l','i','.','%','l','i',0};
/*
* Other things I notice set
*
ScreenY
ScreenX
SystemLanguageID
ComputerName
UserLanguageID
LogonUser
VirtualMemory
PhysicalMemory
Intel
ShellAdvSupport
DefaultUIFont
VersionDatabase
PackagecodeChanging
ProductState
CaptionHeight
BorderTop
BorderSide
TextHeight
ColorBits
RedirectedDllSupport
Time
Date
Privileged
*/
SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth);
strcatW(pth,cszbs);
MSI_SetPropertyW(package, CFF, pth);
SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES,NULL,0,pth);
strcatW(pth,cszbs);
MSI_SetPropertyW(package, PFF, pth);
SHGetFolderPathW(NULL,CSIDL_COMMON_APPDATA,NULL,0,pth);
strcatW(pth,cszbs);
MSI_SetPropertyW(package, CADF, pth);
SHGetFolderPathW(NULL,CSIDL_FAVORITES,NULL,0,pth);
strcatW(pth,cszbs);
MSI_SetPropertyW(package, FaF, pth);
SHGetFolderPathW(NULL,CSIDL_FONTS,NULL,0,pth);
strcatW(pth,cszbs);
MSI_SetPropertyW(package, FoF, pth);
SHGetFolderPathW(NULL,CSIDL_SENDTO,NULL,0,pth);
strcatW(pth,cszbs);
MSI_SetPropertyW(package, SendTF, pth);
SHGetFolderPathW(NULL,CSIDL_STARTMENU,NULL,0,pth);
strcatW(pth,cszbs);
MSI_SetPropertyW(package, SMF, pth);
SHGetFolderPathW(NULL,CSIDL_STARTUP,NULL,0,pth);
strcatW(pth,cszbs);
MSI_SetPropertyW(package, StF, pth);
SHGetFolderPathW(NULL,CSIDL_TEMPLATES,NULL,0,pth);
strcatW(pth,cszbs);
MSI_SetPropertyW(package, TemplF, pth);
SHGetFolderPathW(NULL,CSIDL_DESKTOP,NULL,0,pth);
strcatW(pth,cszbs);
MSI_SetPropertyW(package, DF, pth);
SHGetFolderPathW(NULL,CSIDL_PROGRAMS,NULL,0,pth);
strcatW(pth,cszbs);
MSI_SetPropertyW(package, PMF, pth);
SHGetFolderPathW(NULL,CSIDL_ADMINTOOLS,NULL,0,pth);
strcatW(pth,cszbs);
MSI_SetPropertyW(package, ATF, pth);
SHGetFolderPathW(NULL,CSIDL_APPDATA,NULL,0,pth);
strcatW(pth,cszbs);
MSI_SetPropertyW(package, ADF, pth);
SHGetFolderPathW(NULL,CSIDL_SYSTEM,NULL,0,pth);
strcatW(pth,cszbs);
MSI_SetPropertyW(package, SF, pth);
SHGetFolderPathW(NULL,CSIDL_LOCAL_APPDATA,NULL,0,pth);
strcatW(pth,cszbs);
MSI_SetPropertyW(package, LADF, pth);
SHGetFolderPathW(NULL,CSIDL_MYPICTURES,NULL,0,pth);
strcatW(pth,cszbs);
MSI_SetPropertyW(package, MPF, pth);
SHGetFolderPathW(NULL,CSIDL_PERSONAL,NULL,0,pth);
strcatW(pth,cszbs);
MSI_SetPropertyW(package, PF, pth);
SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
strcatW(pth,cszbs);
MSI_SetPropertyW(package, WF, pth);
GetTempPathW(MAX_PATH,pth);
MSI_SetPropertyW(package, TF, pth);
/* in a wine environment the user is always admin and privileged */
MSI_SetPropertyW(package,szAdminUser,szOne);
MSI_SetPropertyW(package,szPriv,szOne);
/* set the os things */
OSVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
GetVersionExA(&OSVersion);
verval = OSVersion.dwMinorVersion+OSVersion.dwMajorVersion*100;
sprintfW(verstr,szFormat,verval);
switch (OSVersion.dwPlatformId)
{
case VER_PLATFORM_WIN32_WINDOWS:
MSI_SetPropertyW(package,v9x,verstr);
break;
case VER_PLATFORM_WIN32_NT:
MSI_SetPropertyW(package,vNT,verstr);
break;
}
sprintfW(verstr,szFormat,OSVersion.dwBuildNumber);
MSI_SetPropertyW(package,szWinBuild,verstr);
/* just fudge this */
MSI_SetPropertyW(package,szSPL,szSix);
sprintfW( msiver, szFormat2, MSI_MAJORVERSION, MSI_MINORVERSION);
MSI_SetPropertyW( package, szVersionMsi, msiver );
}
UINT MSI_OpenPackageW(LPCWSTR szPackage, MSIPACKAGE **pPackage)
{
UINT rc;
MSIDATABASE *db = NULL;
MSIPACKAGE *package = NULL;
WCHAR uilevel[10];
UINT ret = ERROR_FUNCTION_FAILED;
static const WCHAR OriginalDatabase[] =
{'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
static const WCHAR Database[] =
{'D','A','T','A','B','A','S','E',0};
static const WCHAR szpi[] = {'%','i',0};
static const WCHAR szLevel[] = { 'U','I','L','e','v','e','l',0 };
TRACE("%s %p\n",debugstr_w(szPackage), pPackage);
if (szPackage[0] == '#')
{
INT handle = atoiW(&szPackage[1]);
db = msihandle2msiinfo( handle , MSIHANDLETYPE_DATABASE);
}
else
{
rc = MSI_OpenDatabaseW(szPackage, MSIDBOPEN_READONLY, &db);
if (rc != ERROR_SUCCESS)
return ERROR_FUNCTION_FAILED;
}
package = alloc_msiobject( MSIHANDLETYPE_PACKAGE, sizeof (MSIPACKAGE),
MSI_FreePackage );
if (package)
{
msiobj_addref( &db->hdr );
package->db = db;
package->features = NULL;
package->folders = NULL;
package->components = NULL;
package->files = NULL;
package->loaded_features = 0;
package->loaded_folders = 0;
package->loaded_components= 0;
package->loaded_files = 0;
/* OK, here is where we do a slew of things to the database to
* prep for all that is to come as a package */
clone_properties(db);
set_installer_properties(package);
MSI_SetPropertyW(package, OriginalDatabase, szPackage);
MSI_SetPropertyW(package, Database, szPackage);
sprintfW(uilevel,szpi,gUILevel);
MSI_SetPropertyW(package, szLevel, uilevel);
msiobj_addref( &package->hdr );
*pPackage = package;
ret = ERROR_SUCCESS;
}
if( package )
msiobj_release( &package->hdr );
if( db )
msiobj_release( &db->hdr );
return ret;
}
UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
{
MSIPACKAGE *package = NULL;
UINT ret;
ret = MSI_OpenPackageW( szPackage, &package);
if( ret == ERROR_SUCCESS )
{
*phPackage = alloc_msihandle( &package->hdr );
msiobj_release( &package->hdr );
}
return ret;
}
UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
{
FIXME("%s 0x%08lx %p\n",debugstr_a(szPackage), dwOptions, phPackage);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiOpenPackageExW(LPCWSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
{
FIXME("%s 0x%08lx %p\n",debugstr_w(szPackage), dwOptions, phPackage);
return ERROR_CALL_NOT_IMPLEMENTED;
}
MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
{
MSIPACKAGE *package;
MSIHANDLE handle = 0;
TRACE("(%ld)\n",hInstall);
package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
if( package)
{
handle = alloc_msihandle( &package->db->hdr );
msiobj_release( &package->hdr );
}
return handle;
}
INT MSI_ProcessMessage( MSIPACKAGE *package, INSTALLMESSAGE eMessageType,
MSIRECORD *record)
{
DWORD log_type = 0;
LPWSTR message;
DWORD sz;
DWORD total_size = 0;
INT msg_field=1;
INT i;
INT rc;
char *msg;
int len;
TRACE("%x \n",eMessageType);
rc = 0;
if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ERROR)
log_type |= INSTALLLOGMODE_ERROR;
if ((eMessageType & 0xff000000) == INSTALLMESSAGE_WARNING)
log_type |= INSTALLLOGMODE_WARNING;
if ((eMessageType & 0xff000000) == INSTALLMESSAGE_USER)
log_type |= INSTALLLOGMODE_USER;
if ((eMessageType & 0xff000000) == INSTALLMESSAGE_INFO)
log_type |= INSTALLLOGMODE_INFO;
if ((eMessageType & 0xff000000) == INSTALLMESSAGE_COMMONDATA)
log_type |= INSTALLLOGMODE_COMMONDATA;
if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONSTART)
log_type |= INSTALLLOGMODE_ACTIONSTART;
if ((eMessageType & 0xff000000) == INSTALLMESSAGE_ACTIONDATA)
log_type |= INSTALLLOGMODE_ACTIONDATA;
/* just a guess */
if ((eMessageType & 0xff000000) == INSTALLMESSAGE_PROGRESS)
log_type |= 0x800;
message = HeapAlloc(GetProcessHeap(),0,1*sizeof (WCHAR));
message[0]=0;
msg_field = MSI_RecordGetFieldCount(record);
for (i = 1; i <= msg_field; i++)
{
LPWSTR tmp;
WCHAR number[3];
const static WCHAR format[] = { '%','i',':',' ',0};
const static WCHAR space[] = { ' ',0};
sz = 0;
MSI_RecordGetStringW(record,i,NULL,&sz);
sz+=4;
total_size+=sz*sizeof(WCHAR);
tmp = HeapAlloc(GetProcessHeap(),0,sz*sizeof(WCHAR));
message = HeapReAlloc(GetProcessHeap(),0,message,total_size*sizeof (WCHAR));
MSI_RecordGetStringW(record,i,tmp,&sz);
if (msg_field > 1)
{
sprintfW(number,format,i);
strcatW(message,number);
}
strcatW(message,tmp);
if (msg_field > 1)
strcatW(message,space);
HeapFree(GetProcessHeap(),0,tmp);
}
TRACE("(%p %lx %lx %s)\n",gUIHandler, gUIFilter, log_type,
debugstr_w(message));
/* convert it to ASCII */
len = WideCharToMultiByte( CP_ACP, 0, message, -1,
NULL, 0, NULL, NULL );
msg = HeapAlloc( GetProcessHeap(), 0, len );
WideCharToMultiByte( CP_ACP, 0, message, -1,
msg, len, NULL, NULL );
if (gUIHandler && (gUIFilter & log_type))
{
rc = gUIHandler(gUIContext,eMessageType,msg);
}
if ((!rc) && (gszLogFile[0]) && !((eMessageType & 0xff000000) ==
INSTALLMESSAGE_PROGRESS))
{
DWORD write;
HANDLE log_file = CreateFileW(gszLogFile,GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (log_file != INVALID_HANDLE_VALUE)
{
SetFilePointer(log_file,0, NULL, FILE_END);
WriteFile(log_file,msg,strlen(msg),&write,NULL);
WriteFile(log_file,"\n",1,&write,NULL);
CloseHandle(log_file);
}
}
HeapFree( GetProcessHeap(), 0, msg );
HeapFree(GetProcessHeap(),0,message);
return ERROR_SUCCESS;
}
INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
MSIHANDLE hRecord)
{
UINT ret = ERROR_INVALID_HANDLE;
MSIPACKAGE *package = NULL;
MSIRECORD *record = NULL;
package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE );
if( !package )
goto out;
record = msihandle2msiinfo( hRecord, MSIHANDLETYPE_RECORD );
if( !record )
goto out;
ret = MSI_ProcessMessage( package, eMessageType, record );
out:
if( package )
msiobj_release( &package->hdr );
if( record )
msiobj_release( &record->hdr );
return ret;
}
/* property code */
UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue)
{
LPWSTR szwName = NULL, szwValue = NULL;
UINT hr = ERROR_INSTALL_FAILURE;
UINT len;
if (0 == hInstall) {
return ERROR_INVALID_HANDLE;
}
if (NULL == szName) {
return ERROR_INVALID_PARAMETER;
}
if (NULL == szValue) {
return ERROR_INVALID_PARAMETER;
}
len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
if( !szwName )
goto end;
MultiByteToWideChar( CP_ACP, 0, szName, -1, szwName, len );
len = MultiByteToWideChar( CP_ACP, 0, szValue, -1, NULL, 0 );
szwValue = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
if( !szwValue)
goto end;
MultiByteToWideChar( CP_ACP, 0, szValue , -1, szwValue, len );
hr = MsiSetPropertyW( hInstall, szwName, szwValue);
end:
if( szwName )
HeapFree( GetProcessHeap(), 0, szwName );
if( szwValue )
HeapFree( GetProcessHeap(), 0, szwValue );
return hr;
}
UINT MSI_SetPropertyW( MSIPACKAGE *package, LPCWSTR szName, LPCWSTR szValue)
{
MSIQUERY *view;
MSIRECORD *row;
UINT rc;
DWORD sz = 0;
static const WCHAR Insert[]=
{'I','N','S','E','R','T',' ','i','n','t','o',' ','`','_','P','r','o','p'
,'e','r','t','y','`',' ','(','`','_','P','r','o','p','e','r','t','y','`'
,',','`','V','a','l','u','e','`',')',' ','V','A','L','U','E','S'
,' ','(','?',')',0};
static const WCHAR Update[]=
{'U','P','D','A','T','E',' ','_','P','r','o','p','e'
,'r','t','y',' ','s','e','t',' ','`','V','a','l','u','e','`',' ','='
,' ','?',' ','w','h','e','r','e',' ','`','_','P','r','o','p'
,'e','r','t','y','`',' ','=',' ','\'','%','s','\'',0};
WCHAR Query[1024];
TRACE("Setting property (%s %s)\n",debugstr_w(szName),
debugstr_w(szValue));
rc = MSI_GetPropertyW(package,szName,0,&sz);
if (rc==ERROR_MORE_DATA || rc == ERROR_SUCCESS)
{
sprintfW(Query,Update,szName);
row = MSI_CreateRecord(1);
MSI_RecordSetStringW(row,1,szValue);
}
else
{
strcpyW(Query,Insert);
row = MSI_CreateRecord(2);
MSI_RecordSetStringW(row,1,szName);
MSI_RecordSetStringW(row,2,szValue);
}
rc = MSI_DatabaseOpenViewW(package->db,Query,&view);
if (rc!= ERROR_SUCCESS)
{
msiobj_release(&row->hdr);
return rc;
}
rc = MSI_ViewExecute(view,row);
msiobj_release(&row->hdr);
MSI_ViewClose(view);
msiobj_release(&view->hdr);
return rc;
}
UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
{
MSIPACKAGE *package;
UINT ret;
package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
if( !package)
return ERROR_INVALID_HANDLE;
ret = MSI_SetPropertyW( package, szName, szValue);
msiobj_release( &package->hdr );
return ret;
}
static UINT MSI_GetPropertyRow(MSIPACKAGE *package, LPCWSTR szName, MSIRECORD **row)
{
MSIQUERY *view;
UINT rc, sz;
static const WCHAR select[]=
{'s','e','l','e','c','t',' ','V','a','l','u','e',' ','f','r','o','m',' '
,'_','P','r','o','p','e','r','t','y',' ','w','h','e','r','e',' '
,'_','P','r','o','p','e','r','t','y','=','`','%','s','`',0};
LPWSTR query;
if (!szName)
return ERROR_INVALID_PARAMETER;
sz = sizeof select + strlenW(szName)*sizeof(WCHAR);
query = HeapAlloc(GetProcessHeap(), 0, sz);
sprintfW(query,select,szName);
rc = MSI_DatabaseOpenViewW(package->db, query, &view);
HeapFree(GetProcessHeap(), 0, query);
if (rc == ERROR_SUCCESS)
{
rc = MSI_ViewExecute(view, 0);
if (rc == ERROR_SUCCESS)
rc = MSI_ViewFetch(view,row);
MSI_ViewClose(view);
msiobj_release(&view->hdr);
}
return rc;
}
UINT MSI_GetPropertyW(MSIPACKAGE *package, LPCWSTR szName,
LPWSTR szValueBuf, DWORD* pchValueBuf)
{
MSIRECORD *row;
UINT rc;
rc = MSI_GetPropertyRow(package, szName, &row);
if (rc == ERROR_SUCCESS)
{
rc = MSI_RecordGetStringW(row,1,szValueBuf,pchValueBuf);
msiobj_release(&row->hdr);
}
if (rc == ERROR_SUCCESS)
TRACE("returning %s for property %s\n", debugstr_w(szValueBuf),
debugstr_w(szName));
else
{
*pchValueBuf = 0;
TRACE("property not found\n");
}
return rc;
}
UINT MSI_GetPropertyA(MSIPACKAGE *package, LPCSTR szName,
LPSTR szValueBuf, DWORD* pchValueBuf)
{
MSIRECORD *row;
UINT rc, len;
LPWSTR szwName;
len = MultiByteToWideChar( CP_ACP, 0, szName, -1, NULL, 0 );
szwName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
if (!szwName)
return ERROR_NOT_ENOUGH_MEMORY;
MultiByteToWideChar( CP_ACP, 0, szName, -1, szwName, len );
rc = MSI_GetPropertyRow(package, szwName, &row);
if (rc == ERROR_SUCCESS)
{
rc = MSI_RecordGetStringA(row,1,szValueBuf,pchValueBuf);
msiobj_release(&row->hdr);
}
if (rc == ERROR_SUCCESS)
TRACE("returning %s for property %s\n", debugstr_a(szValueBuf),
debugstr_a(szName));
else
{
*pchValueBuf = 0;
TRACE("property not found\n");
}
HeapFree( GetProcessHeap(), 0, szwName );
return rc;
}
UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, DWORD* pchValueBuf)
{
MSIPACKAGE *package;
UINT ret;
TRACE("%lu %s %lu\n", hInstall, debugstr_a(szName), *pchValueBuf);
if (0 == hInstall)
return ERROR_INVALID_HANDLE;
if (NULL == szName)
return ERROR_INVALID_PARAMETER;
if (NULL != szValueBuf && NULL == pchValueBuf)
return ERROR_INVALID_PARAMETER;
package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
if (!package)
return ERROR_INVALID_HANDLE;
ret = MSI_GetPropertyA(package, szName, szValueBuf, pchValueBuf );
msiobj_release( &package->hdr );
return ret;
}
UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName,
LPWSTR szValueBuf, DWORD* pchValueBuf)
{
MSIPACKAGE *package;
UINT ret;
if (0 == hInstall)
return ERROR_INVALID_HANDLE;
if (NULL == szName)
return ERROR_INVALID_PARAMETER;
if (NULL != szValueBuf && NULL == pchValueBuf)
return ERROR_INVALID_PARAMETER;
package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
if (!package)
return ERROR_INVALID_HANDLE;
ret = MSI_GetPropertyW(package, szName, szValueBuf, pchValueBuf );
msiobj_release( &package->hdr );
return ret;
}

139
reactos/lib/msi/query.h Normal file
View file

@ -0,0 +1,139 @@
/*
* 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 <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "objbase.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
#define EXPR_STRCMP 7
#define EXPR_UTF8 8
#define EXPR_WILDCARD 9
struct sql_str {
LPCWSTR data;
INT len;
};
typedef struct _string_list
{
LPWSTR string;
struct _string_list *next;
} string_list;
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;
char *utf8;
} u;
};
typedef struct _create_col_info
{
LPWSTR colname;
UINT type;
struct _create_col_info *next;
} create_col_info;
typedef struct _value_list
{
struct expr *val;
struct _value_list *next;
} value_list;
typedef struct _column_assignment
{
string_list *col_list;
value_list *val_list;
} column_assignment;
UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phView);
UINT TABLE_CreateView( MSIDATABASE *db, LPCWSTR name, MSIVIEW **view );
UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
string_list *columns );
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,
struct expr *cond );
UINT CREATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
create_col_info *col_info, BOOL temp );
UINT INSERT_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
string_list *columns, value_list *values, BOOL temp );
UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **, LPWSTR table,
column_assignment *list, struct expr *expr );
void delete_expr( struct expr *e );
void delete_string_list( string_list *sl );
void delete_value_list( value_list *vl );
int sqliteGetToken(const WCHAR *z, int *tokenType);
#endif /* __WINE_MSI_QUERY_H */

573
reactos/lib/msi/record.c Normal file
View file

@ -0,0 +1,573 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002-2004 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 <stdarg.h>
#define COBJMACROS
#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
void MSI_FreeField( MSIFIELD *field )
{
switch( field->type )
{
case MSIFIELD_NULL:
case MSIFIELD_INT:
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( MSIOBJECTHDR *arg )
{
MSIRECORD *rec = (MSIRECORD *) arg;
UINT i;
for( i=0; i<=rec->count; i++ )
MSI_FreeField( &rec->fields[i] );
}
MSIRECORD *MSI_CreateRecord( unsigned int cParams )
{
MSIRECORD *rec;
UINT len;
TRACE("%d\n", cParams);
len = sizeof (MSIRECORD) + sizeof (MSIFIELD)*cParams;
rec = alloc_msiobject( MSIHANDLETYPE_RECORD, len, MSI_CloseRecord );
if( rec )
rec->count = cParams;
return rec;
}
MSIHANDLE WINAPI MsiCreateRecord( unsigned int cParams )
{
MSIRECORD *rec;
MSIHANDLE ret = 0;
TRACE("%d\n", cParams);
rec = MSI_CreateRecord( cParams );
if( rec )
ret = alloc_msihandle( &rec->hdr );
return ret;
}
unsigned int MSI_RecordGetFieldCount( MSIRECORD *rec )
{
return rec->count;
}
unsigned int WINAPI MsiRecordGetFieldCount( MSIHANDLE handle )
{
MSIRECORD *rec;
UINT ret;
TRACE("%ld\n", handle );
rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
if( !rec )
{
ERR("Record not found!\n");
return 0;
}
ret = MSI_RecordGetFieldCount( rec );
msiobj_release( &rec->hdr );
return ret;
}
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 MSI_RecordGetInteger( MSIRECORD *rec, unsigned int iField)
{
int ret = 0;
TRACE("%p %d\n", rec, iField );
if( iField > rec->count )
return MSI_NULL_INTEGER;
switch( rec->fields[iField].type )
{
case MSIFIELD_INT:
return rec->fields[iField].u.iVal;
case MSIFIELD_WSTR:
if( string2intW( rec->fields[iField].u.szwVal, &ret ) )
return ret;
return MSI_NULL_INTEGER;
default:
break;
}
return MSI_NULL_INTEGER;
}
int WINAPI MsiRecordGetInteger( MSIHANDLE handle, unsigned int iField)
{
MSIRECORD *rec;
UINT ret;
TRACE("%ld %d\n", handle, iField );
rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
if( !rec )
return MSI_NULL_INTEGER;
ret = MSI_RecordGetInteger( rec, iField );
msiobj_release( &rec->hdr );
return ret;
}
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 MSI_RecordSetInteger( MSIRECORD *rec, unsigned int iField, int iVal )
{
TRACE("%p %u %d\n", rec, iField, iVal);
if( iField <= rec->count )
{
MSI_FreeField( &rec->fields[iField] );
rec->fields[iField].type = MSIFIELD_INT;
rec->fields[iField].u.iVal = iVal;
}
return ERROR_SUCCESS;
}
UINT WINAPI MsiRecordSetInteger( MSIHANDLE handle, unsigned int iField, int iVal )
{
MSIRECORD *rec;
UINT ret;
TRACE("%ld %u %d\n", handle, iField, iVal);
rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
if( !rec )
return ERROR_INVALID_HANDLE;
ret = MSI_RecordSetInteger( rec, iField, iVal );
msiobj_release( &rec->hdr );
return ret;
}
BOOL MSI_RecordIsNull( MSIRECORD *rec, unsigned int iField )
{
BOOL r = TRUE;
TRACE("%p %d\n", rec, iField );
r = ( iField > rec->count ) ||
( rec->fields[iField].type == MSIFIELD_NULL );
return r;
}
BOOL WINAPI MsiRecordIsNull( MSIHANDLE handle, unsigned int iField )
{
MSIRECORD *rec;
UINT ret;
TRACE("%ld %d\n", handle, iField );
rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
if( !rec )
return ERROR_INVALID_HANDLE;
ret = MSI_RecordIsNull( rec, iField );
msiobj_release( &rec->hdr );
return ret;
}
UINT MSI_RecordGetStringA(MSIRECORD *rec, unsigned int iField,
LPSTR szValue, DWORD *pcchValue)
{
UINT len=0, ret;
CHAR buffer[16];
TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
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_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;
case MSIFIELD_NULL:
len = 1;
if( *pcchValue > 0 )
szValue[0] = 0;
break;
default:
ret = ERROR_INVALID_PARAMETER;
break;
}
if( *pcchValue < len )
ret = ERROR_MORE_DATA;
*pcchValue = len;
return ret;
}
UINT WINAPI MsiRecordGetStringA(MSIHANDLE handle, unsigned int iField,
LPSTR szValue, DWORD *pcchValue)
{
MSIRECORD *rec;
UINT ret;
TRACE("%ld %d %p %p\n", handle, iField, szValue, pcchValue);
rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
if( !rec )
return ERROR_INVALID_HANDLE;
ret = MSI_RecordGetStringA( rec, iField, szValue, pcchValue);
msiobj_release( &rec->hdr );
return ret;
}
const WCHAR *MSI_RecordGetString( MSIRECORD *rec, unsigned int iField )
{
if( iField > rec->count )
return NULL;
if( rec->fields[iField].type != MSIFIELD_WSTR )
return NULL;
return rec->fields[iField].u.szwVal;
}
UINT MSI_RecordGetStringW(MSIRECORD *rec, unsigned int iField,
LPWSTR szValue, DWORD *pcchValue)
{
UINT len=0, ret;
WCHAR buffer[16];
static const WCHAR szFormat[] = { '%','d',0 };
TRACE("%p %d %p %p\n", rec, iField, szValue, pcchValue);
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_NULL:
len = 1;
if( *pcchValue > 0 )
szValue[0] = 0;
default:
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 ret;
TRACE("%ld %d %p %p\n", handle, iField, szValue, pcchValue);
rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
if( !rec )
return ERROR_INVALID_HANDLE;
ret = MSI_RecordGetStringW( rec, iField, szValue, pcchValue );
msiobj_release( &rec->hdr );
return ret;
}
UINT WINAPI MsiRecordDataSize(MSIHANDLE hRecord, unsigned int iField)
{
FIXME("%ld %d\n", hRecord, iField);
return 0;
}
UINT MSI_RecordSetStringA( MSIRECORD *rec, unsigned int iField, LPCSTR szValue )
{
LPWSTR str;
UINT len;
TRACE("%p %d %s\n", rec, iField, debugstr_a(szValue));
if( iField > rec->count )
return ERROR_INVALID_FIELD;
len = MultiByteToWideChar( CP_ACP, 0, szValue, -1, NULL, 0 );
str = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
MultiByteToWideChar( CP_ACP, 0, szValue, -1, str, len );
MSI_FreeField( &rec->fields[iField] );
rec->fields[iField].type = MSIFIELD_WSTR;
rec->fields[iField].u.szwVal = str;
return 0;
}
UINT WINAPI MsiRecordSetStringA( MSIHANDLE handle, unsigned int iField, LPCSTR szValue )
{
MSIRECORD *rec;
UINT ret;
TRACE("%ld %d %s\n", handle, iField, debugstr_a(szValue));
rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
if( !rec )
return ERROR_INVALID_HANDLE;
ret = MSI_RecordSetStringA( rec, iField, szValue );
msiobj_release( &rec->hdr );
return ret;
}
UINT MSI_RecordSetStringW( MSIRECORD *rec, unsigned int iField, LPCWSTR szValue )
{
LPWSTR str;
UINT len;
TRACE("%p %d %s\n", rec, iField, debugstr_w(szValue));
if( iField > rec->count )
return ERROR_INVALID_FIELD;
len = lstrlenW(szValue) + 1;
str = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR));
lstrcpyW( str, szValue );
MSI_FreeField( &rec->fields[iField] );
rec->fields[iField].type = MSIFIELD_WSTR;
rec->fields[iField].u.szwVal = str;
return 0;
}
UINT WINAPI MsiRecordSetStringW( MSIHANDLE handle, unsigned int iField, LPCWSTR szValue )
{
MSIRECORD *rec;
UINT ret;
TRACE("%ld %d %s\n", handle, iField, debugstr_w(szValue));
rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
if( !rec )
return ERROR_INVALID_HANDLE;
ret = MSI_RecordSetStringW( rec, iField, szValue );
msiobj_release( &rec->hdr );
return ret;
}
UINT WINAPI MsiFormatRecordA(MSIHANDLE hInstall, MSIHANDLE hRecord, LPSTR szResult, DWORD *sz)
{
FIXME("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
return ERROR_CALL_NOT_IMPLEMENTED;
}
UINT WINAPI MsiFormatRecordW(MSIHANDLE hInstall, MSIHANDLE hRecord, LPWSTR szResult, DWORD *sz)
{
FIXME("%ld %ld %p %p\n", hInstall, hRecord, szResult, sz);
return ERROR_CALL_NOT_IMPLEMENTED;
}
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 MSI_RecordReadStream(MSIRECORD *rec, unsigned int iField, char *buf, DWORD *sz)
{
ULONG count;
HRESULT r;
IStream *stm;
TRACE("%p %d %p %p\n", rec, iField, buf, sz);
if( iField > rec->count )
return ERROR_INVALID_FIELD;
if( rec->fields[iField].type != MSIFIELD_STREAM )
{
*sz = 0;
return ERROR_INVALID_FIELD;
}
stm = rec->fields[iField].u.stream;
if( !stm )
return ERROR_INVALID_FIELD;
/* if there's no buffer pointer, calculate the length to the end */
if( !buf )
{
LARGE_INTEGER ofs;
ULARGE_INTEGER end, cur;
ofs.QuadPart = cur.QuadPart = 0;
end.QuadPart = 0;
r = IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
IStream_Seek( stm, ofs, STREAM_SEEK_END, &end );
ofs.QuadPart = cur.QuadPart;
IStream_Seek( stm, ofs, STREAM_SEEK_SET, &cur );
*sz = end.QuadPart - cur.QuadPart;
return ERROR_SUCCESS;
}
/* read the data */
count = 0;
r = IStream_Read( stm, buf, *sz, &count );
if( FAILED( r ) )
return ERROR_FUNCTION_FAILED;
*sz = count;
return ERROR_SUCCESS;
}
UINT WINAPI MsiRecordReadStream(MSIHANDLE handle, unsigned int iField, char *buf, DWORD *sz)
{
MSIRECORD *rec;
UINT ret;
TRACE("%ld %d %p %p\n", handle, iField, buf, sz);
rec = msihandle2msiinfo( handle, MSIHANDLETYPE_RECORD );
if( !rec )
return ERROR_INVALID_HANDLE;
ret = MSI_RecordReadStream( rec, iField, buf, sz );
msiobj_release( &rec->hdr );
return ret;
}
UINT MSI_RecordSetIStream( MSIRECORD *rec, unsigned int iField, IStream *stm )
{
TRACE("%p %d %p\n", rec, iField, stm);
if( iField > rec->count )
return ERROR_INVALID_FIELD;
MSI_FreeField( &rec->fields[iField] );
rec->fields[iField].type = MSIFIELD_STREAM;
rec->fields[iField].u.stream = stm;
IStream_AddRef( stm );
return ERROR_SUCCESS;
}

624
reactos/lib/msi/regsvr.c Normal file
View file

@ -0,0 +1,624 @@
/*
* self-registerable dll functions for msi.dll
*
* Copyright (C) 2004 Raphael Junqueira
*
* 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 <stdarg.h>
#include <string.h>
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "winreg.h"
#include "winerror.h"
#include "ole2.h"
#include "olectl.h"
#include "wine/debug.h"
#include "msi.h"
#include "initguid.h"
#include "msipriv.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
/*
* Near the bottom of this file are the exported DllRegisterServer and
* DllUnregisterServer, which make all this worthwhile.
*/
/***********************************************************************
* interface for self-registering
*/
struct regsvr_interface {
IID const *iid; /* NULL for end of list */
LPCSTR name; /* can be NULL to omit */
IID const *base_iid; /* can be NULL to omit */
int num_methods; /* can be <0 to omit */
CLSID const *ps_clsid; /* can be NULL to omit */
CLSID const *ps_clsid32; /* can be NULL to omit */
};
static HRESULT register_interfaces(struct regsvr_interface const *list);
static HRESULT unregister_interfaces(struct regsvr_interface const *list);
/**
* @todo: maybe adding typelibs support here
* [Software\\Classes\\CLSID\\{000C1090-0000-0000-C000-000000000046}\\TypeLib] 1080380217
* @="{000C1092-0000-0000-C000-000000000046}"
*/
struct regsvr_coclass {
CLSID const *clsid; /* NULL for end of list */
LPCSTR name; /* can be NULL to omit */
LPCSTR iph32; /* can be NULL to omit */
LPCSTR ips; /* can be NULL to omit */
LPCSTR ips32; /* can be NULL to omit */
LPCSTR ips32_tmodel; /* can be NULL to omit, if apartment, iph32 must be set */
LPCSTR progid; /* can be NULL to omit */
LPCSTR viprogid; /* can be NULL to omit */
LPCSTR progid_extra; /* can be NULL to omit */
};
static HRESULT register_coclasses(struct regsvr_coclass const *list);
static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
/***********************************************************************
* static string constants
*/
static WCHAR const interface_keyname[10] = {
'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
static WCHAR const base_ifa_keyname[14] = {
'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
'e', 0 };
static WCHAR const num_methods_keyname[11] = {
'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
static WCHAR const ps_clsid_keyname[15] = {
'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
'i', 'd', 0 };
static WCHAR const ps_clsid32_keyname[17] = {
'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
'i', 'd', '3', '2', 0 };
static WCHAR const clsid_keyname[6] = {
'C', 'L', 'S', 'I', 'D', 0 };
static WCHAR const curver_keyname[7] = {
'C', 'u', 'r', 'V', 'e', 'r', 0 };
static WCHAR const iph32_keyname[] = {
'I', 'n', 'P', 'r', 'o', 'c', 'H', 'a', 'n', 'd', 'l', 'e', 'r',
'3', '2', 0 };
static WCHAR const ips_keyname[13] = {
'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
0 };
static WCHAR const ips32_keyname[15] = {
'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
'3', '2', 0 };
static WCHAR const progid_keyname[7] = {
'P', 'r', 'o', 'g', 'I', 'D', 0 };
static WCHAR const viprogid_keyname[25] = {
'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
0 };
static char const tmodel_valuename[] = "ThreadingModel";
/***********************************************************************
* static helper functions
*/
static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
WCHAR const *value);
static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
char const *value);
static LONG register_progid(WCHAR const *clsid,
char const *progid, char const *curver_progid,
char const *name, char const *extra);
static LONG recursive_delete_key(HKEY key);
static LONG recursive_delete_keyA(HKEY base, char const *name);
static LONG recursive_delete_keyW(HKEY base, WCHAR const *name);
/***********************************************************************
* register_interfaces
*/
static HRESULT register_interfaces(struct regsvr_interface const *list) {
LONG res = ERROR_SUCCESS;
HKEY interface_key;
res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
if (res != ERROR_SUCCESS) goto error_return;
for (; res == ERROR_SUCCESS && list->iid; ++list) {
WCHAR buf[39];
HKEY iid_key;
StringFromGUID2(list->iid, buf, 39);
res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
if (res != ERROR_SUCCESS) goto error_close_interface_key;
if (list->name) {
res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
(CONST BYTE*)(list->name),
strlen(list->name) + 1);
if (res != ERROR_SUCCESS) goto error_close_iid_key;
}
if (list->base_iid) {
register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
if (res != ERROR_SUCCESS) goto error_close_iid_key;
}
if (0 <= list->num_methods) {
static WCHAR const fmt[3] = { '%', 'd', 0 };
HKEY key;
res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
KEY_READ | KEY_WRITE, NULL, &key, NULL);
if (res != ERROR_SUCCESS) goto error_close_iid_key;
wsprintfW(buf, fmt, list->num_methods);
res = RegSetValueExW(key, NULL, 0, REG_SZ,
(CONST BYTE*)buf,
(lstrlenW(buf) + 1) * sizeof(WCHAR));
RegCloseKey(key);
if (res != ERROR_SUCCESS) goto error_close_iid_key;
}
if (list->ps_clsid) {
register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
if (res != ERROR_SUCCESS) goto error_close_iid_key;
}
if (list->ps_clsid32) {
register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
if (res != ERROR_SUCCESS) goto error_close_iid_key;
}
error_close_iid_key:
RegCloseKey(iid_key);
}
error_close_interface_key:
RegCloseKey(interface_key);
error_return:
return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
}
/***********************************************************************
* unregister_interfaces
*/
static HRESULT unregister_interfaces(struct regsvr_interface const *list) {
LONG res = ERROR_SUCCESS;
HKEY interface_key;
res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
KEY_READ | KEY_WRITE, &interface_key);
if (res == ERROR_FILE_NOT_FOUND) return S_OK;
if (res != ERROR_SUCCESS) goto error_return;
for (; res == ERROR_SUCCESS && list->iid; ++list) {
WCHAR buf[39];
StringFromGUID2(list->iid, buf, 39);
res = recursive_delete_keyW(interface_key, buf);
}
RegCloseKey(interface_key);
error_return:
return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
}
/***********************************************************************
* register_coclasses
*/
static HRESULT register_coclasses(struct regsvr_coclass const *list) {
LONG res = ERROR_SUCCESS;
HKEY coclass_key;
res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
if (res != ERROR_SUCCESS) goto error_return;
for (; res == ERROR_SUCCESS && list->clsid; ++list) {
WCHAR buf[39];
HKEY clsid_key;
StringFromGUID2(list->clsid, buf, 39);
res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
if (res != ERROR_SUCCESS) goto error_close_coclass_key;
if (list->name) {
res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
(CONST BYTE*)(list->name),
strlen(list->name) + 1);
if (res != ERROR_SUCCESS) goto error_close_clsid_key;
}
if (list->iph32) {
HKEY iph32_key;
res = RegCreateKeyExW(clsid_key, iph32_keyname, 0, NULL, 0,
KEY_READ | KEY_WRITE, NULL,
&iph32_key, NULL);
if (res != ERROR_SUCCESS) goto error_close_clsid_key;
res = RegSetValueExA(iph32_key, NULL, 0, REG_SZ,
(CONST BYTE*)list->iph32,
lstrlenA(list->iph32) + 1);
RegCloseKey(iph32_key);
if (res != ERROR_SUCCESS) goto error_close_clsid_key;
}
if (list->ips) {
res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
if (res != ERROR_SUCCESS) goto error_close_clsid_key;
}
if (list->ips32) {
HKEY ips32_key;
res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
KEY_READ | KEY_WRITE, NULL,
&ips32_key, NULL);
if (res != ERROR_SUCCESS) goto error_close_clsid_key;
res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
(CONST BYTE*)list->ips32,
lstrlenA(list->ips32) + 1);
if (res == ERROR_SUCCESS && list->ips32_tmodel)
res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
(CONST BYTE*)list->ips32_tmodel,
strlen(list->ips32_tmodel) + 1);
RegCloseKey(ips32_key);
if (res != ERROR_SUCCESS) goto error_close_clsid_key;
}
if (list->progid) {
res = register_key_defvalueA(clsid_key, progid_keyname,
list->progid);
if (res != ERROR_SUCCESS) goto error_close_clsid_key;
res = register_progid(buf, list->progid, NULL,
list->name, list->progid_extra);
if (res != ERROR_SUCCESS) goto error_close_clsid_key;
}
if (list->viprogid) {
res = register_key_defvalueA(clsid_key, viprogid_keyname,
list->viprogid);
if (res != ERROR_SUCCESS) goto error_close_clsid_key;
res = register_progid(buf, list->viprogid, list->progid,
list->name, list->progid_extra);
if (res != ERROR_SUCCESS) goto error_close_clsid_key;
}
error_close_clsid_key:
RegCloseKey(clsid_key);
}
error_close_coclass_key:
RegCloseKey(coclass_key);
error_return:
return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
}
/***********************************************************************
* unregister_coclasses
*/
static HRESULT unregister_coclasses(struct regsvr_coclass const *list) {
LONG res = ERROR_SUCCESS;
HKEY coclass_key;
res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
KEY_READ | KEY_WRITE, &coclass_key);
if (res == ERROR_FILE_NOT_FOUND) return S_OK;
if (res != ERROR_SUCCESS) goto error_return;
for (; res == ERROR_SUCCESS && list->clsid; ++list) {
WCHAR buf[39];
StringFromGUID2(list->clsid, buf, 39);
res = recursive_delete_keyW(coclass_key, buf);
if (res != ERROR_SUCCESS) goto error_close_coclass_key;
if (list->progid) {
res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid);
if (res != ERROR_SUCCESS) goto error_close_coclass_key;
}
if (list->viprogid) {
res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid);
if (res != ERROR_SUCCESS) goto error_close_coclass_key;
}
}
error_close_coclass_key:
RegCloseKey(coclass_key);
error_return:
return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
}
/***********************************************************************
* regsvr_key_guid
*/
static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid) {
WCHAR buf[39];
StringFromGUID2(guid, buf, 39);
return register_key_defvalueW(base, name, buf);
}
/***********************************************************************
* regsvr_key_defvalueW
*/
static LONG register_key_defvalueW(
HKEY base,
WCHAR const *name,
WCHAR const *value) {
LONG res;
HKEY key;
res = RegCreateKeyExW(base, name, 0, NULL, 0,
KEY_READ | KEY_WRITE, NULL, &key, NULL);
if (res != ERROR_SUCCESS) return res;
res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
(lstrlenW(value) + 1) * sizeof(WCHAR));
RegCloseKey(key);
return res;
}
/***********************************************************************
* regsvr_key_defvalueA
*/
static LONG register_key_defvalueA(
HKEY base,
WCHAR const *name,
char const *value) {
LONG res;
HKEY key;
res = RegCreateKeyExW(base, name, 0, NULL, 0,
KEY_READ | KEY_WRITE, NULL, &key, NULL);
if (res != ERROR_SUCCESS) return res;
res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
lstrlenA(value) + 1);
RegCloseKey(key);
return res;
}
/***********************************************************************
* regsvr_progid
*/
static LONG register_progid(
WCHAR const *clsid,
char const *progid,
char const *curver_progid,
char const *name,
char const *extra) {
LONG res;
HKEY progid_key;
res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
NULL, 0, KEY_READ | KEY_WRITE, NULL,
&progid_key, NULL);
if (res != ERROR_SUCCESS) return res;
if (name) {
res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
(CONST BYTE*)name, strlen(name) + 1);
if (res != ERROR_SUCCESS) goto error_close_progid_key;
}
if (clsid) {
res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
if (res != ERROR_SUCCESS) goto error_close_progid_key;
}
if (curver_progid) {
res = register_key_defvalueA(progid_key, curver_keyname,
curver_progid);
if (res != ERROR_SUCCESS) goto error_close_progid_key;
}
if (extra) {
HKEY extra_key;
res = RegCreateKeyExA(progid_key, extra, 0,
NULL, 0, KEY_READ | KEY_WRITE, NULL,
&extra_key, NULL);
if (res == ERROR_SUCCESS)
RegCloseKey(extra_key);
}
error_close_progid_key:
RegCloseKey(progid_key);
return res;
}
/***********************************************************************
* recursive_delete_key
*/
static LONG recursive_delete_key(HKEY key) {
LONG res;
WCHAR subkey_name[MAX_PATH];
DWORD cName;
HKEY subkey;
for (;;) {
cName = sizeof(subkey_name) / sizeof(WCHAR);
res = RegEnumKeyExW(key, 0, subkey_name, &cName,
NULL, NULL, NULL, NULL);
if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) {
res = ERROR_SUCCESS; /* presumably we're done enumerating */
break;
}
res = RegOpenKeyExW(key, subkey_name, 0,
KEY_READ | KEY_WRITE, &subkey);
if (res == ERROR_FILE_NOT_FOUND) continue;
if (res != ERROR_SUCCESS) break;
res = recursive_delete_key(subkey);
RegCloseKey(subkey);
if (res != ERROR_SUCCESS) break;
}
if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0);
return res;
}
/***********************************************************************
* recursive_delete_keyA
*/
static LONG recursive_delete_keyA(HKEY base, char const *name) {
LONG res;
HKEY key;
res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key);
if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
if (res != ERROR_SUCCESS) return res;
res = recursive_delete_key(key);
RegCloseKey(key);
return res;
}
/***********************************************************************
* recursive_delete_keyW
*/
static LONG recursive_delete_keyW(HKEY base, WCHAR const *name) {
LONG res;
HKEY key;
res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key);
if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
if (res != ERROR_SUCCESS) return res;
res = recursive_delete_key(key);
RegCloseKey(key);
return res;
}
/***********************************************************************
* coclass list
*/
static struct regsvr_coclass const coclass_list[] = {
{
&CLSID_IMsiServer,
"Msi install server",
"ole32.dll",
NULL,
"msi.dll",
"Apartment",
"WindowsInstaller.Installer",
NULL
},
{
&CLSID_IMsiServerMessage,
"Wine Installer Message RPC",
NULL,
NULL,
"msi.dll",
NULL,
"WindowsInstaller.Message",
NULL
},
{
&CLSID_IMsiServerX1,
"Msi install server",
"ole32.dll",
NULL,
"msi.dll",
"Apartment",
"WindowsInstaller.Installer",
NULL
},
{
&CLSID_IMsiServerX2,
"Msi install server",
"ole32.dll",
NULL,
"msi.dll",
"Apartment",
"WindowsInstaller.Installer",
NULL
},
{
&CLSID_IMsiServerX3,
"Msi install server",
"ole32.dll",
NULL,
"msi.dll",
"Apartment",
"WindowsInstaller.Installer",
NULL
},
{ NULL } /* list terminator */
};
/***********************************************************************
* interface list
*/
/*
* we should declare: (@see ole32/regsvr.c for examples)
[-HKEY_CLASSES_ROOT\Interface\{000C101C-0000-0000-C000-000000000046}]
[-HKEY_CLASSES_ROOT\Interface\{000C101D-0000-0000-C000-000000000046}]
[-HKEY_CLASSES_ROOT\Interface\{000C1025-0000-0000-C000-000000000046}]
[-HKEY_CLASSES_ROOT\Interface\{000C1033-0000-0000-C000-000000000046}]
[-HKEY_CLASSES_ROOT\Interface\{000C1090-0000-0000-C000-000000000046}]
[-HKEY_CLASSES_ROOT\Interface\{000C1093-0000-0000-C000-000000000046}]
[-HKEY_CLASSES_ROOT\Interface\{000C1095-0000-0000-C000-000000000046}]
[-HKEY_CLASSES_ROOT\Interface\{000C109A-0000-0000-C000-000000000046}]
[-HKEY_CLASSES_ROOT\Interface\{000C109B-0000-0000-C000-000000000046}]
[-HKEY_CLASSES_ROOT\Interface\{000C109C-0000-0000-C000-000000000046}]
[-HKEY_CLASSES_ROOT\Interface\{000C109D-0000-0000-C000-000000000046}]
[-HKEY_CLASSES_ROOT\Interface\{000C109E-0000-0000-C000-000000000046}]
[-HKEY_CLASSES_ROOT\Interface\{000C109F-0000-0000-C000-000000000046}]
*/
static struct regsvr_interface const interface_list[] = {
{ NULL } /* list terminator */
};
/***********************************************************************
* DllRegisterServer
*/
HRESULT WINAPI MSI_DllRegisterServer(void) {
HRESULT hr;
TRACE("\n");
hr = register_coclasses(coclass_list);
if (SUCCEEDED(hr))
hr = register_interfaces(interface_list);
return hr;
}
/***********************************************************************
* DllUnregisterServer
*/
HRESULT WINAPI MSI_DllUnregisterServer(void) {
HRESULT hr;
TRACE("\n");
hr = unregister_coclasses(coclass_list);
if (SUCCEEDED(hr))
hr = unregister_interfaces(interface_list);
return hr;
}

290
reactos/lib/msi/select.c Normal file
View file

@ -0,0 +1,290 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002-2004 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 <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "wine/debug.h"
#include "msi.h"
#include "msiquery.h"
#include "objbase.h"
#include "objidl.h"
#include "msipriv.h"
#include "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_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm)
{
MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
TRACE("%p %d %d %p\n", sv, row, col, stm );
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_stream( sv->table, row, col, stm );
}
static UINT SELECT_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val )
{
MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
TRACE("%p %d %d %04x\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->set_int( sv->table, row, col, val );
}
static UINT SELECT_insert_row( struct tagMSIVIEW *view, UINT *num )
{
MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
TRACE("%p %p\n", sv, num );
if( !sv->table )
return ERROR_FUNCTION_FAILED;
return sv->table->ops->insert_row( sv->table, num );
}
static UINT SELECT_execute( struct tagMSIVIEW *view, MSIRECORD *record )
{
MSISELECTVIEW *sv = (MSISELECTVIEW*)view;
TRACE("%p %p\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_fetch_stream,
SELECT_set_int,
SELECT_insert_row,
SELECT_execute,
SELECT_close,
SELECT_get_dimensions,
SELECT_get_column_info,
SELECT_modify,
SELECT_delete
};
static UINT SELECT_AddColumn( MSISELECTVIEW *sv, LPWSTR name )
{
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;
}
UINT SELECT_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
string_list *columns )
{
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;
while( columns )
{
r = SELECT_AddColumn( sv, columns->string );
if( r )
break;
columns = columns->next;
}
if( r != ERROR_SUCCESS )
{
sv->view.ops->delete( &sv->view );
sv = NULL;
}
*view = &sv->view;
return r;
}

828
reactos/lib/msi/sql.y Normal file
View file

@ -0,0 +1,828 @@
%{
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002-2004 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 <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include "windef.h"
#include "winbase.h"
#include "query.h"
#include "wine/debug.h"
#include "wine/unicode.h"
#define YYLEX_PARAM info
#define YYPARSE_PARAM info
extern int SQL_error(const char *str);
WINE_DEFAULT_DEBUG_CHANNEL(msi);
typedef struct tag_SQL_input
{
MSIDATABASE *db;
LPCWSTR command;
DWORD n, len;
MSIVIEW **view; /* view structure for the resulting query */
} SQL_input;
static LPWSTR SQL_getstring( struct sql_str *str );
static INT SQL_getint( SQL_input *sql );
static int SQL_lex( void *SQL_lval, SQL_input *info);
static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in,
string_list *columns );
static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in,
string_list *columns );
static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,
string_list *keys);
static struct expr * EXPR_complex( struct expr *l, UINT op, struct expr *r );
static struct expr * EXPR_column( LPWSTR );
static struct expr * EXPR_ival( struct sql_str *);
static struct expr * EXPR_sval( struct sql_str *);
static struct expr * EXPR_wildcard();
%}
%pure-parser
%union
{
struct sql_str str;
LPWSTR string;
string_list *column_list;
value_list *val_list;
MSIVIEW *query;
struct expr *expr;
USHORT column_type;
create_col_info *column_info;
column_assignment update_col_info;
}
%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_CHAR TK_CHECK TK_CLUSTER TK_COLLATE TK_COLUMN
%token TK_COMMA TK_COMMENT TK_COMMIT TK_CONCAT TK_CONFLICT
%token TK_CONSTRAINT TK_COPY TK_CREATE
%token TK_DEFAULT TK_DEFERRABLE TK_DEFERRED TK_DELETE TK_DELIMITERS TK_DESC
%token TK_DISTINCT TK_DOT TK_DROP TK_EACH
%token TK_ELSE TK_END TK_END_OF_FILE TK_EQ TK_EXCEPT TK_EXPLAIN
%token TK_FAIL TK_FLOAT TK_FOR TK_FOREIGN TK_FROM TK_FUNCTION
%token TK_GE TK_GLOB TK_GROUP TK_GT
%token TK_HAVING TK_HOLD
%token TK_IGNORE TK_ILLEGAL TK_IMMEDIATE TK_IN TK_INDEX TK_INITIALLY
%token <str> TK_ID
%token TK_INSERT TK_INSTEAD TK_INT
%token <str> TK_INTEGER
%token TK_INTERSECT TK_INTO TK_IS
%token TK_ISNULL
%token TK_JOIN TK_JOIN_KW
%token TK_KEY
%token TK_LE TK_LIKE TK_LIMIT TK_LONG TK_LONGCHAR TK_LP TK_LSHIFT TK_LT
%token TK_LOCALIZABLE
%token TK_MATCH TK_MINUS
%token TK_NE TK_NOT TK_NOTNULL TK_NULL
%token TK_OBJECT 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_SHORT TK_SLASH TK_SPACE TK_STAR TK_STATEMENT
%token <str> 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 TK_WILDCARD
/*
* 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 <string> column table string_or_id
%type <column_list> selcollist
%type <query> from unorderedsel oneselect onequery onecreate oneinsert oneupdate
%type <expr> expr val column_val const_val
%type <column_type> column_type data_type data_type_l data_count
%type <column_info> column_def table_def
%type <val_list> constlist
%type <update_col_info> column_assignment update_assign_list
%%
onequery:
oneselect
{
SQL_input* sql = (SQL_input*) info;
*sql->view = $1;
}
| onecreate
{
SQL_input* sql = (SQL_input*) info;
*sql->view = $1;
}
| oneinsert
{
SQL_input* sql = (SQL_input*) info;
*sql->view = $1;
}
| oneupdate
{
SQL_input* sql = (SQL_input*) info;
*sql->view = $1;
}
;
oneinsert:
TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP
{
SQL_input *sql = (SQL_input*) info;
MSIVIEW *insert = NULL;
INSERT_CreateView( sql->db, &insert, $3, $5, $9, FALSE );
$$ = insert;
}
| TK_INSERT TK_INTO table TK_LP selcollist TK_RP TK_VALUES TK_LP constlist TK_RP TK_TEMP
{
SQL_input *sql = (SQL_input*) info;
MSIVIEW *insert = NULL;
INSERT_CreateView( sql->db, &insert, $3, $5, $9, TRUE );
$$ = insert;
}
;
onecreate:
TK_CREATE TK_TABLE table TK_LP table_def TK_RP
{
SQL_input* sql = (SQL_input*) info;
MSIVIEW *create = NULL;
if( !$5 )
YYABORT;
CREATE_CreateView( sql->db, &create, $3, $5, FALSE );
$$ = create;
}
| TK_CREATE TK_TABLE table TK_LP table_def TK_RP TK_HOLD
{
SQL_input* sql = (SQL_input*) info;
MSIVIEW *create = NULL;
if( !$5 )
YYABORT;
CREATE_CreateView( sql->db, &create, $3, $5, TRUE );
$$ = create;
}
;
oneupdate:
TK_UPDATE table TK_SET update_assign_list TK_WHERE expr
{
SQL_input* sql = (SQL_input*) info;
MSIVIEW *update = NULL;
UPDATE_CreateView( sql->db, &update, $2, &$4, $6 );
$$ = update;
}
;
table_def:
column_def TK_PRIMARY TK_KEY selcollist
{
if( SQL_MarkPrimaryKeys( $1, $4 ) )
$$ = $1;
else
$$ = NULL;
}
;
column_def:
column_def TK_COMMA column column_type
{
create_col_info *ci;
for( ci = $1; ci->next; ci = ci->next )
;
ci->next = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ );
if( !ci->next )
{
/* FIXME: free $1 */
YYABORT;
}
ci->next->colname = $3;
ci->next->type = $4;
ci->next->next = NULL;
$$ = $1;
}
| column column_type
{
$$ = HeapAlloc( GetProcessHeap(), 0, sizeof *$$ );
if( ! $$ )
YYABORT;
$$->colname = $1;
$$->type = $2;
$$->next = NULL;
}
;
column_type:
data_type_l
{
$$ = $1 | MSITYPE_VALID;
}
| data_type_l TK_LOCALIZABLE
{
FIXME("LOCALIZABLE ignored\n");
$$ = $1 | MSITYPE_VALID;
}
;
data_type_l:
data_type
{
$$ |= MSITYPE_NULLABLE;
}
| data_type TK_NOT TK_NULL
{
$$ = $1;
}
;
data_type:
TK_CHAR
{
$$ = MSITYPE_STRING | 1;
}
| TK_CHAR TK_LP data_count TK_RP
{
$$ = MSITYPE_STRING | 0x400 | $3;
}
| TK_LONGCHAR
{
$$ = 2;
}
| TK_SHORT
{
$$ = 2;
}
| TK_INT
{
$$ = 2;
}
| TK_LONG
{
$$ = 4;
}
| TK_OBJECT
{
$$ = 0;
}
;
data_count:
TK_INTEGER
{
SQL_input* sql = (SQL_input*) info;
int val = SQL_getint(sql);
if( ( val > 255 ) || ( val < 0 ) )
YYABORT;
$$ = val;
}
;
oneselect:
unorderedsel TK_ORDER TK_BY selcollist
{
SQL_input* sql = (SQL_input*) info;
if( !$1 )
YYABORT;
if( $4 )
$$ = do_order_by( sql->db, $1, $4 );
else
$$ = $1;
}
| unorderedsel
;
unorderedsel:
TK_SELECT selcollist from
{
SQL_input* sql = (SQL_input*) info;
if( !$3 )
YYABORT;
if( $2 )
{
$$ = do_one_select( sql->db, $3, $2 );
if( !$$ )
YYABORT;
}
else
$$ = $3;
}
| TK_SELECT TK_DISTINCT selcollist from
{
SQL_input* sql = (SQL_input*) info;
MSIVIEW *view = $4;
if( !view )
YYABORT;
if( $3 )
{
view = do_one_select( sql->db, view, $3 );
if( !view )
YYABORT;
}
DISTINCT_CreateView( sql->db, & $$, view );
}
;
selcollist:
column
{
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
{
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
{
SQL_input* sql = (SQL_input*) info;
UINT r;
$$ = NULL;
TRACE("From table: %s\n",debugstr_w($2));
r = TABLE_CreateView( sql->db, $2, & $$ );
if( r != ERROR_SUCCESS )
YYABORT;
}
| TK_FROM table TK_WHERE expr
{
SQL_input* sql = (SQL_input*) 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, $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
| const_val
;
constlist:
const_val
{
value_list *vals;
vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
if( vals )
{
vals->val = $1;
vals->next = NULL;
}
$$ = vals;
}
| constlist TK_COMMA const_val
{
value_list *vals;
vals = HeapAlloc( GetProcessHeap(), 0, sizeof *vals );
if( vals )
{
vals->val = $3;
vals->next = NULL;
}
$1->next = vals;
$$ = $1;
}
;
update_assign_list:
column_assignment
| column_assignment TK_COMMA update_assign_list
{
$1.col_list->next = $3.col_list;
$1.val_list->next = $3.val_list;
$$ = $1;
}
;
column_assignment:
column TK_EQ const_val
{
$$.col_list = HeapAlloc( GetProcessHeap(), 0, sizeof *$$.col_list );
if( !$$.col_list )
YYABORT;
$$.col_list->string = $1;
$$.col_list->next = NULL;
$$.val_list = HeapAlloc( GetProcessHeap(), 0, sizeof *$$.val_list );
if( !$$.val_list )
YYABORT;
$$.val_list->val = $3;
$$.val_list->next = 0;
}
;
const_val:
TK_INTEGER
{
$$ = EXPR_ival( &$1 );
}
| TK_STRING
{
$$ = EXPR_sval( &$1 );
}
| TK_WILDCARD
{
$$ = EXPR_wildcard();
}
;
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
{
$$ = SQL_getstring( &$1 );
}
| TK_STRING
{
$$ = SQL_getstring( &$1 );
}
;
%%
int SQL_lex( void *SQL_lval, SQL_input *sql)
{
int token;
struct sql_str * str = SQL_lval;
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;
str->data = &sql->command[sql->n];
str->len = sql->len;
}
while( token == TK_SPACE );
TRACE("token : %d (%s)\n", token, debugstr_wn(&sql->command[sql->n], sql->len));
return token;
}
LPWSTR SQL_getstring( struct sql_str *strdata)
{
LPCWSTR p = strdata->data;
UINT len = strdata->len;
LPWSTR str;
/* if there's quotes, remove them */
if( ( (p[0]=='`') && (p[len-1]=='`') ) ||
( (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 SQL_getint( SQL_input *sql )
{
LPCWSTR p = &sql->command[sql->n];
return atoiW( p );
}
int SQL_error(const char *str)
{
return 0;
}
static MSIVIEW *do_one_select( MSIDATABASE *db, MSIVIEW *in,
string_list *columns )
{
MSIVIEW *view = NULL;
SELECT_CreateView( db, &view, in, columns );
delete_string_list( columns );
if( !view )
ERR("Error creating select query\n");
return view;
}
static MSIVIEW *do_order_by( MSIDATABASE *db, MSIVIEW *in,
string_list *columns )
{
MSIVIEW *view = NULL;
ORDER_CreateView( db, &view, in );
if( view )
{
string_list *x = columns;
for( x = columns; x ; x = x->next )
ORDER_AddColumn( view, x->string );
}
else
ERR("Error creating select query\n");
delete_string_list( columns );
return view;
}
static struct expr * EXPR_wildcard()
{
struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
if( e )
{
e->type = EXPR_WILDCARD;
}
return e;
}
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 str )
{
struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
if( e )
{
e->type = EXPR_COLUMN;
e->u.sval = str;
}
return e;
}
static struct expr * EXPR_ival( struct sql_str *str )
{
struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
if( e )
{
e->type = EXPR_IVAL;
e->u.ival = atoiW( str->data );
}
return e;
}
static struct expr * EXPR_sval( struct sql_str *str )
{
struct expr *e = HeapAlloc( GetProcessHeap(), 0, sizeof *e );
if( e )
{
e->type = EXPR_SVAL;
e->u.sval = SQL_getstring( str );
}
return e;
}
void delete_expr( struct expr *e )
{
if( !e )
return;
if( e->type == EXPR_COMPLEX )
{
delete_expr( e->u.expr.left );
delete_expr( e->u.expr.right );
}
else if( e->type == EXPR_UTF8 )
HeapFree( GetProcessHeap(), 0, e->u.utf8 );
else if( e->type == EXPR_SVAL )
HeapFree( GetProcessHeap(), 0, e->u.sval );
HeapFree( GetProcessHeap(), 0, e );
}
void delete_string_list( string_list *sl )
{
while( sl )
{
string_list *t = sl->next;
HeapFree( GetProcessHeap(), 0, sl->string );
HeapFree( GetProcessHeap(), 0, sl );
sl = t;
}
}
void delete_value_list( value_list *vl )
{
while( vl )
{
value_list *t = vl->next;
delete_expr( vl->val );
HeapFree( GetProcessHeap(), 0, vl );
vl = t;
}
}
static BOOL SQL_MarkPrimaryKeys( create_col_info *cols,
string_list *keys )
{
string_list *k;
BOOL found = TRUE;
for( k = keys; k && found; k = k->next )
{
create_col_info *c;
found = FALSE;
for( c = cols; c && !found; c = c->next )
{
if( lstrcmpW( k->string, c->colname ) )
continue;
c->type |= MSITYPE_KEY;
found = TRUE;
}
}
return found;
}
UINT MSI_ParseSQL( MSIDATABASE *db, LPCWSTR command, MSIVIEW **phview )
{
SQL_input sql;
int r;
*phview = NULL;
sql.db = db;
sql.command = command;
sql.n = 0;
sql.len = 0;
sql.view = phview;
r = SQL_parse(&sql);
TRACE("Parse returned %d\n", r);
if( r )
{
if( *sql.view )
(*sql.view)->ops->delete( *sql.view );
*sql.view = NULL;
return ERROR_BAD_QUERY_SYNTAX;
}
return ERROR_SUCCESS;
}

459
reactos/lib/msi/string.c Normal file
View file

@ -0,0 +1,459 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2002-2004, 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 <stdarg.h>
#include <assert.h>
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "wine/debug.h"
#include "wine/unicode.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 _msistring
{
UINT hash;
UINT refcount;
LPWSTR str;
} msistring;
struct string_table
{
UINT maxcount; /* the number of strings */
UINT freeslot;
UINT codepage;
msistring *strings; /* an array of strings (in the tree) */
};
static UINT msistring_makehash( const WCHAR *str )
{
UINT hash = 0;
if (str==NULL)
return hash;
while( *str )
{
hash ^= *str++;
hash *= 53;
hash = (hash<<5) | (hash>>27);
}
return hash;
}
string_table *msi_init_stringtable( int entries, UINT codepage )
{
string_table *st;
st = HeapAlloc( GetProcessHeap(), 0, sizeof (string_table) );
if( !st )
return NULL;
st->strings = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof (msistring) * entries );
if( !st )
{
HeapFree( GetProcessHeap(), 0, st );
return NULL;
}
if( entries < 1 )
entries = 1;
st->maxcount = entries;
st->freeslot = 1;
st->codepage = codepage;
return st;
}
VOID msi_destroy_stringtable( string_table *st )
{
UINT i;
for( i=0; i<st->maxcount; i++ )
{
if( st->strings[i].refcount )
HeapFree( GetProcessHeap(), 0, st->strings[i].str );
}
HeapFree( GetProcessHeap(), 0, st->strings );
HeapFree( GetProcessHeap(), 0, st );
}
static int st_find_free_entry( string_table *st )
{
UINT i, sz;
msistring *p;
TRACE("%p\n", st);
if( st->freeslot )
{
for( i = st->freeslot; i < st->maxcount; i++ )
if( !st->strings[i].refcount )
return i;
}
for( i = 1; i < st->maxcount; i++ )
if( !st->strings[i].refcount )
return i;
/* dynamically resize */
sz = st->maxcount + 1 + st->maxcount/2;
p = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
st->strings, sz*sizeof(msistring) );
if( !p )
return -1;
st->strings = p;
st->freeslot = st->maxcount;
st->maxcount = sz;
if( st->strings[st->freeslot].refcount )
ERR("oops. expected freeslot to be free...\n");
return st->freeslot;
}
static void st_mark_entry_used( string_table *st, UINT n )
{
if( n >= st->maxcount )
return;
st->freeslot = n + 1;
}
int msi_addstring( string_table *st, int n, const CHAR *data, int len, UINT refcount )
{
int sz;
if( !data )
return 0;
if( !data[0] )
return 0;
if( n > 0 )
{
if( st->strings[n].refcount )
return -1;
}
else
{
if( ERROR_SUCCESS == msi_string2idA( st, data, &n ) )
{
st->strings[n].refcount++;
return n;
}
n = st_find_free_entry( st );
if( n < 0 )
return -1;
}
if( n < 1 )
{
ERR("invalid index adding %s (%d)\n", debugstr_a( data ), n );
return -1;
}
/* allocate a new string */
if( len < 0 )
len = strlen(data);
sz = MultiByteToWideChar( st->codepage, 0, data, len, NULL, 0 );
st->strings[n].str = HeapAlloc( GetProcessHeap(), 0, (sz+1)*sizeof(WCHAR) );
if( !st->strings[n].str )
return -1;
MultiByteToWideChar( st->codepage, 0, data, len, st->strings[n].str, sz );
st->strings[n].str[sz] = 0;
st->strings[n].refcount = 1;
st->strings[n].hash = msistring_makehash( st->strings[n].str );
st_mark_entry_used( st, n );
return n;
}
int msi_addstringW( string_table *st, int n, const WCHAR *data, int len, UINT refcount )
{
/* TRACE("[%2d] = %s\n", string_no, debugstr_an(data,len) ); */
if( !data )
return 0;
if( !data[0] )
return 0;
if( n > 0 )
{
if( st->strings[n].refcount )
return -1;
}
else
{
if( ERROR_SUCCESS == msi_string2idW( st, data, &n ) )
{
st->strings[n].refcount++;
return n;
}
n = st_find_free_entry( st );
if( n < 0 )
return -1;
}
if( n < 1 )
{
ERR("invalid index adding %s (%d)\n", debugstr_w( data ), n );
return -1;
}
/* allocate a new string */
if(len<0)
len = strlenW(data);
TRACE("%s, n = %d len = %d\n", debugstr_w(data), n, len );
st->strings[n].str = HeapAlloc( GetProcessHeap(), 0, (len+1)*sizeof(WCHAR) );
if( !st->strings[n].str )
return -1;
TRACE("%d\n",__LINE__);
memcpy( st->strings[n].str, data, len*sizeof(WCHAR) );
st->strings[n].str[len] = 0;
st->strings[n].refcount = 1;
st->strings[n].hash = msistring_makehash( st->strings[n].str );
st_mark_entry_used( st, n );
return n;
}
/* find the string identified by an id - return null if there's none */
const WCHAR *msi_string_lookup_id( string_table *st, UINT id )
{
static const WCHAR zero[] = { 0 };
if( id == 0 )
return zero;
if( id >= st->maxcount )
return NULL;
if( id && !st->strings[id].refcount )
return NULL;
return st->strings[id].str;
}
/*
* msi_id2stringW
*
* [in] st - pointer to the string table
* [in] id - id of the string to retrieve
* [out] buffer - destination of the string
* [in/out] sz - number of bytes available in the buffer on input
* number of bytes used on output
*
* The size includes the terminating nul character. Short buffers
* will be filled, but not nul terminated.
*/
UINT msi_id2stringW( string_table *st, UINT id, LPWSTR buffer, UINT *sz )
{
UINT len;
const WCHAR *str;
TRACE("Finding string %d of %d\n", id, st->maxcount);
str = msi_string_lookup_id( st, id );
if( !str )
return ERROR_FUNCTION_FAILED;
len = strlenW( str ) + 1;
if( !buffer )
{
*sz = len;
return ERROR_SUCCESS;
}
if( *sz < len )
*sz = len;
memcpy( buffer, str, (*sz)*sizeof(WCHAR) );
*sz = len;
return ERROR_SUCCESS;
}
/*
* msi_id2stringA
*
* [in] st - pointer to the string table
* [in] id - id of the string to retrieve
* [out] buffer - destination of the UTF8 string
* [in/out] sz - number of bytes available in the buffer on input
* number of bytes used on output
*
* The size includes the terminating nul character. Short buffers
* will be filled, but not nul terminated.
*/
UINT msi_id2stringA( string_table *st, UINT id, LPSTR buffer, UINT *sz )
{
UINT len;
const WCHAR *str;
int n;
TRACE("Finding string %d of %d\n", id, st->maxcount);
str = msi_string_lookup_id( st, id );
if( !str )
return ERROR_FUNCTION_FAILED;
len = WideCharToMultiByte( st->codepage, 0, str, -1, NULL, 0, NULL, NULL );
if( !buffer )
{
*sz = len;
return ERROR_SUCCESS;
}
if( len > *sz )
{
n = strlenW( str ) + 1;
while( n && (len > *sz) )
len = WideCharToMultiByte( st->codepage, 0,
str, --n, NULL, 0, NULL, NULL );
}
else
n = -1;
*sz = WideCharToMultiByte( st->codepage, 0, str, n, buffer, len, NULL, NULL );
return ERROR_SUCCESS;
}
/*
* msi_string2idW
*
* [in] st - pointer to the string table
* [in] str - string to find in the string table
* [out] id - id of the string, if found
*/
UINT msi_string2idW( string_table *st, LPCWSTR str, UINT *id )
{
UINT hash;
UINT i, r = ERROR_INVALID_PARAMETER;
hash = msistring_makehash( str );
for( i=0; i<st->maxcount; i++ )
{
if ( (str == NULL && st->strings[i].str == NULL) ||
( ( st->strings[i].hash == hash ) &&
!strcmpW( st->strings[i].str, str ) ))
{
r = ERROR_SUCCESS;
*id = i;
break;
}
}
return r;
}
UINT msi_string2idA( string_table *st, LPCSTR buffer, UINT *id )
{
DWORD sz;
UINT r = ERROR_INVALID_PARAMETER;
LPWSTR str;
TRACE("Finding string %s in string table\n", debugstr_a(buffer) );
if( buffer[0] == 0 )
{
*id = 0;
return ERROR_SUCCESS;
}
sz = MultiByteToWideChar( st->codepage, 0, buffer, -1, NULL, 0 );
if( sz <= 0 )
return r;
str = HeapAlloc( GetProcessHeap(), 0, sz*sizeof(WCHAR) );
if( !str )
return ERROR_NOT_ENOUGH_MEMORY;
MultiByteToWideChar( st->codepage, 0, buffer, -1, str, sz );
r = msi_string2idW( st, str, id );
if( str )
HeapFree( GetProcessHeap(), 0, str );
return r;
}
UINT msi_strcmp( string_table *st, UINT lval, UINT rval, UINT *res )
{
const WCHAR *l_str, *r_str;
l_str = msi_string_lookup_id( st, lval );
if( !l_str )
return ERROR_INVALID_PARAMETER;
r_str = msi_string_lookup_id( st, rval );
if( !r_str )
return ERROR_INVALID_PARAMETER;
/* does this do the right thing for all UTF-8 strings? */
*res = strcmpW( l_str, r_str );
return ERROR_SUCCESS;
}
UINT msi_string_count( string_table *st )
{
return st->maxcount;
}
UINT msi_id_refcount( string_table *st, UINT i )
{
if( i >= st->maxcount )
return 0;
return st->strings[i].refcount;
}
UINT msi_string_totalsize( string_table *st, UINT *total )
{
UINT size = 0, i, len;
if( st->strings[0].str || st->strings[0].refcount )
ERR("oops. element 0 has a string\n");
*total = 0;
for( i=1; i<st->maxcount; i++ )
{
if( st->strings[i].str )
{
TRACE("[%u] = %s\n", i, debugstr_w(st->strings[i].str));
len = WideCharToMultiByte( st->codepage, 0,
st->strings[i].str, -1, NULL, 0, NULL, NULL);
if( len )
len--;
size += len;
*total = (i+1);
}
}
TRACE("%u/%u strings %u bytes codepage %x\n", *total, st->maxcount, size, st->codepage );
return size;
}
UINT msi_string_get_codepage( string_table *st )
{
return st->codepage;
}

233
reactos/lib/msi/suminfo.c Normal file
View file

@ -0,0 +1,233 @@
/*
* 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 <stdarg.h>
#define COBJMACROS
#define NONAMELESSUNION
#define PRSPEC_PROPID (1)
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "winnls.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);
static 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( MSIOBJECTHDR *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 )
{
UINT len = MultiByteToWideChar( CP_ACP, 0, szDatabase, -1, NULL, 0 );
szwDatabase = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
if( !szwDatabase )
return ERROR_FUNCTION_FAILED;
MultiByteToWideChar( CP_ACP, 0, szDatabase, -1, szwDatabase, len );
}
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;
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 = MSI_OpenDatabaseW(szDatabase, NULL, &db);
if( res != ERROR_SUCCESS )
return res;
}
else
{
db = msihandle2msiinfo(hDatabase, 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");
if (db)
msiobj_release(&db->hdr);
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;
}
suminfo = alloc_msiobject( MSIHANDLETYPE_SUMMARYINFO,
sizeof (MSISUMMARYINFO), MSI_CloseSummaryInfo );
if( !suminfo )
{
ret = ERROR_FUNCTION_FAILED;
goto end;
}
IPropertyStorage_AddRef(ps);
suminfo->propstg = ps;
handle = alloc_msihandle( &suminfo->hdr );
if( handle )
*phSummaryInfo = handle;
else
ret = ERROR_FUNCTION_FAILED;
msiobj_release( &suminfo->hdr );
end:
if( ps )
IPropertyStorage_Release(ps);
if( psstg )
IPropertySetStorage_Release(psstg);
if (db)
msiobj_release(&db->hdr);
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.u.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.u.lVal;
break;
case VT_LPSTR:
if( pcchValueBuf && szValueBuf )
{
lstrcpynA(szValueBuf, var.u.pszVal, *pcchValueBuf );
*pcchValueBuf = lstrlenA( var.u.pszVal );
}
break;
case VT_FILETIME:
if( pftValue )
memcpy(pftValue, &var.u.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;
}

1425
reactos/lib/msi/table.c Normal file

File diff suppressed because it is too large Load diff

397
reactos/lib/msi/tokenize.c Normal file
View file

@ -0,0 +1,397 @@
/*
** 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 <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include "windef.h"
#include "winbase.h"
#include "wine/debug.h"
#include "winnls.h"
#include "query.h"
#include "sql.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 },
{ "CHAR", TK_CHAR },
{ "CHARACTER", TK_CHAR },
{ "CHECK", TK_CHECK },
{ "CLUSTER", TK_CLUSTER },
{ "COLLATE", TK_COLLATE },
{ "COMMIT", TK_COMMIT },
{ "CONFLICT", TK_CONFLICT },
{ "CONSTRAINT", TK_CONSTRAINT },
{ "COPY", TK_COPY },
{ "CREATE", TK_CREATE },
{ "CROSS", TK_JOIN_KW },
{ "DEFAULT", TK_DEFAULT },
{ "DEFERRED", TK_DEFERRED },
{ "DEFERRABLE", TK_DEFERRABLE },
{ "DELETE", TK_DELETE },
{ "DELIMITERS", TK_DELIMITERS },
{ "DESC", TK_DESC },
{ "DISTINCT", TK_DISTINCT },
{ "DROP", TK_DROP },
{ "END", TK_END },
{ "EACH", TK_EACH },
{ "ELSE", TK_ELSE },
{ "EXCEPT", TK_EXCEPT },
{ "EXPLAIN", TK_EXPLAIN },
{ "FAIL", TK_FAIL },
{ "FOR", TK_FOR },
{ "FOREIGN", TK_FOREIGN },
{ "FROM", TK_FROM },
{ "FULL", TK_JOIN_KW },
{ "GLOB", TK_GLOB },
{ "GROUP", TK_GROUP },
{ "HAVING", TK_HAVING },
{ "HOLD", TK_HOLD },
{ "IGNORE", TK_IGNORE },
{ "IMMEDIATE", TK_IMMEDIATE },
{ "IN", TK_IN },
{ "INDEX", TK_INDEX },
{ "INITIALLY", TK_INITIALLY },
{ "INNER", TK_JOIN_KW },
{ "INSERT", TK_INSERT },
{ "INSTEAD", TK_INSTEAD },
{ "INT", TK_INT },
{ "INTERSECT", TK_INTERSECT },
{ "INTO", TK_INTO },
{ "IS", TK_IS },
{ "ISNULL", TK_ISNULL },
{ "JOIN", TK_JOIN },
{ "KEY", TK_KEY },
{ "LEFT", TK_JOIN_KW },
{ "LIKE", TK_LIKE },
{ "LIMIT", TK_LIMIT },
{ "LOCALIZABLE", TK_LOCALIZABLE },
{ "LONG", TK_LONG },
{ "LONGCHAR", TK_LONGCHAR },
{ "MATCH", TK_MATCH },
{ "NATURAL", TK_JOIN_KW },
{ "NOT", TK_NOT },
{ "NOTNULL", TK_NOTNULL },
{ "NULL", TK_NULL },
{ "OBJECT", TK_OBJECT },
{ "OF", TK_OF },
{ "OFFSET", TK_OFFSET },
{ "ON", TK_ON },
{ "OR", TK_OR },
{ "ORDER", TK_ORDER },
{ "OUTER", TK_JOIN_KW },
{ "PRAGMA", TK_PRAGMA },
{ "PRIMARY", TK_PRIMARY },
{ "RAISE", TK_RAISE },
{ "REFERENCES", TK_REFERENCES },
{ "REPLACE", TK_REPLACE },
{ "RESTRICT", TK_RESTRICT },
{ "RIGHT", TK_JOIN_KW },
{ "ROLLBACK", TK_ROLLBACK },
{ "ROW", TK_ROW },
{ "SELECT", TK_SELECT },
{ "SET", TK_SET },
{ "SHORT", TK_SHORT },
{ "STATEMENT", TK_STATEMENT },
{ "TABLE", TK_TABLE },
{ "TEMP", TK_TEMP },
{ "TEMPORARY", TK_TEMP },
{ "THEN", TK_THEN },
{ "TRANSACTION", TK_TRANSACTION },
{ "TRIGGER", TK_TRIGGER },
{ "UNION", TK_UNION },
{ "UNIQUE", TK_UNIQUE },
{ "UPDATE", TK_UPDATE },
{ "USING", TK_USING },
{ "VACUUM", TK_VACUUM },
{ "VALUES", TK_VALUES },
{ "VIEW", TK_VIEW },
{ "WHEN", TK_WHEN },
{ "WHERE", TK_WHERE },
};
#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){
UINT i, len;
char buffer[0x10];
len = WideCharToMultiByte( CP_ACP, 0, z, n, buffer, sizeof buffer, NULL, NULL );
for(i=0; i<len; i++)
buffer[i] = toupper(buffer[i]);
for(i=0; i<KEYWORD_COUNT; i++)
{
if(memcmp(buffer, aKeywordTable[i].zName, len))
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_WILDCARD;
return 1;
}
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;
}

239
reactos/lib/msi/update.c Normal file
View file

@ -0,0 +1,239 @@
/*
* Implementation of the Microsoft Installer (msi.dll)
*
* Copyright 2004 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 receuved 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 <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "wine/debug.h"
#include "msi.h"
#include "msiquery.h"
#include "objbase.h"
#include "objidl.h"
#include "msipriv.h"
#include "winnls.h"
#include "query.h"
WINE_DEFAULT_DEBUG_CHANNEL(msi);
/* below is the query interface to a table */
typedef struct tagMSIUPDATEVIEW
{
MSIVIEW view;
MSIDATABASE *db;
MSIVIEW *wv;
value_list *vals;
} MSIUPDATEVIEW;
static UINT UPDATE_fetch_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT *val )
{
MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
TRACE("%p %d %d %p\n", uv, row, col, val );
return ERROR_FUNCTION_FAILED;
}
static UINT UPDATE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
{
MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
UINT n, type, val, r, row, col_count = 0, row_count = 0;
MSIVIEW *wv;
TRACE("%p %p\n", uv, record );
if( !record )
return ERROR_FUNCTION_FAILED;
wv = uv->wv;
if( !wv )
return ERROR_FUNCTION_FAILED;
r = wv->ops->execute( wv, 0 );
TRACE("tv execute returned %x\n", r);
if( r )
return r;
r = wv->ops->get_dimensions( wv, &row_count, &col_count );
if( r )
goto err;
for( row = 0; row < row_count; row++ )
{
for( n = 1; n <= col_count; n++ )
{
r = wv->ops->get_column_info( wv, n, NULL, &type );
if( r )
break;
if( type & MSITYPE_STRING )
{
const WCHAR *str = MSI_RecordGetString( record, n );
val = msi_addstringW( uv->db->strings, 0, str, -1, 1 );
}
else
{
val = MSI_RecordGetInteger( record, n );
val |= 0x8000;
}
r = wv->ops->set_int( wv, row, n, val );
if( r )
break;
}
}
err:
return ERROR_SUCCESS;
}
static UINT UPDATE_close( struct tagMSIVIEW *view )
{
MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
MSIVIEW *wv;
TRACE("%p\n", uv);
wv = uv->wv;
if( !wv )
return ERROR_FUNCTION_FAILED;
return wv->ops->close( wv );
}
static UINT UPDATE_get_dimensions( struct tagMSIVIEW *view, UINT *rows, UINT *cols )
{
MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
MSIVIEW *wv;
TRACE("%p %p %p\n", uv, rows, cols );
wv = uv->wv;
if( !wv )
return ERROR_FUNCTION_FAILED;
return wv->ops->get_dimensions( wv, rows, cols );
}
static UINT UPDATE_get_column_info( struct tagMSIVIEW *view,
UINT n, LPWSTR *name, UINT *type )
{
MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
MSIVIEW *wv;
TRACE("%p %d %p %p\n", uv, n, name, type );
wv = uv->wv;
if( !wv )
return ERROR_FUNCTION_FAILED;
return wv->ops->get_column_info( wv, n, name, type );
}
static UINT UPDATE_modify( struct tagMSIVIEW *view, MSIMODIFY eModifyMode, MSIHANDLE hrec)
{
MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
TRACE("%p %d %ld\n", uv, eModifyMode, hrec );
return ERROR_FUNCTION_FAILED;
}
static UINT UPDATE_delete( struct tagMSIVIEW *view )
{
MSIUPDATEVIEW *uv = (MSIUPDATEVIEW*)view;
MSIVIEW *wv;
TRACE("%p\n", uv );
wv = uv->wv;
if( wv )
wv->ops->delete( wv );
delete_value_list( uv->vals );
msiobj_release( &uv->db->hdr );
HeapFree( GetProcessHeap(), 0, uv );
return ERROR_SUCCESS;
}
static MSIVIEWOPS update_ops =
{
UPDATE_fetch_int,
NULL,
NULL,
NULL,
UPDATE_execute,
UPDATE_close,
UPDATE_get_dimensions,
UPDATE_get_column_info,
UPDATE_modify,
UPDATE_delete
};
UINT UPDATE_CreateView( MSIDATABASE *db, MSIVIEW **view, LPWSTR table,
column_assignment *list, struct expr *expr )
{
MSIUPDATEVIEW *uv = NULL;
UINT r;
MSIVIEW *tv = NULL, *sv = NULL, *wv = NULL;
TRACE("%p\n", uv );
r = TABLE_CreateView( db, table, &tv );
if( r != ERROR_SUCCESS )
return r;
/* add conditions first */
r = WHERE_CreateView( db, &wv, tv, expr );
if( r != ERROR_SUCCESS )
{
if( sv )
sv->ops->delete( tv );
return r;
}
/* then select the columns we want */
r = SELECT_CreateView( db, &sv, wv, list->col_list );
if( r != ERROR_SUCCESS )
{
if( tv )
tv->ops->delete( sv );
return r;
}
uv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *uv );
if( !uv )
return ERROR_FUNCTION_FAILED;
/* fill the structure */
uv->view.ops = &update_ops;
msiobj_addref( &db->hdr );
uv->db = db;
uv->vals = list->val_list;
uv->wv = sv;
*view = (MSIVIEW*) uv;
return ERROR_SUCCESS;
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2004 Christian Costa
*
* 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 WINE_FILEDESCRIPTION_STR "Wine MSI dll"
#define WINE_FILENAME_STR "msi.dll"
#define WINE_FILEVERSION 2,0,2600,0
#define WINE_FILEVERSION_STR "2.0.2600.0"
#define WINE_PRODUCTVERSION 2,0,2600,0
#define WINE_PRODUCTVERSION_STR "2.0.2600.0"
#include "wine/wine_common_ver.rc"

471
reactos/lib/msi/where.c Normal file
View file

@ -0,0 +1,471 @@
/*
* 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 <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "wine/debug.h"
#include "wine/unicode.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 WHERE_fetch_stream( struct tagMSIVIEW *view, UINT row, UINT col, IStream **stm )
{
MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
TRACE("%p %d %d %p\n", wv, row, col, stm );
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_stream( wv->table, row, col, stm );
}
static UINT WHERE_set_int( struct tagMSIVIEW *view, UINT row, UINT col, UINT val )
{
MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
TRACE("%p %d %d %04x\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->set_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 const WCHAR *STRING_evaluate( string_table *st,
MSIVIEW *table, UINT row, struct expr *expr, MSIRECORD *record )
{
UINT val = 0, r;
switch( expr->type )
{
case EXPR_COL_NUMBER:
r = table->ops->fetch_int( table, row, expr->u.col_number, &val );
if( r != ERROR_SUCCESS )
return NULL;
return msi_string_lookup_id( st, val );
case EXPR_SVAL:
return expr->u.sval;
case EXPR_WILDCARD:
return MSI_RecordGetString( record, 1 );
default:
ERR("Invalid expression type\n");
break;
}
return NULL;
}
static UINT STRCMP_Evaluate( string_table *st, MSIVIEW *table, UINT row,
struct expr *cond, UINT *val, MSIRECORD *record )
{
int sr;
const WCHAR *l_str, *r_str;
l_str = STRING_evaluate( st, table, row, cond->u.expr.left, record );
r_str = STRING_evaluate( st, table, row, cond->u.expr.right, record );
if( l_str == r_str )
sr = 0;
else if( l_str && ! r_str )
sr = 1;
else if( r_str && ! l_str )
sr = -1;
else
sr = strcmpW( l_str, r_str );
*val = ( cond->u.expr.op == OP_EQ && ( sr == 0 ) ) ||
( cond->u.expr.op == OP_LT && ( sr < 0 ) ) ||
( cond->u.expr.op == OP_GT && ( sr > 0 ) );
return ERROR_SUCCESS;
}
static UINT WHERE_evaluate( MSIDATABASE *db, MSIVIEW *table, UINT row,
struct expr *cond, UINT *val, MSIRECORD *record )
{
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_UVAL:
*val = cond->u.uval;
return ERROR_SUCCESS;
case EXPR_COMPLEX:
r = WHERE_evaluate( db, table, row, cond->u.expr.left, &lval, record );
if( r != ERROR_SUCCESS )
return r;
r = WHERE_evaluate( db, table, row, cond->u.expr.right, &rval, record );
if( r != ERROR_SUCCESS )
return r;
*val = INT_evaluate( lval, cond->u.expr.op, rval );
return ERROR_SUCCESS;
case EXPR_STRCMP:
return STRCMP_Evaluate( db->strings, table, row, cond, val, record );
case EXPR_WILDCARD:
*val = MSI_RecordGetInteger( record, 1 );
return ERROR_SUCCESS;
default:
ERR("Invalid expression type\n");
break;
}
return ERROR_SUCCESS;
}
static UINT WHERE_execute( struct tagMSIVIEW *view, MSIRECORD *record )
{
MSIWHEREVIEW *wv = (MSIWHEREVIEW*)view;
UINT count = 0, r, val, i;
MSIVIEW *table = wv->table;
TRACE("%p %p\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( wv->db, table, i, wv->cond, &val, record );
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 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;
if( wv->cond )
delete_expr( wv->cond );
msiobj_release( &wv->db->hdr );
HeapFree( GetProcessHeap(), 0, wv );
return ERROR_SUCCESS;
}
MSIVIEWOPS where_ops =
{
WHERE_fetch_int,
WHERE_fetch_stream,
WHERE_set_int,
NULL,
WHERE_execute,
WHERE_close,
WHERE_get_dimensions,
WHERE_get_column_info,
WHERE_modify,
WHERE_delete
};
static UINT WHERE_VerifyCondition( MSIDATABASE *db, MSIVIEW *table, struct expr *cond,
UINT *valid )
{
UINT r, val = 0;
switch( cond->type )
{
case EXPR_COLUMN:
r = VIEW_find_column( table, cond->u.column, &val );
if( r == ERROR_SUCCESS )
{
*valid = 1;
cond->type = EXPR_COL_NUMBER;
cond->u.col_number = val;
}
else
{
*valid = 0;
ERR("Couldn't find column %s\n", debugstr_w( cond->u.column ) );
}
break;
case EXPR_COMPLEX:
r = WHERE_VerifyCondition( db, table, cond->u.expr.left, valid );
if( r != ERROR_SUCCESS )
return r;
if( !*valid )
return ERROR_SUCCESS;
r = WHERE_VerifyCondition( db, table, cond->u.expr.right, valid );
if( r != ERROR_SUCCESS )
return r;
/* check the type of the comparison */
if( ( cond->u.expr.left->type == EXPR_SVAL ) ||
( cond->u.expr.right->type == EXPR_SVAL ) )
{
switch( cond->u.expr.op )
{
case OP_EQ:
case OP_GT:
case OP_LT:
break;
default:
*valid = FALSE;
return ERROR_INVALID_PARAMETER;
}
/* FIXME: check we're comparing a string to a column */
cond->type = EXPR_STRCMP;
}
break;
case EXPR_IVAL:
*valid = 1;
cond->type = EXPR_UVAL;
cond->u.uval = cond->u.ival + (1<<15);
break;
case EXPR_WILDCARD:
*valid = 1;
break;
case EXPR_SVAL:
*valid = 1;
break;
default:
ERR("Invalid expression type\n");
*valid = 0;
break;
}
return ERROR_SUCCESS;
}
UINT WHERE_CreateView( MSIDATABASE *db, MSIVIEW **view, MSIVIEW *table,
struct expr *cond )
{
MSIWHEREVIEW *wv = NULL;
UINT count = 0, r, valid = 0;
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;
}
if( cond )
{
r = WHERE_VerifyCondition( db, table, cond, &valid );
if( r != ERROR_SUCCESS )
return r;
if( !valid )
return ERROR_FUNCTION_FAILED;
}
wv = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *wv );
if( !wv )
return ERROR_FUNCTION_FAILED;
/* fill the structure */
wv->view.ops = &where_ops;
msiobj_addref( &db->hdr );
wv->db = db;
wv->table = table;
wv->row_count = 0;
wv->reorder = NULL;
wv->cond = cond;
*view = (MSIVIEW*) wv;
return ERROR_SUCCESS;
}

View file

@ -0,0 +1,67 @@
Only in /root/wine/wine/dlls/msi: .cvsignore
Only in /root/wine/wine/dlls/msi: CVS
Only in ./: Makefile
Only in ./: Makefile.ros-template
diff -u /root/wine/wine/dlls/msi/action.c ./action.c
--- /root/wine/wine/dlls/msi/action.c 2004-10-27 20:43:05.000000000 -0500
+++ ./action.c 2004-10-30 12:14:17.000000000 -0500
@@ -28,6 +28,7 @@
#include <stdarg.h>
#include <stdio.h>
+#include <fcntl.h>
#define COBJMACROS
@@ -39,7 +40,7 @@
#include "fdi.h"
#include "msi.h"
#include "msiquery.h"
-#include "msvcrt/fcntl.h"
+//#include "msvcrt/fcntl.h"
#include "objbase.h"
#include "objidl.h"
#include "msipriv.h"
@@ -3477,7 +3478,7 @@
continue;
}
- res = LoadTypeLib(package->files[index].TargetPath,&ptLib);
+// res = LoadTypeLib(package->files[index].TargetPath,&ptLib);
if (SUCCEEDED(res))
{
WCHAR help[MAX_PATH];
@@ -3488,7 +3489,7 @@
resolve_folder(package,helpid,help,FALSE,FALSE,NULL);
- res = RegisterTypeLib(ptLib,package->files[index].TargetPath,help);
+// res = RegisterTypeLib(ptLib,package->files[index].TargetPath,help);
if (!SUCCEEDED(res))
ERR("Failed to register type library %s\n",
debugstr_w(package->files[index].TargetPath));
@@ -3503,8 +3504,9 @@
debugstr_w(package->files[index].TargetPath));
}
- if (ptLib)
- ITypeLib_Release(ptLib);
+ if (ptLib){
+ //ITypeLib_Release(ptLib);
+ }
}
else
ERR("Failed to load type library %s\n",
Only in ./: patch.diff
diff -u /root/wine/wine/dlls/msi/suminfo.c ./suminfo.c
--- /root/wine/wine/dlls/msi/suminfo.c 2004-10-18 13:20:12.000000000 -0500
+++ ./suminfo.c 2004-10-30 00:09:12.000000000 -0500
@@ -23,6 +23,8 @@
#define COBJMACROS
#define NONAMELESSUNION
+#define PRSPEC_PROPID (1)
+
#include "windef.h"
#include "winbase.h"
#include "winreg.h"