wbemprox: Add support for asynchronous queries.

Hans Leidekker hans at codeweavers.com
Thu May 16 05:04:03 CDT 2013


---
 dlls/wbemprox/services.c    |  216 +++++++++++++++++++++++++++++++++++++++++--
 dlls/wbemprox/tests/query.c |   36 +++++++-
 include/wbemcli.idl         |    7 ++
 3 files changed, 248 insertions(+), 11 deletions(-)

diff --git a/dlls/wbemprox/services.c b/dlls/wbemprox/services.c
index fc964ac..10036ae 100644
--- a/dlls/wbemprox/services.c
+++ b/dlls/wbemprox/services.c
@@ -135,11 +135,68 @@ static const IClientSecurityVtbl client_security_vtbl =
 
 IClientSecurity client_security = { &client_security_vtbl };
 
+struct async_header
+{
+    IWbemObjectSink *sink;
+    void (*proc)( struct async_header * );
+    HANDLE cancel;
+    HANDLE wait;
+};
+
+struct async_query
+{
+    struct async_header hdr;
+    WCHAR *str;
+};
+
+static void free_async( struct async_header *async )
+{
+    if (async->sink) IWbemObjectSink_Release( async->sink );
+    CloseHandle( async->cancel );
+    CloseHandle( async->wait );
+    heap_free( async );
+}
+
+static BOOL init_async( struct async_header *async, IWbemObjectSink *sink,
+                        void (*proc)(struct async_header *) )
+{
+    if (!(async->wait = CreateEventW( NULL, FALSE, FALSE, NULL ))) return FALSE;
+    if (!(async->cancel = CreateEventW( NULL, FALSE, FALSE, NULL )))
+    {
+        CloseHandle( async->wait );
+        return FALSE;
+    }
+    async->proc = proc;
+    async->sink = sink;
+    IWbemObjectSink_AddRef( sink );
+    return TRUE;
+}
+
+static DWORD CALLBACK async_proc( LPVOID param )
+{
+    struct async_header *async = param;
+    HANDLE wait = async->wait;
+
+    async->proc( async );
+
+    WaitForSingleObject( async->cancel, INFINITE );
+    SetEvent( wait );
+    return ERROR_SUCCESS;
+}
+
+static HRESULT queue_async( struct async_header *async )
+{
+    if (QueueUserWorkItem( async_proc, async, WT_EXECUTELONGFUNCTION )) return S_OK;
+    return HRESULT_FROM_WIN32( GetLastError() );
+}
+
 struct wbem_services
 {
     IWbemServices IWbemServices_iface;
     LONG refs;
+    CRITICAL_SECTION cs;
     WCHAR *namespace;
+    struct async_header *async;
 };
 
 static inline struct wbem_services *impl_from_IWbemServices( IWbemServices *iface )
@@ -162,6 +219,17 @@ static ULONG WINAPI wbem_services_Release(
     if (!refs)
     {
         TRACE("destroying %p\n", ws);
+
+        EnterCriticalSection( &ws->cs );
+        if (ws->async) SetEvent( ws->async->cancel );
+        LeaveCriticalSection( &ws->cs );
+        if (ws->async)
+        {
+            WaitForSingleObject( ws->async->wait, INFINITE );
+            free_async( ws->async );
+        }
+        ws->cs.DebugInfo->Spare[0] = 0;
+        DeleteCriticalSection( &ws->cs );
         heap_free( ws->namespace );
         heap_free( ws );
     }
@@ -221,9 +289,27 @@ static HRESULT WINAPI wbem_services_CancelAsyncCall(
     IWbemServices *iface,
     IWbemObjectSink *pSink )
 {
-    FIXME("%p, %p\n", iface, pSink);
+    struct wbem_services *services = impl_from_IWbemServices( iface );
+    struct async_header *async;
+
+    TRACE("%p, %p\n", iface, pSink);
+
+    if (!pSink) return WBEM_E_INVALID_PARAMETER;
+
+    EnterCriticalSection( &services->cs );
+
+    if (!(async = services->async))
+    {
+        LeaveCriticalSection( &services->cs );
+        return WBEM_E_INVALID_PARAMETER;
+    }
+    services->async = NULL;
+    SetEvent( async->cancel );
+
+    LeaveCriticalSection( &services->cs );
 
-    IWbemObjectSink_Release( pSink );
+    WaitForSingleObject( async->wait, INFINITE );
+    free_async( async );
     return S_OK;
 }
 
@@ -532,6 +618,30 @@ static HRESULT WINAPI wbem_services_ExecQuery(
     return exec_query( strQuery, ppEnum );
 }
 
+static void async_exec_query( struct async_header *hdr )
+{
+    struct async_query *query = (struct async_query *)hdr;
+    IEnumWbemClassObject *result;
+    IWbemClassObject *obj;
+    ULONG count;
+    HRESULT hr;
+
+    hr = exec_query( query->str, &result );
+    if (hr == S_OK)
+    {
+        for (;;)
+        {
+            IEnumWbemClassObject_Next( result, WBEM_INFINITE, 1, &obj, &count );
+            if (!count) break;
+            IWbemObjectSink_Indicate( query->hdr.sink, 1, &obj );
+            IWbemClassObject_Release( obj );
+        }
+        IEnumWbemClassObject_Release( result );
+    }
+    IWbemObjectSink_SetStatus( query->hdr.sink, WBEM_STATUS_COMPLETE, hr, NULL, NULL );
+    heap_free( query->str );
+}
+
 static HRESULT WINAPI wbem_services_ExecQueryAsync(
     IWbemServices *iface,
     const BSTR strQueryLanguage,
@@ -540,8 +650,53 @@ static HRESULT WINAPI wbem_services_ExecQueryAsync(
     IWbemContext *pCtx,
     IWbemObjectSink *pResponseHandler )
 {
-    FIXME("\n");
-    return WBEM_E_FAILED;
+    struct wbem_services *services = impl_from_IWbemServices( iface );
+    IWbemObjectSink *sink;
+    HRESULT hr = E_OUTOFMEMORY;
+    struct async_header *async;
+    struct async_query *query;
+
+    TRACE("%p, %s, %s, 0x%08x, %p, %p\n", iface, debugstr_w(strQueryLanguage), debugstr_w(strQuery),
+          lFlags, pCtx, pResponseHandler);
+
+    if (!pResponseHandler) return WBEM_E_INVALID_PARAMETER;
+
+    hr = IWbemObjectSink_QueryInterface( pResponseHandler, &IID_IWbemObjectSink, (void **)&sink );
+    if (FAILED(hr)) return hr;
+
+    EnterCriticalSection( &services->cs );
+
+    if (services->async)
+    {
+        FIXME("handle more than one pending async\n");
+        hr = WBEM_E_FAILED;
+        goto done;
+    }
+    if (!(query = heap_alloc_zero( sizeof(*query) ))) goto done;
+    async = (struct async_header *)query;
+
+    if (!(init_async( async, sink, async_exec_query )))
+    {
+        free_async( async );
+        goto done;
+    }
+    if (!(query->str = heap_strdupW( strQuery )))
+    {
+        free_async( async );
+        goto done;
+    }
+    hr = queue_async( async );
+    if (hr == S_OK) services->async = async;
+    else
+    {
+        heap_free( query->str );
+        free_async( async );
+    }
+
+done:
+    LeaveCriticalSection( &services->cs );
+    IWbemObjectSink_Release( sink );
+    return hr;
 }
 
 static HRESULT WINAPI wbem_services_ExecNotificationQuery(
@@ -564,11 +719,53 @@ static HRESULT WINAPI wbem_services_ExecNotificationQueryAsync(
     IWbemContext *pCtx,
     IWbemObjectSink *pResponseHandler )
 {
-    FIXME("%p, %s, %s, 0x%08x, %p, %p\n", iface, debugstr_w(strQueryLanguage), debugstr_w(strQuery),
+    struct wbem_services *services = impl_from_IWbemServices( iface );
+    IWbemObjectSink *sink;
+    HRESULT hr = E_OUTOFMEMORY;
+    struct async_header *async;
+    struct async_query *query;
+
+    TRACE("%p, %s, %s, 0x%08x, %p, %p\n", iface, debugstr_w(strQueryLanguage), debugstr_w(strQuery),
           lFlags, pCtx, pResponseHandler);
 
-    IWbemObjectSink_AddRef( pResponseHandler );
-    return S_OK;
+    if (!pResponseHandler) return WBEM_E_INVALID_PARAMETER;
+
+    hr = IWbemObjectSink_QueryInterface( pResponseHandler, &IID_IWbemObjectSink, (void **)&sink );
+    if (FAILED(hr)) return hr;
+
+    EnterCriticalSection( &services->cs );
+
+    if (services->async)
+    {
+        FIXME("handle more than one pending async\n");
+        hr = WBEM_E_FAILED;
+        goto done;
+    }
+    if (!(query = heap_alloc_zero( sizeof(*query) ))) goto done;
+    async = (struct async_header *)query;
+
+    if (!(init_async( async, sink, async_exec_query )))
+    {
+        free_async( async );
+        goto done;
+    }
+    if (!(query->str = heap_strdupW( strQuery )))
+    {
+        free_async( async );
+        goto done;
+    }
+    hr = queue_async( async );
+    if (hr == S_OK) services->async = async;
+    else
+    {
+        heap_free( query->str );
+        free_async( async );
+    }
+
+done:
+    LeaveCriticalSection( &services->cs );
+    IWbemObjectSink_Release( sink );
+    return hr;
 }
 
 static HRESULT WINAPI wbem_services_ExecMethod(
@@ -670,8 +867,11 @@ HRESULT WbemServices_create( IUnknown *pUnkOuter, const WCHAR *namespace, LPVOID
     if (!ws) return E_OUTOFMEMORY;
 
     ws->IWbemServices_iface.lpVtbl = &wbem_services_vtbl;
-    ws->refs = 1;
+    ws->refs      = 1;
     ws->namespace = heap_strdupW( namespace );
+    ws->async     = NULL;
+    InitializeCriticalSection( &ws->cs );
+    ws->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": wbemprox_services.cs");
 
     *ppObj = &ws->IWbemServices_iface;
 
diff --git a/dlls/wbemprox/tests/query.c b/dlls/wbemprox/tests/query.c
index 933f315..15fe6f8 100644
--- a/dlls/wbemprox/tests/query.c
+++ b/dlls/wbemprox/tests/query.c
@@ -546,14 +546,14 @@ static ULONG WINAPI sink_Release(
 static HRESULT WINAPI sink_Indicate(
     IWbemObjectSink *iface, LONG count, IWbemClassObject **objects )
 {
-    trace("%d, %p\n", count, objects);
+    trace("Indicate: %d, %p\n", count, objects);
     return S_OK;
 }
 
 static HRESULT WINAPI sink_SetStatus(
     IWbemObjectSink *iface, LONG flags, HRESULT hresult, BSTR str_param, IWbemClassObject *obj_param )
 {
-    trace("%08x, %08x, %s, %p\n", flags, hresult, wine_dbgstr_w(str_param), obj_param);
+    trace("SetStatus: %08x, %08x, %s, %p\n", flags, hresult, wine_dbgstr_w(str_param), obj_param);
     return S_OK;
 }
 
@@ -574,11 +574,40 @@ static void test_notification_query_async( IWbemServices *services )
         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','W','i','n','3','2','_',
          'D','e','v','i','c','e','C','h','a','n','g','e','E','v','e','n','t',0};
     BSTR wql = SysAllocString( wqlW ), query = SysAllocString( queryW );
+    ULONG prev_sink_refs;
     HRESULT hr;
 
+    hr = IWbemServices_ExecNotificationQueryAsync( services, wql, query, 0, NULL, NULL );
+    ok( hr == WBEM_E_INVALID_PARAMETER, "got %08x\n", hr );
+
+    prev_sink_refs = sink_refs;
     hr = IWbemServices_ExecNotificationQueryAsync( services, wql, query, 0, NULL, &sink );
     ok( hr == S_OK || broken(hr == WBEM_E_NOT_FOUND), "got %08x\n", hr );
-    ok( sink_refs, "got %u\n", sink_refs );
+    ok( sink_refs > prev_sink_refs, "got %u refs\n", sink_refs );
+
+    hr =  IWbemServices_CancelAsyncCall( services, &sink );
+    ok( hr == S_OK, "got %08x\n", hr );
+
+    SysFreeString( wql );
+    SysFreeString( query );
+}
+
+static void test_query_async( IWbemServices *services )
+{
+    static const WCHAR queryW[] =
+        {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','W','i','n','3','2','_',
+         'P','r','o','c','e','s','s',0};
+    BSTR wql = SysAllocString( wqlW ), query = SysAllocString( queryW );
+    HRESULT hr;
+
+    hr = IWbemServices_ExecQueryAsync( services, wql, query, 0, NULL, NULL );
+    ok( hr == WBEM_E_INVALID_PARAMETER, "got %08x\n", hr );
+
+    hr = IWbemServices_ExecQueryAsync( services, wql, query, 0, NULL, &sink );
+    ok( hr == S_OK || broken(hr == WBEM_E_NOT_FOUND), "got %08x\n", hr );
+
+    hr =  IWbemServices_CancelAsyncCall( services, NULL );
+    ok( hr == WBEM_E_INVALID_PARAMETER, "got %08x\n", hr );
 
     hr =  IWbemServices_CancelAsyncCall( services, &sink );
     ok( hr == S_OK, "got %08x\n", hr );
@@ -617,6 +646,7 @@ START_TEST(query)
     test_Win32_Service( services );
     test_StdRegProv( services );
     test_notification_query_async( services );
+    test_query_async( services );
 
     SysFreeString( path );
     IWbemServices_Release( services );
diff --git a/include/wbemcli.idl b/include/wbemcli.idl
index 0390e1e..7a309e8 100644
--- a/include/wbemcli.idl
+++ b/include/wbemcli.idl
@@ -176,6 +176,13 @@ typedef [v1_enum] enum tag_WBEMSTATUS
     WBEM_E_PROVIDER_DISABLED                = 0x8004108a
 } WBEMSTATUS;
 
+typedef [v1_enum] enum tag_WBEM_STATUS_TYPE
+{
+    WBEM_STATUS_COMPLETE     = 0,
+    WBEM_STATUS_REQUIREMENTS = 1,
+    WBEM_STATUS_PROGRESS     = 2
+} WBEM_STATUS_TYPE;
+
 typedef [v1_enum] enum tag_WBEM_TIMEOUT_TYPE
 {
     WBEM_NO_WAIT  = 0,
-- 
1.7.10.4






More information about the wine-patches mailing list