mirror of
https://github.com/reactos/reactos.git
synced 2025-04-18 19:47:14 +00:00
First port of Wine projects msi.dll
svn path=/trunk/; revision=11877
This commit is contained in:
parent
6b4f09638b
commit
34151c8b26
29 changed files with 16192 additions and 0 deletions
8
reactos/lib/msi/.cvsignore
Normal file
8
reactos/lib/msi/.cvsignore
Normal file
|
@ -0,0 +1,8 @@
|
|||
*.coff
|
||||
*.dll
|
||||
*.d
|
||||
*.a
|
||||
*.o
|
||||
*.sym
|
||||
*.map
|
||||
*.tmp
|
9
reactos/lib/msi/Makefile
Normal file
9
reactos/lib/msi/Makefile
Normal 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
|
50
reactos/lib/msi/Makefile.in
Normal file
50
reactos/lib/msi/Makefile.in
Normal 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:
|
35
reactos/lib/msi/Makefile.ros-template
Normal file
35
reactos/lib/msi/Makefile.ros-template
Normal 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
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
774
reactos/lib/msi/cond.y
Normal 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
258
reactos/lib/msi/create.c
Normal 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
293
reactos/lib/msi/distinct.c
Normal 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
215
reactos/lib/msi/handle.c
Normal 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
238
reactos/lib/msi/insert.c
Normal 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
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
236
reactos/lib/msi/msi.spec
Normal 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
325
reactos/lib/msi/msipriv.h
Normal 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
485
reactos/lib/msi/msiquery.c
Normal 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
335
reactos/lib/msi/order.c
Normal 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
843
reactos/lib/msi/package.c
Normal 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
139
reactos/lib/msi/query.h
Normal 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
573
reactos/lib/msi/record.c
Normal 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
624
reactos/lib/msi/regsvr.c
Normal 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
290
reactos/lib/msi/select.c
Normal 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
828
reactos/lib/msi/sql.y
Normal 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
459
reactos/lib/msi/string.c
Normal 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
233
reactos/lib/msi/suminfo.c
Normal 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
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
397
reactos/lib/msi/tokenize.c
Normal 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
239
reactos/lib/msi/update.c
Normal 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;
|
||||
}
|
26
reactos/lib/msi/version.rc
Normal file
26
reactos/lib/msi/version.rc
Normal 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
471
reactos/lib/msi/where.c
Normal 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;
|
||||
}
|
67
reactos/lib/msi/winehq2ros.patch
Normal file
67
reactos/lib/msi/winehq2ros.patch
Normal 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"
|
Loading…
Reference in a new issue