class.c 29.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
/*
 * Copyright 2012 Hans Leidekker for CodeWeavers
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#define COBJMACROS

#include <stdarg.h>

#include "windef.h"
#include "winbase.h"
#include "objbase.h"
#include "wbemcli.h"

#include "wine/debug.h"
#include "wbemprox_private.h"

WINE_DEFAULT_DEBUG_CHANNEL(wbemprox);

struct enum_class_object
{
    IEnumWbemClassObject IEnumWbemClassObject_iface;
    LONG refs;
37
    struct query *query;
38
    UINT index;
39
    enum wbm_namespace ns;
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
};

static inline struct enum_class_object *impl_from_IEnumWbemClassObject(
    IEnumWbemClassObject *iface )
{
    return CONTAINING_RECORD(iface, struct enum_class_object, IEnumWbemClassObject_iface);
}

static ULONG WINAPI enum_class_object_AddRef(
    IEnumWbemClassObject *iface )
{
    struct enum_class_object *ec = impl_from_IEnumWbemClassObject( iface );
    return InterlockedIncrement( &ec->refs );
}

static ULONG WINAPI enum_class_object_Release(
    IEnumWbemClassObject *iface )
{
    struct enum_class_object *ec = impl_from_IEnumWbemClassObject( iface );
    LONG refs = InterlockedDecrement( &ec->refs );
    if (!refs)
    {
        TRACE("destroying %p\n", ec);
63
        release_query( ec->query );
64
        free( ec );
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
    }
    return refs;
}

static HRESULT WINAPI enum_class_object_QueryInterface(
    IEnumWbemClassObject *iface,
    REFIID riid,
    void **ppvObject )
{
    struct enum_class_object *ec = impl_from_IEnumWbemClassObject( iface );

    TRACE("%p, %s, %p\n", ec, debugstr_guid( riid ), ppvObject );

    if ( IsEqualGUID( riid, &IID_IEnumWbemClassObject ) ||
         IsEqualGUID( riid, &IID_IUnknown ) )
    {
        *ppvObject = ec;
    }
83 84 85 86 87
    else if ( IsEqualGUID( riid, &IID_IClientSecurity ) )
    {
        *ppvObject = &client_security;
        return S_OK;
    }
88 89 90 91 92 93 94 95 96 97 98 99
    else
    {
        FIXME("interface %s not implemented\n", debugstr_guid(riid));
        return E_NOINTERFACE;
    }
    IEnumWbemClassObject_AddRef( iface );
    return S_OK;
}

static HRESULT WINAPI enum_class_object_Reset(
    IEnumWbemClassObject *iface )
{
100 101 102 103
    struct enum_class_object *ec = impl_from_IEnumWbemClassObject( iface );

    TRACE("%p\n", iface);

104
    ec->index = 0;
105
    return WBEM_S_NO_ERROR;
106 107 108 109 110 111 112 113 114
}

static HRESULT WINAPI enum_class_object_Next(
    IEnumWbemClassObject *iface,
    LONG lTimeout,
    ULONG uCount,
    IWbemClassObject **apObjects,
    ULONG *puReturned )
{
115 116
    struct enum_class_object *ec = impl_from_IEnumWbemClassObject( iface );
    struct view *view = ec->query->view;
117
    struct table *table;
118
    static int once = 0;
119
    HRESULT hr;
120
    ULONG i, j;
121

122
    TRACE( "%p, %ld, %lu, %p, %p\n", iface, lTimeout, uCount, apObjects, puReturned );
123 124

    if (!apObjects || !puReturned) return WBEM_E_INVALID_PARAMETER;
125
    if (lTimeout != WBEM_INFINITE && !once++) FIXME("timeout not supported\n");
126 127 128

    *puReturned = 0;

129 130 131 132
    for (i = 0; i < uCount; i++)
    {
        if (ec->index >= view->result_count) return WBEM_S_FALSE;
        table = get_view_table( view, ec->index );
133
        hr = create_class_object( ec->ns, table->name, iface, ec->index, NULL, &apObjects[i] );
134 135 136 137 138 139 140 141
        if (hr != S_OK)
        {
            for (j = 0; j < i; j++) IWbemClassObject_Release( apObjects[j] );
            return hr;
        }
        ec->index++;
        (*puReturned)++;
    }
142 143

    return WBEM_S_NO_ERROR;
144 145 146 147 148 149 150
}

static HRESULT WINAPI enum_class_object_NextAsync(
    IEnumWbemClassObject *iface,
    ULONG uCount,
    IWbemObjectSink *pSink )
{
151
    FIXME( "%p, %lu, %p\n", iface, uCount, pSink );
152 153 154 155 156 157 158
    return E_NOTIMPL;
}

static HRESULT WINAPI enum_class_object_Clone(
    IEnumWbemClassObject *iface,
    IEnumWbemClassObject **ppEnum )
{
159 160 161 162
    struct enum_class_object *ec = impl_from_IEnumWbemClassObject( iface );

    TRACE("%p, %p\n", iface, ppEnum);

163
    return EnumWbemClassObject_create( ec->query, (void **)ppEnum );
164 165 166 167 168 169 170
}

static HRESULT WINAPI enum_class_object_Skip(
    IEnumWbemClassObject *iface,
    LONG lTimeout,
    ULONG nCount )
{
171 172
    struct enum_class_object *ec = impl_from_IEnumWbemClassObject( iface );
    struct view *view = ec->query->view;
173
    static int once = 0;
174

175
    TRACE( "%p, %ld, %lu\n", iface, lTimeout, nCount );
176

177
    if (lTimeout != WBEM_INFINITE && !once++) FIXME("timeout not supported\n");
178

179
    if (!view->result_count) return WBEM_S_FALSE;
180

181
    if (nCount > view->result_count - ec->index)
182
    {
183
        ec->index = view->result_count - 1;
184 185
        return WBEM_S_FALSE;
    }
186
    ec->index += nCount;
187
    return WBEM_S_NO_ERROR;
188 189 190 191 192 193 194 195 196 197 198 199 200 201
}

static const IEnumWbemClassObjectVtbl enum_class_object_vtbl =
{
    enum_class_object_QueryInterface,
    enum_class_object_AddRef,
    enum_class_object_Release,
    enum_class_object_Reset,
    enum_class_object_Next,
    enum_class_object_NextAsync,
    enum_class_object_Clone,
    enum_class_object_Skip
};

202
HRESULT EnumWbemClassObject_create( struct query *query, LPVOID *ppObj )
203 204 205
{
    struct enum_class_object *ec;

206
    TRACE("%p\n", ppObj);
207

208
    if (!(ec = malloc( sizeof(*ec) ))) return E_OUTOFMEMORY;
209 210 211

    ec->IEnumWbemClassObject_iface.lpVtbl = &enum_class_object_vtbl;
    ec->refs  = 1;
212
    ec->query = addref_query( query );
213
    ec->index = 0;
214
    ec->ns = query->ns;
215 216 217 218 219 220 221

    *ppObj = &ec->IEnumWbemClassObject_iface;

    TRACE("returning iface %p\n", *ppObj);
    return S_OK;
}

222
static struct record *create_record( struct table *table )
223 224 225 226
{
    UINT i;
    struct record *record;

227 228
    if (!(record = malloc( sizeof(struct record) ))) return NULL;
    if (!(record->fields = malloc( table->num_cols * sizeof(struct field) )))
229
    {
230
        free( record );
231 232
        return NULL;
    }
233
    for (i = 0; i < table->num_cols; i++)
234
    {
235
        record->fields[i].type    = table->columns[i].type;
236
        record->fields[i].u.ival  = 0;
237
    }
238 239
    record->count = table->num_cols;
    record->table = addref_table( table );
240 241 242
    return record;
}

243 244
void destroy_array( struct array *array, CIMTYPE type )
{
245
    UINT i;
246
    if (!array) return;
247
    if (type == CIM_STRING || type == CIM_DATETIME || type == CIM_REFERENCE)
248
    {
249
        for (i = 0; i < array->count; i++) free( *(WCHAR **)((char *)array->ptr + i * array->elem_size) );
250
    }
251 252
    free( array->ptr );
    free( array );
253 254
}

255 256 257 258 259
static void destroy_record( struct record *record )
{
    UINT i;

    if (!record) return;
260
    release_table( record->table );
261 262
    for (i = 0; i < record->count; i++)
    {
263 264
        if (record->fields[i].type == CIM_STRING ||
            record->fields[i].type == CIM_DATETIME ||
265
            record->fields[i].type == CIM_REFERENCE) free( record->fields[i].u.sval );
266 267
        else if (record->fields[i].type & CIM_FLAG_ARRAY)
            destroy_array( record->fields[i].u.aval, record->fields[i].type & CIM_TYPE_MASK );
268
    }
269 270
    free( record->fields );
    free( record );
271 272
}

273 274 275 276
struct class_object
{
    IWbemClassObject IWbemClassObject_iface;
    LONG refs;
277
    WCHAR *name;
278 279
    IEnumWbemClassObject *iter;
    UINT index;
280
    UINT index_method;
281
    UINT index_property;
282
    enum wbm_namespace ns;
283
    struct record *record; /* uncommitted instance */
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
};

