MSI: start implementing actions (resend)
Mike McCormack
mike at codeweavers.com
Sat Jun 26 08:44:53 CDT 2004
ChangeLog:
<aric at codeweavers.com>
* start implementing actions
-------------- next part --------------
? dlls/msi/action.c
Index: dlls/msi/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/msi/Makefile.in,v
retrieving revision 1.11
diff -u -r1.11 Makefile.in
--- dlls/msi/Makefile.in 18 May 2004 20:41:47 -0000 1.11
+++ dlls/msi/Makefile.in 26 Jun 2004 14:41:29 -0000
@@ -3,10 +3,11 @@
SRCDIR = @srcdir@
VPATH = @srcdir@
MODULE = msi.dll
-IMPORTS = ole32 user32 advapi32 kernel32
+IMPORTS = ole32 user32 advapi32 kernel32 cabinet shell32
EXTRALIBS = -luuid $(LIBUNICODE)
C_SRCS = \
+ action.c \
create.c \
distinct.c \
handle.c \
Index: dlls/msi/cond.y
===================================================================
RCS file: /home/wine/wine/dlls/msi/cond.y,v
retrieving revision 1.1
diff -u -r1.1 cond.y
--- dlls/msi/cond.y 16 Mar 2004 03:23:43 -0000 1.1
+++ dlls/msi/cond.y 26 Jun 2004 14:41:29 -0000
@@ -52,15 +52,46 @@
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);
-
-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);
+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);
%}
@@ -71,20 +102,27 @@
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 @@
{
$$ = $1;
}
- | boolean_factor COND_AND term
+ | boolean_term COND_AND boolean_factor
{
$$ = $1 && $3;
}
@@ -129,12 +167,33 @@
}
;
+
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 @@
}
;
-comparison_op:
- COND_LT
+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_lt;
+ $$ = comp_eq_s;
+ }
+ | COND_LT COND_GT
+ {
+ $$ = comp_ne_s;
+ }
+ | COND_LT
+ {
+ $$ = comp_lt_s;
}
| COND_GT
{
- $$ = comp_gt;
+ $$ = comp_gt_s;
}
- | COND_LE
+ | COND_LT COND_EQ
{
- $$ = comp_le;
+ $$ = comp_le_s;
}
- | COND_GE
+ | COND_GT COND_EQ
{
- $$ = comp_ge;
+ $$ = comp_ge_s;
}
- | COND_EQ
+ /*string only*/
+ | COND_GT COND_LT
{
- $$ = comp_eq;
+ $$ = comp_substring;
}
- | COND_NE
+ | COND_LT COND_LT
{
- $$ = comp_ne;
+ $$ = comp_start;
+ }
+ | COND_GT COND_GT
+ {
+ $$ = comp_end;
}
;
-value:
- symbol
+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 @@
}
;
-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 @@
}
;
-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:
+ COND_IDENT
+ {
+ COND_input* cond = (COND_input*) info;
+ $$ = COND_GetString(cond);
+ if( !$$ )
+ YYABORT;
+ }
+ ;
+
integer:
COND_NUMBER
{
@@ -252,35 +483,82 @@
%%
-static INT comp_lt(INT a, INT b)
-{
- return (a < 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_ge(INT a, INT b)
-{
- return (a >= b);
-}
-static INT comp_eq(INT a, INT b)
-{
- return (a == b);
-}
+/* the mess of comparison functions */
-static INT comp_ne(INT a, INT b)
-{
- return (a != b);
-}
+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)
+{ 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_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_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_IsNumber( ch ) )
+ {
+ ch = cond->str[cond->n];
+ while( COND_IsNumber( ch ) )
+ ch = cond->str[cond->n++];
+ rc = COND_NUMBER;
+ break;
+ }
+
+ ERR("Got unknown character %c(%x)\n",ch,ch);
+ rc = COND_ERROR;
+ 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++];
- return COND_NUMBER;
- }
-
- return COND_ERROR;
+
+ return rc;
}
static LPWSTR COND_GetString( COND_input *cond )
@@ -348,7 +673,11 @@
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 @@
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;
}
Index: dlls/msi/handle.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/handle.c,v
retrieving revision 1.4
diff -u -r1.4 handle.c
--- dlls/msi/handle.c 19 Mar 2004 19:14:12 -0000 1.4
+++ dlls/msi/handle.c 26 Jun 2004 14:41:29 -0000
@@ -54,6 +54,7 @@
info->magic = MSIHANDLE_MAGIC;
info->type = type;
+ info->refcount = 1;
info->destructor = destroy;
msihandletable[i] = info;
@@ -79,6 +80,26 @@
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);
@@ -95,6 +116,10 @@
ERR("Invalid handle!\n");
return ERROR_INVALID_HANDLE;
}
+
+ info->refcount--;
+ if (info->refcount > 0)
+ return ERROR_SUCCESS;
if( info->destructor )
info->destructor( &info[1] );
Index: dlls/msi/msi.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/msi.c,v
retrieving revision 1.20
diff -u -r1.20 msi.c
--- dlls/msi/msi.c 17 May 2004 21:08:31 -0000 1.20
+++ dlls/msi/msi.c 26 Jun 2004 14:41:30 -0000
@@ -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 @@
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 @@
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 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 @@
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 @@
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 @@
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);*/
@@ -1219,4 +1194,149 @@
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;
}
Index: dlls/msi/msi.spec
===================================================================
RCS file: /home/wine/wine/dlls/msi/msi.spec,v
retrieving revision 1.13
diff -u -r1.13 msi.spec
--- dlls/msi/msi.spec 28 Apr 2004 00:29:25 -0000 1.13
+++ dlls/msi/msi.spec 26 Jun 2004 14:41:30 -0000
@@ -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)
Index: dlls/msi/msipriv.h
===================================================================
RCS file: /home/wine/wine/dlls/msi/msipriv.h,v
retrieving revision 1.12
diff -u -r1.12 msipriv.h
--- dlls/msi/msipriv.h 26 Jun 2004 00:18:36 -0000 1.12
+++ dlls/msi/msipriv.h 26 Jun 2004 14:41:30 -0000
@@ -132,6 +132,7 @@
{
UINT magic;
UINT type;
+ UINT refcount;
msihandledestructor destructor;
struct tagMSIHANDLEINFO *next;
struct tagMSIHANDLEINFO *prev;
@@ -164,6 +165,7 @@
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);
@@ -198,5 +200,10 @@
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__ */
Index: dlls/msi/sql.y
===================================================================
RCS file: /home/wine/wine/dlls/msi/sql.y,v
retrieving revision 1.10
diff -u -r1.10 sql.y
--- dlls/msi/sql.y 26 Jun 2004 00:18:23 -0000 1.10
+++ dlls/msi/sql.y 26 Jun 2004 14:41:30 -0000
@@ -571,7 +571,8 @@
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;
Index: dlls/msi/table.c
===================================================================
RCS file: /home/wine/wine/dlls/msi/table.c,v
retrieving revision 1.12
diff -u -r1.12 table.c
--- dlls/msi/table.c 26 Jun 2004 00:18:36 -0000 1.12
+++ dlls/msi/table.c 26 Jun 2004 14:41:30 -0000
@@ -1254,3 +1254,77 @@
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;
+}
+
--- /dev/null 1994-07-17 18:46:18.000000000 -0500
+++ dlls/msi/action.c 2004-06-26 08:36:26.000000000 -0500
@@ -0,0 +1,1562 @@
+/*
+ * 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
+ */
+
+/*
+ * pages i need
+ *
+http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/installexecutesequence_table.asp
+
+http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/standard_actions_reference.asp
+
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "winreg.h"
+#include "wine/debug.h"
+#include "msi.h"
+#include "msiquery.h"
+#include "objbase.h"
+#include "objidl.h"
+#include "msipriv.h"
+#include "winnls.h"
+#include "winuser.h"
+#include "shlobj.h"
+#include "wine/unicode.h"
+
+#define CUSTOM_ACTION_TYPE_MASK 0x3F
+
+/*
+ * These are hacks to get around the inability to write
+ * to the database and the inability to select on string values
+ * once those values are done then it will be possible to do
+ * all this inside the database.
+ */
+
+#define MAX_PROP 1024
+
+typedef struct {
+ WCHAR *prop_name;
+ WCHAR *prop_value;
+ } internal_property;
+
+static internal_property PropTableHack[MAX_PROP];
+static INT PropCount = 0;
+
+WINE_DEFAULT_DEBUG_CHANNEL(msi);
+
+/*
+ * Prototypes
+ */
+UINT ACTION_PerformAction(MSIHANDLE hPackage, const WCHAR *action);
+static UINT ACTION_CreateFolders(MSIHANDLE hPackage);
+static UINT ACTION_CostFinalize(MSIHANDLE hPackage);
+static UINT ACTION_InstallFiles(MSIHANDLE hPackage);
+static UINT ACTION_DuplicateFiles(MSIHANDLE hPackage);
+static UINT ACTION_WriteRegistryValues(MSIHANDLE hPackage);
+static UINT ACTION_CustomAction(MSIHANDLE hPackage,const WCHAR *action);
+
+static UINT set_property(MSIHANDLE hPackage, const WCHAR* prop,
+ const WCHAR* value);
+UINT get_property(MSIHANDLE hPackage, const WCHAR* prop, WCHAR* value);
+static VOID blitz_propertytable();
+static VOID set_installer_properties(MSIHANDLE hPackage,
+ const WCHAR* szPackagePath,
+ const WCHAR* szCommandLine);
+static DWORD deformat_string(MSIHANDLE hPackage, WCHAR* ptr,WCHAR** data);
+
+/*
+ * consts and values used
+ */
+static const WCHAR cszSourceDir[] = {'S','o','u','r','c','e','D','i','r',0};
+static const WCHAR cszRootDrive[] = {'R','O','O','T','D','R','I','V','E',0};
+static const WCHAR cszTargetDir[] = {'T','A','R','G','E','T','D','I','R',0};
+
+static const WCHAR cszlsb[]={'[',0};
+static const WCHAR cszrsb[]={']',0};
+static const WCHAR cszbs[]={'\\',0};
+
+
+/********************************************************
+ * helper functions to get around current HACKS and such
+ ********************************************************/
+
+static VOID blitz_propertytable()
+{
+ if (PropCount > 0)
+ {
+ int i;
+ TRACE("Clearing %i properties\n",PropCount);
+ for (i = 0; i < PropCount; i++)
+ {
+ HeapFree(GetProcessHeap(), 0, PropTableHack[i].prop_name);
+ HeapFree(GetProcessHeap(), 0, PropTableHack[i].prop_value);
+ }
+ PropCount = 0;
+ }
+}
+
+UINT get_property(MSIHANDLE hPackage, const WCHAR* prop, WCHAR* value)
+{
+ UINT rc = 1;
+ DWORD sz=0x100;
+ int index = 0;
+ WCHAR* pName = PropTableHack[0].prop_name;
+
+ TRACE("Looking for property %s\n",debugstr_w(prop));
+
+ /* prop table hacks take presidence */
+
+ while (pName && strcmpW(pName,prop) && index < PropCount)
+ {
+ index ++;
+ pName = PropTableHack[index].prop_name;
+ }
+
+ if (pName)
+ {
+ strcpyW(value,PropTableHack[index].prop_value);
+ TRACE(" found value %s\n",debugstr_w(value));
+ return 0;
+ }
+
+ rc = MsiGetPropertyW(hPackage,prop,value,&sz);
+
+ if (rc == ERROR_SUCCESS)
+ TRACE(" found value %s\n",debugstr_w(value));
+ else
+ TRACE(" value not found\n");
+
+ return rc;
+}
+
+static UINT set_property(MSIHANDLE hPackage, const WCHAR* prop,
+ const WCHAR* value)
+{
+ /* prop table hacks take precedence */
+ UINT rc;
+ int index = 0;
+ WCHAR* pName = PropTableHack[0].prop_name;
+
+ TRACE("Setting property %s to %s\n",debugstr_w(prop),debugstr_w(value));
+
+ while (pName && strcmpW(pName,prop) && index < PropCount)
+ {
+ index ++;
+ pName = PropTableHack[index].prop_name;
+ }
+
+ if (pName)
+ {
+ strcpyW(PropTableHack[index].prop_value,value);
+ return 0;
+ }
+ else
+ {
+ if (index > MAX_PROP)
+ {
+ ERR("EXCEEDING MAX PROP!!!!\n");
+ return ERROR_FUNCTION_FAILED;
+ }
+ PropTableHack[index].prop_name = HeapAlloc(GetProcessHeap(),0,1024);
+ PropTableHack[index].prop_value= HeapAlloc(GetProcessHeap(),0,1024);
+ strcpyW(PropTableHack[index].prop_name,prop);
+ strcpyW(PropTableHack[index].prop_value,value);
+ PropCount++;
+ return 0;
+ }
+
+ /* currently unreachable */
+ rc = MsiSetPropertyW(hPackage,prop,value);
+ 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(MSIHANDLE hPackage,
+ const WCHAR* szPackagePath,
+ const WCHAR* szCommandLine)
+{
+ WCHAR pth[MAX_PATH];
+ WCHAR *p;
+ WCHAR check[MAX_PATH];
+
+ static const WCHAR OriginalDatabase[] =
+{'O','r','i','g','i','n','a','l','D','a','t','a','b','a','s','e',0};
+ static const WCHAR c_col[] =
+{'C',':','\\',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 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};
+
+
+/* Not yet set ... but needed by iTunes
+ *
+ static const WCHAR DF[] =
+{'D','e','s','k','t','o','p','F','o','l','d','e','r',0};
+ static const WCHAR FF[] =
+{'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};
+PrimaryVolumePath
+ProgramFiles64Folder
+ProgramMenuFolder
+SendToFolder
+StartMenuFolder
+StartupFolder
+System16Folder
+System64Folder
+TempFolder
+TemplateFolder
+ */
+
+/* asked for by iTunes ... but are they installer set?
+ *
+ * GlobalAssemblyCache
+ */
+
+ set_property(hPackage, OriginalDatabase, szPackagePath);
+ set_property(hPackage, cszRootDrive, c_col);
+
+ strcpyW(pth,szPackagePath);
+ p = strrchrW(pth,'\\');
+ if (p)
+ {
+ p++;
+ *p=0;
+ }
+
+ if (get_property(hPackage,cszSourceDir,check) != ERROR_SUCCESS )
+ set_property(hPackage, cszSourceDir, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES_COMMON,NULL,0,pth);
+ strcatW(pth,cszbs);
+ set_property(hPackage, CFF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_PROGRAM_FILES,NULL,0,pth);
+ strcatW(pth,cszbs);
+ set_property(hPackage, PFF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_COMMON_APPDATA,NULL,0,pth);
+ strcatW(pth,cszbs);
+ set_property(hPackage, CADF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_ADMINTOOLS,NULL,0,pth);
+ strcatW(pth,cszbs);
+ set_property(hPackage, ATF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_APPDATA,NULL,0,pth);
+ strcatW(pth,cszbs);
+ set_property(hPackage, ADF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_SYSTEM,NULL,0,pth);
+ strcatW(pth,cszbs);
+ set_property(hPackage, SF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_LOCAL_APPDATA,NULL,0,pth);
+ strcatW(pth,cszbs);
+ set_property(hPackage, LADF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_MYPICTURES,NULL,0,pth);
+ strcatW(pth,cszbs);
+ set_property(hPackage, MPF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_PERSONAL,NULL,0,pth);
+ strcatW(pth,cszbs);
+ set_property(hPackage, PF, pth);
+
+ SHGetFolderPathW(NULL,CSIDL_WINDOWS,NULL,0,pth);
+ strcatW(pth,cszbs);
+ set_property(hPackage, WF, pth);
+}
+
+
+/****************************************************
+ * TOP level entry points
+ *****************************************************/
+
+UINT ACTION_DoTopLevelINSTALL(MSIHANDLE hPackage, LPCWSTR szPackagePath,
+ LPCWSTR szCommandLine)
+{
+ MSIHANDLE view;
+ UINT rc;
+ static const CHAR *ExecSeqQuery =
+"select * from InstallExecuteSequence where Sequence > 0 order by Sequence";
+
+ FIXME("****We do not do any of the UI level stuff yet***\n");
+
+ /* reset our properties */
+ /* HACK ! */
+ memset (&PropTableHack, sizeof(PropTableHack),0);
+ set_installer_properties(hPackage, szPackagePath, szCommandLine);
+
+ rc = MsiDatabaseOpenViewA(hPackage, ExecSeqQuery, &view);
+
+ if (rc == ERROR_SUCCESS)
+ {
+ rc = MsiViewExecute(view, 0);
+
+ if (rc != ERROR_SUCCESS)
+ {
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ goto end;
+ }
+
+ TRACE("Running the actions \n");
+
+ while (1)
+ {
+ WCHAR buffer[0x100];
+ DWORD sz = 0x100;
+ MSIHANDLE row = 0;
+
+ rc = MsiViewFetch(view,&row);
+ if (rc != ERROR_SUCCESS)
+ {
+ rc = ERROR_SUCCESS;
+ break;
+ }
+
+ /* check conditions */
+ if (!MsiRecordIsNull(row,2))
+ {
+ sz=0x100;
+ rc = MsiRecordGetStringW(row,2,buffer,&sz);
+ if (rc != ERROR_SUCCESS)
+ {
+ MsiCloseHandle(row);
+ break;
+ }
+
+ /* this is a hack to skip errors in the condition code */
+ if (MsiEvaluateConditionW(hPackage, buffer) ==
+ MSICONDITION_FALSE)
+ {
+ MsiCloseHandle(row);
+ continue;
+ }
+
+ }
+
+ sz=0x100;
+ rc = MsiRecordGetStringW(row,1,buffer,&sz);
+ if (rc != ERROR_SUCCESS)
+ {
+ ERR("Error is %x\n",rc);
+ MsiCloseHandle(row);
+ break;
+ }
+
+ rc = ACTION_PerformAction(hPackage,buffer);
+
+ if (rc != ERROR_SUCCESS)
+ {
+ ERR("Execution halted due to error (%i)\n",rc);
+ MsiCloseHandle(row);
+ break;
+ }
+
+ MsiCloseHandle(row);
+ }
+
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ }
+
+end:
+ blitz_propertytable();
+ return rc;
+}
+
+
+/********************************************************
+ * ACTION helper functions and functions that perform the actions
+ *******************************************************/
+
+/*
+ * Alot of actions are really important even if they don't do anything
+ * explicit.. Lots of properties are set at the beginning of the installation
+ * CostFinalize does a bunch of work to translated the directorys and such
+ *
+ * But until I get write access to the database that is hard. so I am going to
+ * hack it to see if I can get something to run.
+ */
+UINT ACTION_PerformAction(MSIHANDLE hPackage, const WCHAR *action)
+{
+ const static WCHAR szCreateFolders[] =
+ {'C','r','e','a','t','e','F','o','l','d','e','r','s',0};
+ const static WCHAR szCostFinalize[] =
+ {'C','o','s','t','F','i','n','a','l','i','z','e',0};
+ const static WCHAR szInstallFiles[] =
+ {'I','n','s','t','a','l','l','F','i','l','e','s',0};
+ const static WCHAR szDuplicateFiles[] =
+ {'D','u','p','l','i','c','a','t','e','F','i','l','e','s',0};
+ const static WCHAR szWriteRegistryValues[] =
+{'W','r','i','t','e','R','e','g','i','s','t','r','y','V','a','l','u','e','s',0};
+
+ TRACE("Performing action (%s)\n",debugstr_w(action));
+
+ if (strcmpW(action,szCreateFolders)==0)
+ return ACTION_CreateFolders(hPackage);
+ if (strcmpW(action,szCostFinalize)==0)
+ return ACTION_CostFinalize(hPackage);
+ if (strcmpW(action,szInstallFiles)==0)
+ return ACTION_InstallFiles(hPackage);
+ if (strcmpW(action,szDuplicateFiles)==0)
+ return ACTION_DuplicateFiles(hPackage);
+ if (strcmpW(action,szWriteRegistryValues)==0)
+ return ACTION_WriteRegistryValues(hPackage);
+ /*
+ .
+ .
+ .
+ */
+ if (ACTION_CustomAction(hPackage,action) != ERROR_SUCCESS)
+ ERR("UNHANDLED MSI ACTION %s\n",debugstr_w(action));
+
+ return ERROR_SUCCESS;
+}
+
+
+static UINT ACTION_CustomAction(MSIHANDLE hPackage,const WCHAR *action)
+{
+ UINT rc;
+ MSIHANDLE view;
+ MSIHANDLE row = 0;
+ WCHAR ExecSeqQuery[1024] =
+ {'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','C','u','s','t','o'
+,'m','A','c','t','i','o','n',' ','w','h','e','r','e',' ','`','A','c','t','i'
+,'o','n','`',' ','=',' ','`',0};
+ static const WCHAR end[]={'`',0};
+ UINT type;
+ DWORD sz;
+ WCHAR source[0x100];
+ WCHAR target[0x200];
+ WCHAR *deformated=NULL;
+
+ strcatW(ExecSeqQuery,action);
+ strcatW(ExecSeqQuery,end);
+ rc = MsiDatabaseOpenViewW(hPackage, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return rc;
+
+ rc = MsiViewExecute(view, 0);
+ if (rc != ERROR_SUCCESS)
+ {
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+ }
+
+ rc = MsiViewFetch(view,&row);
+ if (rc != ERROR_SUCCESS)
+ {
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+ }
+
+ TRACE("Handling custom action %s\n",debugstr_w(action));
+ type = MsiRecordGetInteger(row,2);
+
+ switch (type & CUSTOM_ACTION_TYPE_MASK)
+ {
+ case 35: /* Directory set with formatted text. */
+ case 51: /* Property set with formatted text. */
+ sz=0x100;
+ MsiRecordGetStringW(row,3,source,&sz);
+ sz=0x200;
+ MsiRecordGetStringW(row,4,target,&sz);
+ deformat_string(hPackage,target,&deformated);
+ set_property(hPackage,source,deformated);
+ HeapFree(GetProcessHeap(),0,deformated);
+ break;
+ default:
+ ERR("UNHANDLED ACTION TYPE %i\n",type & CUSTOM_ACTION_TYPE_MASK);
+ }
+
+ MsiCloseHandle(row);
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+}
+
+
+/***********************************************************************
+ * create_full_pathW
+ *
+ * Recursively create all directories in the path.
+ *
+ * shamelessly stolen from setupapi/queue.c
+ */
+static BOOL create_full_pathW(const WCHAR *path)
+{
+ BOOL ret = TRUE;
+ int len;
+ WCHAR *new_path;
+
+ new_path = HeapAlloc(GetProcessHeap(), 0, (strlenW(path) + 1) *
+sizeof(WCHAR));
+ strcpyW(new_path, path);
+
+ while((len = strlenW(new_path)) && new_path[len - 1] == '\\')
+ new_path[len - 1] = 0;
+
+ while(!CreateDirectoryW(new_path, NULL))
+ {
+ WCHAR *slash;
+ DWORD last_error = GetLastError();
+ if(last_error == ERROR_ALREADY_EXISTS)
+ break;
+
+ if(last_error != ERROR_PATH_NOT_FOUND)
+ {
+ ret = FALSE;
+ break;
+ }
+
+ if(!(slash = strrchrW(new_path, '\\')))
+ {
+ ret = FALSE;
+ break;
+ }
+
+ len = slash - new_path;
+ new_path[len] = 0;
+ if(!create_full_pathW(new_path))
+ {
+ ret = FALSE;
+ break;
+ }
+ new_path[len] = '\\';
+ }
+
+ HeapFree(GetProcessHeap(), 0, new_path);
+ return ret;
+}
+
+/*
+ * Also we cannot enable/disable components either, so for now I am just going
+ * to do all the directorys for all the components.
+ */
+static UINT ACTION_CreateFolders(MSIHANDLE hPackage)
+{
+ static const CHAR *ExecSeqQuery = "select * from CreateFolder";
+ UINT rc;
+ MSIHANDLE view;
+
+ rc = MsiDatabaseOpenViewA(hPackage, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return rc;
+
+ rc = MsiViewExecute(view, 0);
+ if (rc != ERROR_SUCCESS)
+ {
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+ }
+
+ while (1)
+ {
+ WCHAR dir[0x100];
+ WCHAR full_path[MAX_PATH];
+ DWORD sz;
+ MSIHANDLE row = 0;
+
+ rc = MsiViewFetch(view,&row);
+ if (rc != ERROR_SUCCESS)
+ {
+ rc = ERROR_SUCCESS;
+ break;
+ }
+
+ sz=0x100;
+ rc = MsiRecordGetStringW(row,1,dir,&sz);
+
+ if (rc!= ERROR_SUCCESS)
+ {
+ ERR("Unable to get folder id \n");
+ MsiCloseHandle(row);
+ continue;
+ }
+
+ rc = get_property(hPackage, dir,full_path);
+
+ if (rc != ERROR_SUCCESS)
+ {
+ ERR("Unable to resolve folder id %s\n",debugstr_w(dir));
+ MsiCloseHandle(row);
+ continue;
+ }
+
+ TRACE("Folder is %s\n",debugstr_w(full_path));
+ create_full_pathW(full_path);
+
+ MsiCloseHandle(row);
+ }
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+
+ return rc;
+}
+
+/*
+ * Workhorse function for creating the directories
+ * during Costing
+ */
+static UINT resolve_directory(MSIHANDLE hPackage, const WCHAR* dir,
+ WCHAR* path, BOOL source)
+{
+ static const WCHAR cszsrc[]={'_','S','o','u','r','c','e',0};
+ static const WCHAR cszsrcroot[]=
+ {'[','S','o','u','r','c','e','D','i','r',']',0};
+
+ WCHAR Query[1024] =
+{'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','D','i','r','e','c',
+'t','o','r','y',' ','w','h','e','r','e',' ','`','D','i','r','e','c','t',
+'o','r','y','`',' ','=',' ','`',0};
+ static const WCHAR end[]={'`',0};
+ UINT rc;
+ MSIHANDLE view;
+ WCHAR targetbuffer[0x100];
+ WCHAR *srcdir = NULL;
+ WCHAR *targetdir = NULL;
+ WCHAR buffer[0x100];
+ WCHAR parent[0x100];
+ WCHAR parent_path[MAX_PATH];
+ DWORD sz=0x100;
+ MSIHANDLE row = 0;
+ WCHAR full_path[MAX_PATH];
+ WCHAR name_source[0x100];
+
+ if (get_property(hPackage,dir,path)==ERROR_SUCCESS)
+ return ERROR_SUCCESS;
+
+ TRACE("Working to resolve %s\n",debugstr_w(dir));
+
+ /* special case... root drive */
+ if (strcmpW(dir,cszTargetDir)==0)
+ {
+ if (!source)
+ {
+ if(!get_property(hPackage,cszRootDrive,buffer))
+ {
+ set_property(hPackage,cszTargetDir,buffer);
+ strcpyW(path,buffer);
+ }
+ else
+ {
+ ERR("No RootDrive property defined disaster!\n");
+ MsiCloseHandle(row);
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return ERROR_FUNCTION_FAILED;
+ }
+ }
+ else
+ strcpyW(path,cszsrcroot);
+
+ return ERROR_SUCCESS;
+ }
+
+ strcatW(Query,dir);
+ strcatW(Query,end);
+ rc = MsiDatabaseOpenViewW(hPackage, Query, &view);
+ if (rc != ERROR_SUCCESS)
+ return rc;
+
+ rc = MsiViewExecute(view, 0);
+ if (rc != ERROR_SUCCESS)
+ {
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+ }
+
+ rc = MsiViewFetch(view,&row);
+ if (rc != ERROR_SUCCESS)
+ {
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+ }
+
+ sz=0x100;
+ MsiRecordGetStringW(row,3,targetbuffer,&sz);
+ targetdir=targetbuffer;
+
+ /* split src and target dir */
+ if (strchrW(targetdir,':'))
+ {
+ srcdir=strchrW(targetdir,':');
+ *srcdir=0;
+ srcdir ++;
+ }
+ else
+ srcdir=NULL;
+
+ /* for now only pick long filename versions */
+ if (strchrW(targetdir,'|'))
+ {
+ targetdir = strchrW(targetdir,'|');
+ *targetdir = 0;
+ targetdir ++;
+ }
+ if (srcdir && strchrW(srcdir,'|'))
+ {
+ srcdir= strchrW(srcdir,'|');
+ *srcdir= 0;
+ srcdir ++;
+ }
+
+ /* now check for root dirs */
+ if (targetdir[0] == '.' && targetdir[1] == 0)
+ targetdir = NULL;
+
+ if (srcdir && srcdir[0] == '.' && srcdir[1] == 0)
+ srcdir = NULL;
+
+ if (MsiRecordIsNull(row,2))
+ parent[0]=0;
+ else
+ {
+ sz=0x100;
+ MsiRecordGetStringW(row,2,parent,&sz);
+ }
+
+ if (parent[0])
+ {
+ resolve_directory(hPackage,parent,parent_path,FALSE);
+ strcpyW(full_path,parent_path);
+ if (targetdir)
+ {
+ strcatW(full_path,targetdir);
+ strcatW(full_path,cszbs);
+ }
+ set_property(hPackage,dir,full_path);
+ if (!source)
+ strcpyW(path,full_path);
+
+ resolve_directory(hPackage,parent,parent_path,TRUE);
+ strcpyW(full_path,parent_path);
+ if (srcdir)
+ {
+ strcatW(full_path,srcdir);
+ strcatW(full_path,cszbs);
+ }
+ else if (targetdir)
+ {
+ strcatW(full_path,targetdir);
+ strcatW(full_path,cszbs);
+ }
+
+ strcpyW(name_source,dir);
+ strcatW(name_source,cszsrc);
+ set_property(hPackage,name_source,full_path);
+ if (source)
+ strcpyW(path,full_path);
+ }
+
+ MsiCloseHandle(row);
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+}
+
+/*
+ * Alot is done in this function aside from just the costing.
+ * The costing needs to be implemented at some point but for now i am going
+ * to focus on the directory building
+ *
+ * Note about directory names: I know that directory names get processed into
+ * properties. I am still very unclear where the name_source
+ * part is used but I am preserving it just as a precaution
+ */
+static UINT ACTION_CostFinalize(MSIHANDLE hPackage)
+{
+ static const CHAR *ExecSeqQuery = "select * from Directory";
+ UINT rc;
+ MSIHANDLE view;
+
+ TRACE("Building Directory properties\n");
+
+ rc = MsiDatabaseOpenViewA(hPackage, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return rc;
+
+ rc = MsiViewExecute(view, 0);
+ if (rc != ERROR_SUCCESS)
+ {
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+ }
+
+ while (1)
+ {
+ WCHAR name[0x100];
+ WCHAR path[MAX_PATH];
+ MSIHANDLE row = 0;
+ DWORD sz;
+
+ rc = MsiViewFetch(view,&row);
+
+ if (rc != ERROR_SUCCESS)
+ {
+ rc = ERROR_SUCCESS;
+ break;
+ }
+
+ sz=0x100;
+ MsiRecordGetStringW(row,1,name,&sz);
+
+ /* This helper function now does ALL the work */
+ TRACE("Dir %s ...\n",debugstr_w(name));
+ resolve_directory(hPackage,name,path,FALSE);
+ TRACE("resolves to %s\n",debugstr_w(path));
+
+ MsiCloseHandle(row);
+ }
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+
+ return ERROR_SUCCESS;
+}
+
+/*
+ * This is a helper function for handling embedded cabinet media
+ */
+static UINT writeout_cabinet_stream(MSIHANDLE hPackage, WCHAR* stream_name,
+ WCHAR* source)
+{
+ UINT rc;
+ USHORT* data;
+ UINT size;
+ DWORD write;
+ HANDLE the_file;
+
+ rc = read_raw_stream_data(hPackage,stream_name,&data,&size);
+
+ if (rc != ERROR_SUCCESS)
+ return rc;
+
+ if (get_property(hPackage, cszSourceDir, source))
+ {
+ ERR("No Source dir defined \n");
+ rc = ERROR_FUNCTION_FAILED;
+ goto end;
+ }
+
+ strcatW(source,stream_name);
+ the_file = CreateFileW(source, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (the_file == INVALID_HANDLE_VALUE)
+ {
+ rc = ERROR_FUNCTION_FAILED;
+ goto end;
+ }
+
+ WriteFile(the_file,data,size,&write,NULL);
+ CloseHandle(the_file);
+ TRACE("wrote %li bytes to %s\n",write,debugstr_w(source));
+end:
+ HeapFree(GetProcessHeap(),0,data);
+ return rc;
+}
+
+inline static char *strdupWtoA( const WCHAR *str )
+{
+ char *ret = NULL;
+ if (str)
+ {
+ DWORD len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL
+);
+ if ((ret = HeapAlloc( GetProcessHeap(), 0, len )))
+ WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
+ }
+ return ret;
+}
+
+/***********************************************************************
+ * extract_cabinet_file
+ *
+ * Extract a file from a .cab file.
+ */
+static BOOL extract_cabinet_file( const WCHAR *cabinet, const WCHAR *root)
+
+{
+ static const WCHAR extW[] = {'.','c','a','b',0};
+
+ /* from cabinet.h */
+ typedef struct {
+ long result1; /* 0x000 */
+ long unknown1[3]; /* 0x004 */
+ void* filelist; /* 0x010 */
+ long filecount; /* 0x014 */
+ long unknown2; /* 0x018 */
+ char directory[0x104]; /* 0x01c */
+ char lastfile[0x20c]; /* 0x120 */
+ } EXTRACTdest;
+ extern HRESULT Extract(EXTRACTdest*, LPCSTR);
+
+ char *cab_path, *src_path;
+ int len = strlenW( cabinet );
+ EXTRACTdest exd;
+
+ /* make sure the cabinet file has a .cab extension */
+ if (len <= 4 || strcmpiW( cabinet + len - 4, extW )) return FALSE;
+
+ if (!(cab_path = strdupWtoA( cabinet ))) return FALSE;
+ if (!(src_path = strdupWtoA( root ))) return FALSE;
+
+ memset(&exd,0,sizeof(exd));
+ strcpy(exd.directory,src_path);
+ Extract(&exd,cab_path);
+ HeapFree( GetProcessHeap(), 0, cab_path );
+ HeapFree( GetProcessHeap(), 0, src_path );
+ return TRUE;
+}
+
+static UINT ready_media_for_file(MSIHANDLE hPackage, UINT sequence,
+ WCHAR* path)
+{
+ UINT rc;
+ MSIHANDLE view;
+ MSIHANDLE row = 0;
+ WCHAR source[MAX_PATH];
+ static const CHAR *ExecSeqQuery =
+ "select * from Media where LastSequence > %i order by LastSequence";
+ CHAR Query[1024];
+ WCHAR cab[0x100];
+ DWORD sz=0x100;
+ INT seq;
+ static INT last_sequence = 0;
+
+ if (sequence <= last_sequence)
+ {
+ TRACE("Media already ready (%i, %i)\n",sequence,last_sequence);
+ return ERROR_SUCCESS;
+ }
+
+ sprintf(Query,ExecSeqQuery,sequence);
+
+ rc = MsiDatabaseOpenViewA(hPackage, Query, &view);
+ if (rc != ERROR_SUCCESS)
+ return rc;
+
+ rc = MsiViewExecute(view, 0);
+ if (rc != ERROR_SUCCESS)
+ {
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+ }
+
+ rc = MsiViewFetch(view,&row);
+ if (rc != ERROR_SUCCESS)
+ {
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+ }
+ seq = MsiRecordGetInteger(row,2);
+ last_sequence = seq;
+
+ if (!MsiRecordIsNull(row,4))
+ {
+ sz=0x100;
+ MsiRecordGetStringW(row,4,cab,&sz);
+ /* the stream does not contain the # character */
+ if (cab[0]=='#')
+ {
+ writeout_cabinet_stream(hPackage,&cab[1],source);
+ strcpyW(path,source);
+ *(strrchrW(path,'\\')+1)=0;
+ }
+ else
+ {
+ if (get_property(hPackage, cszSourceDir, source))
+ {
+ ERR("No Source dir defined \n");
+ rc = ERROR_FUNCTION_FAILED;
+ }
+ else
+ {
+ strcpyW(path,source);
+ strcatW(source,cab);
+ }
+ }
+ rc = !extract_cabinet_file(source,path);
+ }
+ MsiCloseHandle(row);
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+}
+
+static void reduce_to_longfilename(WCHAR* filename)
+{
+ if (strchrW(filename,'|'))
+ {
+ WCHAR newname[MAX_PATH];
+ strcpyW(newname,strchrW(filename,'|')+1);
+ strcpyW(filename,newname);
+ }
+}
+
+static UINT get_directory_for_component(MSIHANDLE hPackage,
+ const WCHAR* component, WCHAR* install_path)
+{
+ UINT rc;
+ MSIHANDLE view;
+ MSIHANDLE row = 0;
+ WCHAR ExecSeqQuery[1023] =
+{'s','e','l','e','c','t',' ','*',' ','f','r','o','m',' ','C','o','m'
+,'p','o','n','e','n','t',' ','w','h','e','r','e',' ','C','o','m'
+,'p','o','n','e','n','t',' ','=',' ','`',0};
+ static const WCHAR end[]={'`',0};
+ WCHAR dir[0x100];
+ DWORD sz=0x100;
+
+ strcatW(ExecSeqQuery,component);
+ strcatW(ExecSeqQuery,end);
+
+ rc = MsiDatabaseOpenViewW(hPackage, ExecSeqQuery, &view);
+
+ if (rc != ERROR_SUCCESS)
+ return rc;
+
+ rc = MsiViewExecute(view, 0);
+ if (rc != ERROR_SUCCESS)
+ {
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+ }
+
+ rc = MsiViewFetch(view,&row);
+ if (rc != ERROR_SUCCESS)
+ {
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ MsiCloseHandle(row);
+ return rc;
+ }
+
+ sz=0x100;
+ MsiRecordGetStringW(row,3,dir,&sz);
+ rc = get_property(hPackage, dir, install_path);
+
+ MsiCloseHandle(row);
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+}
+
+static UINT ACTION_InstallFiles(MSIHANDLE hPackage)
+{
+ UINT rc;
+ MSIHANDLE view;
+ MSIHANDLE row = 0;
+ static const CHAR *ExecSeqQuery =
+ "select * from File order by Sequence";
+
+ /* REALLY what we want to do is go through all the enabled
+ * features and check all the components of that feature and
+ * make sure that component is not already install and blah
+ * blah blah... I will do it that way some day.. really
+ * but for sheer gratification I am going to just brute force
+ * install all the files
+ */
+
+ rc = MsiDatabaseOpenViewA(hPackage, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return rc;
+
+ rc = MsiViewExecute(view, 0);
+ if (rc != ERROR_SUCCESS)
+ {
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+ }
+
+ while (1)
+ {
+ INT seq = 0;
+ WCHAR component[0x100];
+ WCHAR install_path[MAX_PATH];
+ WCHAR path_to_source[MAX_PATH];
+ WCHAR src_path[MAX_PATH];
+ WCHAR filename[0x100];
+ WCHAR sourcename[0x100];
+ DWORD sz=0x100;
+
+ rc = MsiViewFetch(view,&row);
+ if (rc != ERROR_SUCCESS)
+ {
+ rc = ERROR_SUCCESS;
+ break;
+ }
+
+ seq = MsiRecordGetInteger(row,8);
+ rc = ready_media_for_file(hPackage,seq,path_to_source);
+ if (rc != ERROR_SUCCESS)
+ {
+ ERR("Unable to ready media\n");
+ MsiCloseHandle(row);
+ break;
+ }
+ sz=0x100;
+ rc = MsiRecordGetStringW(row,2,component,&sz);
+ if (rc != ERROR_SUCCESS)
+ {
+ ERR("Unable to read component\n");
+ MsiCloseHandle(row);
+ break;
+ }
+ rc = get_directory_for_component(hPackage,component,install_path);
+ if (rc != ERROR_SUCCESS)
+ {
+ ERR("Unable to get directory\n");
+ MsiCloseHandle(row);
+ break;
+ }
+
+ sz=0x100;
+ rc = MsiRecordGetStringW(row,1,sourcename,&sz);
+ if (rc != ERROR_SUCCESS)
+ {
+ ERR("Unable to get sourcename\n");
+ MsiCloseHandle(row);
+ break;
+ }
+ strcpyW(src_path,path_to_source);
+ strcatW(src_path,sourcename);
+
+ sz=0x100;
+ rc = MsiRecordGetStringW(row,3,filename,&sz);
+ if (rc != ERROR_SUCCESS)
+ {
+ ERR("Unable to get filename\n");
+ MsiCloseHandle(row);
+ break;
+ }
+ reduce_to_longfilename(filename);
+ strcatW(install_path,filename);
+
+ TRACE("Installing file %s to %s\n",debugstr_w(src_path),
+ debugstr_w(install_path));
+
+ rc = !MoveFileW(src_path,install_path);
+ if (rc)
+ {
+ ERR("Unable to move file\n");
+ }
+
+ /* for future use lets keep track of this file and where it went */
+ set_property(hPackage,sourcename,install_path);
+
+ MsiCloseHandle(row);
+ }
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+
+ return rc;
+}
+
+static UINT ACTION_DuplicateFiles(MSIHANDLE hPackage)
+{
+ UINT rc;
+ MSIHANDLE view;
+ MSIHANDLE row = 0;
+ static const CHAR *ExecSeqQuery = "select * from DuplicateFile";
+
+
+ /*
+ * Yes we should only do this for componenets that are installed
+ * but again I need to do that went I track components.
+ */
+
+ rc = MsiDatabaseOpenViewA(hPackage, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return rc;
+
+ rc = MsiViewExecute(view, 0);
+ if (rc != ERROR_SUCCESS)
+ {
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+ }
+
+ while (1)
+ {
+ WCHAR file_key[0x100];
+ WCHAR file_source[MAX_PATH];
+ WCHAR dest_name[0x100];
+ WCHAR dest_path[MAX_PATH];
+
+ DWORD sz=0x100;
+
+ rc = MsiViewFetch(view,&row);
+ if (rc != ERROR_SUCCESS)
+ {
+ rc = ERROR_SUCCESS;
+ break;
+ }
+
+ sz=0x100;
+ rc = MsiRecordGetStringW(row,3,file_key,&sz);
+ if (rc != ERROR_SUCCESS)
+ {
+ ERR("Unable to get file key\n");
+ MsiCloseHandle(row);
+ break;
+ }
+
+ rc = get_property(hPackage,file_key,file_source);
+ if (rc != ERROR_SUCCESS)
+ {
+ ERR("Original file unknown %s\n",debugstr_w(file_key));
+ MsiCloseHandle(row);
+ break;
+ }
+
+ if (MsiRecordIsNull(row,4))
+ strcpyW(dest_name,strrchrW(file_source,'\\')+1);
+ else
+ {
+ sz=0x100;
+ MsiRecordGetStringW(row,4,dest_name,&sz);
+ reduce_to_longfilename(dest_name);
+ }
+
+ if (MsiRecordIsNull(row,5))
+ {
+ strcpyW(dest_path,file_source);
+ *strrchrW(dest_path,'\\')=0;
+ }
+ else
+ {
+ WCHAR destkey[0x100];
+ sz=0x100;
+ MsiRecordGetStringW(row,5,destkey,&sz);
+ rc = get_property(hPackage, destkey, dest_path);
+ if (rc != ERROR_SUCCESS)
+ {
+ ERR("Unable to get destination folder\n");
+ MsiCloseHandle(row);
+ break;
+ }
+ }
+
+ strcatW(dest_path,dest_name);
+
+ TRACE("Duplicating file %s to %s\n",debugstr_w(file_source),
+ debugstr_w(dest_path));
+
+ if (strcmpW(file_source,dest_path))
+ rc = !CopyFileW(file_source,dest_path,TRUE);
+ else
+ rc = ERROR_SUCCESS;
+
+ if (rc != ERROR_SUCCESS)
+ ERR("Failed to copy file\n");
+
+ MsiCloseHandle(row);
+ }
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+
+}
+
+
+static LPSTR parse_value(MSIHANDLE hPackage, WCHAR *value, DWORD *type,
+ DWORD *size)
+{
+ LPSTR data = NULL;
+ if (value[0]=='#' && value[1]!='#')
+ {
+ ERR("UNHANDLED VALUE TYPE\n");
+ }
+ else
+ {
+ WCHAR *ptr;
+ if (value[0]=='#')
+ ptr = &value[1];
+ else
+ ptr=value;
+
+ *type=REG_SZ;
+ *size = deformat_string(hPackage, ptr,(LPWSTR*)&data);
+ }
+ return data;
+}
+
+static UINT ACTION_WriteRegistryValues(MSIHANDLE hPackage)
+{
+ UINT rc;
+ MSIHANDLE view;
+ MSIHANDLE row = 0;
+ static const CHAR *ExecSeqQuery = "select * from Registry";
+
+ /* Again here we want to key off of the components being installed...
+ * oh well
+ */
+
+ rc = MsiDatabaseOpenViewA(hPackage, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return rc;
+
+ rc = MsiViewExecute(view, 0);
+ if (rc != ERROR_SUCCESS)
+ {
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+ }
+
+ while (1)
+ {
+ WCHAR key[0x100];
+ WCHAR name[0x100];
+ WCHAR value[0x100];
+ LPSTR value_data = NULL;
+ HKEY root_key, hkey;
+ DWORD type,size;
+
+ INT root;
+ DWORD sz=0x100;
+
+ rc = MsiViewFetch(view,&row);
+ if (rc != ERROR_SUCCESS)
+ {
+ rc = ERROR_SUCCESS;
+ break;
+ }
+
+ /* null values have special meanings during uninstalls and such */
+
+ if(MsiRecordIsNull(row,5))
+ {
+ MsiCloseHandle(row);
+ continue;
+ }
+
+ root = MsiRecordGetInteger(row,2);
+ sz = 0x100;
+ MsiRecordGetStringW(row,3,key,&sz);
+
+ sz = 0x100;
+ if (MsiRecordIsNull(row,4))
+ name[0]=0;
+ else
+ MsiRecordGetStringW(row,4,name,&sz);
+
+ sz=0x100;
+ MsiRecordGetStringW(row,5,value,&sz);
+
+
+ /* get the root key */
+ switch (root)
+ {
+ case 0: root_key = HKEY_CLASSES_ROOT; break;
+ case 1: root_key = HKEY_CURRENT_USER; break;
+ case 2: root_key = HKEY_LOCAL_MACHINE; break;
+ case 3: root_key = HKEY_USERS; break;
+ default:
+ ERR("Unknown root %i\n",root);
+ root_key=NULL;
+ break;
+ }
+ if (!root_key)
+ {
+ MsiCloseHandle(row);
+ continue;
+ }
+
+ if (RegCreateKeyW( root_key, key, &hkey))
+ {
+ ERR("Could not create key %s\n",debugstr_w(key));
+ MsiCloseHandle(row);
+ continue;
+ }
+
+ value_data = parse_value(hPackage, value, &type, &size);
+
+ if (value_data)
+ {
+ TRACE("Setting value %s\n",debugstr_w(name));
+ RegSetValueExW(hkey, name, 0, type, value_data, size);
+ HeapFree(GetProcessHeap(),0,value_data);
+ }
+
+ MsiCloseHandle(row);
+ }
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+}
+
+/*
+ * This helper function should probably go alot of places
+ */
+static DWORD deformat_string(MSIHANDLE hPackage, WCHAR* ptr,WCHAR** data)
+{
+ WCHAR* mark=NULL;
+ DWORD size=0;
+ DWORD chunk=0;
+ WCHAR key[0x100];
+ WCHAR value[0x100];
+
+ /* scan for special characters */
+ if (!strchrW(ptr,'[') || (strchrW(ptr,'[') && !strchrW(ptr,']')))
+ {
+ /* not formatted */
+ size = (strlenW(ptr)+1) * sizeof(WCHAR);
+ *data = HeapAlloc(GetProcessHeap(),0,size);
+ strcpyW(*data,ptr);
+ return size;
+ }
+
+ /* formatted string located */
+ mark = strchrW(ptr,'[');
+ if (mark != ptr)
+ {
+ INT cnt = (mark - ptr);
+ TRACE("%i (%i) characters before marker\n",cnt,(mark-ptr));
+ size = cnt * sizeof(WCHAR);
+ size += sizeof(WCHAR);
+ *data = HeapAlloc(GetProcessHeap(),0,size);
+ strncpyW(*data,ptr,cnt);
+ (*data)[cnt]=0;
+ }
+ else
+ {
+ size = sizeof(WCHAR);
+ *data = HeapAlloc(GetProcessHeap(),0,size);
+ (*data)[0]=0;
+ }
+ mark++;
+ strcpyW(key,mark);
+ *strchrW(key,']')=0;
+ mark = strchrW(mark,']');
+ mark++;
+ TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
+ if (get_property(hPackage, key, value) == ERROR_SUCCESS)
+ {
+ LPWSTR newdata;
+ chunk = (strlenW(value)+1) * sizeof(WCHAR);
+ size+=chunk;
+ newdata = HeapReAlloc(GetProcessHeap(),0,*data,size);
+ *data = newdata;
+ strcatW(*data,value);
+ }
+ TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
+ if (*mark!=0)
+ {
+ LPWSTR newdata;
+ chunk = (strlenW(mark)+1) * sizeof(WCHAR);
+ size+=chunk;
+ newdata = HeapReAlloc(GetProcessHeap(),0,*data,size);
+ *data = newdata;
+ strcatW(*data,mark);
+ }
+ (*data)[strlenW(*data)]=0;
+ TRACE("Current %s .. %s\n",debugstr_w(*data),debugstr_w(mark));
+
+ /* recursivly do this to clean up */
+ mark = HeapAlloc(GetProcessHeap(),0,size);
+ strcpyW(mark,*data);
+ TRACE("String at this point %s\n",debugstr_w(mark));
+ size = deformat_string(hPackage,mark,data);
+ HeapFree(GetProcessHeap(),0,mark);
+ return size;
+}
+
+
+
+#if 0
+static UINT ACTION_Template(MSIHANDLE hPackage)
+{
+ UINT rc;
+ MSIHANDLE view;
+ MSIHANDLE row = 0;
+ static const CHAR *ExecSeqQuery;
+
+ rc = MsiDatabaseOpenViewA(hPackage, ExecSeqQuery, &view);
+ if (rc != ERROR_SUCCESS)
+ return rc;
+
+ rc = MsiViewExecute(view, 0);
+ if (rc != ERROR_SUCCESS)
+ {
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+ }
+
+ while (1)
+ {
+ rc = MsiViewFetch(view,&row);
+ if (rc != ERROR_SUCCESS)
+ {
+ rc = ERROR_SUCCESS;
+ break;
+ }
+
+ MsiCloseHandle(row);
+ }
+ MsiViewClose(view);
+ MsiCloseHandle(view);
+ return rc;
+}
+#endif
More information about the wine-patches
mailing list