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