static inline struct class_object *impl_from_IWbemClassObject(
    IWbemClassObject *iface )
{
    return CONTAINING_RECORD(iface, struct class_object, IWbemClassObject_iface);
}

static ULONG WINAPI class_object_AddRef(
    IWbemClassObject *iface )
{
    struct class_object *co = impl_from_IWbemClassObject( iface );
    return InterlockedIncrement( &co->refs );
}

static ULONG WINAPI class_object_Release(
    IWbemClassObject *iface )
{
    struct class_object *co = impl_from_IWbemClassObject( iface );
    LONG refs = InterlockedDecrement( &co->refs );
    if (!refs)
    {
        TRACE("destroying %p\n", co);
307
        if (co->iter) IEnumWbemClassObject_Release( co->iter );
308
        destroy_record( co->record );
309 310
        free( co->name );
        free( co );
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
    }
    return refs;
}

static HRESULT WINAPI class_object_QueryInterface(
    IWbemClassObject *iface,
    REFIID riid,
    void **ppvObject )
{
    struct class_object *co = impl_from_IWbemClassObject( iface );

    TRACE("%p, %s, %p\n", co, debugstr_guid( riid ), ppvObject );

    if ( IsEqualGUID( riid, &IID_IWbemClassObject ) ||
         IsEqualGUID( riid, &IID_IUnknown ) )
    {
        *ppvObject = co;
    }
329 330 331 332 333
    else if (IsEqualGUID( riid, &IID_IClientSecurity ))
    {
        *ppvObject = &client_security;
        return S_OK;
    }
334 335 336 337 338 339 340 341 342 343 344 345 346
    else
    {
        FIXME("interface %s not implemented\n", debugstr_guid(riid));
        return E_NOINTERFACE;
    }
    IWbemClassObject_AddRef( iface );
    return S_OK;
}

