[PATCH 7/7] wbemprox: Add support for evaluating ASSOCIATORS OF queries.

Hans Leidekker hans at codeweavers.com
Tue Sep 10 10:09:14 CDT 2019


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/wbemprox/builtin.c          |  40 ++-
 dlls/wbemprox/class.c            |  36 ++-
 dlls/wbemprox/query.c            | 509 ++++++++++++++++++++++++-------
 dlls/wbemprox/services.c         |  21 +-
 dlls/wbemprox/wbemprox_private.h |  36 ++-
 dlls/wbemprox/wql.y              |  10 +-
 6 files changed, 496 insertions(+), 156 deletions(-)

diff --git a/dlls/wbemprox/builtin.c b/dlls/wbemprox/builtin.c
index de793f3f7e..8bb5be0aac 100644
--- a/dlls/wbemprox/builtin.c
+++ b/dlls/wbemprox/builtin.c
@@ -50,6 +50,8 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(wbemprox);
 
+static const WCHAR class_associatorsW[] =
+    {'_','_','A','S','S','O','C','I','A','T','O','R','S',0};
 static const WCHAR class_baseboardW[] =
     {'W','i','n','3','2','_','B','a','s','e','B','o','a','r','d',0};
 static const WCHAR class_biosW[] =
@@ -137,6 +139,10 @@ static const WCHAR prop_antecedentW[] =
     {'A','n','t','e','c','e','d','e','n','t',0};
 static const WCHAR prop_architectureW[] =
     {'A','r','c','h','i','t','e','c','t','u','r','e',0};
+static const WCHAR prop_assocclassW[] =
+    {'A','s','s','o','c','C','l','a','s','s',0};
+static const WCHAR prop_associatorW[] =
+    {'A','s','s','o','c','i','a','t','o','r',0};
 static const WCHAR prop_attributesW[] =
     {'A','t','t','r','i','b','u','t','e','s',0};
 static const WCHAR prop_availabilityW[] =
@@ -433,6 +439,12 @@ static const WCHAR prop_workingsetsizeW[] =
     {'W','o','r','k','i','n','g','S','e','t','S','i','z','e',0};
 
 /* column definitions must be kept in sync with record structures below */
