wbemprox: Add support for uncommitted instances in IWbemClassObject::Get.
[wine] / dlls / wbemprox / class.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 "objbase.h"
27 #include "wbemcli.h"
28
29 #include "wine/debug.h"
30 #include "wbemprox_private.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(wbemprox);
33
34 struct enum_class_object
35 {
36     IEnumWbemClassObject IEnumWbemClassObject_iface;
37     LONG refs;
38     struct query *query;
39     UINT index;
40 };
41
42 static inline struct enum_class_object *impl_from_IEnumWbemClassObject(
43     IEnumWbemClassObject *iface )
44 {
45     return CONTAINING_RECORD(iface, struct enum_class_object, IEnumWbemClassObject_iface);
46 }
47
48 static ULONG WINAPI enum_class_object_AddRef(
49     IEnumWbemClassObject *iface )
50 {
51     struct enum_class_object *ec = impl_from_IEnumWbemClassObject( iface );
52     return InterlockedIncrement( &ec->refs );
53 }
54
55 static ULONG WINAPI enum_class_object_Release(
56     IEnumWbemClassObject *iface )
57 {
58     struct enum_class_object *ec = impl_from_IEnumWbemClassObject( iface );
59     LONG refs = InterlockedDecrement( &ec->refs );
60     if (!refs)
61     {
62         TRACE("destroying %p\n", ec);
63         release_query( ec->query );
64         heap_free( ec );
65     }
66     return refs;
67 }
68
69 static HRESULT WINAPI enum_class_object_QueryInterface(
70     IEnumWbemClassObject *iface,
71     REFIID riid,
72     void **ppvObject )
73 {
74     struct enum_class_object *ec = impl_from_IEnumWbemClassObject( iface );
75
76     TRACE("%p, %s, %p\n", ec, debugstr_guid( riid ), ppvObject );
77
78     if ( IsEqualGUID( riid, &IID_IEnumWbemClassObject ) ||
79          IsEqualGUID( riid, &IID_IUnknown ) )
80     {
81         *ppvObject = ec;
82     }
83     else if ( IsEqualGUID( riid, &IID_IClientSecurity ) )
84     {
85         *ppvObject = &client_security;
86         return S_OK;
87     }
88     else
89     {
90         FIXME("interface %s not implemented\n", debugstr_guid(riid));
91         return E_NOINTERFACE;
92     }
93     IEnumWbemClassObject_AddRef( iface );
94     return S_OK;
95 }
96
97 static HRESULT WINAPI enum_class_object_Reset(
98     IEnumWbemClassObject *iface )
99 {
100     struct enum_class_object *ec = impl_from_IEnumWbemClassObject( iface );
101
102     TRACE("%p\n", iface);
103
104     ec->index = 0;
105     return WBEM_S_NO_ERROR;
106 }
107
108 static HRESULT WINAPI enum_class_object_Next(
109     IEnumWbemClassObject *iface,
110     LONG lTimeout,
111     ULONG uCount,
112     IWbemClassObject **apObjects,
113     ULONG *puReturned )
114 {
115     struct enum_class_object *ec = impl_from_IEnumWbemClassObject( iface );
116     struct view *view = ec->query->view;
117     HRESULT hr;
118
119     TRACE("%p, %d, %u, %p, %p\n", iface, lTimeout, uCount, apObjects, puReturned);
120
121     if (!uCount) return WBEM_S_FALSE;
122     if (!apObjects || !puReturned) return WBEM_E_INVALID_PARAMETER;
123     if (lTimeout != WBEM_INFINITE) FIXME("timeout not supported\n");
124
125     *puReturned = 0;
126     if (ec->index + uCount > view->count) return WBEM_S_FALSE;
127
128     hr = create_class_object( view->table->name, iface, ec->index, NULL, apObjects );
129     if (hr != S_OK) return hr;
130
131     ec->index++;
132     *puReturned = 1;
133     if (ec->index == view->count) return WBEM_S_FALSE;
134     if (uCount > 1) return WBEM_S_TIMEDOUT;
135     return WBEM_S_NO_ERROR;
136 }
137
138 static HRESULT WINAPI enum_class_object_NextAsync(
139     IEnumWbemClassObject *iface,
140     ULONG uCount,
141     IWbemObjectSink *pSink )
142 {
143     FIXME("%p, %u, %p\n", iface, uCount, pSink);
144     return E_NOTIMPL;
145 }
146
147 static HRESULT WINAPI enum_class_object_Clone(
148     IEnumWbemClassObject *iface,
149     IEnumWbemClassObject **ppEnum )
150 {
151     struct enum_class_object *ec = impl_from_IEnumWbemClassObject( iface );
152
153     TRACE("%p, %p\n", iface, ppEnum);
154
155     return EnumWbemClassObject_create( NULL, ec->query, (void **)ppEnum );
156 }
157
158 static HRESULT WINAPI enum_class_object_Skip(
159     IEnumWbemClassObject *iface,
160     LONG lTimeout,
161     ULONG nCount )
162 {
163     struct enum_class_object *ec = impl_from_IEnumWbemClassObject( iface );
164     struct view *view = ec->query->view;
165
166     TRACE("%p, %d, %u\n", iface, lTimeout, nCount);
167
168     if (lTimeout != WBEM_INFINITE) FIXME("timeout not supported\n");
169
170     if (!view->count) return WBEM_S_FALSE;
171
172     if (nCount > view->count - ec->index)
173     {
174         ec->index = view->count - 1;
175         return WBEM_S_FALSE;
176     }
177     ec->index += nCount;
178     return WBEM_S_NO_ERROR;
179 }
180
181 static const IEnumWbemClassObjectVtbl enum_class_object_vtbl =
182 {
183     enum_class_object_QueryInterface,
184     enum_class_object_AddRef,
185     enum_class_object_Release,
186     enum_class_object_Reset,
187     enum_class_object_Next,
188     enum_class_object_NextAsync,
189     enum_class_object_Clone,
190     enum_class_object_Skip
191 };
192
193 HRESULT EnumWbemClassObject_create(
194     IUnknown *pUnkOuter, struct query *query, LPVOID *ppObj )
195 {
196     struct enum_class_object *ec;
197
198     TRACE("%p, %p\n", pUnkOuter, ppObj);
199
200     ec = heap_alloc( sizeof(*ec) );
201     if (!ec) return E_OUTOFMEMORY;
202
203     ec->IEnumWbemClassObject_iface.lpVtbl = &enum_class_object_vtbl;
204     ec->refs  = 1;
205     ec->query = query;
206     addref_query( query );
207     ec->index = 0;
208
209     *ppObj = &ec->IEnumWbemClassObject_iface;
210
211     TRACE("returning iface %p\n", *ppObj);
212     return S_OK;
213 }
214
215 static struct record *create_record( const struct column *columns, UINT num_cols )
216 {
217     UINT i;
218     struct record *record;
219
220     if (!(record = heap_alloc( sizeof(struct record) ))) return NULL;
221     if (!(record->fields = heap_alloc( num_cols * sizeof(struct field) )))
222     {
223         heap_free( record );
224         return NULL;
225     }
226     for (i = 0; i < num_cols; i++)
227     {
228         record->fields[i].type   = columns[i].type;
229         record->fields[i].u.ival = 0;
230     }
231     record->count = num_cols;
232     return record;
233 }
234
235 static void destroy_record( struct record *record )
236 {
237     UINT i;
238
239     if (!record) return;
240     for (i = 0; i < record->count; i++)
241     {
242         if (record->fields[i].type == CIM_STRING || record->fields[i].type == CIM_DATETIME)
243             heap_free( record->fields[i].u.sval );
244     }
245     heap_free( record->fields );
246     heap_free( record );
247 }
248
249 struct class_object
250 {
251     IWbemClassObject IWbemClassObject_iface;
252     LONG refs;
253     WCHAR *name;
254     IEnumWbemClassObject *iter;
255     UINT index;
256     UINT index_method;
257     UINT index_property;
258     struct record *record; /* uncommitted instance */
259 };
260
261 static inline struct class_object *impl_from_IWbemClassObject(
262     IWbemClassObject *iface )
263 {
264     return CONTAINING_RECORD(iface, struct class_object, IWbemClassObject_iface);
265 }
266
267 static ULONG WINAPI class_object_AddRef(
268     IWbemClassObject *iface )
269 {
270     struct class_object *co = impl_from_IWbemClassObject( iface );
271     return InterlockedIncrement( &co->refs );
272 }
273
274 static ULONG WINAPI class_object_Release(
275     IWbemClassObject *iface )
276 {
277     struct class_object *co = impl_from_IWbemClassObject( iface );
278     LONG refs = InterlockedDecrement( &co->refs );
279     if (!refs)
280     {
281         TRACE("destroying %p\n", co);
282         if (co->iter) IEnumWbemClassObject_Release( co->iter );
283         destroy_record( co->record );
284         heap_free( co->name );
285         heap_free( co );
286     }
287     return refs;
288 }
289
290 static HRESULT WINAPI class_object_QueryInterface(
291     IWbemClassObject *iface,
292     REFIID riid,
293     void **ppvObject )
294 {
295     struct class_object *co = impl_from_IWbemClassObject( iface );
296
297     TRACE("%p, %s, %p\n", co, debugstr_guid( riid ), ppvObject );
298
299     if ( IsEqualGUID( riid, &IID_IWbemClassObject ) ||
300          IsEqualGUID( riid, &IID_IUnknown ) )
301     {
302         *ppvObject = co;
303     }
304     else if (IsEqualGUID( riid, &IID_IClientSecurity ))
305     {
306         *ppvObject = &client_security;
307         return S_OK;
308     }
309     else
310     {
311         FIXME("interface %s not implemented\n", debugstr_guid(riid));
312         return E_NOINTERFACE;
313     }
314     IWbemClassObject_AddRef( iface );
315     return S_OK;
316 }
317
318 static HRESULT WINAPI class_object_GetQualifierSet(
319     IWbemClassObject *iface,
320     IWbemQualifierSet **ppQualSet )
321 {
322     FIXME("%p, %p\n", iface, ppQualSet);
323     return E_NOTIMPL;
324 }
325
326 static HRESULT record_get_value( const struct record *record, UINT index, VARIANT *var, CIMTYPE *type )
327 {
328     if (type) *type = record->fields[index].type;
329
330     switch (record->fields[index].type)
331     {
332     case CIM_STRING:
333     case CIM_DATETIME:
334         V_VT( var ) = VT_BSTR;
335         V_BSTR( var ) = SysAllocString( record->fields[index].u.sval );
336         return S_OK;
337     case CIM_SINT32:
338         V_VT( var ) = VT_I4;
339         V_I4( var ) = record->fields[index].u.ival;
340         return S_OK;
341     case CIM_UINT32:
342         V_VT( var ) = VT_UI4;
343         V_UI4( var ) = record->fields[index].u.ival;
344         return S_OK;
345     default:
346         FIXME("unhandled type %u\n", record->fields[index].type);
347         break;
348     }
349     return WBEM_E_INVALID_PARAMETER;
350 }
351
352 static HRESULT WINAPI class_object_Get(
353     IWbemClassObject *iface,
354     LPCWSTR wszName,
355     LONG lFlags,
356     VARIANT *pVal,
357     CIMTYPE *pType,
358     LONG *plFlavor )
359 {
360     struct class_object *co = impl_from_IWbemClassObject( iface );
361     struct enum_class_object *ec = impl_from_IEnumWbemClassObject( co->iter );
362
363     TRACE("%p, %s, %08x, %p, %p, %p\n", iface, debugstr_w(wszName), lFlags, pVal, pType, plFlavor);
364
365     if (co->record)
366     {
367         struct table *table = grab_table( co->name );
368         UINT index;
369         HRESULT hr;
370
371         if (!table) return WBEM_E_FAILED;
372         hr = get_column_index( table, wszName, &index );
373         release_table( table );
374         if (hr != S_OK) return hr;
375         return record_get_value( co->record, index, pVal, pType );
376     }
377     return get_propval( ec->query->view, co->index, wszName, pVal, pType, plFlavor );
378 }
379
380 static HRESULT record_set_value( struct record *record, UINT index, VARIANT *var )
381 {
382     LONGLONG val;
383     CIMTYPE type;
384     HRESULT hr;
385
386     if ((hr = variant_to_longlong( var, &val, &type )) != S_OK) return hr;
387     if (type != record->fields[index].type) return WBEM_E_TYPE_MISMATCH;
388
389     switch (type)
390     {
391     case CIM_STRING:
392     case CIM_DATETIME:
393         record->fields[index].u.sval = (WCHAR *)(INT_PTR)val;
394         return S_OK;
395     case CIM_SINT16:
396     case CIM_UINT16:
397     case CIM_SINT32:
398     case CIM_UINT32:
399         record->fields[index].u.ival = val;
400         return S_OK;
401     default:
402         FIXME("unhandled type %u\n", type);
403         break;
404     }
405     return WBEM_E_INVALID_PARAMETER;
406 }
407
408 static HRESULT WINAPI class_object_Put(
409     IWbemClassObject *iface,
410     LPCWSTR wszName,
411     LONG lFlags,
412     VARIANT *pVal,
413     CIMTYPE Type )
414 {
415     struct class_object *co = impl_from_IWbemClassObject( iface );
416     struct enum_class_object *ec = impl_from_IEnumWbemClassObject( co->iter );
417
418     TRACE("%p, %s, %08x, %p, %u\n", iface, debugstr_w(wszName), lFlags, pVal, Type);
419
420     if (co->record)
421     {
422         struct table *table = grab_table( co->name );
423         UINT index;
424         HRESULT hr;
425
426         if (!table) return WBEM_E_FAILED;
427         hr = get_column_index( table, wszName, &index );
428         release_table( table );
429         if (hr != S_OK) return hr;
430         return record_set_value( co->record, index, pVal );
431     }
432     return put_propval( ec->query->view, co->index, wszName, pVal, Type );
433 }
434
435 static HRESULT WINAPI class_object_Delete(
436     IWbemClassObject *iface,
437     LPCWSTR wszName )
438 {
439     FIXME("%p, %s\n", iface, debugstr_w(wszName));
440     return E_NOTIMPL;
441 }
442
443 static HRESULT WINAPI class_object_GetNames(
444     IWbemClassObject *iface,
445     LPCWSTR wszQualifierName,
446     LONG lFlags,
447     VARIANT *pQualifierVal,
448     SAFEARRAY **pNames )
449 {
450     struct class_object *co = impl_from_IWbemClassObject( iface );
451     struct enum_class_object *ec = impl_from_IEnumWbemClassObject( co->iter );
452
453     TRACE("%p, %s, %08x, %p, %p\n", iface, debugstr_w(wszQualifierName), lFlags, pQualifierVal, pNames);
454
455     if (wszQualifierName || pQualifierVal)
456     {
457         FIXME("qualifier not supported\n");
458         return E_NOTIMPL;
459     }
460     if (lFlags != WBEM_FLAG_ALWAYS)
461     {
462         FIXME("flags %08x not supported\n", lFlags);
463         return E_NOTIMPL;
464     }
465     return get_properties( ec->query->view, pNames );
466 }
467
468 static HRESULT WINAPI class_object_BeginEnumeration(
469     IWbemClassObject *iface,
470     LONG lEnumFlags )
471 {
472     struct class_object *co = impl_from_IWbemClassObject( iface );
473
474     TRACE("%p, %08x\n", iface, lEnumFlags);
475
476     if (lEnumFlags) FIXME("flags 0x%08x not supported\n", lEnumFlags);
477
478     co->index_property = 0;
479     return S_OK;
480 }
481
482 static HRESULT WINAPI class_object_Next(
483     IWbemClassObject *iface,
484     LONG lFlags,
485     BSTR *strName,
486     VARIANT *pVal,
487     CIMTYPE *pType,
488     LONG *plFlavor )
489 {
490     struct class_object *co = impl_from_IWbemClassObject( iface );
491     struct enum_class_object *ec = impl_from_IEnumWbemClassObject( co->iter );
492     struct view *view = ec->query->view;
493     BSTR property;
494     HRESULT hr;
495
496     TRACE("%p, %08x, %p, %p, %p, %p\n", iface, lFlags, strName, pVal, pType, plFlavor);
497
498     if (!(property = get_property_name( co->name, co->index_property ))) return WBEM_S_NO_MORE_DATA;
499     if ((hr = get_propval( view, co->index, property, pVal, pType, plFlavor ) != S_OK))
500     {
501         SysFreeString( property );
502         return hr;
503     }
504     *strName = property;
505     co->index_property++;
506     return S_OK;
507 }
508
509 static HRESULT WINAPI class_object_EndEnumeration(
510     IWbemClassObject *iface )
511 {
512     struct class_object *co = impl_from_IWbemClassObject( iface );
513
514     TRACE("%p\n", iface);
515
516     co->index_property = 0;
517     return S_OK;
518 }
519
520 static HRESULT WINAPI class_object_GetPropertyQualifierSet(
521     IWbemClassObject *iface,
522     LPCWSTR wszProperty,
523     IWbemQualifierSet **ppQualSet )
524 {
525     FIXME("%p, %s, %p\n", iface, debugstr_w(wszProperty), ppQualSet);
526     return E_NOTIMPL;
527 }
528
529 static HRESULT WINAPI class_object_Clone(
530     IWbemClassObject *iface,
531     IWbemClassObject **ppCopy )
532 {
533     FIXME("%p, %p\n", iface, ppCopy);
534     return E_NOTIMPL;
535 }
536
537 static BSTR get_body_text( const struct table *table, UINT row, UINT *len )
538 {
539     static const WCHAR fmtW[] = {'\n','\t','%','s',' ','=',' ','%','s',';',0};
540     BSTR value, ret;
541     WCHAR *p;
542     UINT i;
543
544     *len = 0;
545     for (i = 0; i < table->num_cols; i++)
546     {
547         *len += sizeof(fmtW) / sizeof(fmtW[0]);
548         *len += strlenW( table->columns[i].name );
549         value = get_value_bstr( table, row, i );
550         *len += SysStringLen( value );
551         SysFreeString( value );
552     }
553     if (!(ret = SysAllocStringLen( NULL, *len ))) return NULL;
554     p = ret;
555     for (i = 0; i < table->num_cols; i++)
556     {
557         value = get_value_bstr( table, row, i );
558         p += sprintfW( p, fmtW, table->columns[i].name, value );
559         SysFreeString( value );
560     }
561     return ret;
562 }
563
564 static BSTR get_object_text( const struct view *view, UINT index )
565 {
566     static const WCHAR fmtW[] =
567         {'\n','i','n','s','t','a','n','c','e',' ','o','f',' ','%','s','\n','{','%','s','\n','}',';',0};
568     UINT len, len_body, row = view->result[index];
569     BSTR ret, body;
570
571     len = sizeof(fmtW) / sizeof(fmtW[0]);
572     len += strlenW( view->table->name );
573     if (!(body = get_body_text( view->table, row, &len_body ))) return NULL;
574     len += len_body;
575
576     if (!(ret = SysAllocStringLen( NULL, len ))) return NULL;
577     sprintfW( ret, fmtW, view->table->name, body );
578     SysFreeString( body );
579     return ret;
580 }
581
582 static HRESULT WINAPI class_object_GetObjectText(
583     IWbemClassObject *iface,
584     LONG lFlags,
585     BSTR *pstrObjectText )
586 {
587     struct class_object *co = impl_from_IWbemClassObject( iface );
588     struct enum_class_object *ec = impl_from_IEnumWbemClassObject( co->iter );
589     struct view *view = ec->query->view;
590     BSTR text;
591
592     TRACE("%p, %08x, %p\n", iface, lFlags, pstrObjectText);
593
594     if (lFlags) FIXME("flags %08x not implemented\n", lFlags);
595
596     if (!(text = get_object_text( view, co->index ))) return E_OUTOFMEMORY;
597     *pstrObjectText = text;
598     return S_OK;
599 }
600
601 static HRESULT WINAPI class_object_SpawnDerivedClass(
602     IWbemClassObject *iface,
603     LONG lFlags,
604     IWbemClassObject **ppNewClass )
605 {
606     FIXME("%p, %08x, %p\n", iface, lFlags, ppNewClass);
607     return E_NOTIMPL;
608 }
609
610 static HRESULT WINAPI class_object_SpawnInstance(
611     IWbemClassObject *iface,
612     LONG lFlags,
613     IWbemClassObject **ppNewInstance )
614 {
615     struct class_object *co = impl_from_IWbemClassObject( iface );
616     struct enum_class_object *ec = impl_from_IEnumWbemClassObject( co->iter );
617     struct view *view = ec->query->view;
618     struct record *record;
619
620     TRACE("%p, %08x, %p\n", iface, lFlags, ppNewInstance);
621
622     if (!(record = create_record( view->table->columns, view->table->num_cols )))
623         return E_OUTOFMEMORY;
624
625     return create_class_object( co->name, NULL, 0, record, ppNewInstance );
626 }
627
628 static HRESULT WINAPI class_object_CompareTo(
629     IWbemClassObject *iface,
630     LONG lFlags,
631     IWbemClassObject *pCompareTo )
632 {
633     FIXME("%p, %08x, %p\n", iface, lFlags, pCompareTo);
634     return E_NOTIMPL;
635 }
636
637 static HRESULT WINAPI class_object_GetPropertyOrigin(
638     IWbemClassObject *iface,
639     LPCWSTR wszName,
640     BSTR *pstrClassName )
641 {
642     FIXME("%p, %s, %p\n", iface, debugstr_w(wszName), pstrClassName);
643     return E_NOTIMPL;
644 }
645
646 static HRESULT WINAPI class_object_InheritsFrom(
647     IWbemClassObject *iface,
648     LPCWSTR strAncestor )
649 {
650     FIXME("%p, %s\n", iface, debugstr_w(strAncestor));
651     return E_NOTIMPL;
652 }
653
654 static UINT count_instances( IEnumWbemClassObject *iter )
655 {
656     UINT count = 0;
657     while (!IEnumWbemClassObject_Skip( iter, WBEM_INFINITE, 1 )) count++;
658     IEnumWbemClassObject_Reset( iter );
659     return count;
660 }
661
662 static void set_default_value( CIMTYPE type, UINT val, BYTE *ptr )
663 {
664     switch (type)
665     {
666     case CIM_SINT16:
667         *(INT16 *)ptr = val;
668         break;
669     case CIM_UINT16:
670         *(UINT16 *)ptr = val;
671         break;
672     case CIM_SINT32:
673         *(INT32 *)ptr = val;
674         break;
675     case CIM_UINT32:
676         *(UINT32 *)ptr = val;
677         break;
678     default:
679         FIXME("unhandled type %u\n", type);
680         break;
681     }
682 }
683
684 static HRESULT create_signature_columns_and_data( IEnumWbemClassObject *iter, UINT *num_cols,
685                                            struct column **cols, BYTE **data )
686 {
687     static const WCHAR parameterW[] = {'P','a','r','a','m','e','t','e','r',0};
688     static const WCHAR typeW[] = {'T','y','p','e',0};
689     static const WCHAR defaultvalueW[] = {'D','e','f','a','u','l','t','V','a','l','u','e',0};
690     struct column *columns;
691     BYTE *row;
692     IWbemClassObject *param;
693     VARIANT val;
694     HRESULT hr = E_OUTOFMEMORY;
695     UINT offset = 0;
696     ULONG count;
697     int i = 0;
698
699     count = count_instances( iter );
700     if (!(columns = heap_alloc( count * sizeof(struct column) ))) return E_OUTOFMEMORY;
701     if (!(row = heap_alloc_zero( count * sizeof(LONGLONG) ))) goto error;
702
703     for (;;)
704     {
705         IEnumWbemClassObject_Next( iter, WBEM_INFINITE, 1, &param, &count );
706         if (!count) break;
707
708         hr = IWbemClassObject_Get( param, parameterW, 0, &val, NULL, NULL );
709         if (hr != S_OK) goto error;
710         columns[i].name = heap_strdupW( V_BSTR( &val ) );
711         VariantClear( &val );
712
713         hr = IWbemClassObject_Get( param, typeW, 0, &val, NULL, NULL );
714         if (hr != S_OK) goto error;
715         columns[i].type    = V_UI4( &val );
716         columns[i].vartype = 0;
717
718         hr = IWbemClassObject_Get( param, defaultvalueW, 0, &val, NULL, NULL );
719         if (hr != S_OK) goto error;
720         if (V_UI4( &val )) set_default_value( columns[i].type, V_UI4( &val ), row + offset );
721         offset += get_type_size( columns[i].type );
722
723         IWbemClassObject_Release( param );
724         i++;
725     }
726     *num_cols = i;
727     *cols = columns;
728     *data = row;
729     return S_OK;
730
731 error:
732     for (; i >= 0; i--) heap_free( (WCHAR *)columns[i].name );
733     heap_free( columns );
734     heap_free( row );
735     return hr;
736 }
737
738 static HRESULT create_signature_table( IEnumWbemClassObject *iter, WCHAR *name )
739 {
740     HRESULT hr;
741     struct table *table;
742     struct column *columns;
743     UINT num_cols;
744     BYTE *row;
745
746     hr = create_signature_columns_and_data( iter, &num_cols, &columns, &row );
747     if (hr != S_OK) return hr;
748
749     if (!(table = create_table( name, num_cols, columns, 1, row, NULL )))
750     {
751         free_columns( columns, num_cols );
752         heap_free( row );
753         return E_OUTOFMEMORY;
754     }
755     if (!add_table( table )) free_table( table ); /* already exists */
756     return S_OK;
757 }
758
759 static WCHAR *build_signature_table_name( const WCHAR *class, const WCHAR *method, enum param_direction dir )
760 {
761     static const WCHAR fmtW[] = {'_','_','%','s','_','%','s','_','%','s',0};
762     static const WCHAR outW[] = {'O','U','T',0};
763     static const WCHAR inW[] = {'I','N',0};
764     UINT len = SIZEOF(fmtW) + SIZEOF(outW) + strlenW( class ) + strlenW( method );
765     WCHAR *ret;
766
767     if (!(ret = heap_alloc( len * sizeof(WCHAR) ))) return NULL;
768     sprintfW( ret, fmtW, class, method, dir == PARAM_IN ? inW : outW );
769     return struprW( ret );
770 }
771
772 static HRESULT create_signature( const WCHAR *class, const WCHAR *method, enum param_direction dir,
773                                  IWbemClassObject **sig )
774 {
775     static const WCHAR selectW[] =
776         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',
777          '_','_','P','A','R','A','M','E','T','E','R','S',' ','W','H','E','R','E',' ',
778          'C','l','a','s','s','=','\'','%','s','\'',' ','A','N','D',' ',
779          'M','e','t','h','o','d','=','\'','%','s','\'',' ','A','N','D',' ',
780          'D','i','r','e','c','t','i','o','n','%','s',0};
781     static const WCHAR geW[] = {'>','=','0',0};
782     static const WCHAR leW[] = {'<','=','0',0};
783     UINT len = SIZEOF(selectW) + SIZEOF(geW);
784     IEnumWbemClassObject *iter;
785     WCHAR *query, *name;
786     HRESULT hr;
787
788     len += strlenW( class ) + strlenW( method );
789     if (!(query = heap_alloc( len * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
790     sprintfW( query, selectW, class, method, dir >= 0 ? geW : leW );
791
792     hr = exec_query( query, &iter );
793     heap_free( query );
794     if (hr != S_OK) return hr;
795
796     if (!(name = build_signature_table_name( class, method, dir )))
797     {
798         IEnumWbemClassObject_Release( iter );
799         return E_OUTOFMEMORY;
800     }
801     hr = create_signature_table( iter, name );
802     IEnumWbemClassObject_Release( iter );
803     if (hr != S_OK)
804     {
805         heap_free( name );
806         return hr;
807     }
808     return get_object( name, sig );
809 }
810
811 static HRESULT WINAPI class_object_GetMethod(
812     IWbemClassObject *iface,
813     LPCWSTR wszName,
814     LONG lFlags,
815     IWbemClassObject **ppInSignature,
816     IWbemClassObject **ppOutSignature )
817 {
818     struct class_object *co = impl_from_IWbemClassObject( iface );
819     HRESULT hr;
820
821     TRACE("%p, %s, %08x, %p, %p\n", iface, debugstr_w(wszName), lFlags, ppInSignature, ppOutSignature);
822
823     hr = create_signature( co->name, wszName, PARAM_IN, ppInSignature );
824     if (hr != S_OK) return hr;
825
826     hr = create_signature( co->name, wszName, PARAM_OUT, ppOutSignature );
827     if (hr != S_OK) IWbemClassObject_Release( *ppInSignature );
828     return hr;
829 }
830
831 static HRESULT WINAPI class_object_PutMethod(
832     IWbemClassObject *iface,
833     LPCWSTR wszName,
834     LONG lFlags,
835     IWbemClassObject *pInSignature,
836     IWbemClassObject *pOutSignature )
837 {
838     FIXME("%p, %s, %08x, %p, %p\n", iface, debugstr_w(wszName), lFlags, pInSignature, pOutSignature);
839     return E_NOTIMPL;
840 }
841
842 static HRESULT WINAPI class_object_DeleteMethod(
843     IWbemClassObject *iface,
844     LPCWSTR wszName )
845 {
846     FIXME("%p, %s\n", iface, debugstr_w(wszName));
847     return E_NOTIMPL;
848 }
849
850 static HRESULT WINAPI class_object_BeginMethodEnumeration(
851     IWbemClassObject *iface,
852     LONG lEnumFlags)
853 {
854     struct class_object *co = impl_from_IWbemClassObject( iface );
855
856     TRACE("%p, %08x\n", iface, lEnumFlags);
857
858     if (lEnumFlags) FIXME("flags 0x%08x not supported\n", lEnumFlags);
859
860     if (co->iter)
861     {
862         WARN("not allowed on instance\n");
863         return WBEM_E_ILLEGAL_OPERATION;
864     }
865     co->index_method = 0;
866     return S_OK;
867 }
868
869 static HRESULT WINAPI class_object_NextMethod(
870     IWbemClassObject *iface,
871     LONG lFlags,
872     BSTR *pstrName,
873     IWbemClassObject **ppInSignature,
874     IWbemClassObject **ppOutSignature)
875 {
876     struct class_object *co = impl_from_IWbemClassObject( iface );
877     BSTR method;
878     HRESULT hr;
879
880     TRACE("%p, %08x, %p, %p, %p\n", iface, lFlags, pstrName, ppInSignature, ppOutSignature);
881
882     if (!(method = get_method_name( co->name, co->index_method ))) return WBEM_S_NO_MORE_DATA;
883
884     hr = create_signature( co->name, method, PARAM_IN, ppInSignature );
885     if (hr != S_OK)
886     {
887         SysFreeString( method );
888         return hr;
889     }
890     hr = create_signature( co->name, method, PARAM_OUT, ppOutSignature );
891     if (hr != S_OK)
892     {
893         SysFreeString( method );
894         IWbemClassObject_Release( *ppInSignature );
895     }
896     else
897     {
898         *pstrName = method;
899         co->index_method++;
900     }
901     return hr;
902 }
903
904 static HRESULT WINAPI class_object_EndMethodEnumeration(
905     IWbemClassObject *iface )
906 {
907     struct class_object *co = impl_from_IWbemClassObject( iface );
908
909     TRACE("%p\n", iface);
910
911     co->index_method = 0;
912     return S_OK;
913 }
914
915 static HRESULT WINAPI class_object_GetMethodQualifierSet(
916     IWbemClassObject *iface,
917     LPCWSTR wszMethod,
918     IWbemQualifierSet **ppQualSet)
919 {
920     FIXME("%p, %s, %p\n", iface, debugstr_w(wszMethod), ppQualSet);
921     return E_NOTIMPL;
922 }
923
924 static HRESULT WINAPI class_object_GetMethodOrigin(
925     IWbemClassObject *iface,
926     LPCWSTR wszMethodName,
927     BSTR *pstrClassName)
928 {
929     FIXME("%p, %s, %p\n", iface, debugstr_w(wszMethodName), pstrClassName);
930     return E_NOTIMPL;
931 }
932
933 static const IWbemClassObjectVtbl class_object_vtbl =
934 {
935     class_object_QueryInterface,
936     class_object_AddRef,
937     class_object_Release,
938     class_object_GetQualifierSet,
939     class_object_Get,
940     class_object_Put,
941     class_object_Delete,
942     class_object_GetNames,
943     class_object_BeginEnumeration,
944     class_object_Next,
945     class_object_EndEnumeration,
946     class_object_GetPropertyQualifierSet,
947     class_object_Clone,
948     class_object_GetObjectText,
949     class_object_SpawnDerivedClass,
950     class_object_SpawnInstance,
951     class_object_CompareTo,
952     class_object_GetPropertyOrigin,
953     class_object_InheritsFrom,
954     class_object_GetMethod,
955     class_object_PutMethod,
956     class_object_DeleteMethod,
957     class_object_BeginMethodEnumeration,
958     class_object_NextMethod,
959     class_object_EndMethodEnumeration,
960     class_object_GetMethodQualifierSet,
961     class_object_GetMethodOrigin
962 };
963
964 HRESULT create_class_object( const WCHAR *name, IEnumWbemClassObject *iter, UINT index,
965                              struct record *record, IWbemClassObject **obj )
966 {
967     struct class_object *co;
968
969     TRACE("%s, %p\n", debugstr_w(name), obj);
970
971     co = heap_alloc( sizeof(*co) );
972     if (!co) return E_OUTOFMEMORY;
973
974     co->IWbemClassObject_iface.lpVtbl = &class_object_vtbl;
975     co->refs  = 1;
976     co->name  = heap_strdupW( name );
977     if (!co->name)
978     {
979         heap_free( co );
980         return E_OUTOFMEMORY;
981     }
982     co->iter           = iter;
983     co->index          = index;
984     co->index_method   = 0;
985     co->index_property = 0;
986     co->record         = record;
987     if (iter) IEnumWbemClassObject_AddRef( iter );
988
989     *obj = &co->IWbemClassObject_iface;
990
991     TRACE("returning iface %p\n", *obj);
992     return S_OK;
993 }