Moved midimap to the top-level dlls directory.
[wine] / dlls / msi / cond.y
1 %{
2
3 /*
4  * Implementation of the Microsoft Installer (msi.dll)
5  *
6  * Copyright 2003 Mike McCormack for CodeWeavers
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wine/debug.h"
32 #include "wine/unicode.h"
33
34 #include "msi.h"
35 #include "msiquery.h"
36 #include "msipriv.h"
37
38 #define YYLEX_PARAM info
39 #define YYPARSE_PARAM info
40
41 static int COND_error(const char *str);
42
43 WINE_DEFAULT_DEBUG_CHANNEL(msi);
44
45 typedef struct tag_yyinput
46 {
47     MSIPACKAGE *package;
48     LPCWSTR str;
49     INT    n;
50     MSICONDITION result;
51 } COND_input;
52
53 struct cond_str {
54     LPCWSTR data;
55     INT len;
56 };
57
58 static LPWSTR COND_GetString( struct cond_str *str );
59 static LPWSTR COND_GetLiteral( struct cond_str *str );
60 static int COND_lex( void *COND_lval, COND_input *info);
61
62 typedef INT (*comp_int)(INT a, INT b);
63 typedef INT (*comp_str)(LPWSTR a, LPWSTR b, BOOL caseless);
64 typedef INT (*comp_m1)(LPWSTR a,int b);
65 typedef INT (*comp_m2)(int a,LPWSTR b);
66
67 static INT comp_lt_i(INT a, INT b);
68 static INT comp_gt_i(INT a, INT b);
69 static INT comp_le_i(INT a, INT b);
70 static INT comp_ge_i(INT a, INT b);
71 static INT comp_eq_i(INT a, INT b);
72 static INT comp_ne_i(INT a, INT b);
73 static INT comp_bitand(INT a, INT b);
74 static INT comp_highcomp(INT a, INT b);
75 static INT comp_lowcomp(INT a, INT b);
76
77 static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless);
78 static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless);
79 static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless);
80 static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless);
81 static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless);
82 static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless);
83 static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless);
84 static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless);
85 static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless);
86
87 static INT comp_eq_m1(LPWSTR a, INT b);
88 static INT comp_ne_m1(LPWSTR a, INT b);
89 static INT comp_lt_m1(LPWSTR a, INT b);
90 static INT comp_gt_m1(LPWSTR a, INT b);
91 static INT comp_le_m1(LPWSTR a, INT b);
92 static INT comp_ge_m1(LPWSTR a, INT b);
93
94 static INT comp_eq_m2(INT a, LPWSTR b);
95 static INT comp_ne_m2(INT a, LPWSTR b);
96 static INT comp_lt_m2(INT a, LPWSTR b);
97 static INT comp_gt_m2(INT a, LPWSTR b);
98 static INT comp_le_m2(INT a, LPWSTR b);
99 static INT comp_ge_m2(INT a, LPWSTR b);
100
101 %}
102
103 %pure-parser
104
105 %union
106 {
107     struct cond_str str;
108     LPWSTR    string;
109     INT       value;
110     comp_int  fn_comp_int;
111     comp_str  fn_comp_str;
112     comp_m1   fn_comp_m1;
113     comp_m2   fn_comp_m2;
114 }
115
116 %token COND_SPACE COND_EOF COND_SPACE
117 %token COND_OR COND_AND COND_NOT
118 %token COND_LT COND_GT COND_EQ 
119 %token COND_LPAR COND_RPAR COND_TILDA
120 %token COND_PERCENT COND_DOLLARS COND_QUESTION COND_AMPER COND_EXCLAM
121 %token <str> COND_IDENT <str> COND_NUMBER <str> COND_LITER
122
123 %nonassoc COND_EOF COND_ERROR
124
125 %type <value> expression boolean_term boolean_factor 
126 %type <value> term value_i symbol_i integer
127 %type <string> identifier value_s symbol_s literal
128 %type <fn_comp_int> comp_op_i
129 %type <fn_comp_str> comp_op_s 
130 %type <fn_comp_m1>  comp_op_m1 
131 %type <fn_comp_m2>  comp_op_m2
132
133 %%
134
135 condition:
136     expression
137         {
138             COND_input* cond = (COND_input*) info;
139             cond->result = $1;
140         }
141     ;
142
143 expression:
144     boolean_term 
145         {
146             $$ = $1;
147         }
148   | boolean_term COND_OR expression
149         {
150             $$ = $1 || $3;
151         }
152     ;
153
154 boolean_term:
155     boolean_factor
156         {
157             $$ = $1;
158         }
159     | boolean_term COND_AND boolean_factor
160         {
161             $$ = $1 && $3;
162         }
163     ;
164
165 boolean_factor:
166     term
167         {
168             $$ = $1;
169         }
170   | COND_NOT term
171         {
172             $$ = ! $2;
173         }
174     ;
175
176
177 term:
178     value_i
179         {
180             $$ = $1;
181         }
182   | value_s
183         {
184             $$ = ($1 && $1[0]) ? MSICONDITION_TRUE : MSICONDITION_FALSE;
185         }
186   | value_i comp_op_i value_i
187         {
188             $$ = $2( $1, $3 );
189         }
190   | value_s comp_op_s value_s
191         {
192             $$ = $2( $1, $3, FALSE );
193         }
194   | value_s COND_TILDA comp_op_s value_s
195         {
196             $$ = $3( $1, $4, TRUE );
197         }
198   | value_s comp_op_m1 value_i
199         {
200             $$ = $2( $1, $3 );
201         }
202   | value_i comp_op_m2 value_s
203         {
204             $$ = $2( $1, $3 );
205         }
206   | COND_LPAR expression COND_RPAR
207         {
208             $$ = $2;
209         }
210     ;
211
212 comp_op_i:
213     /* common functions */
214    COND_EQ
215         {
216             $$ = comp_eq_i;
217         }
218   | COND_LT COND_GT
219         {
220             $$ = comp_ne_i;
221         }
222   | COND_LT
223         {
224             $$ = comp_lt_i;
225         }
226   | COND_GT
227         {
228             $$ = comp_gt_i;
229         }
230   | COND_LT COND_EQ
231         {
232             $$ = comp_le_i;
233         }
234   | COND_GT COND_EQ
235         {
236             $$ = comp_ge_i;
237         }
238   /*Int only*/
239   | COND_GT COND_LT
240         {
241             $$ = comp_bitand;
242         }
243   | COND_LT COND_LT
244         {
245             $$ = comp_highcomp;
246         }
247   | COND_GT COND_GT
248         {
249             $$ = comp_lowcomp;
250         }
251     ;
252
253 comp_op_s:
254     /* common functions */
255    COND_EQ
256         {
257             $$ = comp_eq_s;
258         }
259   | COND_LT COND_GT
260         {
261             $$ = comp_ne_s;
262         }
263   | COND_LT
264         {
265             $$ = comp_lt_s;
266         }
267   | COND_GT
268         {
269             $$ = comp_gt_s;
270         }
271   | COND_LT COND_EQ
272         {
273             $$ = comp_le_s;
274         }
275   | COND_GT COND_EQ
276         {
277             $$ = comp_ge_s;
278         }
279   /*string only*/
280   | COND_GT COND_LT
281         {
282             $$ = comp_substring;
283         }
284   | COND_LT COND_LT
285         {
286             $$ = comp_start;
287         }
288   | COND_GT COND_GT
289         {
290             $$ = comp_end;
291         }
292     ;
293
294 comp_op_m1:
295     /* common functions */
296    COND_EQ
297         {
298             $$ = comp_eq_m1;
299         }
300   | COND_LT COND_GT
301         {
302             $$ = comp_ne_m1;
303         }
304   | COND_LT
305         {
306             $$ = comp_lt_m1;
307         }
308   | COND_GT
309         {
310             $$ = comp_gt_m1;
311         }
312   | COND_LT COND_EQ
313         {
314             $$ = comp_le_m1;
315         }
316   | COND_GT COND_EQ
317         {
318             $$ = comp_ge_m1;
319         }
320   /*Not valid for mixed compares*/
321   | COND_GT COND_LT
322         {
323             $$ = 0;
324         }
325   | COND_LT COND_LT
326         {
327             $$ = 0;
328         }
329   | COND_GT COND_GT
330         {
331             $$ = 0;
332         }
333     ;
334
335 comp_op_m2:
336     /* common functions */
337    COND_EQ
338         {
339             $$ = comp_eq_m2;
340         }
341   | COND_LT COND_GT
342         {
343             $$ = comp_ne_m2;
344         }
345   | COND_LT
346         {
347             $$ = comp_lt_m2;
348         }
349   | COND_GT
350         {
351             $$ = comp_gt_m2;
352         }
353   | COND_LT COND_EQ
354         {
355             $$ = comp_le_m2;
356         }
357   | COND_GT COND_EQ
358         {
359             $$ = comp_ge_m2;
360         }
361   /*Not valid for mixed compares*/
362   | COND_GT COND_LT
363         {
364             $$ = 0;
365         }
366   | COND_LT COND_LT
367         {
368             $$ = 0;
369         }
370   | COND_GT COND_GT
371         {
372             $$ = 0;
373         }
374     ;
375
376 value_i:
377     symbol_i
378         {
379             $$ = $1;
380         }
381   | integer
382         {
383             $$ = $1;
384         }
385     ;
386
387 value_s:
388   symbol_s
389     {
390         $$ = $1;
391     } 
392   | literal
393     {
394         $$ = $1;
395     }
396     ;
397
398 literal:
399     COND_LITER
400         {
401             $$ = COND_GetLiteral(&$1);
402             if( !$$ )
403                 YYABORT;
404         }
405     ;
406
407 symbol_i:
408     COND_DOLLARS identifier
409         {
410             COND_input* cond = (COND_input*) info;
411             INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
412       
413             MSI_GetComponentStateW(cond->package, $2, &install, &action );
414             $$ = action;
415             HeapFree( GetProcessHeap(), 0, $2 );
416         }
417   | COND_QUESTION identifier
418         {
419             COND_input* cond = (COND_input*) info;
420             INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
421       
422             MSI_GetComponentStateW(cond->package, $2, &install, &action );
423             $$ = install;
424             HeapFree( GetProcessHeap(), 0, $2 );
425         }
426   | COND_AMPER identifier
427         {
428             COND_input* cond = (COND_input*) info;
429             INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
430       
431             MSI_GetFeatureStateW(cond->package, $2, &install, &action );
432             $$ = action;
433             HeapFree( GetProcessHeap(), 0, $2 );
434         }
435   | COND_EXCLAM identifier
436         {
437             COND_input* cond = (COND_input*) info;
438             INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
439       
440             MSI_GetFeatureStateW(cond->package, $2, &install, &action );
441             $$ = install;
442             HeapFree( GetProcessHeap(), 0, $2 );
443         }
444     ;
445
446 symbol_s:
447     identifier
448         {
449             DWORD sz;
450             COND_input* cond = (COND_input*) info;
451
452             sz = 0;
453             MSI_GetPropertyW(cond->package, $1, NULL, &sz);
454             if (sz == 0)
455             {
456                 $$ = HeapAlloc( GetProcessHeap(), 0 ,sizeof(WCHAR));
457                 $$[0] = 0;
458             }
459             else
460             {
461                 sz ++;
462                 $$ = HeapAlloc( GetProcessHeap(), 0, sz*sizeof (WCHAR) );
463
464                 /* Lookup the identifier */
465
466                 MSI_GetPropertyW(cond->package,$1,$$,&sz);
467             }
468             HeapFree( GetProcessHeap(), 0, $1 );
469         }
470     | COND_PERCENT identifier
471         {
472             UINT len = GetEnvironmentVariableW( $2, NULL, 0 );
473             if( len++ )
474             {
475                 $$ = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
476                 if( $$ )
477                     GetEnvironmentVariableW( $2, $$, len );
478             }
479             HeapFree( GetProcessHeap(), 0, $2 );
480         }
481     ;
482
483 identifier:
484     COND_IDENT
485         {
486             $$ = COND_GetString(&$1);
487             if( !$$ )
488                 YYABORT;
489         }
490     ;
491
492 integer:
493     COND_NUMBER
494         {
495             LPWSTR szNum = COND_GetString(&$1);
496             if( !szNum )
497                 YYABORT;
498             $$ = atoiW( szNum );
499             HeapFree( GetProcessHeap(), 0, szNum );
500         }
501     ;
502
503 %%
504
505
506 static int COND_IsAlpha( WCHAR x )
507 {
508     return( ( ( x >= 'A' ) && ( x <= 'Z' ) ) ||
509             ( ( x >= 'a' ) && ( x <= 'z' ) ) ||
510             ( ( x == '_' ) ) );
511 }
512
513 static int COND_IsNumber( WCHAR x )
514 {
515     return( (( x >= '0' ) && ( x <= '9' ))  || (x =='-') || (x =='.') );
516 }
517
518
519 /* the mess of comparison functions */
520
521 static INT comp_lt_i(INT a, INT b)
522 { return (a < b); }
523 static INT comp_gt_i(INT a, INT b)
524 { return (a > b); }
525 static INT comp_le_i(INT a, INT b)
526 { return (a <= b); }
527 static INT comp_ge_i(INT a, INT b)
528 { return (a >= b); }
529 static INT comp_eq_i(INT a, INT b)
530 { return (a == b); }
531 static INT comp_ne_i(INT a, INT b)
532 { return (a != b); }
533 static INT comp_bitand(INT a, INT b)
534 { return a & b;}
535 static INT comp_highcomp(INT a, INT b)
536 { return HIWORD(a)==b; }
537 static INT comp_lowcomp(INT a, INT b)
538 { return LOWORD(a)==b; }
539
540 static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless)
541 { if (casless) return !strcmpiW(a,b); else return !strcmpW(a,b);}
542 static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless)
543 { if (casless) return strcmpiW(a,b); else  return strcmpW(a,b);}
544 static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless)
545 { if (casless) return strcmpiW(a,b)<0; else return strcmpW(a,b)<0;}
546 static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless)
547 { if (casless) return strcmpiW(a,b)>0; else return strcmpW(a,b)>0;}
548 static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless)
549 { if (casless) return strcmpiW(a,b)<=0; else return strcmpW(a,b)<=0;}
550 static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless)
551 { if (casless) return strcmpiW(a,b)>=0; else return  strcmpW(a,b)>=0;}
552 static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless)
553 /* ERROR NOT WORKING REWRITE */
554 { if (casless) return strstrW(a,b)!=NULL; else return strstrW(a,b)!=NULL;}
555 static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless)
556 { if (casless) return strncmpiW(a,b,strlenW(b))==0; 
557   else return strncmpW(a,b,strlenW(b))==0;}
558 static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless)
559
560     int i = strlenW(a); 
561     int j = strlenW(b); 
562     if (j>i)
563         return 0;
564     if (casless) return (!strcmpiW(&a[i-j-1],b));
565     else  return (!strcmpW(&a[i-j-1],b));
566 }
567
568
569 static INT comp_eq_m1(LPWSTR a, INT b)
570 { if (COND_IsNumber(a[0])) return atoiW(a)==b; else return 0;}
571 static INT comp_ne_m1(LPWSTR a, INT b)
572 { if (COND_IsNumber(a[0])) return atoiW(a)!=b; else return 1;}
573 static INT comp_lt_m1(LPWSTR a, INT b)
574 { if (COND_IsNumber(a[0])) return atoiW(a)<b; else return 0;}
575 static INT comp_gt_m1(LPWSTR a, INT b)
576 { if (COND_IsNumber(a[0])) return atoiW(a)>b; else return 0;}
577 static INT comp_le_m1(LPWSTR a, INT b)
578 { if (COND_IsNumber(a[0])) return atoiW(a)<=b; else return 0;}
579 static INT comp_ge_m1(LPWSTR a, INT b)
580 { if (COND_IsNumber(a[0])) return atoiW(a)>=b; else return 0;}
581
582 static INT comp_eq_m2(INT a, LPWSTR b)
583 { if (COND_IsNumber(b[0])) return a == atoiW(b); else return 0;}
584 static INT comp_ne_m2(INT a, LPWSTR b)
585 { if (COND_IsNumber(b[0])) return a != atoiW(b); else return 1;}
586 static INT comp_lt_m2(INT a, LPWSTR b)
587 { if (COND_IsNumber(b[0])) return a < atoiW(b); else return 0;}
588 static INT comp_gt_m2(INT a, LPWSTR b)
589 { if (COND_IsNumber(b[0])) return a > atoiW(b); else return 0;}
590 static INT comp_le_m2(INT a, LPWSTR b)
591 { if (COND_IsNumber(b[0])) return a <= atoiW(b); else return 0;}
592 static INT comp_ge_m2(INT a, LPWSTR b)
593 { if (COND_IsNumber(b[0])) return a >= atoiW(b); else return 0;}
594
595
596
597 static int COND_IsIdent( WCHAR x )
598 {
599     return( COND_IsAlpha( x ) || COND_IsNumber( x ) || ( x == '_' ) 
600             || ( x == '#' ) || (x == '.') );
601 }
602
603 static int COND_GetOne( struct cond_str *str, COND_input *cond )
604 {
605     static const WCHAR szNot[] = {'N','O','T',0};
606     static const WCHAR szAnd[] = {'A','N','D',0};
607     static const WCHAR szOr[] = {'O','R',0};
608     WCHAR ch;
609     int rc, len = 1;
610
611     str->data = &cond->str[cond->n];
612
613     ch = str->data[0];
614     switch( ch )
615     {
616     case 0: return 0;
617     case '(': rc = COND_LPAR; break;
618     case ')': rc = COND_RPAR; break;
619     case '&': rc = COND_AMPER; break;
620     case '!': rc = COND_EXCLAM; break;
621     case '$': rc = COND_DOLLARS; break;
622     case '?': rc = COND_QUESTION; break;
623     case '%': rc = COND_PERCENT; break;
624     case ' ': rc = COND_SPACE; break;
625     case '=': rc = COND_EQ; break;
626     case '~': rc = COND_TILDA; break;
627     case '<': rc = COND_LT; break;
628     case '>': rc = COND_GT; break;
629     case '"':
630         {
631             const WCHAR *ch2 = str->data + 1;
632
633
634             while ( *ch2 && *ch2 != '"' )
635                 ++ch2;
636             if (*ch2 == '"')
637             {
638                 len = ch2 - str->data + 1;
639                 rc = COND_LITER;
640                 break;
641             }
642         }
643         ERR("Unterminated string\n");
644         rc = COND_ERROR;
645         break;
646     default: 
647         if( COND_IsAlpha( ch ) )
648         {
649             while( COND_IsIdent( str->data[len] ) )
650                 len++;
651             rc = COND_IDENT;
652             break;
653         }
654
655         if( COND_IsNumber( ch ) )
656         {
657             while( COND_IsNumber( str->data[len] ) )
658                 len++;
659             rc = COND_NUMBER;
660             break;
661         }
662
663         ERR("Got unknown character %c(%x)\n",ch,ch);
664         rc = COND_ERROR;
665         break;
666     }
667
668     /* keyword identifiers */
669     if( rc == COND_IDENT )
670     {
671         if( (len==3) && (strncmpiW(str->data,szNot,len)==0) )
672             rc = COND_NOT;
673         else if( (len==3) && (strncmpiW(str->data,szAnd,len)==0) )
674             rc = COND_AND;
675         else if( (len==2) && (strncmpiW(str->data,szOr,len)==0) )
676             rc = COND_OR;
677     }
678
679     cond->n += len;
680     str->len = len;
681
682     return rc;
683 }
684
685 static int COND_lex( void *COND_lval, COND_input *cond )
686 {
687     int rc;
688     struct cond_str *str = COND_lval;
689
690     do {
691         rc = COND_GetOne( str, cond );
692     } while (rc == COND_SPACE);
693     
694     return rc;
695 }
696
697 static LPWSTR COND_GetString( struct cond_str *str )
698 {
699     LPWSTR ret;
700
701     ret = HeapAlloc( GetProcessHeap(), 0, (str->len+1) * sizeof (WCHAR) );
702     if( ret )
703     {
704         memcpy( ret, str->data, str->len * sizeof(WCHAR));
705         ret[str->len]=0;
706     }
707     TRACE("Got identifier %s\n",debugstr_w(ret));
708     return ret;
709 }
710
711 static LPWSTR COND_GetLiteral( struct cond_str *str )
712 {
713     LPWSTR ret;
714
715     ret = HeapAlloc( GetProcessHeap(), 0, (str->len-1) * sizeof (WCHAR) );
716     if( ret )
717     {
718         memcpy( ret, str->data+1, (str->len-2) * sizeof(WCHAR) );
719         ret[str->len - 2]=0;
720     }
721     TRACE("Got literal %s\n",debugstr_w(ret));
722     return ret;
723 }
724
725 static int COND_error(const char *str)
726 {
727     return 0;
728 }
729
730 MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition )
731 {
732     COND_input cond;
733     MSICONDITION r;
734
735     cond.package = package;
736     cond.str   = szCondition;
737     cond.n     = 0;
738     cond.result = -1;
739     
740     TRACE("Evaluating %s\n",debugstr_w(szCondition));    
741
742     if ( szCondition == NULL || szCondition[0] == 0)
743         r = MSICONDITION_NONE;
744     else if ( !COND_parse( &cond ) )
745         r = cond.result;
746     else
747         r = MSICONDITION_ERROR;
748
749     TRACE("Evaluates to %i\n",r);
750     return r;
751 }
752
753 MSICONDITION WINAPI MsiEvaluateConditionW( MSIHANDLE hInstall, LPCWSTR szCondition )
754 {
755     MSIPACKAGE *package;
756     UINT ret;
757
758     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
759     if( !package)
760         return ERROR_INVALID_HANDLE;
761     ret = MSI_EvaluateConditionW( package, szCondition );
762     msiobj_release( &package->hdr );
763     return ret;
764 }
765
766 MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szCondition )
767 {
768     LPWSTR szwCond = NULL;
769     MSICONDITION r;
770
771     if( szCondition )
772     {
773         UINT len = MultiByteToWideChar( CP_ACP, 0, szCondition, -1, NULL, 0 );
774         szwCond = HeapAlloc( GetProcessHeap(), 0, len * sizeof (WCHAR) );
775         MultiByteToWideChar( CP_ACP, 0, szCondition, -1, szwCond, len );
776     }
777
778     r = MsiEvaluateConditionW( hInstall, szwCond );
779
780     HeapFree( GetProcessHeap(), 0, szwCond );
781
782     return r;
783 }