static HRESULT WINAPI class_object_GetQualifierSet(
    IWbemClassObject *iface,
    IWbemQualifierSet **ppQualSet )
{
347 348 349 350
    struct class_object *co = impl_from_IWbemClassObject( iface );

    TRACE("%p, %p\n", iface, ppQualSet);

351
    return WbemQualifierSet_create( co->ns, co->name, NULL, (void **)ppQualSet );
352 353
}

354 355
static HRESULT record_get_value( const struct record *record, UINT index, VARIANT *var, CIMTYPE *type )
{
356
    VARTYPE vartype = to_vartype( record->fields[index].type & CIM_TYPE_MASK );
357

358
    if (type) *type = record->fields[index].type;
359
    if (!var) return S_OK;
360

361 362
    if (record->fields[index].type & CIM_FLAG_ARRAY)
    {
363
        V_VT( var ) = vartype | VT_ARRAY;
364
        V_ARRAY( var ) = to_safearray( record->fields[index].u.aval, record->fields[index].type & CIM_TYPE_MASK );
365 366
        return S_OK;
    }
367 368 369 370
    switch (record->fields[index].type)
    {
    case CIM_STRING:
    case CIM_DATETIME:
371
    case CIM_REFERENCE:
372
        V_BSTR( var ) = SysAllocString( record->fields[index].u.sval );
373
        break;
374 375
    case CIM_SINT32:
        V_I4( var ) = record->fields[index].u.ival;
376
        break;
377 378
    case CIM_UINT32:
        V_UI4( var ) = record->fields[index].u.ival;
379
        break;
380 381
    default:
        FIXME("unhandled type %u\n", record->fields[index].type);
382
        return WBEM_E_INVALID_PARAMETER;
383
    }
384 385
    V_VT( var ) = vartype;
    return S_OK;
386 387
}

388 389 390 391 392 393 394 395
static HRESULT WINAPI class_object_Get(
    IWbemClassObject *iface,
    LPCWSTR wszName,
    LONG lFlags,
    VARIANT *pVal,
    CIMTYPE *pType,
    LONG *plFlavor )
{
396 397 398
    struct class_object *co = impl_from_IWbemClassObject( iface );
    struct enum_class_object *ec = impl_from_IEnumWbemClassObject( co->iter );

399
    TRACE( "%p, %s, %#lx, %p, %p, %p\n", iface, debugstr_w(wszName), lFlags, pVal, pType, plFlavor );
400

401 402 403 404 405
    if (co->record)
    {
        UINT index;
        HRESULT hr;

406
        if ((hr = get_column_index( co->record->table, wszName, &index )) != S_OK) return hr;
407 408 409
        return record_get_value( co->record, index, pVal, pType );
    }
    return get_propval( ec->query->view, co->index, wszName, pVal, pType, plFlavor );
410 411
}

412 413 414 415 416 417
static HRESULT record_set_value( struct record *record, UINT index, VARIANT *var )
{
    LONGLONG val;
    CIMTYPE type;
    HRESULT hr;

418
    if ((hr = to_longlong( var, &val, &type )) != S_OK) return hr;
419 420
    if (type != record->fields[index].type) return WBEM_E_TYPE_MISMATCH;

421 422 423 424 425
    if (type & CIM_FLAG_ARRAY)
    {
        record->fields[index].u.aval = (struct array *)(INT_PTR)val;
        return S_OK;
    }
426 427 428 429
    switch (type)
    {
    case CIM_STRING:
    case CIM_DATETIME:
430
    case CIM_REFERENCE:
431 432 433 434 435 436 437 438 439
        record->fields[index].u.sval = (WCHAR *)(INT_PTR)val;
        return S_OK;
    case CIM_SINT16:
    case CIM_UINT16:
    case CIM_SINT32:
    case CIM_UINT32:
        record->fields[index].u.ival = val;
        return S_OK;
    default:
440
        FIXME( "unhandled type %lu\n", type );
441 442 443 444 445
        break;
    }
    return WBEM_E_INVALID_PARAMETER;
}

446 447 448 449 450 451 452
static HRESULT WINAPI class_object_Put(
    IWbemClassObject *iface,
    LPCWSTR wszName,
    LONG lFlags,
    VARIANT *pVal,
    CIMTYPE Type )
{
453 454 455
    struct class_object *co = impl_from_IWbemClassObject( iface );
    struct enum_class_object *ec = impl_from_IEnumWbemClassObject( co->iter );

456
    TRACE( "%p, %s, %#lx, %p, %lu\n", iface, debugstr_w(wszName), lFlags, pVal, Type );
457

458 459 460 461 462
    if (co->record)
    {
        UINT index;
        HRESULT hr;

463
        if ((hr = get_column_index( co->record->table, wszName, &index )) != S_OK) return hr;
464 465
        return record_set_value( co->record, index, pVal );
    }
466 467 468

    if (!ec) return S_OK;

469
    return put_propval( ec->query->view, co->index, wszName, pVal, Type );
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
}

static HRESULT WINAPI class_object_Delete(
    IWbemClassObject *iface,
    LPCWSTR wszName )
{
    FIXME("%p, %s\n", iface, debugstr_w(wszName));
    return E_NOTIMPL;
}

static HRESULT WINAPI class_object_GetNames(
    IWbemClassObject *iface,
    LPCWSTR wszQualifierName,
    LONG lFlags,
    VARIANT *pQualifierVal,
485
    SAFEARRAY **pNames )
486
{
487 488 489
    struct class_object *co = impl_from_IWbemClassObject( iface );
    struct enum_class_object *ec = impl_from_IEnumWbemClassObject( co->iter );

490
    TRACE( "%p, %s, %#lx, %s, %p\n", iface, debugstr_w(wszQualifierName), lFlags,
491
          debugstr_variant(pQualifierVal), pNames);
492

493 494 495 496 497 498 499 500
    if (!pNames)
        return WBEM_E_INVALID_PARAMETER;

    /* Combination used in a handful of broken apps */
    if (lFlags == (WBEM_FLAG_ALWAYS | WBEM_MASK_CONDITION_ORIGIN))
        lFlags = WBEM_FLAG_ALWAYS;

    if (lFlags && (lFlags != WBEM_FLAG_ALWAYS &&
501
        lFlags != WBEM_FLAG_NONSYSTEM_ONLY &&
502
        lFlags != WBEM_FLAG_SYSTEM_ONLY))
503
    {
504
        FIXME( "flags %#lx not supported\n", lFlags );
505 506
        return E_NOTIMPL;
    }
507

508 509 510
    if (wszQualifierName || pQualifierVal)
        FIXME("qualifier not supported\n");

511
    return get_properties( ec->query->view, co->index, lFlags, pNames );
512 513 514 515 516 517
}

static HRESULT WINAPI class_object_BeginEnumeration(
    IWbemClassObject *iface,
    LONG lEnumFlags )
{
518 519
    struct class_object *co = impl_from_IWbemClassObject( iface );

520
    TRACE( "%p, %#lx\n", iface, lEnumFlags );
521

522
    if (lEnumFlags) FIXME( "flags %#lx not supported\n", lEnumFlags );
523 524 525

    co->index_property = 0;
    return S_OK;
526 527 528 529 530 531 532 533 534 535
}

static HRESULT WINAPI class_object_Next(
    IWbemClassObject *iface,
    LONG lFlags,
    BSTR *strName,
    VARIANT *pVal,
    CIMTYPE *pType,
    LONG *plFlavor )
{
536 537 538
    struct class_object *obj = impl_from_IWbemClassObject( iface );
    struct enum_class_object *iter = impl_from_IEnumWbemClassObject( obj->iter );
    struct view *view = iter->query->view;
539
    struct table *table = get_view_table( view, obj->index );
540
    BSTR prop;
541
    HRESULT hr;
542
    UINT i;
543

544
    TRACE( "%p, %#lx, %p, %p, %p, %p\n", iface, lFlags, strName, pVal, pType, plFlavor );
545

546
    for (i = obj->index_property; i < table->num_cols; i++)
547
    {
548 549 550
        if (is_method( table, i )) continue;
        if (!is_result_prop( view, table->columns[i].name )) continue;
        if (!(prop = SysAllocString( table->columns[i].name ))) return E_OUTOFMEMORY;
551 552 553 554 555 556 557 558 559 560 561
        if (obj->record)
        {
            UINT index;

            if ((hr = get_column_index( table, table->columns[i].name, &index )) == S_OK)
                hr = record_get_value( obj->record, index, pVal, pType );
        }
        else
            hr = get_propval( view, obj->index, prop, pVal, pType, plFlavor );

        if (FAILED(hr))
562 563 564 565
        {
            SysFreeString( prop );
            return hr;
        }
566

567
        obj->index_property = i + 1;
568 569 570
        if (strName) *strName = prop;
        else SysFreeString( prop );

571
        return S_OK;
572
    }
573
    return WBEM_S_NO_MORE_DATA;
574 575 576 577 578
}

