wbemprox: Add support for asynchronous queries.
This commit is contained in:
parent
633c3cb086
commit
46cbc36041
|
@ -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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue