wbemprox: Add support for asynchronous queries.

This commit is contained in:
Hans Leidekker 2013-05-16 12:04:03 +02:00 committed by Alexandre Julliard
parent 633c3cb086
commit 46cbc36041
3 changed files with 248 additions and 11 deletions

View File

@ -135,11 +135,68 @@ static const IClientSecurityVtbl client_security_vtbl =
IClientSecurity client_security = { &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 struct wbem_services
{ {
IWbemServices IWbemServices_iface; IWbemServices IWbemServices_iface;
LONG refs; LONG refs;
CRITICAL_SECTION cs;
WCHAR *namespace; WCHAR *namespace;
struct async_header *async;
}; };
static inline struct wbem_services *impl_from_IWbemServices( IWbemServices *iface ) static inline struct wbem_services *impl_from_IWbemServices( IWbemServices *iface )
@ -162,6 +219,17 @@ static ULONG WINAPI wbem_services_Release(
if (!refs) if (!refs)
{ {
TRACE("destroying %p\n", ws); 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->namespace );
heap_free( ws ); heap_free( ws );
} }
@ -221,9 +289,27 @@ static HRESULT WINAPI wbem_services_CancelAsyncCall(
IWbemServices *iface, IWbemServices *iface,
IWbemObjectSink *pSink ) IWbemObjectSink *pSink )
{ {
FIXME("%p, %p\n", iface, pSink); struct wbem_services *services = impl_from_IWbemServices( iface );
struct async_header *async;
IWbemObjectSink_Release( pSink ); 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 );
WaitForSingleObject( async->wait, INFINITE );
free_async( async );
return S_OK; return S_OK;
} }
@ -532,6 +618,30 @@ static HRESULT WINAPI wbem_services_ExecQuery(
return exec_query( strQuery, ppEnum ); 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( static HRESULT WINAPI wbem_services_ExecQueryAsync(
IWbemServices *iface, IWbemServices *iface,
const BSTR strQueryLanguage, const BSTR strQueryLanguage,
@ -540,8 +650,53 @@ static HRESULT WINAPI wbem_services_ExecQueryAsync(
IWbemContext *pCtx, IWbemContext *pCtx,
IWbemObjectSink *pResponseHandler ) IWbemObjectSink *pResponseHandler )
{ {
FIXME("\n"); struct wbem_services *services = impl_from_IWbemServices( iface );
return WBEM_E_FAILED; 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( static HRESULT WINAPI wbem_services_ExecNotificationQuery(
@ -564,11 +719,53 @@ static HRESULT WINAPI wbem_services_ExecNotificationQueryAsync(
IWbemContext *pCtx, IWbemContext *pCtx,
IWbemObjectSink *pResponseHandler ) 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); lFlags, pCtx, pResponseHandler);
IWbemObjectSink_AddRef( pResponseHandler ); if (!pResponseHandler) return WBEM_E_INVALID_PARAMETER;
return S_OK;
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( static HRESULT WINAPI wbem_services_ExecMethod(
@ -670,8 +867,11 @@ HRESULT WbemServices_create( IUnknown *pUnkOuter, const WCHAR *namespace, LPVOID
if (!ws) return E_OUTOFMEMORY; if (!ws) return E_OUTOFMEMORY;
ws->IWbemServices_iface.lpVtbl = &wbem_services_vtbl; ws->IWbemServices_iface.lpVtbl = &wbem_services_vtbl;
ws->refs = 1; ws->refs = 1;
ws->namespace = heap_strdupW( namespace ); 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; *ppObj = &ws->IWbemServices_iface;

View File

@ -546,14 +546,14 @@ static ULONG WINAPI sink_Release(
static HRESULT WINAPI sink_Indicate( static HRESULT WINAPI sink_Indicate(
IWbemObjectSink *iface, LONG count, IWbemClassObject **objects ) IWbemObjectSink *iface, LONG count, IWbemClassObject **objects )
{ {
trace("%d, %p\n", count, objects); trace("Indicate: %d, %p\n", count, objects);
return S_OK; return S_OK;
} }
static HRESULT WINAPI sink_SetStatus( static HRESULT WINAPI sink_SetStatus(
IWbemObjectSink *iface, LONG flags, HRESULT hresult, BSTR str_param, IWbemClassObject *obj_param ) 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; 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','_', {'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}; '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 ); BSTR wql = SysAllocString( wqlW ), query = SysAllocString( queryW );
ULONG prev_sink_refs;
HRESULT hr; 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 ); hr = IWbemServices_ExecNotificationQueryAsync( services, wql, query, 0, NULL, &sink );
ok( hr == S_OK || broken(hr == WBEM_E_NOT_FOUND), "got %08x\n", hr ); 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 ); hr = IWbemServices_CancelAsyncCall( services, &sink );
ok( hr == S_OK, "got %08x\n", hr ); ok( hr == S_OK, "got %08x\n", hr );
@ -617,6 +646,7 @@ START_TEST(query)
test_Win32_Service( services ); test_Win32_Service( services );
test_StdRegProv( services ); test_StdRegProv( services );
test_notification_query_async( services ); test_notification_query_async( services );
test_query_async( services );
SysFreeString( path ); SysFreeString( path );
IWbemServices_Release( services ); IWbemServices_Release( services );

View File

@ -176,6 +176,13 @@ typedef [v1_enum] enum tag_WBEMSTATUS
WBEM_E_PROVIDER_DISABLED = 0x8004108a WBEM_E_PROVIDER_DISABLED = 0x8004108a
} WBEMSTATUS; } 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 typedef [v1_enum] enum tag_WBEM_TIMEOUT_TYPE
{ {
WBEM_NO_WAIT = 0, WBEM_NO_WAIT = 0,