static HRESULT WINAPI class_object_EndEnumeration(
    IWbemClassObject *iface )
{
579 580 581 582 583 584
    struct class_object *co = impl_from_IWbemClassObject( iface );

    TRACE("%p\n", iface);

    co->index_property = 0;
    return S_OK;
585 586 587 588 589 590 591
}

static HRESULT WINAPI class_object_GetPropertyQualifierSet(
    IWbemClassObject *iface,
    LPCWSTR wszProperty,
    IWbemQualifierSet **ppQualSet )
{
592 593 594 595
    struct class_object *co = impl_from_IWbemClassObject( iface );

    TRACE("%p, %s, %p\n", iface, debugstr_w(wszProperty), ppQualSet);

596
    return WbemQualifierSet_create( co->ns, co->name, wszProperty, (void **)ppQualSet );
597 598 599 600 601 602 603 604 605 606
}

static HRESULT WINAPI class_object_Clone(
    IWbemClassObject *iface,
    IWbemClassObject **ppCopy )
{
    FIXME("%p, %p\n", iface, ppCopy);
    return E_NOTIMPL;
}

607 608 609 610 611 612 613 614 615
static BSTR get_body_text( const struct table *table, UINT row, UINT *len )
{
    BSTR value, ret;
    WCHAR *p;
    UINT i;

    *len = 0;
    for (i = 0; i < table->num_cols; i++)
    {
616 617
        if ((value = get_value_bstr( table, row, i )))
        {
618
            *len += ARRAY_SIZE( L"\n\t%s = %s;" );
619
            *len += lstrlenW( table->columns[i].name );
620 621 622
            *len += SysStringLen( value );
            SysFreeString( value );
        }
623 624 625 626 627
    }
    if (!(ret = SysAllocStringLen( NULL, *len ))) return NULL;
    p = ret;
    for (i = 0; i < table->num_cols; i++)
    {
628 629
        if ((value = get_value_bstr( table, row, i )))
        {
630
            p += swprintf( p, *len - (p - ret), L"\n\t%s = %s;", table->columns[i].name, value );
631 632
            SysFreeString( value );
        }
633 634 635 636 637 638 639
    }
    return ret;
}

static BSTR get_object_text( const struct view *view, UINT index )
{
    UINT len, len_body, row = view->result[index];
640
    struct table *table = get_view_table( view, index );
641 642
    BSTR ret, body;

643
    len = ARRAY_SIZE( L"\ninstance of %s\n{%s\n};" );
644 645
    len += lstrlenW( table->name );
    if (!(body = get_body_text( table, row, &len_body ))) return NULL;
646 647 648
    len += len_body;

    if (!(ret = SysAllocStringLen( NULL, len ))) return NULL;
649
    swprintf( ret, len, L"\ninstance of %s\n{%s\n};", table->name, body );
650 651 652 653
    SysFreeString( body );
    return ret;
}

654 655 656 657 658
static HRESULT WINAPI class_object_GetObjectText(
    IWbemClassObject *iface,
    LONG lFlags,
    BSTR *pstrObjectText )
{
659 660 661 662 663
    struct class_object *co = impl_from_IWbemClassObject( iface );
    struct enum_class_object *ec = impl_from_IEnumWbemClassObject( co->iter );
    struct view *view = ec->query->view;
    BSTR text;

664
    TRACE( "%p, %#lx, %p\n", iface, lFlags, pstrObjectText );
665

666
    if (lFlags) FIXME( "flags %#lx not implemented\n", lFlags );
667 668 669 670

    if (!(text = get_object_text( view, co->index ))) return E_OUTOFMEMORY;
    *pstrObjectText = text;
    return S_OK;
671 672 673 674 675 676 677
}

static HRESULT WINAPI class_object_SpawnDerivedClass(
    IWbemClassObject *iface,
    LONG lFlags,
    IWbemClassObject **ppNewClass )
{
678
    FIXME( "%p, %#lx, %p\n", iface, lFlags, ppNewClass );
679 680 681 682 683 684 685 686
    return E_NOTIMPL;
}

static HRESULT WINAPI class_object_SpawnInstance(
    IWbemClassObject *iface,
    LONG lFlags,
    IWbemClassObject **ppNewInstance )
{
687 688
    struct class_object *co = impl_from_IWbemClassObject( iface );
    struct enum_class_object *ec = impl_from_IEnumWbemClassObject( co->iter );
689
    struct table *table = get_view_table( ec->query->view, co->index );
690
    IEnumWbemClassObject *iter;
691
    struct record *record;
692
    HRESULT hr;
693

694
    TRACE( "%p, %#lx, %p\n", iface, lFlags, ppNewInstance );
695

696
    if (!(record = create_record( table ))) return E_OUTOFMEMORY;
697 698 699 700 701
    if (FAILED(hr = IEnumWbemClassObject_Clone( co->iter, &iter )))
    {
        destroy_record( record );
        return hr;
    }
702
    hr = create_class_object( co->ns, co->name, iter, 0, record, ppNewInstance );
703 704
    IEnumWbemClassObject_Release( iter );
    return hr;
705 706 707 708 709 710 711
}

static HRESULT WINAPI class_object_CompareTo(
    IWbemClassObject *iface,
    LONG lFlags,
    IWbemClassObject *pCompareTo )
{
712
    FIXME( "%p, %#lx, %p\n", iface, lFlags, pCompareTo );
713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
    return E_NOTIMPL;
}

static HRESULT WINAPI class_object_GetPropertyOrigin(
    IWbemClassObject *iface,
    LPCWSTR wszName,
    BSTR *pstrClassName )
{
    FIXME("%p, %s, %p\n", iface, debugstr_w(wszName), pstrClassName);
    return E_NOTIMPL;
}

static HRESULT WINAPI class_object_InheritsFrom(
    IWbemClassObject *iface,
    LPCWSTR strAncestor )
{
    FIXME("%p, %s\n", iface, debugstr_w(strAncestor));
    return E_NOTIMPL;
}

733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
static UINT count_instances( IEnumWbemClassObject *iter )
{
    UINT count = 0;
    while (!IEnumWbemClassObject_Skip( iter, WBEM_INFINITE, 1 )) count++;
    IEnumWbemClassObject_Reset( iter );
    return count;
}

static void set_default_value( CIMTYPE type, UINT val, BYTE *ptr )
{
    switch (type)
    {
    case CIM_SINT16:
        *(INT16 *)ptr = val;
        break;
    case CIM_UINT16:
        *(UINT16 *)ptr = val;
        break;
    case CIM_SINT32:
        *(INT32 *)ptr = val;
        break;
    case CIM_UINT32:
        *(UINT32 *)ptr = val;
        break;
    default:
758
        FIXME( "unhandled type %lu\n", type );
759 760 761 762
        break;
    }
}

763
static HRESULT create_signature_columns_and_data( IEnumWbemClassObject *iter, UINT *num_cols,
764 765 766 767 768 769 770 771 772 773 774 775
                                           struct column **cols, BYTE **data )
{
    struct column *columns;
    BYTE *row;
    IWbemClassObject *param;
    VARIANT val;
    HRESULT hr = E_OUTOFMEMORY;
    UINT offset = 0;
    ULONG count;
    int i = 0;

    count = count_instances( iter );
776 777
    if (!(columns = malloc( count * sizeof(struct column) ))) return E_OUTOFMEMORY;
    if (!(row = calloc( count, sizeof(LONGLONG) ))) goto error;
778 779 780 781 782 783

    for (;;)
    {
        IEnumWbemClassObject_Next( iter, WBEM_INFINITE, 1, &param, &count );
        if (!count) break;

784
        hr = IWbemClassObject_Get( param, L"Parameter", 0, &val, NULL, NULL );
785
        if (hr != S_OK) goto error;
786
        columns[i].name = wcsdup( V_BSTR( &val ) );
787 788
        VariantClear( &val );

789
        hr = IWbemClassObject_Get( param, L"Type", 0, &val, NULL, NULL );
790
        if (hr != S_OK) goto error;
791 792
        columns[i].type = V_UI4( &val );

793
        hr = IWbemClassObject_Get( param, L"DefaultValue", 0, &val, NULL, NULL );
794 795 796 797 798 799 800 801 802 803 804 805 806
        if (hr != S_OK) goto error;
        if (V_UI4( &val )) set_default_value( columns[i].type, V_UI4( &val ), row + offset );
        offset += get_type_size( columns[i].type );

        IWbemClassObject_Release( param );
        i++;
    }
    *num_cols = i;
    *cols = columns;
    *data = row;
    return S_OK;

error:
807 808 809
    for (; i >= 0; i--) free( (WCHAR *)columns[i].name );
    free( columns );
    free( row );
810 811 812
    return hr;
}

813
static HRESULT create_signature_table( IEnumWbemClassObject *iter, enum wbm_namespace ns, WCHAR *name )
814 815 816 817 818 819 820 821 822 823
{
    HRESULT hr;
    struct table *table;
    struct column *columns;
    UINT num_cols;
    BYTE *row;

    hr = create_signature_columns_and_data( iter, &num_cols, &columns, &row );
    if (hr != S_OK) return hr;

824
    if (!(table = create_table( name, num_cols, columns, 1, 1, row, NULL )))
825 826
    {
        free_columns( columns, num_cols );
827
        free( row );
828 829
        return E_OUTOFMEMORY;
    }
830
    if (!add_table( ns, table )) free_table( table ); /* already exists */
831 832 833
    return S_OK;
}

