wbemprox: Always convert from BSTR.
[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 void addref_query( struct query *query )
294 {
295     InterlockedIncrement( &query->refs );
296 }
297
298 void release_query( struct query *query )
299 {
300     if (!InterlockedDecrement( &query->refs )) free_query( query );
301 }
302
303 HRESULT exec_query( const WCHAR *str, IEnumWbemClassObject **result )
304 {
305     HRESULT hr;
306     struct query *query;
307
308     *result = NULL;
309     if (!(query = create_query())) return E_OUTOFMEMORY;
310     hr = parse_query( str, &query->view, &query->mem );
311     if (hr != S_OK) goto done;
312     hr = execute_view( query->view );
313     if (hr != S_OK) goto done;
314     hr = EnumWbemClassObject_create( NULL, query, (void **)result );
315
316 done:
317     release_query( query );
318     return hr;
319 }
320
321 static BOOL is_selected_prop( const struct view *view, const WCHAR *name )
322 {
323     const struct property *prop = view->proplist;
324
325     if (!prop) return TRUE;
326     while (prop)
327     {
328         if (!strcmpiW( prop->name, name )) return TRUE;
329         prop = prop->next;
330     }
331     return FALSE;
332 }
333
334 static BOOL is_system_prop( const WCHAR *name )
335 {
336     return (name[0] == '_' && name[1] == '_');
337 }
338
339 static BSTR build_servername( const struct view *view )
340 {
341     WCHAR server[MAX_COMPUTERNAME_LENGTH + 1], *p;
342     DWORD len = sizeof(server)/sizeof(server[0]);
343
344     if (view->proplist) return NULL;
345
346     if (!(GetComputerNameW( server, &len ))) return NULL;
347     for (p = server; *p; p++) *p = toupperW( *p );
348     return SysAllocString( server );
349 }
350
351 static BSTR build_classname( const struct view *view )
352 {
353     return SysAllocString( view->table->name );
354 }
355
356 static BSTR build_namespace( const struct view *view )
357 {
358     static const WCHAR cimv2W[] = {'R','O','O','T','\\','C','I','M','V','2',0};
359
360     if (view->proplist) return NULL;
361     return SysAllocString( cimv2W );
362 }
363
364 static BSTR build_proplist( const struct view *view, UINT index, UINT count, UINT *len )
365 {
366     static const WCHAR fmtW[] = {'%','s','=','%','s',0};
367     UINT i, j, offset, row = view->result[index];
368     BSTR *values, ret = NULL;
369
370     if (!(values = heap_alloc( count * sizeof(BSTR) ))) return NULL;
371
372     *len = j = 0;
373     for (i = 0; i < view->table->num_cols; i++)
374     {
375         if (view->table->columns[i].type & COL_FLAG_KEY)
376         {
377             const WCHAR *name = view->table->columns[i].name;
378
379             values[j] = get_value_bstr( view->table, row, i );
380             *len += strlenW( fmtW ) + strlenW( name ) + strlenW( values[j] );
381             j++;
382         }
383     }
384     if ((ret = SysAllocStringLen( NULL, *len )))
385     {
386         offset = j = 0;
387         for (i = 0; i < view->table->num_cols; i++)
388         {
389             if (view->table->columns[i].type & COL_FLAG_KEY)
390             {
391                 const WCHAR *name = view->table->columns[i].name;
392
393                 offset += sprintfW( ret + offset, fmtW, name, values[j] );
394                 if (j < count - 1) ret[offset++] = ',';
395                 j++;
396             }
397         }
398     }
399     for (i = 0; i < count; i++) SysFreeString( values[i] );
400     heap_free( values );
401     return ret;
402 }
403
404 static UINT count_key_columns( const struct view *view )
405 {
406     UINT i, num_keys = 0;
407
408     for (i = 0; i < view->table->num_cols; i++)
409     {
410         if (view->table->columns[i].type & COL_FLAG_KEY) num_keys++;
411     }
412     return num_keys;
413 }
414
415 static BSTR build_relpath( const struct view *view, UINT index, const WCHAR *name )
416 {
417     static const WCHAR fmtW[] = {'%','s','.','%','s',0};
418     BSTR class, proplist, ret = NULL;
419     UINT num_keys, len;
420
421     if (view->proplist) return NULL;
422
423     if (!(class = build_classname( view ))) return NULL;
424     if (!(num_keys = count_key_columns( view ))) return class;
425     if (!(proplist = build_proplist( view, index, num_keys, &len ))) goto done;
426
427     len += strlenW( fmtW ) + SysStringLen( class );
428     if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
429     sprintfW( ret, fmtW, class, proplist );
430
431 done:
432     SysFreeString( class );
433     SysFreeString( proplist );
434     return ret;
435 }
436
437 static BSTR build_path( const struct view *view, UINT index, const WCHAR *name )
438 {
439     static const WCHAR fmtW[] = {'\\','\\','%','s','\\','%','s',':','%','s',0};
440     BSTR server, namespace = NULL, relpath = NULL, ret = NULL;
441     UINT len;
442
443     if (view->proplist) return NULL;
444
445     if (!(server = build_servername( view ))) return NULL;
446     if (!(namespace = build_namespace( view ))) goto done;
447     if (!(relpath = build_relpath( view, index, name ))) goto done;
448
449     len = strlenW( fmtW ) + SysStringLen( server ) + SysStringLen( namespace ) + SysStringLen( relpath );
450     if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
451     sprintfW( ret, fmtW, server, namespace, relpath );
452
453 done:
454     SysFreeString( server );
455     SysFreeString( namespace );
456     SysFreeString( relpath );
457     return ret;
458 }
459
460 static inline BOOL is_method( const struct table *table, UINT column )
461 {
462     return table->columns[column].type & COL_FLAG_METHOD;
463 }
464
465 static UINT count_properties( const struct view *view )
466 {
467     UINT i, num_props = 0;
468
469     for (i = 0; i < view->table->num_cols; i++)
470     {
471         if (!is_method( view->table, i)) num_props++;
472     }
473     return num_props;
474 }
475
476 static UINT count_selected_properties( const struct view *view )
477 {
478     const struct property *prop = view->proplist;
479     UINT count;
480
481     if (!prop) return count_properties( view );
482
483     count = 1;
484     while ((prop = prop->next)) count++;
485     return count;
486 }
487
488 static HRESULT get_system_propval( const struct view *view, UINT index, const WCHAR *name,
489                                    VARIANT *ret, CIMTYPE *type, LONG *flavor )
490 {
491     static const WCHAR classW[] = {'_','_','C','L','A','S','S',0};
492     static const WCHAR genusW[] = {'_','_','G','E','N','U','S',0};
493     static const WCHAR pathW[] = {'_','_','P','A','T','H',0};
494     static const WCHAR namespaceW[] = {'_','_','N','A','M','E','S','P','A','C','E',0};
495     static const WCHAR propcountW[] = {'_','_','P','R','O','P','E','R','T','Y','_','C','O','U','N','T',0};
496     static const WCHAR relpathW[] = {'_','_','R','E','L','P','A','T','H',0};
497     static const WCHAR serverW[] = {'_','_','S','E','R','V','E','R',0};
498
499     if (flavor) *flavor = WBEM_FLAVOR_ORIGIN_SYSTEM;
500
501     if (!strcmpiW( name, classW ))
502     {
503         V_VT( ret ) = VT_BSTR;
504         V_BSTR( ret ) = build_classname( view );
505         if (type) *type = CIM_STRING;
506         return S_OK;
507     }
508     if (!strcmpiW( name, genusW ))
509     {
510         V_VT( ret ) = VT_I4;
511         V_I4( ret ) = WBEM_GENUS_INSTANCE; /* FIXME */
512         if (type) *type = CIM_SINT32;
513         return S_OK;
514     }
515     else if (!strcmpiW( name, namespaceW ))
516     {
517         V_VT( ret ) = VT_BSTR;
518         V_BSTR( ret ) = build_namespace( view );
519         if (type) *type = CIM_STRING;
520         return S_OK;
521     }
522     else if (!strcmpiW( name, pathW ))
523     {
524         V_VT( ret ) = VT_BSTR;
525         V_BSTR( ret ) = build_path( view, index, name );
526         if (type) *type = CIM_STRING;
527         return S_OK;
528     }
529     if (!strcmpiW( name, propcountW ))
530     {
531         V_VT( ret ) = VT_I4;
532         V_I4( ret ) = count_selected_properties( view );
533         if (type) *type = CIM_SINT32;
534         return S_OK;
535     }
536     else if (!strcmpiW( name, relpathW ))
537     {
538         V_VT( ret ) = VT_BSTR;
539         V_BSTR( ret ) = build_relpath( view, index, name );
540         if (type) *type = CIM_STRING;
541         return S_OK;
542     }
543     else if (!strcmpiW( name, serverW ))
544     {
545         V_VT( ret ) = VT_BSTR;
546         V_BSTR( ret ) = build_servername( view );
547         if (type) *type = CIM_STRING;
548         return S_OK;
549     }
550     FIXME("system property %s not implemented\n", debugstr_w(name));
551     return WBEM_E_NOT_FOUND;
552 }
553
554 VARTYPE to_vartype( CIMTYPE type )
555 {
556     switch (type)
557     {
558     case CIM_BOOLEAN:  return VT_BOOL;
559     case CIM_STRING:
560     case CIM_DATETIME: return VT_BSTR;
561     case CIM_SINT16:   return VT_I2;
562     case CIM_UINT16:   return VT_UI2;
563     case CIM_SINT32:   return VT_I4;
564     case CIM_UINT32:   return VT_UI4;
565     case CIM_SINT64:   return VT_I8;
566     case CIM_UINT64:   return VT_UI8;
567     default:
568         ERR("unhandled type %u\n", type);
569         break;
570     }
571     return 0;
572 }
573
574 SAFEARRAY *to_safearray( const struct array *array, CIMTYPE type )
575 {
576     SAFEARRAY *ret;
577     UINT size = get_type_size( type );
578     VARTYPE vartype = to_vartype( type );
579     LONG i;
580
581     if (!(ret = SafeArrayCreateVector( vartype, 0, array->count ))) return NULL;
582
583     for (i = 0; i < array->count; i++)
584     {
585         void *ptr = (char *)array->ptr + i * size;
586         if (vartype == VT_BSTR)
587         {
588             BSTR str = SysAllocString( *(const WCHAR **)ptr );
589             if (!str || SafeArrayPutElement( ret, &i, str ) != S_OK)
590             {
591                 SysFreeString( str );
592                 SafeArrayDestroy( ret );
593                 return NULL;
594             }
595         }
596         else if (SafeArrayPutElement( ret, &i, ptr ) != S_OK)
597         {
598             SafeArrayDestroy( ret );
599             return NULL;
600         }
601     }
602     return ret;
603 }
604
605 static void set_variant( VARTYPE type, LONGLONG val, void *val_ptr, VARIANT *ret )
606 {
607     if (type & VT_ARRAY)
608     {
609         V_VT( ret ) = type;
610         V_ARRAY( ret ) = val_ptr;
611         return;
612     }
613     switch (type)
614     {
615     case VT_BOOL:
616         V_BOOL( ret ) = val;
617         break;
618     case VT_BSTR:
619         V_BSTR( ret ) = val_ptr;
620         break;
621     case VT_I2:
622         V_I2( ret ) = val;
623         break;
624     case VT_UI2:
625         V_UI2( ret ) = val;
626         break;
627     case VT_I4:
628         V_I4( ret ) = val;
629         break;
630     case VT_UI4:
631         V_UI4( ret ) = val;
632         break;
633     case VT_NULL:
634         break;
635     default:
636         ERR("unhandled variant type %u\n", type);
637         return;
638     }
639     V_VT( ret ) = type;
640 }
641
642 HRESULT get_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *ret,
643                      CIMTYPE *type, LONG *flavor )
644 {
645     HRESULT hr;
646     UINT column, row = view->result[index];
647     VARTYPE vartype;
648     void *val_ptr = NULL;
649     LONGLONG val;
650
651     if (is_system_prop( name )) return get_system_propval( view, index, name, ret, type, flavor );
652     if (!is_selected_prop( view, name )) return WBEM_E_NOT_FOUND;
653
654     hr = get_column_index( view->table, name, &column );
655     if (hr != S_OK || is_method( view->table, column )) return WBEM_E_NOT_FOUND;
656
657     vartype = view->table->columns[column].vartype;
658
659     hr = get_value( view->table, row, column, &val );
660     if (hr != S_OK) return hr;
661
662     if (view->table->columns[column].type & CIM_FLAG_ARRAY)
663     {
664         CIMTYPE basetype = view->table->columns[column].type & CIM_TYPE_MASK;
665
666         val_ptr = to_safearray( (const struct array *)(INT_PTR)val, basetype );
667         if (!vartype) vartype = to_vartype( basetype ) | VT_ARRAY;
668         goto done;
669     }
670     switch (view->table->columns[column].type & COL_TYPE_MASK)
671     {
672     case CIM_BOOLEAN:
673         if (!vartype) vartype = VT_BOOL;
674         break;
675     case CIM_STRING:
676     case CIM_DATETIME:
677         if (val)
678         {
679             vartype = VT_BSTR;
680             val_ptr = SysAllocString( (const WCHAR *)(INT_PTR)val );
681         }
682         else
683             vartype = VT_NULL;
684         break;
685     case CIM_SINT16:
686         if (!vartype) vartype = VT_I2;
687         break;
688     case CIM_UINT16:
689         if (!vartype) vartype = VT_UI2;
690         break;
691     case CIM_SINT32:
692         if (!vartype) vartype = VT_I4;
693         break;
694     case CIM_UINT32:
695         if (!vartype) vartype = VT_UI4;
696         break;
697     case CIM_SINT64:
698         vartype = VT_BSTR;
699         val_ptr = get_value_bstr( view->table, row, column );
700         break;
701     case CIM_UINT64:
702         vartype = VT_BSTR;
703         val_ptr = get_value_bstr( view->table, row, column );
704         break;
705     default:
706         ERR("unhandled column type %u\n", view->table->columns[column].type);
707         return WBEM_E_FAILED;
708     }
709
710 done:
711     set_variant( vartype, val, val_ptr, ret );
712     if (type) *type = view->table->columns[column].type & COL_TYPE_MASK;
713     if (flavor) *flavor = 0;
714     return S_OK;
715 }
716
717 static CIMTYPE to_cimtype( VARTYPE type )
718 {
719     switch (type)
720     {
721     case VT_BOOL:  return CIM_BOOLEAN;
722     case VT_BSTR:  return CIM_STRING;
723     case VT_I2:    return CIM_SINT16;
724     case VT_UI2:   return CIM_UINT16;
725     case VT_I4:    return CIM_SINT32;
726     case VT_UI4:   return CIM_UINT32;
727     case VT_I8:    return CIM_SINT64;
728     case VT_UI8:   return CIM_UINT64;
729     default:
730         ERR("unhandled type %u\n", type);
731         break;
732     }
733     return 0;
734 }
735
736 static struct array *to_array( VARIANT *var, CIMTYPE *type )
737 {
738     struct array *ret;
739     LONG bound, i;
740     VARTYPE vartype;
741     CIMTYPE basetype;
742     UINT size;
743
744     if (SafeArrayGetVartype( V_ARRAY( var ), &vartype ) != S_OK) return NULL;
745     if (!(basetype = to_cimtype( vartype ))) return NULL;
746     if (SafeArrayGetUBound( V_ARRAY( var ), 1, &bound ) != S_OK) return NULL;
747     if (!(ret = heap_alloc( sizeof(struct array) ))) return NULL;
748
749     ret->count = bound + 1;
750     size = get_type_size( basetype );
751     if (!(ret->ptr = heap_alloc_zero( ret->count * size )))
752     {
753         heap_free( ret );
754         return NULL;
755     }
756     for (i = 0; i < ret->count; i++)
757     {
758         void *ptr = (char *)ret->ptr + i * size;
759         if (vartype == VT_BSTR)
760         {
761             BSTR str;
762             if (SafeArrayGetElement( V_ARRAY( var ), &i, &str ) != S_OK)
763             {
764                 destroy_array( ret, basetype );
765                 return NULL;
766             }
767             *(WCHAR **)ptr = heap_strdupW( str );
768             SysFreeString( str );
769             if (!*(WCHAR **)ptr)
770             {
771                 destroy_array( ret, basetype );
772                 return NULL;
773             }
774         }
775         else if (SafeArrayGetElement( V_ARRAY( var ), &i, ptr ) != S_OK)
776         {
777             destroy_array( ret, basetype );
778             return NULL;
779         }
780     }
781     *type = basetype | CIM_FLAG_ARRAY;
782     return ret;
783 }
784
785 HRESULT to_longlong( VARIANT *var, LONGLONG *val, CIMTYPE *type )
786 {
787     if (!var)
788     {
789         *val = 0;
790         return S_OK;
791     }
792     if (V_VT( var ) & VT_ARRAY)
793     {
794         *val = (INT_PTR)to_array( var, type );
795         if (!*val) return E_OUTOFMEMORY;
796         return S_OK;
797     }
798     switch (V_VT( var ))
799     {
800     case VT_BOOL:
801         *val = V_BOOL( var );
802         *type = CIM_BOOLEAN;
803         break;
804     case VT_BSTR:
805         *val = (INT_PTR)heap_strdupW( V_BSTR( var ) );
806         if (!*val) return E_OUTOFMEMORY;
807         *type = CIM_STRING;
808         break;
809     case VT_I2:
810         *val = V_I2( var );
811         *type = CIM_SINT16;
812         break;
813     case VT_UI2:
814         *val = V_UI2( var );
815         *type = CIM_UINT16;
816         break;
817     case VT_I4:
818         *val = V_I4( var );
819         *type = CIM_SINT32;
820         break;
821     case VT_UI4:
822         *val = V_UI4( var );
823         *type = CIM_UINT32;
824         break;
825     case VT_NULL:
826         *val = 0;
827         break;
828     default:
829         ERR("unhandled type %u\n", V_VT( var ));
830         return WBEM_E_FAILED;
831     }
832     return S_OK;
833 }
834
835 HRESULT put_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *var, CIMTYPE type )
836 {
837     HRESULT hr;
838     UINT column, row = view->result[index];
839     LONGLONG val;
840
841     hr = get_column_index( view->table, name, &column );
842     if (hr != S_OK)
843     {
844         FIXME("no support for creating new properties\n");
845         return WBEM_E_FAILED;
846     }
847     if (is_method( view->table, column ) || !(view->table->columns[column].type & COL_FLAG_DYNAMIC))
848         return WBEM_E_FAILED;
849
850     hr = to_longlong( var, &val, &type );
851     if (hr != S_OK) return hr;
852
853     return set_value( view->table, row, column, val, type );
854 }
855
856 HRESULT get_properties( const struct view *view, SAFEARRAY **props )
857 {
858     SAFEARRAY *sa;
859     BSTR str;
860     LONG i;
861     UINT num_props = count_properties( view );
862
863     if (!(sa = SafeArrayCreateVector( VT_BSTR, 0, num_props ))) return E_OUTOFMEMORY;
864
865     for (i = 0; i < view->table->num_cols; i++)
866     {
867         if (is_method( view->table, i )) continue;
868
869         str = SysAllocString( view->table->columns[i].name );
870         if (!str || SafeArrayPutElement( sa, &i, str ) != S_OK)
871         {
872             SysFreeString( str );
873             SafeArrayDestroy( sa );
874             return E_OUTOFMEMORY;
875         }
876     }
877     *props = sa;
878     return S_OK;
879 }