+static const struct column col_associator[] =
+{
+    { prop_assocclassW, CIM_STRING },
+    { prop_classW,      CIM_STRING },
+    { prop_associatorW, CIM_STRING }
+};
 static const struct column col_baseboard[] =
 {
     { prop_manufacturerW,  CIM_STRING|COL_FLAG_DYNAMIC },
@@ -871,6 +883,12 @@ static const WCHAR videocontroller_statusW[] =
     {'O','K',0};
 
 #include "pshpack1.h"
+struct record_associator
+{
+    const WCHAR *assocclass;
+    const WCHAR *class;
+    const WCHAR *associator;
+};
 struct record_baseboard
 {
     const WCHAR *manufacturer;
@@ -1214,6 +1232,11 @@ struct record_videocontroller
 };
 #include "poppack.h"
 
+static const struct record_associator data_associator[] =
+{
+    { class_diskdrivetodiskpartitionW, class_diskpartitionW, class_diskdriveW },
+    { class_logicaldisktopartitionW, class_logicaldiskW, class_diskpartitionW },
+};
 static const struct record_param data_param[] =
 {
     { class_processW, method_getownerW, -1, param_returnvalueW, CIM_UINT32, VT_I4 },
@@ -2489,9 +2512,9 @@ static struct association *get_diskdrivetodiskpartition_pairs( UINT *count )
     if ((hr = parse_query( select2W, &query2->view, &query2->mem )) != S_OK) goto done;
     if ((hr = execute_view( query2->view )) != S_OK) goto done;
 
-    if (!(ret = heap_alloc_zero( query->view->count * sizeof(*ret) ))) goto done;
+    if (!(ret = heap_alloc_zero( query->view->result_count * sizeof(*ret) ))) goto done;
 
-    for (i = 0; i < query->view->count; i++)
+    for (i = 0; i < query->view->result_count; i++)
     {
         if ((hr = get_propval( query->view, i, pathW, &val, NULL, NULL )) != S_OK) goto done;
         if (!(ret[i].ref = heap_strdupW( V_BSTR(&val) ))) goto done;
@@ -2502,10 +2525,10 @@ static struct association *get_diskdrivetodiskpartition_pairs( UINT *count )
         VariantClear( &val );
     }
 
-    *count = query->view->count;
+    *count = query->view->result_count;
 
 done:
-    if (!ret) free_assocations( ret, query->view->count );
+    if (!ret) free_assocations( ret, query->view->result_count );
     free_query( query );
     free_query( query2 );
     return ret;
@@ -2754,10 +2777,10 @@ static struct association *get_logicaldisktopartition_pairs( UINT *count )
     if ((hr = parse_query( select2W, &query2->view, &query2->mem )) != S_OK) goto done;
     if ((hr = execute_view( query2->view )) != S_OK) goto done;
 
-    if (!(ret = heap_alloc_zero( query->view->count * sizeof(*ret) ))) goto done;
+    if (!(ret = heap_alloc_zero( query->view->result_count * sizeof(*ret) ))) goto done;
 
     /* assume fixed and removable disks are enumerated in the same order as partitions */
-    for (i = 0; i < query->view->count; i++)
+    for (i = 0; i < query->view->result_count; i++)
     {
         if ((hr = get_propval( query->view, i, pathW, &val, NULL, NULL )) != S_OK) goto done;
         if (!(ret[i].ref = heap_strdupW( V_BSTR(&val) ))) goto done;
@@ -2768,10 +2791,10 @@ static struct association *get_logicaldisktopartition_pairs( UINT *count )
         VariantClear( &val );
     }
 
-    *count = query->view->count;
+    *count = query->view->result_count;
 
 done:
-    if (!ret) free_assocations( ret, query->view->count );
+    if (!ret) free_assocations( ret, query->view->result_count );
     free_query( query );
     free_query( query2 );
     return ret;
@@ -4266,6 +4289,7 @@ done:
 #define D(d) sizeof(d)/sizeof(d[0]), 0, (BYTE *)d
 static struct table builtin_classes[] =
 {
+    { class_associatorsW, C(col_associator), D(data_associator) },
     { class_baseboardW, C(col_baseboard), 0, 0, NULL, fill_baseboard },
     { class_biosW, C(col_bios), 0, 0, NULL, fill_bios },
     { class_cdromdriveW, C(col_cdromdrive), 0, 0, NULL, fill_cdromdrive },
diff --git a/dlls/wbemprox/class.c b/dlls/wbemprox/class.c
index d0522787a2..5f8dcea10d 100644
--- a/dlls/wbemprox/class.c
+++ b/dlls/wbemprox/class.c
@@ -113,6 +113,7 @@ static HRESULT WINAPI enum_class_object_Next(
 {
     struct enum_class_object *ec = impl_from_IEnumWbemClassObject( iface );
     struct view *view = ec->query->view;
+    struct table *table;
     static int once = 0;
     HRESULT hr;
 
@@ -123,14 +124,15 @@ static HRESULT WINAPI enum_class_object_Next(
     if (lTimeout != WBEM_INFINITE && !once++) FIXME("timeout not supported\n");
 
     *puReturned = 0;
-    if (ec->index >= view->count) return WBEM_S_FALSE;
+    if (ec->index >= view->result_count) return WBEM_S_FALSE;
 
-    hr = create_class_object( view->table->name, iface, ec->index, NULL, apObjects );
+    table = get_view_table( view, ec->index );
+    hr = create_class_object( table->name, iface, ec->index, NULL, apObjects );
     if (hr != S_OK) return hr;
 
     ec->index++;
     *puReturned = 1;
-    if (ec->index == view->count && uCount > 1) return WBEM_S_FALSE;
+    if (ec->index == view->result_count && uCount > 1) return WBEM_S_FALSE;
     if (uCount > 1) return WBEM_S_TIMEDOUT;
     return WBEM_S_NO_ERROR;
 }
@@ -168,11 +170,11 @@ static HRESULT WINAPI enum_class_object_Skip(
 
     if (lTimeout != WBEM_INFINITE && !once++) FIXME("timeout not supported\n");
 
-    if (!view->count) return WBEM_S_FALSE;
+    if (!view->result_count) return WBEM_S_FALSE;
 
-    if (nCount > view->count - ec->index)
+    if (nCount > view->result_count - ec->index)
     {
-        ec->index = view->count - 1;
+        ec->index = view->result_count - 1;
         return WBEM_S_FALSE;
     }
     ec->index += nCount;
@@ -491,7 +493,7 @@ static HRESULT WINAPI class_object_GetNames(
     if (wszQualifierName || pQualifierVal)
         FIXME("qualifier not supported\n");
 
-    return get_properties( ec->query->view, lFlags, pNames );
+    return get_properties( ec->query->view, co->index, lFlags, pNames );
 }
 
 static HRESULT WINAPI class_object_BeginEnumeration(
@@ -519,17 +521,18 @@ static HRESULT WINAPI class_object_Next(
     struct class_object *obj = impl_from_IWbemClassObject( iface );
     struct enum_class_object *iter = impl_from_IEnumWbemClassObject( obj->iter );
     struct view *view = iter->query->view;
+    struct table *table = get_view_table( view, obj->index );
     BSTR prop;
     HRESULT hr;
     UINT i;
 
     TRACE("%p, %08x, %p, %p, %p, %p\n", iface, lFlags, strName, pVal, pType, plFlavor);
 
-    for (i = obj->index_property; i < view->table->num_cols; i++)
+    for (i = obj->index_property; i < table->num_cols; i++)
     {
-        if (is_method( view->table, i )) continue;
-        if (!is_selected_prop( view, view->table->columns[i].name )) continue;
-        if (!(prop = SysAllocString( view->table->columns[i].name ))) return E_OUTOFMEMORY;
+        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;
         if ((hr = get_propval( view, obj->index, prop, pVal, pType, plFlavor )) != S_OK)
         {
             SysFreeString( prop );
@@ -612,15 +615,16 @@ static BSTR get_object_text( const struct view *view, UINT index )
     static const WCHAR fmtW[] =
         {'\n','i','n','s','t','a','n','c','e',' ','o','f',' ','%','s','\n','{','%','s','\n','}',';',0};
     UINT len, len_body, row = view->result[index];
+    struct table *table = get_view_table( view, index );
     BSTR ret, body;
 
     len = ARRAY_SIZE( fmtW );
-    len += lstrlenW( view->table->name );
-    if (!(body = get_body_text( view->table, row, &len_body ))) return NULL;
+    len += lstrlenW( table->name );
+    if (!(body = get_body_text( table, row, &len_body ))) return NULL;
     len += len_body;
 
     if (!(ret = SysAllocStringLen( NULL, len ))) return NULL;
-    swprintf( ret, len, fmtW, view->table->name, body );
+    swprintf( ret, len, fmtW, table->name, body );
     SysFreeString( body );
     return ret;
 }
@@ -660,12 +664,12 @@ static HRESULT WINAPI class_object_SpawnInstance(
 {
     struct class_object *co = impl_from_IWbemClassObject( iface );
     struct enum_class_object *ec = impl_from_IEnumWbemClassObject( co->iter );
-    struct view *view = ec->query->view;
+    struct table *table = get_view_table( ec->query->view, co->index );
     struct record *record;
 
     TRACE("%p, %08x, %p\n", iface, lFlags, ppNewInstance);
 
-    if (!(record = create_record( view->table ))) return E_OUTOFMEMORY;
+    if (!(record = create_record( table ))) return E_OUTOFMEMORY;
 
     return create_class_object( co->name, NULL, 0, record, ppNewInstance );
 }
diff --git a/dlls/wbemprox/query.c b/dlls/wbemprox/query.c
index 7b194fbabf..b311fdaf2d 100644
--- a/dlls/wbemprox/query.c
+++ b/dlls/wbemprox/query.c
@@ -29,25 +29,56 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(wbemprox);
 
-HRESULT create_view( const WCHAR *path, const struct keyword *keywordlist, const WCHAR *class,
+static HRESULT append_table( struct view *view, struct table *table )
+{
+    struct table **tmp;
+    if (!(tmp = heap_realloc( view->table, (view->table_count + 1) * sizeof(*tmp) ))) return E_OUTOFMEMORY;
+    view->table = tmp;
+    view->table[view->table_count++] = table;
+    return S_OK;
+}
+
+HRESULT create_view( enum view_type type, const WCHAR *path, const struct keyword *keywordlist, const WCHAR *class,
                      const struct property *proplist, const struct expr *cond, struct view **ret )
 {
     struct view *view = heap_alloc_zero( sizeof(*view) );
 
     if (!view) return E_OUTOFMEMORY;
-    view->path        = path;
-    view->keywordlist = keywordlist;
-    view->proplist    = proplist;
-    view->table       = grab_table( class );
-    view->cond        = cond;
+
+    switch (type)
+    {
+    case VIEW_TYPE_ASSOCIATORS:
+        view->path        = path;
+        view->keywordlist = keywordlist;
+        break;
+
+    case VIEW_TYPE_SELECT:
+    {
+        struct table *table = grab_table( class );
+        HRESULT hr;
+
+        if (table && (hr = append_table( view, table )) != S_OK) return hr;
+        view->proplist = proplist;
+        view->cond     = cond;
+        break;
+    }
+    default:
+        ERR( "unhandled type %u\n", type );
+        heap_free( view );
+        return E_INVALIDARG;
+    }
+
+    view->type = type;
     *ret = view;
     return S_OK;
 }
 
 void destroy_view( struct view *view )
 {
+    ULONG i;
     if (!view) return;
-    if (view->table) release_table( view->table );
+    for (i = 0; i < view->table_count; i++) release_table( view->table[i] );
+    heap_free( view->table );
     heap_free( view->result );
     heap_free( view );
 }
@@ -440,24 +471,242 @@ HRESULT eval_cond( const struct table *table, UINT row, const struct expr *cond,
     return WBEM_E_INVALID_QUERY;
 }
 
-HRESULT execute_view( struct view *view )
+static WCHAR *build_assoc_query( const WCHAR *class, UINT class_len )
+{
+    static const WCHAR fmtW[] =
+        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','_','_','A','S','S','O','C','I','A','T','O','R','S',
+         ' ','W','H','E','R','E',' ','C','l','a','s','s','=','\'','%','s','\'',0};
+    UINT len = class_len + ARRAY_SIZE(fmtW);
+    WCHAR *ret;
+
+    if (!(ret = heap_alloc( len * sizeof(WCHAR) ))) return NULL;
+    swprintf( ret, len, fmtW, class );
+    return ret;
+}
+
+static HRESULT create_assoc_enum( const WCHAR *class, UINT class_len, IEnumWbemClassObject **iter )
+{
+    WCHAR *query;
+    HRESULT hr;
+
+    if (!(query = build_assoc_query( class, class_len ))) return E_OUTOFMEMORY;
+    hr = exec_query( query, iter );
+    heap_free( query );
+    return hr;
+}
+
+static WCHAR *build_antecedent_query( const WCHAR *assocclass, const WCHAR *dependent )
+{
+    static const WCHAR fmtW[] =
+        {'S','E','L','E','C','T',' ','A','n','t','e','c','e','d','e','n','t',' ','F','R','O','M',' ','%','s',' ',
+         'W','H','E','R','E',' ','D','e','p','e','n','d','e','n','t','=','\'','%','s','\'',0};
+    UINT len = lstrlenW(assocclass) + lstrlenW(dependent) + ARRAY_SIZE(fmtW);
+    WCHAR *ret;
+
+    if (!(ret = heap_alloc( len * sizeof(WCHAR) ))) return NULL;
+    swprintf( ret, len, fmtW, assocclass, dependent );
+    return ret;
+}
+
+static BSTR build_servername(void)
+{
+    WCHAR server[MAX_COMPUTERNAME_LENGTH + 1], *p;
+    DWORD len = ARRAY_SIZE( server );
+
+    if (!(GetComputerNameW( server, &len ))) return NULL;
+    for (p = server; *p; p++) *p = towupper( *p );
+    return SysAllocString( server );
+}
+
+static BSTR build_namespace(void)
+{
+    static const WCHAR cimv2W[] = {'R','O','O','T','\\','C','I','M','V','2',0};
+    return SysAllocString( cimv2W );
+}
+
+static WCHAR *build_canonical_path( const WCHAR *relpath )
+{
+    static const WCHAR fmtW[] = {'\\','\\','%','s','\\','%','s',':',0};
+    BSTR server, namespace;
+    WCHAR *ret;
+    UINT len, i;
+
+    if (!(server = build_servername())) return NULL;
+    if (!(namespace = build_namespace()))
+    {
+        SysFreeString( server );
+        return NULL;
+    }
+
+    len = ARRAY_SIZE( fmtW ) + SysStringLen( server ) + SysStringLen( namespace ) + lstrlenW( relpath );
+    if ((ret = heap_alloc( len * sizeof(WCHAR ) )))
+    {
+        len = swprintf( ret, len, fmtW, server, namespace );
+        for (i = 0; i < lstrlenW( relpath ); i ++)
+        {
+            if (relpath[i] == '\'') ret[len++] = '"';
+            else ret[len++] = relpath[i];
+        }
+        ret[len] = 0;
+    }
+
+    SysFreeString( server );
+    SysFreeString( namespace );
+    return ret;
+}
+
+static HRESULT get_antecedent( const WCHAR *assocclass, const WCHAR *dependent, BSTR *ret )
+{
+    static const WCHAR antecedentW[] = {'A','n','t','e','c','e','d','e','n','t',0};
+    WCHAR *fullpath, *str;
+    IEnumWbemClassObject *iter = NULL;
+    IWbemClassObject *obj;
+    HRESULT hr = E_OUTOFMEMORY;
+    ULONG count;
+    VARIANT var;
+
+    if (!(fullpath = build_canonical_path( dependent ))) return E_OUTOFMEMORY;
+    if (!(str = build_antecedent_query( assocclass, fullpath ))) goto done;
+    if ((hr = exec_query( str, &iter )) != S_OK) goto done;
+
+    IEnumWbemClassObject_Next( iter, WBEM_INFINITE, 1, &obj, &count );
+    if (!count)
+    {
+        *ret = NULL;
+        goto done;
+    }
+
+    hr = IWbemClassObject_Get( obj, antecedentW, 0, &var, NULL, NULL );
+    IWbemClassObject_Release( obj );
+    if (hr != S_OK) goto done;
+    *ret = V_BSTR( &var );
+
+done:
+    if (iter) IEnumWbemClassObject_Release( iter );
+    heap_free( str );
+    heap_free( fullpath );
+    return hr;
+}
+
+static HRESULT do_query( const WCHAR *str, struct query **ret_query )
+{
+    struct query *query;
+    HRESULT hr;
+
+    if (!(query = create_query())) return E_OUTOFMEMORY;
+    if ((hr = parse_query( str, &query->view, &query->mem )) != S_OK || (hr = execute_view( query->view )) != S_OK)
+    {
+        release_query( query );
+        return hr;
+    }
+    *ret_query = query;
+    return S_OK;
+}
+
+static HRESULT get_antecedent_table( const WCHAR *assocclass, const WCHAR *dependent, struct table **table )
+{
+    BSTR antecedent = NULL;
+    struct path *path = NULL;
+    WCHAR *str = NULL;
+    struct query *query = NULL;
+    HRESULT hr;
+
+    if ((hr = get_antecedent( assocclass, dependent, &antecedent )) != S_OK) return hr;
+    if (!antecedent)
+    {
+        *table = NULL;
+        return S_OK;
+    }
+    if ((hr = parse_path( antecedent, &path )) != S_OK) goto done;
+    if (!(str = query_from_path( path )))
+    {
+        hr = E_OUTOFMEMORY;
+        goto done;
+    }
+
+    if ((hr = do_query( str, &query )) != S_OK) goto done;
+    if (query->view->table_count) *table = addref_table( query->view->table[0] );
+    else *table = NULL;
+
+done:
+    if (query) release_query( query );
+    free_path( path );
+    SysFreeString( antecedent );
+    return hr;
+}
+
+static HRESULT exec_assoc_view( struct view *view )
+{
+    static const WCHAR assocclassW[] = {'A','s','s','o','c','C','l','a','s','s',0};
+    IEnumWbemClassObject *iter = NULL;
+    struct path *path;
+    HRESULT hr;
+
+    if (view->keywordlist) FIXME( "ignoring keywords\n" );
+    if ((hr = parse_path( view->path, &path )) != S_OK) return hr;
+
+    if ((hr = create_assoc_enum( path->class, path->class_len, &iter )) != S_OK) goto done;
+    for (;;)
+    {
+        ULONG count;
+        IWbemClassObject *obj;
+        struct table *table;
+        VARIANT var;
+
+        IEnumWbemClassObject_Next( iter, WBEM_INFINITE, 1, &obj, &count );
+        if (!count) break;
+
+        if ((hr = IWbemClassObject_Get( obj, assocclassW, 0, &var, NULL, NULL )) != S_OK)
+        {
+            IWbemClassObject_Release( obj );
+            goto done;
+        }
+        IWbemClassObject_Release( obj );
+
+        hr = get_antecedent_table( V_BSTR(&var), view->path, &table );
+        VariantClear( &var );
+        if (hr != S_OK) goto done;
+
+        if (table && (hr = append_table( view, table )) != S_OK)
+        {
+            release_table( table );
+            goto done;
+        }
+    }
+
+    if (view->table_count)
+    {
+        if (!(view->result = heap_alloc_zero( view->table_count * sizeof(UINT) ))) hr = E_OUTOFMEMORY;
+        else view->result_count = view->table_count;
+    }
+
+done:
+    if (iter) IEnumWbemClassObject_Release( iter );
+    free_path( path );
+    return hr;
+}
+
+static HRESULT exec_select_view( struct view *view )
 {
     UINT i, j = 0, len;
     enum fill_status status = FILL_STATUS_UNFILTERED;
+    struct table *table;
 
-    if (!view->table) return S_OK;
-    if (view->table->fill)
+    if (!view->table_count) return S_OK;
+
+    table = view->table[0];
+    if (table->fill)
     {
-        clear_table( view->table );
-        status = view->table->fill( view->table, view->cond );
+        clear_table( table );
+        status = table->fill( table, view->cond );
     }
     if (status == FILL_STATUS_FAILED) return WBEM_E_FAILED;
-    if (!view->table->num_rows) return S_OK;
+    if (!table->num_rows) return S_OK;
 
-    len = min( view->table->num_rows, 16 );
+    len = min( table->num_rows, 16 );
     if (!(view->result = heap_alloc( len * sizeof(UINT) ))) return E_OUTOFMEMORY;
 
-    for (i = 0; i < view->table->num_rows; i++)
+    for (i = 0; i < table->num_rows; i++)
     {
         HRESULT hr;
         LONGLONG val = 0;
@@ -471,13 +720,30 @@ HRESULT execute_view( struct view *view )
             view->result = tmp;
         }
         if (status == FILL_STATUS_FILTERED) val = 1;
-        else if ((hr = eval_cond( view->table, i, view->cond, &val, &type )) != S_OK) return hr;
+        else if ((hr = eval_cond( table, i, view->cond, &val, &type )) != S_OK) return hr;
         if (val) view->result[j++] = i;
     }
-    view->count = j;
+
+    view->result_count = j;
     return S_OK;
 }
 
+HRESULT execute_view( struct view *view )
+{
+    switch (view->type)
+    {
+    case VIEW_TYPE_ASSOCIATORS:
+        return exec_assoc_view( view );
+
+    case VIEW_TYPE_SELECT:
+        return exec_select_view( view );
+
+    default:
+        ERR( "unhandled type %u\n", view->type );
+        return E_INVALIDARG;
+    }
+}
+
 struct query *create_query(void)
 {
     struct query *query;
@@ -527,10 +793,9 @@ done:
     return hr;
 }
 
-BOOL is_selected_prop( const struct view *view, const WCHAR *name )
+BOOL is_result_prop( const struct view *view, const WCHAR *name )
 {
     const struct property *prop = view->proplist;
-
     if (!prop) return TRUE;
     while (prop)
     {
@@ -545,47 +810,21 @@ static BOOL is_system_prop( const WCHAR *name )
     return (name[0] == '_' && name[1] == '_');
 }
 
-static BSTR build_servername( const struct view *view )
-{
-    WCHAR server[MAX_COMPUTERNAME_LENGTH + 1], *p;
-    DWORD len = ARRAY_SIZE( server );
-
-    if (view->proplist) return NULL;
-
-    if (!(GetComputerNameW( server, &len ))) return NULL;
-    for (p = server; *p; p++) *p = towupper( *p );
-    return SysAllocString( server );
-}
-
-static BSTR build_classname( const struct view *view )
-{
-    return SysAllocString( view->table->name );
-}
-
-static BSTR build_namespace( const struct view *view )
-{
-    static const WCHAR cimv2W[] = {'R','O','O','T','\\','C','I','M','V','2',0};
-
-    if (view->proplist) return NULL;
-    return SysAllocString( cimv2W );
-}
-
-static BSTR build_proplist( const struct view *view, UINT index, UINT count, UINT *len )
+static BSTR build_proplist( const struct table *table, UINT row, UINT count, UINT *len )
 {
     static const WCHAR fmtW[] = {'%','s','=','%','s',0};
-    UINT i, j, offset, row = view->result[index];
+    UINT i, j, offset;
     BSTR *values, ret = NULL;
 
     if (!(values = heap_alloc( count * sizeof(BSTR) ))) return NULL;
 
     *len = j = 0;
-    for (i = 0; i < view->table->num_cols; i++)
+    for (i = 0; i < table->num_cols; i++)
     {
-        if (view->table->columns[i].type & COL_FLAG_KEY)
+        if (table->columns[i].type & COL_FLAG_KEY)
         {
-            const WCHAR *name = view->table->columns[i].name;
-
-            values[j] = get_value_bstr( view->table, row, i );
+            const WCHAR *name = table->columns[i].name;
+            values[j] = get_value_bstr( table, row, i );
             *len += lstrlenW( fmtW ) + lstrlenW( name ) + lstrlenW( values[j] );
             j++;
         }
@@ -593,12 +832,11 @@ static BSTR build_proplist( const struct view *view, UINT index, UINT count, UIN
     if ((ret = SysAllocStringLen( NULL, *len )))
     {
         offset = j = 0;
-        for (i = 0; i < view->table->num_cols; i++)
+        for (i = 0; i < table->num_cols; i++)
         {
-            if (view->table->columns[i].type & COL_FLAG_KEY)
+            if (table->columns[i].type & COL_FLAG_KEY)
             {
-                const WCHAR *name = view->table->columns[i].name;
-
+                const WCHAR *name = table->columns[i].name;
                 offset += swprintf( ret + offset, *len - offset, fmtW, name, values[j] );
                 if (j < count - 1) ret[offset++] = ',';
                 j++;
@@ -610,28 +848,30 @@ static BSTR build_proplist( const struct view *view, UINT index, UINT count, UIN
     return ret;
 }
 
-static UINT count_key_columns( const struct view *view )
+static UINT count_key_columns( const struct table *table )
 {
     UINT i, num_keys = 0;
 
-    for (i = 0; i < view->table->num_cols; i++)
+    for (i = 0; i < table->num_cols; i++)
     {
-        if (view->table->columns[i].type & COL_FLAG_KEY) num_keys++;
+        if (table->columns[i].type & COL_FLAG_KEY) num_keys++;
     }
     return num_keys;
 }
 
-static BSTR build_relpath( const struct view *view, UINT index, const WCHAR *name )
+static BSTR build_relpath( const struct view *view, UINT table_index, UINT result_index, const WCHAR *name )
 {
     static const WCHAR fmtW[] = {'%','s','.','%','s',0};
     BSTR class, proplist, ret = NULL;
+    struct table *table = view->table[table_index];
+    UINT row = view->result[result_index];
     UINT num_keys, len;
 
     if (view->proplist) return NULL;
 
-    if (!(class = build_classname( view ))) return NULL;
-    if (!(num_keys = count_key_columns( view ))) return class;
-    if (!(proplist = build_proplist( view, index, num_keys, &len ))) goto done;
+    if (!(class = SysAllocString( view->table[table_index]->name ))) return NULL;
+    if (!(num_keys = count_key_columns( table ))) return class;
+    if (!(proplist = build_proplist( table, row, num_keys, &len ))) goto done;
 
     len += lstrlenW( fmtW ) + SysStringLen( class );
     if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
@@ -643,7 +883,7 @@ done:
     return ret;
 }
 
-static BSTR build_path( const struct view *view, UINT index, const WCHAR *name )
+static BSTR build_path( const struct view *view, UINT table_index, UINT result_index, const WCHAR *name )
 {
     static const WCHAR fmtW[] = {'\\','\\','%','s','\\','%','s',':','%','s',0};
     BSTR server, namespace = NULL, relpath = NULL, ret = NULL;
@@ -651,9 +891,9 @@ static BSTR build_path( const struct view *view, UINT index, const WCHAR *name )
 
     if (view->proplist) return NULL;
 
-    if (!(server = build_servername( view ))) return NULL;
-    if (!(namespace = build_namespace( view ))) goto done;
-    if (!(relpath = build_relpath( view, index, name ))) goto done;
+    if (!(server = build_servername())) return NULL;
+    if (!(namespace = build_namespace())) goto done;
+    if (!(relpath = build_relpath( view, table_index, result_index, name ))) goto done;
 
     len = lstrlenW( fmtW ) + SysStringLen( server ) + SysStringLen( namespace ) + SysStringLen( relpath );
     if (!(ret = SysAllocStringLen( NULL, len ))) goto done;
@@ -671,30 +911,30 @@ BOOL is_method( const struct table *table, UINT column )
     return table->columns[column].type & COL_FLAG_METHOD;
 }
 
-static UINT count_properties( const struct view *view )
+static UINT count_properties( const struct table *table )
 {
     UINT i, num_props = 0;
 
-    for (i = 0; i < view->table->num_cols; i++)
+    for (i = 0; i < table->num_cols; i++)
     {
-        if (!is_method( view->table, i)) num_props++;
+        if (!is_method( table, i )) num_props++;
     }
     return num_props;
 }
 
-static UINT count_selected_properties( const struct view *view )
+static UINT count_result_properties( const struct view *view, UINT table_index )
 {
     const struct property *prop = view->proplist;
     UINT count;
 
-    if (!prop) return count_properties( view );
+    if (!prop) return count_properties( view->table[table_index] );
 
     count = 1;
     while ((prop = prop->next)) count++;
     return count;
 }
 
-static HRESULT get_system_propval( const struct view *view, UINT index, const WCHAR *name,
+static HRESULT get_system_propval( const struct view *view, UINT table_index, UINT result_index, const WCHAR *name,
                                    VARIANT *ret, CIMTYPE *type, LONG *flavor )
 {
     static const WCHAR classW[] = {'_','_','C','L','A','S','S',0};
@@ -712,7 +952,7 @@ static HRESULT get_system_propval( const struct view *view, UINT index, const WC
         if (ret)
         {
             V_VT( ret ) = VT_BSTR;
-            V_BSTR( ret ) = build_classname( view );
+            V_BSTR( ret ) = SysAllocString( view->table[table_index]->name );
         }
         if (type) *type = CIM_STRING;
         return S_OK;
@@ -732,7 +972,7 @@ static HRESULT get_system_propval( const struct view *view, UINT index, const WC
         if (ret)
         {
             V_VT( ret ) = VT_BSTR;
-            V_BSTR( ret ) = build_namespace( view );
+            V_BSTR( ret ) = view->proplist ? NULL : build_namespace();
         }
         if (type) *type = CIM_STRING;
         return S_OK;
@@ -742,7 +982,7 @@ static HRESULT get_system_propval( const struct view *view, UINT index, const WC
         if (ret)
         {
             V_VT( ret ) = VT_BSTR;
-            V_BSTR( ret ) = build_path( view, index, name );
+            V_BSTR( ret ) = build_path( view, table_index, result_index, name );
         }
         if (type) *type = CIM_STRING;
         return S_OK;
@@ -752,7 +992,7 @@ static HRESULT get_system_propval( const struct view *view, UINT index, const WC
         if (ret)
         {
             V_VT( ret ) = VT_I4;
-            V_I4( ret ) = count_selected_properties( view );
+            V_I4( ret ) = count_result_properties( view, table_index );
         }
         if (type) *type = CIM_SINT32;
         return S_OK;
@@ -762,7 +1002,7 @@ static HRESULT get_system_propval( const struct view *view, UINT index, const WC
         if (ret)
         {
             V_VT( ret ) = VT_BSTR;
-            V_BSTR( ret ) = build_relpath( view, index, name );
+            V_BSTR( ret ) = build_relpath( view, table_index, result_index, name );
         }
         if (type) *type = CIM_STRING;
         return S_OK;
@@ -772,7 +1012,7 @@ static HRESULT get_system_propval( const struct view *view, UINT index, const WC
         if (ret)
         {
             V_VT( ret ) = VT_BSTR;
-            V_BSTR( ret ) = build_servername( view );
+            V_BSTR( ret ) = view->proplist ? NULL : build_servername();
         }
         if (type) *type = CIM_STRING;
         return S_OK;
@@ -871,6 +1111,9 @@ void set_variant( VARTYPE type, LONGLONG val, void *val_ptr, VARIANT *ret )
         break;
     case VT_NULL:
         break;
+    case VT_R4:
+        V_R4( ret ) = *(FLOAT *)&val;
+        break;
     default:
         ERR("unhandled variant type %u\n", type);
         return;
@@ -878,34 +1121,74 @@ void set_variant( VARTYPE type, LONGLONG val, void *val_ptr, VARIANT *ret )
     V_VT( ret ) = type;
 }
 
-HRESULT get_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *ret,
-                     CIMTYPE *type, LONG *flavor )
+static HRESULT map_view_index( const struct view *view, UINT index, UINT *table_index, UINT *result_index )
+{
+    switch (view->type)
+    {
+    case VIEW_TYPE_SELECT:
+        *table_index = 0;
+        *result_index = index;
+        break;
+
+    case VIEW_TYPE_ASSOCIATORS:
+        *table_index = *result_index = index;
+        break;
+
+    default:
+        ERR( "unhandled view type %u\n", view->type );
+        return WBEM_E_FAILED;
+    }
+    return S_OK;
+}
+
+struct table *get_view_table( const struct view *view, UINT index )
+{
+    switch (view->type)
+    {
+    case VIEW_TYPE_SELECT:
+        return view->table[0];
+
+    case VIEW_TYPE_ASSOCIATORS:
+        return view->table[index];
+
+    default:
+        ERR( "unhandled view type %u\n", view->type );
+        return NULL;
+    }
+}
+
+HRESULT get_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *ret, CIMTYPE *type,
+                     LONG *flavor )
 {
     HRESULT hr;
-    UINT column, row;
+    UINT column, row, table_index, result_index;
+    struct table *table;
     VARTYPE vartype;
     void *val_ptr = NULL;
     LONGLONG val;
 
-    if (is_system_prop( name )) return get_system_propval( view, index, name, ret, type, flavor );
-    if (!view->count || !is_selected_prop( view, name )) return WBEM_E_NOT_FOUND;
+    if ((hr = map_view_index( view, index, &table_index, &result_index )) != S_OK) return hr;
 
-    hr = get_column_index( view->table, name, &column );
-    if (hr != S_OK || is_method( view->table, column )) return WBEM_E_NOT_FOUND;
+    if (is_system_prop( name )) return get_system_propval( view, table_index, result_index, name, ret, type, flavor );
+    if (!view->result_count || !is_result_prop( view, name )) return WBEM_E_NOT_FOUND;
 
-    row = view->result[index];
-    hr = get_value( view->table, row, column, &val );
+    table = view->table[table_index];
+    hr = get_column_index( table, name, &column );
+    if (hr != S_OK || is_method( table, column )) return WBEM_E_NOT_FOUND;
+
+    row = view->result[result_index];
+    hr = get_value( table, row, column, &val );
     if (hr != S_OK) return hr;
 
-    if (type) *type = view->table->columns[column].type & COL_TYPE_MASK;
+    if (type) *type = table->columns[column].type & COL_TYPE_MASK;
     if (flavor) *flavor = 0;
 
     if (!ret) return S_OK;
 
-    vartype = view->table->columns[column].vartype;
-    if (view->table->columns[column].type & CIM_FLAG_ARRAY)
+    vartype = table->columns[column].vartype;
+    if (table->columns[column].type & CIM_FLAG_ARRAY)
     {
-        CIMTYPE basetype = view->table->columns[column].type & CIM_TYPE_MASK;
+        CIMTYPE basetype = table->columns[column].type & CIM_TYPE_MASK;
 
         val_ptr = to_safearray( (const struct array *)(INT_PTR)val, basetype );
         if (!val_ptr) vartype = VT_NULL;
@@ -914,7 +1197,7 @@ HRESULT get_propval( const struct view *view, UINT index, const WCHAR *name, VAR
         return S_OK;
     }
 
-    switch (view->table->columns[column].type & COL_TYPE_MASK)
+    switch (table->columns[column].type & COL_TYPE_MASK)
     {
     case CIM_BOOLEAN:
         if (!vartype) vartype = VT_BOOL;
@@ -950,14 +1233,17 @@ HRESULT get_propval( const struct view *view, UINT index, const WCHAR *name, VAR
         break;
     case CIM_SINT64:
         vartype = VT_BSTR;
-        val_ptr = get_value_bstr( view->table, row, column );
+        val_ptr = get_value_bstr( table, row, column );
         break;
     case CIM_UINT64:
         vartype = VT_BSTR;
-        val_ptr = get_value_bstr( view->table, row, column );
+        val_ptr = get_value_bstr( table, row, column );
+        break;
+    case CIM_REAL32:
+        if (!vartype) vartype = VT_R4;
         break;
     default:
-        ERR("unhandled column type %u\n", view->table->columns[column].type);
+        ERR("unhandled column type %u\n", table->columns[column].type);
         return WBEM_E_FAILED;
     }
 
@@ -1087,45 +1373,56 @@ HRESULT to_longlong( VARIANT *var, LONGLONG *val, CIMTYPE *type )
 HRESULT put_propval( const struct view *view, UINT index, const WCHAR *name, VARIANT *var, CIMTYPE type )
 {
     HRESULT hr;
-    UINT column, row = view->result[index];
+    UINT row, column, table_index, result_index;
+    struct table *table;
     LONGLONG val;
 
-    hr = get_column_index( view->table, name, &column );
+    if ((hr = map_view_index( view, index, &table_index, &result_index )) != S_OK) return hr;
+
+    table = view->table[table_index];
+    hr = get_column_index( table, name, &column );
     if (hr != S_OK)
     {
         FIXME("no support for creating new properties\n");
         return WBEM_E_FAILED;
     }
-    if (is_method( view->table, column ) || !(view->table->columns[column].type & COL_FLAG_DYNAMIC))
+    if (is_method( table, column ) || !(table->columns[column].type & COL_FLAG_DYNAMIC))
         return WBEM_E_FAILED;
 
     hr = to_longlong( var, &val, &type );
     if (hr != S_OK) return hr;
 
-    return set_value( view->table, row, column, val, type );
+    row = view->result[result_index];
+    return set_value( table, row, column, val, type );
 }
 
-HRESULT get_properties( const struct view *view, LONG flags, SAFEARRAY **props )
+HRESULT get_properties( const struct view *view, UINT index, LONG flags, SAFEARRAY **props )
 {
     SAFEARRAY *sa;
     BSTR str;
-    UINT i, num_props = count_selected_properties( view );
+    UINT i, table_index, result_index, num_props;
+    struct table *table;
+    HRESULT hr;
     LONG j;
 
+    if ((hr = map_view_index( view, index, &table_index, &result_index )) != S_OK) return hr;
+
+    num_props = count_result_properties( view, table_index );
     if (!(sa = SafeArrayCreateVector( VT_BSTR, 0, num_props ))) return E_OUTOFMEMORY;
 
-    for (i = 0, j = 0; i < view->table->num_cols; i++)
+    table = view->table[table_index];
+    for (i = 0, j = 0; i < table->num_cols; i++)
     {
         BOOL is_system;
 
-        if (is_method( view->table, i )) continue;
-        if (!is_selected_prop( view, view->table->columns[i].name )) continue;
+        if (is_method( table, i )) continue;
+        if (!is_result_prop( view, table->columns[i].name )) continue;
 
-        is_system = is_system_prop( view->table->columns[i].name );
+        is_system = is_system_prop( table->columns[i].name );
         if ((flags & WBEM_FLAG_NONSYSTEM_ONLY) && is_system) continue;
         else if ((flags & WBEM_FLAG_SYSTEM_ONLY) && !is_system) continue;
 
-        str = SysAllocString( view->table->columns[i].name );
+        str = SysAllocString( table->columns[i].name );
         if (!str || SafeArrayPutElement( sa, &j, str ) != S_OK)
         {
             SysFreeString( str );
diff --git a/dlls/wbemprox/services.c b/dlls/wbemprox/services.c
index 0af02a4a1d..e1cd2466e4 100644
--- a/dlls/wbemprox/services.c
+++ b/dlls/wbemprox/services.c
@@ -320,15 +320,7 @@ static HRESULT WINAPI wbem_services_QueryObjectSink(
     return WBEM_E_FAILED;
 }
 
-struct path
-{
-    WCHAR *class;
-    UINT   class_len;
-    WCHAR *filter;
-    UINT   filter_len;
-};
-
-static HRESULT parse_path( const WCHAR *str, struct path **ret )
+HRESULT parse_path( const WCHAR *str, struct path **ret )
 {
     struct path *path;
     const WCHAR *p = str, *q;
@@ -397,14 +389,15 @@ static HRESULT parse_path( const WCHAR *str, struct path **ret )
     return S_OK;
 }
 
-static void free_path( struct path *path )
+void free_path( struct path *path )
 {
+    if (!path) return;
     heap_free( path->class );
     heap_free( path->filter );
     heap_free( path );
 }
 
-static WCHAR *query_from_path( const struct path *path )
+WCHAR *query_from_path( const struct path *path )
 {
     static const WCHAR selectW[] =
         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','%','s',' ',
@@ -819,6 +812,7 @@ static HRESULT WINAPI wbem_services_ExecMethod(
     struct path *path;
     WCHAR *str;
     class_method *func;
+    struct table *table;
     HRESULT hr;
 
     TRACE("%p, %s, %s, %08x, %p, %p, %p, %p\n", iface, debugstr_w(strObjectPath),
@@ -846,10 +840,11 @@ static HRESULT WINAPI wbem_services_ExecMethod(
     hr = EnumWbemClassObject_create( query, (void **)&result );
     if (hr != S_OK) goto done;
 
-    hr = create_class_object( query->view->table->name, result, 0, NULL, &obj );
+    table = get_view_table( query->view, 0 );
+    hr = create_class_object( table->name, result, 0, NULL, &obj );
     if (hr != S_OK) goto done;
 
-    hr = get_method( query->view->table, strMethodName, &func );
+    hr = get_method( table, strMethodName, &func );
     if (hr != S_OK) goto done;
 
     hr = func( obj, pInParams, ppOutParams );
diff --git a/dlls/wbemprox/wbemprox_private.h b/dlls/wbemprox/wbemprox_private.h
index c1b1ae8679..7e61cf5ead 100644
--- a/dlls/wbemprox/wbemprox_private.h
+++ b/dlls/wbemprox/wbemprox_private.h
@@ -155,15 +155,23 @@ struct keyword
     const struct keyword *next;
 };
 
+enum view_type
+{
+    VIEW_TYPE_SELECT,
+    VIEW_TYPE_ASSOCIATORS,
+};
+
 struct view
 {
+    enum view_type type;
     const WCHAR *path;                      /* ASSOCIATORS OF query */
     const struct keyword *keywordlist;
-    const struct property *proplist;
-    struct table *table;
+    const struct property *proplist;        /* SELECT query */
     const struct expr *cond;
+    UINT table_count;
+    struct table **table;
+    UINT result_count;
     UINT *result;
-    UINT  count;
 };
 
 struct query
@@ -173,16 +181,29 @@ struct query
     struct list mem;
 };
 
+struct path
+{
+    WCHAR *class;
+    UINT   class_len;
+    WCHAR *filter;
+    UINT   filter_len;
+};
+
+HRESULT parse_path( const WCHAR *, struct path ** ) DECLSPEC_HIDDEN;
+void free_path( struct path * ) DECLSPEC_HIDDEN;
+WCHAR *query_from_path( const struct path * ) DECLSPEC_HIDDEN;
+
 struct query *create_query(void) DECLSPEC_HIDDEN;
 void free_query( struct query * ) DECLSPEC_HIDDEN;
 struct query *addref_query( struct query * ) DECLSPEC_HIDDEN;
 void release_query( struct query *query ) DECLSPEC_HIDDEN;
 HRESULT exec_query( const WCHAR *, IEnumWbemClassObject ** ) DECLSPEC_HIDDEN;
 HRESULT parse_query( const WCHAR *, struct view **, struct list * ) DECLSPEC_HIDDEN;
-HRESULT create_view( const WCHAR *, const struct keyword *, const WCHAR *, const struct property *,
+HRESULT create_view( enum view_type, const WCHAR *, const struct keyword *, const WCHAR *, const struct property *,
                      const struct expr *, struct view ** ) DECLSPEC_HIDDEN;
 void destroy_view( struct view * ) DECLSPEC_HIDDEN;
 HRESULT execute_view( struct view * ) DECLSPEC_HIDDEN;
+struct table *get_view_table( const struct view *, UINT ) DECLSPEC_HIDDEN;
 void init_table_list( void ) DECLSPEC_HIDDEN;
 struct table *grab_table( const WCHAR * ) DECLSPEC_HIDDEN;
 struct table *addref_table( struct table * ) DECLSPEC_HIDDEN;
@@ -202,15 +223,14 @@ BSTR get_value_bstr( const struct table *, UINT, UINT ) DECLSPEC_HIDDEN;
 HRESULT set_value( const struct table *, UINT, UINT, LONGLONG, CIMTYPE ) DECLSPEC_HIDDEN;
 BOOL is_method( const struct table *, UINT ) DECLSPEC_HIDDEN;
 HRESULT get_method( const struct table *, const WCHAR *, class_method ** ) DECLSPEC_HIDDEN;
-HRESULT get_propval( const struct view *, UINT, const WCHAR *, VARIANT *,
-                     CIMTYPE *, LONG * ) DECLSPEC_HIDDEN;
+HRESULT get_propval( const struct view *, UINT, const WCHAR *, VARIANT *, CIMTYPE *, LONG * ) DECLSPEC_HIDDEN;
 HRESULT put_propval( const struct view *, UINT, const WCHAR *, VARIANT *, CIMTYPE ) DECLSPEC_HIDDEN;
 HRESULT to_longlong( VARIANT *, LONGLONG *, CIMTYPE * ) DECLSPEC_HIDDEN;
 SAFEARRAY *to_safearray( const struct array *, CIMTYPE ) DECLSPEC_HIDDEN;
 VARTYPE to_vartype( CIMTYPE ) DECLSPEC_HIDDEN;
 void destroy_array( struct array *, CIMTYPE ) DECLSPEC_HIDDEN;
-BOOL is_selected_prop( const struct view *, const WCHAR * ) DECLSPEC_HIDDEN;
-HRESULT get_properties( const struct view *, LONG, SAFEARRAY ** ) DECLSPEC_HIDDEN;
+BOOL is_result_prop( const struct view *, const WCHAR * ) DECLSPEC_HIDDEN;
+HRESULT get_properties( const struct view *, UINT, LONG, SAFEARRAY ** ) DECLSPEC_HIDDEN;
 HRESULT get_object( const WCHAR *, IWbemClassObject ** ) DECLSPEC_HIDDEN;
 BSTR get_method_name( const WCHAR *, UINT ) DECLSPEC_HIDDEN;
 void set_variant( VARTYPE, LONGLONG, void *, VARIANT * ) DECLSPEC_HIDDEN;
diff --git a/dlls/wbemprox/wql.y b/dlls/wbemprox/wql.y
index 99279149ae..12f4cb5104 100644
--- a/dlls/wbemprox/wql.y
+++ b/dlls/wbemprox/wql.y
@@ -289,7 +289,7 @@ associatorsof:
             struct parser *parser = ctx;
             struct view *view;
 
-            hr = create_view( $3, NULL, NULL, NULL, NULL, &view );
+            hr = create_view( VIEW_TYPE_ASSOCIATORS, $3, NULL, NULL, NULL, NULL, &view );
             if (hr != S_OK)
                 YYABORT;
 
@@ -301,7 +301,7 @@ associatorsof:
             struct parser *parser = ctx;
             struct view *view;
 
-            hr = create_view( $3, $5, NULL, NULL, NULL, &view );
+            hr = create_view( VIEW_TYPE_ASSOCIATORS, $3, $5, NULL, NULL, NULL, &view );
             if (hr != S_OK)
                 YYABORT;
 
@@ -316,7 +316,7 @@ select:
             struct parser *parser = ctx;
             struct view *view;
 
-            hr = create_view( NULL, NULL, $3, NULL, NULL, &view );
+            hr = create_view( VIEW_TYPE_SELECT, NULL, NULL, $3, NULL, NULL, &view );
             if (hr != S_OK)
                 YYABORT;
 
@@ -328,7 +328,7 @@ select:
             struct parser *parser = ctx;
             struct view *view;
 
-            hr = create_view( NULL, NULL, $4, $2, NULL, &view );
+            hr = create_view( VIEW_TYPE_SELECT, NULL, NULL, $4, $2, NULL, &view );
             if (hr != S_OK)
                 YYABORT;
 
@@ -340,7 +340,7 @@ select:
             struct parser *parser = ctx;
             struct view *view;
 
-            hr = create_view( NULL, NULL, $4, $2, $6, &view );
+            hr = create_view( VIEW_TYPE_SELECT, NULL, NULL, $4, $2, $6, &view );
             if (hr != S_OK)
                 YYABORT;
 
-- 
2.20.1




More information about the wine-devel mailing list