834
static WCHAR *build_signature_table_name( const WCHAR *class, const WCHAR *method, enum param_direction dir )
835
{
836
    UINT len = ARRAY_SIZE(L"__%s_%s_%s") + ARRAY_SIZE(L"OUT") + lstrlenW( class ) + lstrlenW( method );
837 838
    WCHAR *ret;

839
    if (!(ret = malloc( len * sizeof(WCHAR) ))) return NULL;
840
    swprintf( ret, len, L"__%s_%s_%s", class, method, dir == PARAM_IN ? L"IN" : L"OUT" );
841
    return wcsupr( ret );
842 843
}

844
HRESULT create_signature( enum wbm_namespace ns, const WCHAR *class, const WCHAR *method, enum param_direction dir,
845
                          IWbemClassObject **sig )
846
{
847 848
    static const WCHAR selectW[] = L"SELECT * FROM __PARAMETERS WHERE Class='%s' AND Method='%s' AND Direction%s";
    UINT len = ARRAY_SIZE(selectW) + ARRAY_SIZE(L">=0");
849 850 851 852
    IEnumWbemClassObject *iter;
    WCHAR *query, *name;
    HRESULT hr;

853
    len += lstrlenW( class ) + lstrlenW( method );
854
    if (!(query = malloc( len * sizeof(WCHAR) ))) return E_OUTOFMEMORY;
855
    swprintf( query, len, selectW, class, method, dir >= 0 ? L">=0" : L"<=0" );
856

857
    hr = exec_query( ns, query, &iter );
858
    free( query );
859 860
    if (hr != S_OK) return hr;

861 862 863 864 865 866 867
    if (!count_instances( iter ))
    {
        *sig = NULL;
        IEnumWbemClassObject_Release( iter );
        return S_OK;
    }

868 869 870 871 872
    if (!(name = build_signature_table_name( class, method, dir )))
    {
        IEnumWbemClassObject_Release( iter );
        return E_OUTOFMEMORY;
    }
873
    hr = create_signature_table( iter, ns, name );
874
    IEnumWbemClassObject_Release( iter );
875
    if (hr == S_OK)
876
        hr = get_object( ns, name, sig );
877

878
    free( name );
879
    return hr;
880 881
}

882 883 884 885 886 887 888
static HRESULT WINAPI class_object_GetMethod(
    IWbemClassObject *iface,
    LPCWSTR wszName,
    LONG lFlags,
    IWbemClassObject **ppInSignature,
    IWbemClassObject **ppOutSignature )
{
889
    struct class_object *co = impl_from_IWbemClassObject( iface );
890
    IWbemClassObject *in, *out;
891 892
    struct table *table;
    unsigned int i;
893 894
    HRESULT hr;

895
    TRACE( "%p, %s, %#lx, %p, %p\n", iface, debugstr_w(wszName), lFlags, ppInSignature, ppOutSignature );
896

897 898 899 900 901 902 903 904 905 906 907 908 909 910 911
    if (ppInSignature) *ppInSignature = NULL;
    if (ppOutSignature) *ppOutSignature = NULL;

    table = get_view_table( impl_from_IEnumWbemClassObject( co->iter )->query->view, co->index );

    for (i = 0; i < table->num_cols; ++i)
    {
        if (is_method( table, i ) && !lstrcmpiW( table->columns[i].name, wszName )) break;
    }
    if (i == table->num_cols)
    {
        FIXME("Method %s not found in class %s.\n", debugstr_w(wszName), debugstr_w(co->name));
        return WBEM_E_NOT_FOUND;
    }

912
    hr = create_signature( co->ns, co->name, wszName, PARAM_IN, &in );
913
    if (hr != S_OK) return hr;
914

915
    hr = create_signature( co->ns, co->name, wszName, PARAM_OUT, &out );
916 917 918
    if (hr == S_OK)
    {
        if (ppInSignature) *ppInSignature = in;
919
        else if (in) IWbemClassObject_Release( in );
920
        if (ppOutSignature) *ppOutSignature = out;
921
        else if (out) IWbemClassObject_Release( out );
922 923
    }
    else IWbemClassObject_Release( in );
924
    return hr;
925 926 927 928 929 930 931 932 933
}

static HRESULT WINAPI class_object_PutMethod(
    IWbemClassObject *iface,
    LPCWSTR wszName,
    LONG lFlags,
    IWbemClassObject *pInSignature,
    IWbemClassObject *pOutSignature )
{
934
    FIXME( "%p, %s, %#lx, %p, %p\n", iface, debugstr_w(wszName), lFlags, pInSignature, pOutSignature );
935 936 937 938 939 940 941 942 943 944 945 946 947 948 949
    return E_NOTIMPL;
}

static HRESULT WINAPI class_object_DeleteMethod(
    IWbemClassObject *iface,
    LPCWSTR wszName )
{
    FIXME("%p, %s\n", iface, debugstr_w(wszName));
    return E_NOTIMPL;
}

static HRESULT WINAPI class_object_BeginMethodEnumeration(
    IWbemClassObject *iface,
    LONG lEnumFlags)
{
950 951
    struct class_object *co = impl_from_IWbemClassObject( iface );

952
    TRACE( "%p, %#lx\n", iface, lEnumFlags );
953

954
    if (lEnumFlags) FIXME( "flags %#lx not supported\n", lEnumFlags );
955 956 957

    co->index_method = 0;
    return S_OK;
958 959 960 961 962 963 964 965 966
}

static HRESULT WINAPI class_object_NextMethod(
    IWbemClassObject *iface,
    LONG lFlags,
    BSTR *pstrName,
    IWbemClassObject **ppInSignature,
    IWbemClassObject **ppOutSignature)
{
967
    struct class_object *co = impl_from_IWbemClassObject( iface );
968
    BSTR method;
969 970
    HRESULT hr;

971
    TRACE( "%p, %#lx, %p, %p, %p\n", iface, lFlags, pstrName, ppInSignature, ppOutSignature );
972

973
    if (!(method = get_method_name( co->ns, co->name, co->index_method ))) return WBEM_S_NO_MORE_DATA;
974

975
    hr = create_signature( co->ns, co->name, method, PARAM_IN, ppInSignature );
976 977 978 979 980
    if (hr != S_OK)
    {
        SysFreeString( method );
        return hr;
    }
981
    hr = create_signature( co->ns, co->name, method, PARAM_OUT, ppOutSignature );
982 983 984
    if (hr != S_OK)
    {
        SysFreeString( method );
985 986
        if (*ppInSignature)
            IWbemClassObject_Release( *ppInSignature );
987
    }
988 989
    else
    {
990
        *pstrName = method;
991 992 993
        co->index_method++;
    }
    return hr;
994 995 996 997 998
}

static HRESULT WINAPI class_object_EndMethodEnumeration(
    IWbemClassObject *iface )
{
999 1000 1001 1002 1003 1004
    struct class_object *co = impl_from_IWbemClassObject( iface );

    TRACE("%p\n", iface);

    co->index_method = 0;
    return S_OK;
1005 1006 1007 1008 1009 1010 1011
}

static HRESULT WINAPI class_object_GetMethodQualifierSet(
    IWbemClassObject *iface,
    LPCWSTR wszMethod,
    IWbemQualifierSet **ppQualSet)
{
1012 1013 1014 1015
    struct class_object *co = impl_from_IWbemClassObject( iface );

    TRACE("%p, %s, %p\n", iface, debugstr_w(wszMethod), ppQualSet);

1016
    return WbemQualifierSet_create( co->ns, co->name, wszMethod, (void **)ppQualSet );
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058
}

static HRESULT WINAPI class_object_GetMethodOrigin(
    IWbemClassObject *iface,
    LPCWSTR wszMethodName,
    BSTR *pstrClassName)
{
    FIXME("%p, %s, %p\n", iface, debugstr_w(wszMethodName), pstrClassName);
    return E_NOTIMPL;
}

static const IWbemClassObjectVtbl class_object_vtbl =
{
    class_object_QueryInterface,
    class_object_AddRef,
    class_object_Release,
    class_object_GetQualifierSet,
    class_object_Get,
    class_object_Put,
    class_object_Delete,
    class_object_GetNames,
    class_object_BeginEnumeration,
    class_object_Next,
    class_object_EndEnumeration,
    class_object_GetPropertyQualifierSet,
    class_object_Clone,
    class_object_GetObjectText,
    class_object_SpawnDerivedClass,
    class_object_SpawnInstance,
    class_object_CompareTo,
    class_object_GetPropertyOrigin,
    class_object_InheritsFrom,
    class_object_GetMethod,
    class_object_PutMethod,
    class_object_DeleteMethod,
    class_object_BeginMethodEnumeration,
    class_object_NextMethod,
    class_object_EndMethodEnumeration,
    class_object_GetMethodQualifierSet,
    class_object_GetMethodOrigin
};

1059
HRESULT create_class_object( enum wbm_namespace ns, const WCHAR *name, IEnumWbemClassObject *iter, UINT index,
1060
                             struct record *record, IWbemClassObject **obj )
1061 1062 1063
{
    struct class_object *co;

1064
    TRACE("%s, %p\n", debugstr_w(name), obj);
1065

1066
    if (!(co = malloc( sizeof(*co) ))) return E_OUTOFMEMORY;
1067 1068

    co->IWbemClassObject_iface.lpVtbl = &class_object_vtbl;
1069
    co->refs  = 1;
1070
    if (!name) co->name = NULL;
1071
    else if (!(co->name = wcsdup( name )))
1072
    {
1073
        free( co );
1074 1075
        return E_OUTOFMEMORY;
    }
1076 1077 1078
    co->iter           = iter;
    co->index          = index;
    co->index_method   = 0;
1079
    co->index_property = 0;
1080
    co->record         = record;
1081
    co->ns             = ns;
1082
    if (iter) IEnumWbemClassObject_AddRef( iter );
1083

1084
    *obj = &co->IWbemClassObject_iface;
1085

1086
    TRACE("returning iface %p\n", *obj);
1087 1088
    return S_OK;
}