ddraw: Avoid LPD3DTRIANGLE.
[wine] / dlls / wbemprox / query.c
1 /*
2  * Copyright 2012 Hans Leidekker for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #define COBJMACROS
20
21 #include "config.h"
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wbemcli.h"
27
28 #include "wine/debug.h"
29 #include "wbemprox_private.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(wbemprox);
32
33 HRESULT create_view( const struct property *proplist, const WCHAR *class,
34                      const struct expr *cond, struct view **ret )
35 {
36     struct view *view = heap_alloc( sizeof(struct view) );
37
38     if (!view) return E_OUTOFMEMORY;
39     view->proplist = proplist;
40     view->table    = grab_table( class );
41     view->cond     = cond;
42     view->result   = NULL;
43     view->count    = 0;
44     *ret = view;
45     return S_OK;
46 }
47
48 void destroy_view( struct view *view )
49 {
50     if (view->table) release_table( view->table );
51     heap_free( view->result );
52     heap_free( view );
53 }
54
55 static BOOL eval_like( const WCHAR *lstr, const WCHAR *rstr )
56 {
57     const WCHAR *p = lstr, *q = rstr;
58
59     while (*p && *q)
60     {
61         if (*q == '%')
62         {
63             while (*q == '%') q++;
64             if (!*q) return TRUE;
65             while (*p && toupperW( p[1] ) != toupperW( q[1] )) p++;
66             if (!*p) return TRUE;
67         }
68         if (toupperW( *p++ ) != toupperW( *q++ )) return FALSE;
69     }
70     return TRUE;
71 }
72
73 static HRESULT eval_strcmp( UINT op, const WCHAR *lstr, const WCHAR *rstr, LONGLONG *val )
74 {
75     if (!lstr || !rstr)
76     {
77         *val = 0;
78         return S_OK;
79     }
80     switch (op)
81     {
82     case OP_EQ:
83         *val = !strcmpW( lstr, rstr );
84         break;
85     case OP_GT:
86         *val = strcmpW( lstr, rstr ) > 0;
87         break;
88     case OP_LT:
89         *val = strcmpW( lstr, rstr ) < 0;
90         break;
91     case OP_LE:
92         *val = strcmpW( lstr, rstr ) <= 0;
93         break;
94     case OP_GE:
95         *val = strcmpW( lstr, rstr ) >= 0;
96         break;
97     case OP_NE:
98         *val = strcmpW( lstr, rstr );
99         break;
100     case OP_LIKE:
101         *val = eval_like( lstr, rstr );
102         break;
103     default:
104         ERR("unhandled operator %u\n", op);
105         return WBEM_E_INVALID_QUERY;
106     }
107     return S_OK;
108 }
109
110 static inline BOOL is_strcmp( const struct complex_expr *expr )
111 {
112     return ((expr->left->type == EXPR_PROPVAL && expr->right->type == EXPR_SVAL) ||
113             (expr->left->type == EXPR_SVAL && expr->right->type == EXPR_PROPVAL));
114 }
115
116 static HRESULT eval_cond( const struct table *, UINT, const struct expr *, LONGLONG * );
117
118 static HRESULT eval_binary( const struct table *table, UINT row, const struct complex_expr *expr,
119                             LONGLONG *val )
120 {
121     HRESULT lret, rret;
122     LONGLONG lval, rval;
123
124     lret = eval_cond( table, row, expr->left, &lval );
125     rret = eval_cond( table, row, expr->right, &rval );
126     if (lret != S_OK || rret != S_OK) return WBEM_E_INVALID_QUERY;
127
128     if (is_strcmp( expr ))
129     {
130         const WCHAR *lstr = (const WCHAR *)(INT_PTR)lval;
131         const WCHAR *rstr = (const WCHAR *)(INT_PTR)rval;
132
133         return eval_strcmp( expr->op, lstr, rstr, val );
134     }
135     switch (expr->op)
136     {
137     case OP_EQ:
138         *val = (lval == rval);
139         break;
140     case OP_AND:
141         *val = (lval && rval);
142         break;
143     case OP_OR:
144         *val = (lval || rval);
145         break;
146     case OP_GT:
147         *val = (lval > rval);
148         break;
149     case OP_LT:
150         *val = (lval < rval);
151         break;
152     case OP_LE:
153         *val = (lval <= rval);
154         break;
155     case OP_GE:
156         *val = (lval >= rval);
157         break;
158     case OP_NE:
159         *val = (lval != rval);
160         break;
161     default:
162         ERR("unhandled operator %u\n", expr->op);
163         return WBEM_E_INVALID_QUERY;
164     }
165     return S_OK;
166 }
167
168 static HRESULT eval_unary( const struct table *table, UINT row, const struct complex_expr *expr,
169                            LONGLONG *val )
170
171 {
172     HRESULT hr;
173     UINT column;
174     LONGLONG lval;
175
176     hr = get_column_index( table, expr->left->u.propval->name, &column );
177     if (hr != S_OK)
178         return hr;
179
180     hr = get_value( table, row, column, &lval );
181     if (hr != S_OK)
182         return hr;
183
184     switch (expr->op)
185     {
186     case OP_ISNULL:
187         *val = !lval;
188         break;
189     case OP_NOTNULL:
190         *val = lval;
191         break;
192     default:
193         ERR("unknown operator %u\n", expr->op);
194         return WBEM_E_INVALID_QUERY;
195     }
196     return S_OK;
197 }
198
199 static HRESULT eval_propval( const struct table *table, UINT row, const struct property *propval,
200                              LONGLONG *val )
201
202 {
203     HRESULT hr;
204     UINT column;
205
206     hr = get_column_index( table, propval->name, &column );
207     if (hr != S_OK)
208         return hr;
209
210     return get_value( table, row, column, val );
211 }
212
213 static HRESULT eval_cond( const struct table *table, UINT row, const struct expr *cond,
214                           LONGLONG *val )
215 {
216     if (!cond)
217     {
218         *val = 1;
219         return S_OK;
220     }
221     switch (cond->type)
222     {
223     case EXPR_COMPLEX:
224         return eval_binary( table, row, &cond->u.expr, val );
225     case EXPR_UNARY:
226         return eval_unary( table, row, &cond->u.expr, val );
227     case EXPR_PROPVAL:
228         return eval_propval( table, row, cond->u.propval, val );
229     case EXPR_SVAL:
230         *val = (INT_PTR)cond->u.sval;
231         return S_OK;
232     case EXPR_IVAL:
233     case EXPR_BVAL:
234         *val = cond->u.ival;
235         return S_OK;
236     default:
237         ERR("invalid expression type\n");
238         break;
239     }
240     return WBEM_E_INVALID_QUERY;
241 }
242
243 static HRESULT execute_view( struct view *view )
244 {
245     UINT i, j = 0, len;
246
247     if (!view->table || !view->table->num_rows) return S_OK;
248
249     len = min( view->table->num_rows, 16 );
250     if (!(view->result = heap_alloc( len * sizeof(UINT) ))) return E_OUTOFMEMORY;
251
252     for (i = 0; i < view->table->num_rows; i++)
253     {
254         HRESULT hr;
255         LONGLONG val = 0;
256
257         if (j >= len)
258         {
259             UINT *tmp;
260             len *= 2;
261             if (!(tmp = heap_realloc( view->result, len * sizeof(UINT) ))) return E_OUTOFMEMORY;
262             view->result = tmp;
263         }
264         if ((hr = eval_cond( view->table, i, view->cond, &val )) != S_OK) return hr;
265         if (val) view->result[j++] = i;
266     }
267     view->count = j;
268     return S_OK;
269 }
270
271 static struct query *create_query(void)
272 {
273     struct query *query;
274
275     if (!(query = heap_alloc( sizeof(*query) ))) return NULL;
276     list_init( &query->mem );
277     query->refs = 1;
278     return query;
279 }
280
281 static void free_query( struct query *query )
282 {
283     struct list *mem, *next;
284
285     destroy_view( query->view );
286     LIST_FOR_EACH_SAFE( mem, next, &query->mem )
287     {
288         heap_free( mem );
289     }
290     heap_free( query );
291 }
292
293 struct query *addref_query( struct query *query )
294 {
295     InterlockedIncrement( &query->refs );
296     return query;
297 }
298
299 void release_query( struct query *query )
300 {
301     if (!InterlockedDecrement( &query->refs )) free_query( query );
302 }
303
304 HRESULT exec_query( const WCHAR *str, IEnumWbemClassObject **result )
305 {
306     HRESULT hr;
307     struct query *query;
308
309     *result = NULL;
310     if (!(query = create_query())) return E_OUTOFMEMORY;
311     hr = parse_query( str, &query->view, &query->mem );
312     if (hr != S_OK) goto done;
313     hr = execute_view( query->view );
314     if (hr != S_OK) goto done;
315     hr = EnumWbemClassObject_create( NULL, query, (void **)result );
316
317 done:
318     release_query( query );
319     return hr;
320 }
321
322 static BOOL is_selected_prop( const struct view *view, const WCHAR *name )
323 {
324     const struct property *prop = view->proplist;
325
326     if (!prop) return TRUE;
327     while (prop)
328     {
329         if (!strcmpiW( prop->name, name )) return TRUE;
330         prop = prop->next;
331     }
332     return FALSE;
333 }
334
335 static BOOL is_system_prop( const WCHAR *name )
336 {
337     return (name[0] == '_' && name[1] == '_');
338 }
339
340 static BSTR build_servername( const struct view *view )
341 {
342     WCHAR server[MAX_COMPUTERNAME_LENGTH + 1], *p;
343     DWORD len = sizeof(server)/sizeof(server[0]);
344
345     if (view->proplist) return NULL;
346
347     if (!(GetComputerNameW( server, &len ))) return NULL;
348     for (p = server; *p; p++) *p = toupperW( *p );
349     return SysAllocString( server );
350 }
351
352 static BSTR build_classname( const struct view *view )
353 {
354     return SysAllocString( view->table->name );
355 }
356
357 static BSTR build_namespace( const struct view *view )
358 {
359     static const WCHAR cimv2W[] = {'R','O','O','T','\\','C','I','M','V','2',0};
360
361     if (view->proplist) return NULL;
362     return SysAllocString( cimv2W );
363 }
364
365 static BSTR build_proplist( const struct view *view, UINT index, UINT count, UINT *len )
366 {
367     static const WCHAR fmtW[] = {'%','s','=','%','s',0};
368     UINT i, j, offset, row = view->result[index];
369     BSTR *values, ret = NULL;
370
371     if (!(values = heap_alloc( count * sizeof(BSTR) ))) return NULL;
372
373     *len = j = 0;
374     for (i = 0; i < view->table->num_cols; i++)
375     {
376         if (view->table->columns[i].type & COL_FLAG_KEY)
377         {
378             const WCHAR *name = view->table->columns[i].name;
379
380             values[j] = get_value_bstr( view->table, row, i );
381             *len += strlenW( fmtW ) + strlenW( name ) + strlenW( values[j] );
382             j++;
383         }
384     }
385     if ((ret = SysAllocStringLen( NULL, *len )))
386     {
387         offset = j = 0;
388         for (i = 0; i < view->table->num_cols; i++)
389         {
390             if (view->table->columns[i].type & COL_FLAG_KEY)
391             {
392                 const WCHAR *name = view->table->columns[i].name;
393
394                 offset += sprintfW( ret + offset, fmtW, name, values[j] );
395                 if (j < count - 1) ret[offset++] = ',';
396                 j++;
397             }
398         }
399     }
400     for (i = 0; i < count; i++) SysFreeString( values[i] );
401     heap_free( values );
402     return ret;
403 }
404
405 static UINT count_key_columns( const struct view *view )
406 {
407     UINT i, num_keys = 0;
408
409     for (i = 0; i < view->table->num_cols; i++)
410     {
411         if (view->table->columns[i].type & COL_FLAG_KEY) num_keys++;
412     }
413     return num_keys;
414 }
415
416 static BSTR build_relpath( const struct view *view, UINT index, const WCHAR *name )
417 {
418     static const WCHAR fmtW[] = {'%','s','.','%','s',0};
419     BSTR class, proplist, ret = NULL;
420     UINT num_keys, len;
421
422     if (view->proplist) return NULL;
423
424     if (!(class = build_classname( view ))) return NULL;
425     if (!(num_keys = count_key_columns( view ))) return class;
426     if (!(proplist = build_proplist( view, index, num_keys, &len ))) goto done;
427
428     len += strlenW( fmtW ) + SysStringLen( class );
429     if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
430     sprintfW( ret, fmtW, class, proplist );
431
432 done:
433     SysFreeString( class );
434     SysFreeString( proplist );
435     return ret;
436 }
437
438 static BSTR build_path( const struct view *view, UINT index, const WCHAR *name )
439 {
440     static const WCHAR fmtW[] = {'\\','\\','%','s','\\','%','s',':','%','s',0};
441     BSTR server, namespace = NULL, relpath = NULL, ret = NULL;
442     UINT len;
443
444     if (view->proplist) return NULL;
445
446     if (!(server = build_servername( view ))) return NULL;
447     if (!(namespace = build_namespace( view ))) goto done;
448     if (!(relpath = build_relpath( view, index, name ))) goto done;
449
450     len = strlenW( fmtW ) + SysStringLen( server ) + SysStringLen( namespace ) + SysStringLen( relpath );
451     if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
452     sprintfW( ret, fmtW, server, namespace, relpath );
453
454 done:
455     SysFreeString( server );
456     SysFreeString( namespace );
457     SysFreeString( relpath );
458     return ret;
459 }
460
461 static inline BOOL is_method( const struct table *table, UINT column )
462 {
463     return table->columns[column].type & COL_FLAG_METHOD;
464 }
465
466 static UINT count_properties( const struct view *view )
467 {
468     UINT i, num_props = 0;
469
470     for (i = 0; i < view->table->num_cols; i++)
471     {
472         if (!is_method( view->table, i)) num_props++;
473     }
474     return num_props;
475 }
476
477 static UINT count_selected_properties( const struct view *view )
478 {
479     const struct property *prop = view->proplist;
480     UINT count;
481
482     if (!prop) return count_properties( view );
483
484     count = 1;
485     while ((prop = prop->next)) count++;
486     return count;
487 }
488
489 static HRESULT get_system_propval( const struct view *view, UINT index, const WCHAR *name,
490                                    VARIANT *ret, CIMTYPE *type, LONG *flavor )
491 {
492     static const WCHAR classW[] = {'_','_','C','L','A','S','S',0};
493     static const WCHAR genusW[] = {'_','_','G','E','N','U','S',0};
494     static const WCHAR pathW[] = {'_','_','P','A','T','H',0};
495     static const WCHAR namespaceW[] = {'_','_','N','A','M','E','S','P','A','C','E',0};
496     static const WCHAR propcountW[] = {'_','_','P','R','O','P','E','R','T','Y','_','C','O','U','N','T',0};
497     static const WCHAR relpathW[] = {'_','_','R','E','L','P','A','T','H',0};
498     static const WCHAR serverW[] = {'_','_','S','E','R','V','E','R',0};
499
500     if (flavor) *flavor = WBEM_FLAVOR_ORIGIN_SYSTEM;
501
502     if (!strcmpiW( name, classW ))
503     {
504         V_VT( ret ) = VT_BSTR;
505         V_BSTR( ret ) = build_classname( view );
506         if (type) *type = CIM_STRING;
507         return S_OK;
508     }
509     if (!strcmpiW( name, genusW ))
510     {
511         V_VT( ret ) = VT_I4;
512         V_I4( ret ) = WBEM_GENUS_INSTANCE; /* FIXME */
513         if (type) *type = CIM_SINT32;
514         return S_OK;
515     }
516     else if (!strcmpiW( name, namespaceW ))
517     {
518         V_VT( ret ) = VT_BSTR;
519         V_BSTR( ret ) = build_namespace( view );
520         if (type) *type = CIM_STRING;
521         return S_OK;
522     }
523     else if (!strcmpiW( name, pathW ))
524     {
525         V_VT( ret ) = VT_BSTR;
526         V_BSTR( ret ) = build_path( view, index, name );
527         if (type) *type = CIM_STRING;
528         return S_OK;
529     }
530     if (!strcmpiW( name, propcountW ))
531     {
532         V_VT( ret ) = VT_I4;
533         V_I4( ret ) = count_selected_properties( view );
534         if (type) *type = CIM_SINT32;
535         return S_OK;
536     }
537     else if (!strcmpiW( name, relpathW ))
538     {
539         V_VT( ret ) = VT_BSTR;
540         V_BSTR( ret ) = build_relpath( view, index, name );
541         if (type) *type = CIM_STRING;
542         return S_OK;
543     }
544     else if (!strcmpiW( name, serverW ))
545     {
546         V_VT( ret ) = VT_BSTR;
547         V_BSTR( ret ) = build_servername( view );
548         if (type) *type = CIM_STRING;
549         return S_OK;
550     }
551     FIXME("system property %s not implemented\n", debugstr_w(name));
552     return WBEM_E_NOT_FOUND;
553 }
554
555 VARTYPE to_vartype( CIMTYPE type )
556 {
557     switch (type)
558     {
559     case CIM_BOOLEAN:  return VT_BOOL;
560     case CIM_STRING:
561     case CIM_DATETIME: return VT_BSTR;
562     case CIM_SINT16:   return VT_I2;
563     case CIM_UINT16:   return VT_UI2;
564     case CIM_SINT32:   return VT_I4;
565     case CIM_UINT32:   return VT_UI4;
566     case CIM_SINT64:   return VT_I8;
567     case CIM_UINT64:   return VT_UI8;
568     default:
569         ERR("unhandled type %u\n", type);
570         break;
571     }
572     return 0;
573 }
574
575 SAFEARRAY *to_safearray( const struct array *array, CIMTYPE type )
576 {
577     SAFEARRAY *ret;
578     UINT size = get_type_size( type );
579     VARTYPE vartype = to_vartype( type );
580     LONG i;
581
582     if (!(ret = SafeArrayCreateVector( vartype, 0, array->count ))) return NULL;
583
584     for (i = 0; i < array->count; i++)
585     {
586         void *ptr = (char *)array->ptr + i * size;
587         if (vartype == VT_BSTR)
588         {
589             BSTR str = SysAllocString( *(const WCHAR **)ptr );
590             if (!str || SafeArrayPutElement( ret, &i, str ) != S_OK)
591             {
592                 SysFreeString( str );
593                 SafeArrayDestroy( ret );
594                 return NULL;
595             }
596         }
597         else if (SafeArrayPutElement( ret, &i, ptr ) != S_OK)
598         {
599             SafeArrayDestroy( ret );
600             return NULL;
601         }
602     }
603     return ret;
604 }
605
606 void set_variant( VARTYPE type, LONGLONG val, void *val_ptr, VARIANT *ret )
607 {
608     if (type & VT_ARRAY)
609     {
610         V_VT( ret ) = type;
611         V_ARRAY( ret ) = val_ptr;
612         return;
613     }
614     switch (type)
615     {
616     case VT_BOOL:
617         V_BOOL( ret ) = val;
618         break;
619     case VT_BSTR:
620         V_BSTR( ret ) = val_ptr;
621         break;
622     case VT_I2:
623         V_I2( ret ) = val;
624         break;
625     case VT_UI2:
626         V_UI2( ret ) = val;
627         break;
628     case VT_I4:
629         V_I4( ret ) = val;
630         break;
631     case VT_UI4:
632         V_UI4( ret ) = val;
633         break;
634     case VT_NULL:
635         break;
636     default:
637         ERR("unhandled variant type %u\n", type);
638         return;
639     }
640     V_VT( ret ) = type;
641 }
642
643 HRESULT get_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *ret,
644                      CIMTYPE *type, LONG *flavor )
645 {
646     HRESULT hr;
647     UINT column, row;
648     VARTYPE vartype;
649     void *val_ptr = NULL;
650     LONGLONG val;
651
652     if (is_system_prop( name )) return get_system_propval( view, index, name, ret, type, flavor );
653     if (!view->result || !is_selected_prop( view, name )) return WBEM_E_NOT_FOUND;
654
655     hr = get_column_index( view->table, name, &column );
656     if (hr != S_OK || is_method( view->table, column )) return WBEM_E_NOT_FOUND;
657
658     row = view->result[index];
659     hr = get_value( view->table, row, column, &val );
660     if (hr != S_OK) return hr;
661
662     vartype = view->table->columns[column].vartype;
663     if (view->table->columns[column].type & CIM_FLAG_ARRAY)
664     {
665         CIMTYPE basetype = view->table->columns[column].type & CIM_TYPE_MASK;
666
667         val_ptr = to_safearray( (const struct array *)(INT_PTR)val, basetype );
668         if (!vartype) vartype = to_vartype( basetype ) | VT_ARRAY;
669         goto done;
670     }
671     switch (view->table->columns[column].type & COL_TYPE_MASK)
672     {
673     case CIM_BOOLEAN:
674         if (!vartype) vartype = VT_BOOL;
675         break;
676     case CIM_STRING:
677     case CIM_DATETIME:
678         if (val)
679         {
680             vartype = VT_BSTR;
681             val_ptr = SysAllocString( (const WCHAR *)(INT_PTR)val );
682         }
683         else
684             vartype = VT_NULL;
685         break;
686     case CIM_SINT16:
687         if (!vartype) vartype = VT_I2;
688         break;
689     case CIM_UINT16:
690         if (!vartype) vartype = VT_UI2;
691         break;
692     case CIM_SINT32:
693         if (!vartype) vartype = VT_I4;
694         break;
695     case CIM_UINT32:
696         if (!vartype) vartype = VT_UI4;
697         break;
698     case CIM_SINT64:
699         vartype = VT_BSTR;
700         val_ptr = get_value_bstr( view->table, row, column );
701         break;
702     case CIM_UINT64:
703         vartype = VT_BSTR;
704         val_ptr = get_value_bstr( view->table, row, column );
705         break;
706     default:
707         ERR("unhandled column type %u\n", view->table->columns[column].type);
708         return WBEM_E_FAILED;
709     }
710
711 done:
712     set_variant( vartype, val, val_ptr, ret );
713     if (type) *type = view->table->columns[column].type & COL_TYPE_MASK;
714     if (flavor) *flavor = 0;
715     return S_OK;
716 }
717
718 static CIMTYPE to_cimtype( VARTYPE type )
719 {
720     switch (type)
721     {
722     case VT_BOOL:  return CIM_BOOLEAN;
723     case VT_BSTR:  return CIM_STRING;
724     case VT_I2:    return CIM_SINT16;
725     case VT_UI2:   return CIM_UINT16;
726     case VT_I4:    return CIM_SINT32;
727     case VT_UI4:   return CIM_UINT32;
728     case VT_I8:    return CIM_SINT64;
729     case VT_UI8:   return CIM_UINT64;
730     default:
731         ERR("unhandled type %u\n", type);
732         break;
733     }
734     return 0;
735 }
736
737 static struct array *to_array( VARIANT *var, CIMTYPE *type )
738 {
739     struct array *ret;
740     LONG bound, i;
741     VARTYPE vartype;
742     CIMTYPE basetype;
743     UINT size;
744
745     if (SafeArrayGetVartype( V_ARRAY( var ), &vartype ) != S_OK) return NULL;
746     if (!(basetype = to_cimtype( vartype ))) return NULL;
747     if (SafeArrayGetUBound( V_ARRAY( var ), 1, &bound ) != S_OK) return NULL;
748     if (!(ret = heap_alloc( sizeof(struct array) ))) return NULL;
749
750     ret->count = bound + 1;
751     size = get_type_size( basetype );
752     if (!(ret->ptr = heap_alloc_zero( ret->count * size )))
753     {
754         heap_free( ret );
755         return NULL;
756     }
757     for (i = 0; i < ret->count; i++)
758     {
759         void *ptr = (char *)ret->ptr + i * size;
760         if (vartype == VT_BSTR)
761         {
762             BSTR str;
763             if (SafeArrayGetElement( V_ARRAY( var ), &i, &str ) != S_OK)
764             {
765                 destroy_array( ret, basetype );
766                 return NULL;
767             }
768             *(WCHAR **)ptr = heap_strdupW( str );
769             SysFreeString( str );
770             if (!*(WCHAR **)ptr)
771             {
772                 destroy_array( ret, basetype );
773                 return NULL;
774             }
775         }
776         else if (SafeArrayGetElement( V_ARRAY( var ), &i, ptr ) != S_OK)
777         {
778             destroy_array( ret, basetype );
779             return NULL;
780         }
781     }
782     *type = basetype | CIM_FLAG_ARRAY;
783     return ret;
784 }
785
786 HRESULT to_longlong( VARIANT *var, LONGLONG *val, CIMTYPE *type )
787 {
788     if (!var)
789     {
790         *val = 0;
791         return S_OK;
792     }
793     if (V_VT( var ) & VT_ARRAY)
794     {
795         *val = (INT_PTR)to_array( var, type );
796         if (!*val) return E_OUTOFMEMORY;
797         return S_OK;
798     }
799     switch (V_VT( var ))
800     {
801     case VT_BOOL:
802         *val = V_BOOL( var );
803         *type = CIM_BOOLEAN;
804         break;
805     case VT_BSTR:
806         *val = (INT_PTR)heap_strdupW( V_BSTR( var ) );
807         if (!*val) return E_OUTOFMEMORY;
808         *type = CIM_STRING;
809         break;
810     case VT_I2:
811         *val = V_I2( var );
812         *type = CIM_SINT16;
813         break;
814     case VT_UI2:
815         *val = V_UI2( var );
816         *type = CIM_UINT16;
817         break;
818     case VT_I4:
819         *val = V_I4( var );
820         *type = CIM_SINT32;
821         break;
822     case VT_UI4:
823         *val = V_UI4( var );
824         *type = CIM_UINT32;
825         break;
826     case VT_NULL:
827         *val = 0;
828         break;
829     default:
830         ERR("unhandled type %u\n", V_VT( var ));
831         return WBEM_E_FAILED;
832     }
833     return S_OK;
834 }
835
836 HRESULT put_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *var, CIMTYPE type )
837 {
838     HRESULT hr;
839     UINT column, row = view->result[index];
840     LONGLONG val;
841
842     hr = get_column_index( view->table, name, &column );
843     if (hr != S_OK)
844     {
845         FIXME("no support for creating new properties\n");
846         return WBEM_E_FAILED;
847     }
848     if (is_method( view->table, column ) || !(view->table->columns[column].type & COL_FLAG_DYNAMIC))
849         return WBEM_E_FAILED;
850
851     hr = to_longlong( var, &val, &type );
852     if (hr != S_OK) return hr;
853
854     return set_value( view->table, row, column, val, type );
855 }
856
857 HRESULT get_properties( const struct view *view, SAFEARRAY **props )
858 {
859     SAFEARRAY *sa;
860     BSTR str;
861     LONG i;
862     UINT num_props = count_properties( view );
863
864     if (!(sa = SafeArrayCreateVector( VT_BSTR, 0, num_props ))) return E_OUTOFMEMORY;
865
866     for (i = 0; i < view->table->num_cols; i++)
867     {
868         if (is_method( view->table, i )) continue;
869
870         str = SysAllocString( view->table->columns[i].name );
871         if (!str || SafeArrayPutElement( sa, &i, str ) != S_OK)
872         {
873             SysFreeString( str );
874             SafeArrayDestroy( sa );
875             return E_OUTOFMEMORY;
876         }
877     }
878     *props = sa;
879     return S_OK;
880 }