Start implementing actions.
This commit is contained in:
parent
c390bb2aea
commit
401bd3f772
|
@ -3,10 +3,11 @@ TOPOBJDIR = ../..
|
|||
SRCDIR = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
MODULE = msi.dll
|
||||
IMPORTS = ole32 user32 advapi32 kernel32
|
||||
IMPORTS = shell32 cabinet ole32 user32 advapi32 kernel32
|
||||
EXTRALIBS = -luuid $(LIBUNICODE)
|
||||
|
||||
C_SRCS = \
|
||||
action.c \
|
||||
create.c \
|
||||
distinct.c \
|
||||
handle.c \
|
||||
|
|
File diff suppressed because it is too large
Load Diff
508
dlls/msi/cond.y
508
dlls/msi/cond.y
|
@ -52,15 +52,46 @@ typedef struct tag_yyinput
|
|||
|
||||
static LPWSTR COND_GetString( COND_input *info );
|
||||
static int COND_lex( void *COND_lval, COND_input *info);
|
||||
UINT get_property(MSIHANDLE hPackage, const WCHAR* prop, WCHAR* value);
|
||||
|
||||
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(INT a, INT b);
|
||||
static INT comp_gt(INT a, INT b);
|
||||
static INT comp_le(INT a, INT b);
|
||||
static INT comp_ge(INT a, INT b);
|
||||
static INT comp_eq(INT a, INT b);
|
||||
static INT comp_ne(INT a, INT 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);
|
||||
|
||||
%}
|
||||
|
||||
|
@ -71,20 +102,27 @@ static INT comp_ne(INT a, INT b);
|
|||
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_LE COND_GE COND_EQ COND_NE
|
||||
%token COND_LPAR COND_RPAR
|
||||
%token COND_LT COND_GT COND_EQ
|
||||
%token COND_LPAR COND_RPAR COND_DBLQ COND_TILDA
|
||||
%token COND_PERCENT COND_DOLLARS COND_QUESTION COND_AMPER COND_EXCLAM
|
||||
%token COND_IDENT COND_NUMBER
|
||||
|
||||
%nonassoc COND_EOF COND_ERROR
|
||||
|
||||
%type <value> expression boolean_term boolean_factor term value symbol integer
|
||||
%type <string> identifier
|
||||
%type <fn_comp_int> comparison_op
|
||||
%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
|
||||
|
||||
%%
|
||||
|
||||
|
@ -112,7 +150,7 @@ boolean_term:
|
|||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| boolean_factor COND_AND term
|
||||
| boolean_term COND_AND boolean_factor
|
||||
{
|
||||
$$ = $1 && $3;
|
||||
}
|
||||
|
@ -129,12 +167,33 @@ boolean_factor:
|
|||
}
|
||||
;
|
||||
|
||||
|
||||
term:
|
||||
value
|
||||
value_i
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| value comparison_op value
|
||||
| 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 );
|
||||
}
|
||||
|
@ -144,35 +203,172 @@ term:
|
|||
}
|
||||
;
|
||||
|
||||
comparison_op:
|
||||
COND_LT
|
||||
comp_op_i:
|
||||
/* common functions */
|
||||
COND_EQ
|
||||
{
|
||||
$$ = comp_lt;
|
||||
$$ = comp_eq_i;
|
||||
}
|
||||
| COND_LT COND_GT
|
||||
{
|
||||
$$ = comp_ne_i;
|
||||
}
|
||||
| COND_LT
|
||||
{
|
||||
$$ = comp_lt_i;
|
||||
}
|
||||
| COND_GT
|
||||
{
|
||||
$$ = comp_gt;
|
||||
$$ = comp_gt_i;
|
||||
}
|
||||
| COND_LE
|
||||
| COND_LT COND_EQ
|
||||
{
|
||||
$$ = comp_le;
|
||||
$$ = comp_le_i;
|
||||
}
|
||||
| COND_GE
|
||||
| COND_GT COND_EQ
|
||||
{
|
||||
$$ = comp_ge;
|
||||
$$ = comp_ge_i;
|
||||
}
|
||||
| COND_EQ
|
||||
/*Int only*/
|
||||
| COND_GT COND_LT
|
||||
{
|
||||
$$ = comp_eq;
|
||||
$$ = comp_bitand;
|
||||
}
|
||||
| COND_NE
|
||||
| COND_LT COND_LT
|
||||
{
|
||||
$$ = comp_ne;
|
||||
$$ = comp_highcomp;
|
||||
}
|
||||
| COND_GT COND_GT
|
||||
{
|
||||
$$ = comp_lowcomp;
|
||||
}
|
||||
;
|
||||
|
||||
value:
|
||||
symbol
|
||||
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;
|
||||
}
|
||||
|
@ -182,7 +378,25 @@ value:
|
|||
}
|
||||
;
|
||||
|
||||
symbol:
|
||||
value_s:
|
||||
symbol_s
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| literal
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
literal:
|
||||
COND_DBLQ identifier COND_DBLQ
|
||||
{
|
||||
$$ = $2;
|
||||
}
|
||||
;
|
||||
|
||||
symbol_i:
|
||||
COND_DOLLARS identifier
|
||||
{
|
||||
COND_input* cond = (COND_input*) info;
|
||||
|
@ -217,15 +431,22 @@ symbol:
|
|||
}
|
||||
;
|
||||
|
||||
identifier:
|
||||
COND_IDENT
|
||||
symbol_s:
|
||||
identifier
|
||||
{
|
||||
COND_input* cond = (COND_input*) info;
|
||||
$$ = COND_GetString(cond);
|
||||
if( !$$ )
|
||||
YYABORT;
|
||||
$$ = HeapAlloc( GetProcessHeap(), 0, 0x100*sizeof (WCHAR) );
|
||||
|
||||
/* Lookup the identifier */
|
||||
/* This will not really work until we have write access to the table*/
|
||||
/* HACK ALERT HACK ALERT... */
|
||||
|
||||
if (get_property(cond->hInstall,$1,$$) != ERROR_SUCCESS)
|
||||
{
|
||||
$$[0]=0;
|
||||
}
|
||||
}
|
||||
| COND_PERCENT identifier
|
||||
| COND_PERCENT identifier
|
||||
{
|
||||
UINT len = GetEnvironmentVariableW( $2, NULL, 0 );
|
||||
if( len++ )
|
||||
|
@ -238,6 +459,16 @@ identifier:
|
|||
}
|
||||
;
|
||||
|
||||
identifier:
|
||||
COND_IDENT
|
||||
{
|
||||
COND_input* cond = (COND_input*) info;
|
||||
$$ = COND_GetString(cond);
|
||||
if( !$$ )
|
||||
YYABORT;
|
||||
}
|
||||
;
|
||||
|
||||
integer:
|
||||
COND_NUMBER
|
||||
{
|
||||
|
@ -252,35 +483,82 @@ integer:
|
|||
|
||||
%%
|
||||
|
||||
static INT comp_lt(INT a, INT b)
|
||||
{
|
||||
return (a < b);
|
||||
|
||||
/* 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_gt(INT a, INT b)
|
||||
{
|
||||
return (a > b);
|
||||
}
|
||||
|
||||
static INT comp_le(INT a, INT b)
|
||||
{
|
||||
return (a <= b);
|
||||
}
|
||||
static INT comp_eq_m1(LPWSTR a, INT b)
|
||||
{ return atoiW(a)==b; }
|
||||
static INT comp_ne_m1(LPWSTR a, INT b)
|
||||
{ return atoiW(a)!=b; }
|
||||
static INT comp_lt_m1(LPWSTR a, INT b)
|
||||
{ return atoiW(a)<b; }
|
||||
static INT comp_gt_m1(LPWSTR a, INT b)
|
||||
{ return atoiW(a)>b; }
|
||||
static INT comp_le_m1(LPWSTR a, INT b)
|
||||
{ return atoiW(a)<=b; }
|
||||
static INT comp_ge_m1(LPWSTR a, INT b)
|
||||
{ return atoiW(a)>=b; }
|
||||
|
||||
static INT comp_ge(INT a, INT b)
|
||||
{
|
||||
return (a >= b);
|
||||
}
|
||||
|
||||
static INT comp_eq(INT a, INT b)
|
||||
{
|
||||
return (a == b);
|
||||
}
|
||||
|
||||
static INT comp_ne(INT a, INT b)
|
||||
{
|
||||
return (a != b);
|
||||
}
|
||||
static INT comp_eq_m2(INT a, LPWSTR b)
|
||||
{ return a == atoiW(b); }
|
||||
static INT comp_ne_m2(INT a, LPWSTR b)
|
||||
{ return a != atoiW(b); }
|
||||
static INT comp_lt_m2(INT a, LPWSTR b)
|
||||
{ return a < atoiW(b); }
|
||||
static INT comp_gt_m2(INT a, LPWSTR b)
|
||||
{ return a > atoiW(b); }
|
||||
static INT comp_le_m2(INT a, LPWSTR b)
|
||||
{ return a <= atoiW(b); }
|
||||
static INT comp_ge_m2(INT a, LPWSTR b)
|
||||
{ return a >= atoiW(b); }
|
||||
|
||||
|
||||
static int COND_IsAlpha( WCHAR x )
|
||||
|
@ -296,48 +574,95 @@ static int COND_IsNumber( WCHAR x )
|
|||
|
||||
static int COND_IsIdent( WCHAR x )
|
||||
{
|
||||
return( COND_IsAlpha( x ) || COND_IsNumber( x ) || ( x == '_' ) );
|
||||
return( COND_IsAlpha( x ) || COND_IsNumber( x ) || ( x == '_' )
|
||||
|| ( x == '#' ) || (x == '.') );
|
||||
}
|
||||
|
||||
static int COND_lex( void *COND_lval, COND_input *cond )
|
||||
{
|
||||
WCHAR ch;
|
||||
/* grammer */
|
||||
static const WCHAR NOT[] = {'O','T',' ',0};
|
||||
static const WCHAR AND[] = {'N','D',' ',0};
|
||||
static const WCHAR OR[] = {'R',' ',0};
|
||||
|
||||
int rc = COND_SPACE;
|
||||
|
||||
while (rc == COND_SPACE)
|
||||
{
|
||||
|
||||
cond->start = cond->n;
|
||||
ch = cond->str[cond->n];
|
||||
if( !ch )
|
||||
return COND_EOF;
|
||||
if( ch == 0 )
|
||||
return 0;
|
||||
cond->n++;
|
||||
|
||||
switch( ch )
|
||||
{
|
||||
case '(': return COND_LPAR;
|
||||
case ')': return COND_RPAR;
|
||||
case '&': return COND_AMPER;
|
||||
case '!': return COND_EXCLAM;
|
||||
case '$': return COND_DOLLARS;
|
||||
case '?': return COND_QUESTION;
|
||||
case '%': return COND_PERCENT;
|
||||
case ' ': return COND_SPACE;
|
||||
}
|
||||
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_DBLQ; break;
|
||||
case '~': rc = COND_TILDA; break;
|
||||
case '<': rc = COND_LT; break;
|
||||
case '>': rc = COND_GT; break;
|
||||
case 'N':
|
||||
case 'n':
|
||||
if (strncmpiW(&cond->str[cond->n],NOT,3)==0)
|
||||
{
|
||||
cond->n+=3;
|
||||
rc = COND_NOT;
|
||||
}
|
||||
break;
|
||||
case 'A':
|
||||
case 'a':
|
||||
if (strncmpiW(&cond->str[cond->n],AND,3)==0)
|
||||
{
|
||||
cond->n+=3;
|
||||
rc = COND_AND;
|
||||
}
|
||||
break;
|
||||
case 'O':
|
||||
case 'o':
|
||||
if (strncmpiW(&cond->str[cond->n],OR,2)==0)
|
||||
{
|
||||
cond->n+=2;
|
||||
rc = COND_OR;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if( COND_IsAlpha( ch ) )
|
||||
{
|
||||
ch = cond->str[cond->n];
|
||||
while( COND_IsIdent( ch ) )
|
||||
ch = cond->str[cond->n++];
|
||||
cond->n--;
|
||||
rc = COND_IDENT;
|
||||
break;
|
||||
}
|
||||
|
||||
if( COND_IsAlpha( ch ) )
|
||||
{
|
||||
ch = cond->str[cond->n];
|
||||
while( COND_IsIdent( ch ) )
|
||||
ch = cond->str[cond->n++];
|
||||
return COND_IDENT;
|
||||
}
|
||||
if( COND_IsNumber( ch ) )
|
||||
{
|
||||
ch = cond->str[cond->n];
|
||||
while( COND_IsNumber( ch ) )
|
||||
ch = cond->str[cond->n++];
|
||||
rc = COND_NUMBER;
|
||||
break;
|
||||
}
|
||||
|
||||
if( COND_IsNumber( ch ) )
|
||||
{
|
||||
ch = cond->str[cond->n];
|
||||
while( COND_IsNumber( ch ) )
|
||||
ch = cond->str[cond->n++];
|
||||
return COND_NUMBER;
|
||||
ERR("Got unknown character %c(%x)\n",ch,ch);
|
||||
rc = COND_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
return COND_ERROR;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static LPWSTR COND_GetString( COND_input *cond )
|
||||
|
@ -348,7 +673,11 @@ static LPWSTR COND_GetString( COND_input *cond )
|
|||
len = cond->n - cond->start;
|
||||
str = HeapAlloc( GetProcessHeap(), 0, (len+1) * sizeof (WCHAR) );
|
||||
if( str )
|
||||
{
|
||||
strncpyW( str, &cond->str[cond->start], len );
|
||||
str[len]=0;
|
||||
}
|
||||
TRACE("Got identifier %s\n",debugstr_w(str));
|
||||
return str;
|
||||
}
|
||||
|
||||
|
@ -366,13 +695,16 @@ MSICONDITION WINAPI MsiEvaluateConditionW( MSIHANDLE hInstall, LPCWSTR szConditi
|
|||
cond.str = szCondition;
|
||||
cond.n = 0;
|
||||
cond.start = 0;
|
||||
cond.result = MSICONDITION_ERROR;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ MSIHANDLE alloc_msihandle(UINT type, UINT size, msihandledestructor destroy, voi
|
|||
|
||||
info->magic = MSIHANDLE_MAGIC;
|
||||
info->type = type;
|
||||
info->refcount = 1;
|
||||
info->destructor = destroy;
|
||||
|
||||
msihandletable[i] = info;
|
||||
|
@ -79,6 +80,26 @@ void *msihandle2msiinfo(MSIHANDLE handle, UINT type)
|
|||
return &msihandletable[handle][1];
|
||||
}
|
||||
|
||||
void msihandle_addref(MSIHANDLE handle)
|
||||
{
|
||||
MSIHANDLEINFO *info = msihandle2msiinfo(handle, 0);
|
||||
|
||||
TRACE("%lx\n",handle);
|
||||
|
||||
if( !info )
|
||||
return;
|
||||
|
||||
info--;
|
||||
|
||||
if( info->magic != MSIHANDLE_MAGIC )
|
||||
{
|
||||
ERR("Invalid handle!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
info->refcount++;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiCloseHandle(MSIHANDLE handle)
|
||||
{
|
||||
MSIHANDLEINFO *info = msihandle2msiinfo(handle, 0);
|
||||
|
@ -96,6 +117,10 @@ UINT WINAPI MsiCloseHandle(MSIHANDLE handle)
|
|||
return ERROR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
info->refcount--;
|
||||
if (info->refcount > 0)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
if( info->destructor )
|
||||
info->destructor( &info[1] );
|
||||
|
||||
|
|
242
dlls/msi/msi.c
242
dlls/msi/msi.c
|
@ -33,6 +33,7 @@
|
|||
#include "msipriv.h"
|
||||
#include "objidl.h"
|
||||
#include "wincrypt.h"
|
||||
#include "wine/unicode.h"
|
||||
#include "objbase.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msi);
|
||||
|
@ -302,18 +303,24 @@ UINT WINAPI MsiOpenProductW(LPCWSTR szProduct, MSIHANDLE *phProduct)
|
|||
|
||||
r = RegOpenKeyW( HKEY_LOCAL_MACHINE, szKey, &hKeyUninstall );
|
||||
if( r != ERROR_SUCCESS )
|
||||
return r;
|
||||
return ERROR_UNKNOWN_PRODUCT;
|
||||
|
||||
r = RegOpenKeyW( hKeyUninstall, szProduct, &hKeyProduct );
|
||||
if( r != ERROR_SUCCESS )
|
||||
{
|
||||
r = ERROR_UNKNOWN_PRODUCT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* find the size of the path */
|
||||
type = count = 0;
|
||||
r = RegQueryValueExW( hKeyProduct, szLocalPackage,
|
||||
NULL, &type, NULL, &count );
|
||||
if( r != ERROR_SUCCESS )
|
||||
{
|
||||
r = ERROR_UNKNOWN_PRODUCT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* now alloc and fetch the path of the database to open */
|
||||
path = HeapAlloc( GetProcessHeap(), 0, count );
|
||||
|
@ -323,7 +330,10 @@ UINT WINAPI MsiOpenProductW(LPCWSTR szProduct, MSIHANDLE *phProduct)
|
|||
r = RegQueryValueExW( hKeyProduct, szLocalPackage,
|
||||
NULL, &type, (LPBYTE) path, &count );
|
||||
if( r != ERROR_SUCCESS )
|
||||
{
|
||||
r = ERROR_UNKNOWN_PRODUCT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
r = MsiOpenPackageW( path, phProduct );
|
||||
|
||||
|
@ -345,8 +355,10 @@ UINT WINAPI MsiOpenPackageA(LPCSTR szPackage, MSIHANDLE *phPackage)
|
|||
|
||||
UINT WINAPI MsiOpenPackageW(LPCWSTR szPackage, MSIHANDLE *phPackage)
|
||||
{
|
||||
UINT rc;
|
||||
FIXME("%s %p\n",debugstr_w(szPackage), phPackage);
|
||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
rc = MsiOpenDatabaseW(szPackage,MSIDBOPEN_READONLY,phPackage);
|
||||
return rc;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiOpenPackageExA(LPCSTR szPackage, DWORD dwOptions, MSIHANDLE *phPackage)
|
||||
|
@ -426,9 +438,23 @@ end:
|
|||
|
||||
UINT WINAPI MsiInstallProductW(LPCWSTR szPackagePath, LPCWSTR szCommandLine)
|
||||
{
|
||||
MSIHANDLE dbhandle;
|
||||
UINT rc = ERROR_SUCCESS;
|
||||
|
||||
FIXME("%s %s\n",debugstr_w(szPackagePath), debugstr_w(szCommandLine));
|
||||
|
||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
rc = MsiVerifyPackageW(szPackagePath);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
return rc;
|
||||
|
||||
rc = MsiOpenDatabaseW(szPackagePath,MSIDBOPEN_READONLY,&dbhandle);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
return rc;
|
||||
|
||||
ACTION_DoTopLevelINSTALL(dbhandle, szPackagePath, szCommandLine);
|
||||
|
||||
MsiCloseHandle(dbhandle);
|
||||
return rc;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiConfigureProductA(LPCSTR szProduct, int iInstallLevel, INSTALLSTATE eInstallState)
|
||||
|
@ -511,66 +537,8 @@ UINT WINAPI MsiGetProductCodeW(LPCWSTR szComponent, LPWSTR szBuffer)
|
|||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, DWORD* pchValueBuf)
|
||||
{
|
||||
LPWSTR szwName = NULL, szwValueBuf = NULL;
|
||||
UINT hr = ERROR_INSTALL_FAILURE;
|
||||
|
||||
if (0 == hInstall) {
|
||||
return ERROR_INVALID_HANDLE;
|
||||
}
|
||||
if (NULL == szName) {
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
FIXME("%lu %s %lu\n", hInstall, debugstr_a(szName), *pchValueBuf);
|
||||
|
||||
if (NULL != szValueBuf && NULL == pchValueBuf) {
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
if( szName )
|
||||
{
|
||||
UINT 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 );
|
||||
} else {
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
if( szValueBuf )
|
||||
{
|
||||
szwValueBuf = HeapAlloc( GetProcessHeap(), 0, (*pchValueBuf) * sizeof(WCHAR) );
|
||||
if( !szwValueBuf )
|
||||
goto end;
|
||||
}
|
||||
|
||||
hr = MsiGetPropertyW( hInstall, szwName, szwValueBuf, pchValueBuf );
|
||||
|
||||
if( ERROR_SUCCESS == hr )
|
||||
{
|
||||
WideCharToMultiByte(CP_ACP, 0, szwValueBuf, -1, szValueBuf, *pchValueBuf, NULL, NULL);
|
||||
}
|
||||
|
||||
end:
|
||||
if( szwName )
|
||||
HeapFree( GetProcessHeap(), 0, szwName );
|
||||
if( szwValueBuf )
|
||||
HeapFree( GetProcessHeap(), 0, szwValueBuf );
|
||||
|
||||
return hr;
|
||||
}
|
||||
UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName, LPWSTR szValueBuf, DWORD* pchValueBuf)
|
||||
{
|
||||
FIXME("%lu %s %lu\n", hInstall, debugstr_w(szName), *pchValueBuf);
|
||||
if (0 == hInstall) {
|
||||
return ERROR_INVALID_HANDLE;
|
||||
}
|
||||
if (NULL == szName) {
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
return ERROR_CALL_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiGetProductInfoA(LPCSTR szProduct, LPCSTR szAttribute, LPSTR szBuffer, DWORD *pcchValueBuf)
|
||||
{
|
||||
|
@ -715,6 +683,13 @@ INSTALLUILEVEL WINAPI MsiSetInternalUI(INSTALLUILEVEL dwUILevel, HWND *phWnd)
|
|||
return dwUILevel;
|
||||
}
|
||||
|
||||
INSTALLUI_HANDLERA WINAPI MsiSetExternalUIA(INSTALLUI_HANDLERA puiHandler,
|
||||
DWORD dwMessageFilter, LPVOID pvContext)
|
||||
{
|
||||
FIXME("STUB\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiLoadStringA(HINSTANCE hInstance, UINT uID, LPSTR lpBuffer, int nBufferMax, DWORD e)
|
||||
{
|
||||
/*FIXME("%08lx %08lx %08lx %08lx %08lx\n",a,b,c,d,e);*/
|
||||
|
@ -1220,3 +1195,148 @@ BOOL WINAPI MSI_DllCanUnloadNow(void)
|
|||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
|
||||
/* property code */
|
||||
UINT WINAPI MsiSetPropertyA( MSIHANDLE hInstall, LPCSTR szName, LPCSTR szValue)
|
||||
{
|
||||
FIXME("STUB until write access is done: (%s %s)\n", szName,
|
||||
szValue);
|
||||
|
||||
if (!hInstall)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiSetPropertyW( MSIHANDLE hInstall, LPCWSTR szName, LPCWSTR szValue)
|
||||
{
|
||||
FIXME("STUB until write access is done: (%s %s)\n",debugstr_w(szName),
|
||||
debugstr_w(szValue));
|
||||
|
||||
if (!hInstall)
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiGetPropertyA(MSIHANDLE hInstall, LPCSTR szName, LPSTR szValueBuf, DWORD* pchValueBuf)
|
||||
{
|
||||
LPWSTR szwName = NULL, szwValueBuf = NULL;
|
||||
UINT hr = ERROR_INSTALL_FAILURE;
|
||||
|
||||
if (0 == hInstall) {
|
||||
return ERROR_INVALID_HANDLE;
|
||||
}
|
||||
if (NULL == szName) {
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
FIXME("%lu %s %lu\n", hInstall, debugstr_a(szName), *pchValueBuf);
|
||||
|
||||
if (NULL != szValueBuf && NULL == pchValueBuf) {
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
if( szName )
|
||||
{
|
||||
UINT 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 );
|
||||
} else {
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
if( szValueBuf )
|
||||
{
|
||||
szwValueBuf = HeapAlloc( GetProcessHeap(), 0, (*pchValueBuf) * sizeof(WCHAR) );
|
||||
if( !szwValueBuf )
|
||||
goto end;
|
||||
}
|
||||
|
||||
hr = MsiGetPropertyW( hInstall, szwName, szwValueBuf, pchValueBuf );
|
||||
|
||||
if( ERROR_SUCCESS == hr )
|
||||
{
|
||||
WideCharToMultiByte(CP_ACP, 0, szwValueBuf, -1, szValueBuf, *pchValueBuf, NULL, NULL);
|
||||
}
|
||||
|
||||
end:
|
||||
if( szwName )
|
||||
HeapFree( GetProcessHeap(), 0, szwName );
|
||||
if( szwValueBuf )
|
||||
HeapFree( GetProcessHeap(), 0, szwValueBuf );
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
UINT WINAPI MsiGetPropertyW(MSIHANDLE hInstall, LPCWSTR szName,
|
||||
LPWSTR szValueBuf, DWORD* pchValueBuf)
|
||||
{
|
||||
MSIHANDLE view,row;
|
||||
UINT rc;
|
||||
WCHAR Query[1024]=
|
||||
{'s','e','l','e','c','t',' ','*',' ','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','`','=','`',0};
|
||||
|
||||
static const WCHAR szEnd[]={'`',0};
|
||||
|
||||
if (0 == hInstall) {
|
||||
return ERROR_INVALID_HANDLE;
|
||||
}
|
||||
if (NULL == szName) {
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
strcatW(Query,szName);
|
||||
strcatW(Query,szEnd);
|
||||
|
||||
rc = MsiDatabaseOpenViewW(hInstall, Query, &view);
|
||||
if (rc == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD sz;
|
||||
WCHAR value[0x100];
|
||||
|
||||
rc = MsiViewExecute(view, 0);
|
||||
if (rc != ERROR_SUCCESS)
|
||||
{
|
||||
MsiViewClose(view);
|
||||
MsiCloseHandle(view);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = MsiViewFetch(view,&row);
|
||||
if (rc == ERROR_SUCCESS)
|
||||
{
|
||||
sz=0x100;
|
||||
rc = MsiRecordGetStringW(row,2,value,&sz);
|
||||
strncpyW(szValueBuf,value,min(sz+1,*pchValueBuf));
|
||||
*pchValueBuf = sz+1;
|
||||
MsiCloseHandle(row);
|
||||
}
|
||||
MsiViewClose(view);
|
||||
MsiCloseHandle(view);
|
||||
}
|
||||
|
||||
if (rc == ERROR_SUCCESS)
|
||||
TRACE("returning %s for property %s\n", debugstr_w(szValueBuf),
|
||||
debugstr_w(szName));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
INT WINAPI MsiProcessMessage( MSIHANDLE hInstall, INSTALLMESSAGE eMessageType,
|
||||
MSIHANDLE hRecord)
|
||||
{
|
||||
FIXME("STUB: \n");
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
MSIHANDLE WINAPI MsiGetActiveDatabase(MSIHANDLE hInstall)
|
||||
{
|
||||
FIXME("Is this correct?\n");
|
||||
msihandle_addref(hInstall);
|
||||
return hInstall;
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
46 stdcall MsiEvaluateConditionA(long str)
|
||||
47 stdcall MsiEvaluateConditionW(long wstr)
|
||||
48 stub MsiGetLastErrorRecord
|
||||
49 stub MsiGetActiveDatabase
|
||||
49 stdcall MsiGetActiveDatabase(long)
|
||||
50 stdcall MsiGetComponentStateA(long str ptr ptr)
|
||||
51 stdcall MsiGetComponentStateW(long wstr ptr ptr)
|
||||
52 stub MsiGetDatabaseState
|
||||
|
@ -100,7 +100,7 @@
|
|||
100 stub MsiPreviewDialogW
|
||||
101 stub MsiProcessAdvertiseScriptA
|
||||
102 stub MsiProcessAdvertiseScriptW
|
||||
103 stub MsiProcessMessage
|
||||
103 stdcall MsiProcessMessage(long long long)
|
||||
104 stub MsiProvideComponentA
|
||||
105 stdcall MsiProvideComponentFromDescriptorA(str ptr ptr ptr)
|
||||
106 stdcall MsiProvideComponentFromDescriptorW(wstr ptr ptr ptr)
|
||||
|
@ -133,7 +133,7 @@
|
|||
133 stub MsiSequenceW
|
||||
134 stub MsiSetComponentStateA
|
||||
135 stub MsiSetComponentStateW
|
||||
136 stub MsiSetExternalUIA
|
||||
136 stdcall MsiSetExternalUIA(ptr long ptr)
|
||||
137 stub MsiSetExternalUIW
|
||||
138 stub MsiSetFeatureStateA
|
||||
139 stub MsiSetFeatureStateW
|
||||
|
@ -141,8 +141,8 @@
|
|||
141 stdcall MsiSetInternalUI(long ptr)
|
||||
142 stub MsiVerifyDiskSpace
|
||||
143 stub MsiSetMode
|
||||
144 stub MsiSetPropertyA
|
||||
145 stub MsiSetPropertyW
|
||||
144 stdcall MsiSetPropertyA(long str str)
|
||||
145 stdcall MsiSetPropertyW(long wstr wstr)
|
||||
146 stub MsiSetTargetPathA
|
||||
147 stub MsiSetTargetPathW
|
||||
148 stdcall MsiSummaryInfoGetPropertyA(long long ptr ptr ptr ptr ptr)
|
||||
|
|
|
@ -132,6 +132,7 @@ typedef struct tagMSIHANDLEINFO
|
|||
{
|
||||
UINT magic;
|
||||
UINT type;
|
||||
UINT refcount;
|
||||
msihandledestructor destructor;
|
||||
struct tagMSIHANDLEINFO *next;
|
||||
struct tagMSIHANDLEINFO *prev;
|
||||
|
@ -164,6 +165,7 @@ DEFINE_GUID(CLSID_IMsiServerMessage, 0x000C101D,0x0000,0x0000,0xC0,0x00,0x00,0x0
|
|||
extern void *msihandle2msiinfo(MSIHANDLE handle, UINT type);
|
||||
|
||||
MSIHANDLE alloc_msihandle(UINT type, UINT extra, msihandledestructor destroy, void **out);
|
||||
void msihandle_addref(MSIHANDLE handle);
|
||||
|
||||
/* add this table to the list of cached tables in the database */
|
||||
extern void add_table(MSIDATABASE *db, MSITABLE *table);
|
||||
|
@ -199,4 +201,9 @@ UINT VIEW_find_column( MSIVIEW *view, LPWSTR name, UINT *n );
|
|||
|
||||
extern BOOL TABLE_Exists( MSIDATABASE *db, LPWSTR name );
|
||||
|
||||
UINT read_raw_stream_data( MSIHANDLE hdb, LPCWSTR stname,
|
||||
USHORT **pdata, UINT *psz );
|
||||
UINT ACTION_DoTopLevelINSTALL(MSIHANDLE hPackage, LPCWSTR szPackagePath,
|
||||
LPCWSTR szCommandLine);
|
||||
|
||||
#endif /* __WINE_MSI_PRIVATE__ */
|
||||
|
|
|
@ -571,7 +571,8 @@ LPWSTR SQL_getstring( struct sql_str *strdata)
|
|||
LPWSTR str;
|
||||
|
||||
/* if there's quotes, remove them */
|
||||
if( (p[0]=='`') && (p[len-1]=='`') )
|
||||
if( ( (p[0]=='`') && (p[len-1]=='`') ) ||
|
||||
( (p[0]=='\'') && (p[len-1]=='\'') ) )
|
||||
{
|
||||
p++;
|
||||
len -= 2;
|
||||
|
|
|
@ -1254,3 +1254,76 @@ UINT MSI_CommitTables( MSIDATABASE *db )
|
|||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
UINT read_raw_stream_data( MSIHANDLE hdb, LPCWSTR stname,
|
||||
USHORT **pdata, UINT *psz )
|
||||
{
|
||||
HRESULT r;
|
||||
UINT ret = ERROR_FUNCTION_FAILED;
|
||||
VOID *data;
|
||||
ULONG sz, count;
|
||||
IStream *stm = NULL;
|
||||
IStorage *stg = NULL;
|
||||
STATSTG stat;
|
||||
WCHAR encname[0x20];
|
||||
MSIDATABASE *db;
|
||||
|
||||
db = msihandle2msiinfo(hdb, MSIHANDLETYPE_DATABASE );
|
||||
|
||||
if ( !db )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
stg = db->storage;
|
||||
|
||||
encode_streamname(FALSE, stname, encname);
|
||||
|
||||
TRACE("%s -> %s\n",debugstr_w(stname),debugstr_w(encname));
|
||||
|
||||
r = IStorage_OpenStream(stg, encname, NULL,
|
||||
STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
|
||||
if( FAILED( r ) )
|
||||
{
|
||||
WARN("open stream failed r = %08lx - empty table?\n",r);
|
||||
return ret;
|
||||
}
|
||||
|
||||
r = IStream_Stat(stm, &stat, STATFLAG_NONAME );
|
||||
if( FAILED( r ) )
|
||||
{
|
||||
ERR("open stream failed r = %08lx!\n",r);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if( stat.cbSize.QuadPart >> 32 )
|
||||
{
|
||||
ERR("Too big!\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
sz = stat.cbSize.QuadPart;
|
||||
data = HeapAlloc( GetProcessHeap(), 0, sz );
|
||||
if( !data )
|
||||
{
|
||||
ERR("couldn't allocate memory r=%08lx!\n",r);
|
||||
ret = ERROR_NOT_ENOUGH_MEMORY;
|
||||
goto end;
|
||||
}
|
||||
|
||||
r = IStream_Read(stm, data, sz, &count );
|
||||
if( FAILED( r ) || ( count != sz ) )
|
||||
{
|
||||
HeapFree( GetProcessHeap(), 0, data );
|
||||
ERR("read stream failed r = %08lx!\n",r);
|
||||
goto end;
|
||||
}
|
||||
|
||||
*pdata = data;
|
||||
*psz = sz;
|
||||
ret = ERROR_SUCCESS;
|
||||
|
||||
end:
|
||||
IStream_Release( stm );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue