xref: /reactos/dll/win32/wbemprox/services.c (revision 465745b6)
1 /*
2  * Copyright 2012 Hans Leidekker for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #define COBJMACROS
20 
21 #include <stdarg.h>
22 #ifdef __REACTOS__
23 #include <wchar.h>
24 #endif
25 
26 #include "windef.h"
27 #include "winbase.h"
28 #include "objbase.h"
29 #include "wbemcli.h"
30 
31 #include "wine/debug.h"
32 #include "wbemprox_private.h"
33 
34 WINE_DEFAULT_DEBUG_CHANNEL(wbemprox);
35 
36 struct client_security
37 {
38     IClientSecurity IClientSecurity_iface;
39 };
40 
41 static inline struct client_security *impl_from_IClientSecurity( IClientSecurity *iface )
42 {
43     return CONTAINING_RECORD( iface, struct client_security, IClientSecurity_iface );
44 }
45 
46 static HRESULT WINAPI client_security_QueryInterface(
47     IClientSecurity *iface,
48     REFIID riid,
49     void **ppvObject )
50 {
51     struct client_security *cs = impl_from_IClientSecurity( iface );
52 
53     TRACE("%p %s %p\n", cs, debugstr_guid( riid ), ppvObject );
54 
55     if ( IsEqualGUID( riid, &IID_IClientSecurity ) ||
56          IsEqualGUID( riid, &IID_IUnknown ) )
57     {
58         *ppvObject = cs;
59     }
60     else
61     {
62         FIXME("interface %s not implemented\n", debugstr_guid(riid));
63         return E_NOINTERFACE;
64     }
65     IClientSecurity_AddRef( iface );
66     return S_OK;
67 }
68 
69 static ULONG WINAPI client_security_AddRef(
70     IClientSecurity *iface )
71 {
72     FIXME("%p\n", iface);
73     return 2;
74 }
75 
76 static ULONG WINAPI client_security_Release(
77     IClientSecurity *iface )
78 {
79     FIXME("%p\n", iface);
80     return 1;
81 }
82 
83 static HRESULT WINAPI client_security_QueryBlanket(
84     IClientSecurity *iface,
85     IUnknown *pProxy,
86     DWORD *pAuthnSvc,
87     DWORD *pAuthzSvc,
88     OLECHAR **pServerPrincName,
89     DWORD *pAuthnLevel,
90     DWORD *pImpLevel,
91     void **pAuthInfo,
92     DWORD *pCapabilities )
93 {
94     FIXME("\n");
95     return WBEM_E_FAILED;
96 }
97 
98 static HRESULT WINAPI client_security_SetBlanket(
99     IClientSecurity *iface,
100     IUnknown *pProxy,
101     DWORD AuthnSvc,
102     DWORD AuthzSvc,
103     OLECHAR *pServerPrincName,
104     DWORD AuthnLevel,
105     DWORD ImpLevel,
106     void *pAuthInfo,
107     DWORD Capabilities )
108 {
109     static const OLECHAR defaultW[] =
110         {'<','C','O','L','E','_','D','E','F','A','U','L','T','_','P','R','I','N','C','I','P','A','L','>',0};
111     const OLECHAR *princname = (pServerPrincName == COLE_DEFAULT_PRINCIPAL) ? defaultW : pServerPrincName;
112 
113     FIXME("%p, %p, %u, %u, %s, %u, %u, %p, 0x%08x\n", iface, pProxy, AuthnSvc, AuthzSvc,
114           debugstr_w(princname), AuthnLevel, ImpLevel, pAuthInfo, Capabilities);
115     return WBEM_NO_ERROR;
116 }
117 
118 static HRESULT WINAPI client_security_CopyProxy(
119     IClientSecurity *iface,
120     IUnknown *pProxy,
121     IUnknown **ppCopy )
122 {
123     FIXME("\n");
124     return WBEM_E_FAILED;
125 }
126 
127 static const IClientSecurityVtbl client_security_vtbl =
128 {
129     client_security_QueryInterface,
130     client_security_AddRef,
131     client_security_Release,
132     client_security_QueryBlanket,
133     client_security_SetBlanket,
134     client_security_CopyProxy
135 };
136 
137 IClientSecurity client_security = { &client_security_vtbl };
138 
139 struct async_header
140 {
141     IWbemObjectSink *sink;
142     void (*proc)( struct async_header * );
143     HANDLE cancel;
144     HANDLE wait;
145 };
146 
147 struct async_query
148 {
149     struct async_header hdr;
150     WCHAR *str;
151 };
152 
153 static void free_async( struct async_header *async )
154 {
155     if (async->sink) IWbemObjectSink_Release( async->sink );
156     CloseHandle( async->cancel );
157     CloseHandle( async->wait );
158     heap_free( async );
159 }
160 
161 static BOOL init_async( struct async_header *async, IWbemObjectSink *sink,
162                         void (*proc)(struct async_header *) )
163 {
164     if (!(async->wait = CreateEventW( NULL, FALSE, FALSE, NULL ))) return FALSE;
165     if (!(async->cancel = CreateEventW( NULL, FALSE, FALSE, NULL )))
166     {
167         CloseHandle( async->wait );
168         return FALSE;
169     }
170     async->proc = proc;
171     async->sink = sink;
172     IWbemObjectSink_AddRef( sink );
173     return TRUE;
174 }
175 
176 static DWORD CALLBACK async_proc( LPVOID param )
177 {
178     struct async_header *async = param;
179     HANDLE wait = async->wait;
180 
181     async->proc( async );
182 
183     WaitForSingleObject( async->cancel, INFINITE );
184     SetEvent( wait );
185     return ERROR_SUCCESS;
186 }
187 
188 static HRESULT queue_async( struct async_header *async )
189 {
190     if (QueueUserWorkItem( async_proc, async, WT_EXECUTELONGFUNCTION )) return S_OK;
191     return HRESULT_FROM_WIN32( GetLastError() );
192 }
193 
194 struct wbem_services
195 {
196     IWbemServices IWbemServices_iface;
197     LONG refs;
198     CRITICAL_SECTION cs;
199     WCHAR *namespace;
200     struct async_header *async;
201 };
202 
203 static inline struct wbem_services *impl_from_IWbemServices( IWbemServices *iface )
204 {
205     return CONTAINING_RECORD( iface, struct wbem_services, IWbemServices_iface );
206 }
207 
208 static ULONG WINAPI wbem_services_AddRef(
209     IWbemServices *iface )
210 {
211     struct wbem_services *ws = impl_from_IWbemServices( iface );
212     return InterlockedIncrement( &ws->refs );
213 }
214 
215 static ULONG WINAPI wbem_services_Release(
216     IWbemServices *iface )
217 {
218     struct wbem_services *ws = impl_from_IWbemServices( iface );
219     LONG refs = InterlockedDecrement( &ws->refs );
220     if (!refs)
221     {
222         TRACE("destroying %p\n", ws);
223 
224         EnterCriticalSection( &ws->cs );
225         if (ws->async) SetEvent( ws->async->cancel );
226         LeaveCriticalSection( &ws->cs );
227         if (ws->async)
228         {
229             WaitForSingleObject( ws->async->wait, INFINITE );
230             free_async( ws->async );
231         }
232         ws->cs.DebugInfo->Spare[0] = 0;
233         DeleteCriticalSection( &ws->cs );
234         heap_free( ws->namespace );
235         heap_free( ws );
236     }
237     return refs;
238 }
239 
240 static HRESULT WINAPI wbem_services_QueryInterface(
241     IWbemServices *iface,
242     REFIID riid,
243     void **ppvObject )
244 {
245     struct wbem_services *ws = impl_from_IWbemServices( iface );
246 
247     TRACE("%p %s %p\n", ws, debugstr_guid( riid ), ppvObject );
248 
249     if ( IsEqualGUID( riid, &IID_IWbemServices ) ||
250          IsEqualGUID( riid, &IID_IUnknown ) )
251     {
252         *ppvObject = ws;
253     }
254     else if ( IsEqualGUID( riid, &IID_IClientSecurity ) )
255     {
256         *ppvObject = &client_security;
257         return S_OK;
258     }
259     else
260     {
261         FIXME("interface %s not implemented\n", debugstr_guid(riid));
262         return E_NOINTERFACE;
263     }
264     IWbemServices_AddRef( iface );
265     return S_OK;
266 }
267 
268 static HRESULT WINAPI wbem_services_OpenNamespace(
269     IWbemServices *iface,
270     const BSTR strNamespace,
271     LONG lFlags,
272     IWbemContext *pCtx,
273     IWbemServices **ppWorkingNamespace,
274     IWbemCallResult **ppResult )
275 {
276     static const WCHAR cimv2W[] = {'c','i','m','v','2',0};
277     static const WCHAR defaultW[] = {'d','e','f','a','u','l','t',0};
278     struct wbem_services *ws = impl_from_IWbemServices( iface );
279 
280     TRACE("%p, %s, 0x%08x, %p, %p, %p\n", iface, debugstr_w(strNamespace), lFlags,
281           pCtx, ppWorkingNamespace, ppResult);
282 
283     if ((wcsicmp( strNamespace, cimv2W ) && wcsicmp( strNamespace, defaultW )) || ws->namespace)
284         return WBEM_E_INVALID_NAMESPACE;
285 
286     return WbemServices_create( cimv2W, (void **)ppWorkingNamespace );
287 }
288 
289 static HRESULT WINAPI wbem_services_CancelAsyncCall(
290     IWbemServices *iface,
291     IWbemObjectSink *pSink )
292 {
293     struct wbem_services *services = impl_from_IWbemServices( iface );
294     struct async_header *async;
295 
296     TRACE("%p, %p\n", iface, pSink);
297 
298     if (!pSink) return WBEM_E_INVALID_PARAMETER;
299 
300     EnterCriticalSection( &services->cs );
301 
302     if (!(async = services->async))
303     {
304         LeaveCriticalSection( &services->cs );
305         return WBEM_E_INVALID_PARAMETER;
306     }
307     services->async = NULL;
308     SetEvent( async->cancel );
309 
310     LeaveCriticalSection( &services->cs );
311 
312     WaitForSingleObject( async->wait, INFINITE );
313     free_async( async );
314     return S_OK;
315 }
316 
317 static HRESULT WINAPI wbem_services_QueryObjectSink(
318     IWbemServices *iface,
319     LONG lFlags,
320     IWbemObjectSink **ppResponseHandler )
321 {
322     FIXME("\n");
323     return WBEM_E_FAILED;
324 }
325 
326 HRESULT parse_path( const WCHAR *str, struct path **ret )
327 {
328     struct path *path;
329     const WCHAR *p = str, *q;
330     UINT len;
331 
332     if (!(path = heap_alloc_zero( sizeof(*path) ))) return E_OUTOFMEMORY;
333 
334     if (*p == '\\')
335     {
336         static const WCHAR cimv2W[] = {'R','O','O','T','\\','C','I','M','V','2',0};
337         WCHAR server[MAX_COMPUTERNAME_LENGTH+1];
338         DWORD server_len = ARRAY_SIZE(server);
339 
340         p++;
341         if (*p != '\\')
342         {
343             heap_free( path );
344             return WBEM_E_INVALID_OBJECT_PATH;
345         }
346         p++;
347 
348         q = p;
349         while (*p && *p != '\\') p++;
350         if (!*p)
351         {
352             heap_free( path );
353             return WBEM_E_INVALID_OBJECT_PATH;
354         }
355 
356         len = p - q;
357         if (!GetComputerNameW( server, &server_len ) || server_len != len || _wcsnicmp( q, server, server_len ))
358         {
359             heap_free( path );
360             return WBEM_E_NOT_SUPPORTED;
361         }
362 
363         q = ++p;
364         while (*p && *p != ':') p++;
365         if (!*p)
366         {
367             heap_free( path );
368             return WBEM_E_INVALID_OBJECT_PATH;
369         }
370 
371         len = p - q;
372         if (len != ARRAY_SIZE(cimv2W) - 1 || _wcsnicmp( q, cimv2W, ARRAY_SIZE(cimv2W) - 1 ))
373         {
374             heap_free( path );
375             return WBEM_E_INVALID_NAMESPACE;
376         }
377         p++;
378     }
379 
380     q = p;
381     while (*p && *p != '.') p++;
382 
383     len = p - q;
384     if (!(path->class = heap_alloc( (len + 1) * sizeof(WCHAR) )))
385     {
386         heap_free( path );
387         return E_OUTOFMEMORY;
388     }
389     memcpy( path->class, q, len * sizeof(WCHAR) );
390     path->class[len] = 0;
391     path->class_len = len;
392 
393     if (p[0] == '.' && p[1])
394     {
395         q = ++p;
396         while (*q) q++;
397 
398         len = q - p;
399         if (!(path->filter = heap_alloc( (len + 1) * sizeof(WCHAR) )))
400         {
401             heap_free( path->class );
402             heap_free( path );
403             return E_OUTOFMEMORY;
404         }
405         memcpy( path->filter, p, len * sizeof(WCHAR) );
406         path->filter[len] = 0;
407         path->filter_len = len;
408     }
409     *ret = path;
410     return S_OK;
411 }
412 
413 void free_path( struct path *path )
414 {
415     if (!path) return;
416     heap_free( path->class );
417     heap_free( path->filter );
418     heap_free( path );
419 }
420 
421 WCHAR *query_from_path( const struct path *path )
422 {
423     static const WCHAR selectW[] =
424         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ','%','s',' ',
425          'W','H','E','R','E',' ','%','s',0};
426     static const WCHAR select_allW[] =
427         {'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ',0};
428     WCHAR *query;
429     UINT len;
430 
431     if (path->filter)
432     {
433         len = path->class_len + path->filter_len + ARRAY_SIZE(selectW);
434         if (!(query = heap_alloc( len * sizeof(WCHAR) ))) return NULL;
435         swprintf( query, selectW, path->class, path->filter );
436     }
437     else
438     {
439         len = path->class_len + ARRAY_SIZE(select_allW);
440         if (!(query = heap_alloc( len * sizeof(WCHAR) ))) return NULL;
441         lstrcpyW( query, select_allW );
442         lstrcatW( query, path->class );
443     }
444     return query;
445 }
446 
447 static HRESULT create_instance_enum( const struct path *path, IEnumWbemClassObject **iter )
448 {
449     WCHAR *query;
450     HRESULT hr;
451 
452     if (!(query = query_from_path( path ))) return E_OUTOFMEMORY;
453     hr = exec_query( query, iter );
454     heap_free( query );
455     return hr;
456 }
457 
458 HRESULT get_object( const WCHAR *object_path, IWbemClassObject **obj )
459 {
460     IEnumWbemClassObject *iter;
461     struct path *path;
462     HRESULT hr;
463 
464     hr = parse_path( object_path, &path );
465     if (hr != S_OK) return hr;
466 
467     hr = create_instance_enum( path, &iter );
468     if (hr != S_OK)
469     {
470         free_path( path );
471         return hr;
472     }
473     hr = create_class_object( path->class, iter, 0, NULL, obj );
474     IEnumWbemClassObject_Release( iter );
475     free_path( path );
476     return hr;
477 }
478 
479 static HRESULT WINAPI wbem_services_GetObject(
480     IWbemServices *iface,
481     const BSTR strObjectPath,
482     LONG lFlags,
483     IWbemContext *pCtx,
484     IWbemClassObject **ppObject,
485     IWbemCallResult **ppCallResult )
486 {
487     TRACE("%p, %s, 0x%08x, %p, %p, %p\n", iface, debugstr_w(strObjectPath), lFlags,
488           pCtx, ppObject, ppCallResult);
489 
490     if (lFlags) FIXME("unsupported flags 0x%08x\n", lFlags);
491 
492     if (!strObjectPath || !strObjectPath[0])
493         return create_class_object( NULL, NULL, 0, NULL, ppObject );
494 
495     return get_object( strObjectPath, ppObject );
496 }
497 
498 static HRESULT WINAPI wbem_services_GetObjectAsync(
499     IWbemServices *iface,
500     const BSTR strObjectPath,
501     LONG lFlags,
502     IWbemContext *pCtx,
503     IWbemObjectSink *pResponseHandler )
504 {
505     FIXME("\n");
506     return WBEM_E_FAILED;
507 }
508 
509 static HRESULT WINAPI wbem_services_PutClass(
510     IWbemServices *iface,
511     IWbemClassObject *pObject,
512     LONG lFlags,
513     IWbemContext *pCtx,
514     IWbemCallResult **ppCallResult )
515 {
516     FIXME("\n");
517     return WBEM_E_FAILED;
518 }
519 
520 static HRESULT WINAPI wbem_services_PutClassAsync(
521     IWbemServices *iface,
522     IWbemClassObject *pObject,
523     LONG lFlags,
524     IWbemContext *pCtx,
525     IWbemObjectSink *pResponseHandler )
526 {
527     FIXME("\n");
528     return WBEM_E_FAILED;
529 }
530 
531 static HRESULT WINAPI wbem_services_DeleteClass(
532     IWbemServices *iface,
533     const BSTR strClass,
534     LONG lFlags,
535     IWbemContext *pCtx,
536     IWbemCallResult **ppCallResult )
537 {
538     FIXME("\n");
539     return WBEM_E_FAILED;
540 }
541 
542 static HRESULT WINAPI wbem_services_DeleteClassAsync(
543     IWbemServices *iface,
544     const BSTR strClass,
545     LONG lFlags,
546     IWbemContext *pCtx,
547     IWbemObjectSink *pResponseHandler )
548 {
549     FIXME("\n");
550     return WBEM_E_FAILED;
551 }
552 
553 static HRESULT WINAPI wbem_services_CreateClassEnum(
554     IWbemServices *iface,
555     const BSTR strSuperclass,
556     LONG lFlags,
557     IWbemContext *pCtx,
558     IEnumWbemClassObject **ppEnum )
559 {
560     FIXME("\n");
561     return WBEM_E_FAILED;
562 }
563 
564 static HRESULT WINAPI wbem_services_CreateClassEnumAsync(
565     IWbemServices *iface,
566     const BSTR strSuperclass,
567     LONG lFlags,
568     IWbemContext *pCtx,
569     IWbemObjectSink *pResponseHandler )
570 {
571     FIXME("\n");
572     return WBEM_E_FAILED;
573 }
574 
575 static HRESULT WINAPI wbem_services_PutInstance(
576     IWbemServices *iface,
577     IWbemClassObject *pInst,
578     LONG lFlags,
579     IWbemContext *pCtx,
580     IWbemCallResult **ppCallResult )
581 {
582     FIXME("\n");
583     return WBEM_E_FAILED;
584 }
585 
586 static HRESULT WINAPI wbem_services_PutInstanceAsync(
587     IWbemServices *iface,
588     IWbemClassObject *pInst,
589     LONG lFlags,
590     IWbemContext *pCtx,
591     IWbemObjectSink *pResponseHandler )
592 {
593     FIXME("\n");
594     return WBEM_E_FAILED;
595 }
596 
597 static HRESULT WINAPI wbem_services_DeleteInstance(
598     IWbemServices *iface,
599     const BSTR strObjectPath,
600     LONG lFlags,
601     IWbemContext *pCtx,
602     IWbemCallResult **ppCallResult )
603 {
604     FIXME("\n");
605     return WBEM_E_FAILED;
606 }
607 
608 static HRESULT WINAPI wbem_services_DeleteInstanceAsync(
609     IWbemServices *iface,
610     const BSTR strObjectPath,
611     LONG lFlags,
612     IWbemContext *pCtx,
613     IWbemObjectSink *pResponseHandler )
614 {
615     FIXME("\n");
616     return WBEM_E_FAILED;
617 }
618 
619 static HRESULT WINAPI wbem_services_CreateInstanceEnum(
620     IWbemServices *iface,
621     const BSTR strClass,
622     LONG lFlags,
623     IWbemContext *pCtx,
624     IEnumWbemClassObject **ppEnum )
625 {
626     struct path *path;
627     HRESULT hr;
628 
629     TRACE("%p, %s, 0%08x, %p, %p\n", iface, debugstr_w(strClass), lFlags, pCtx, ppEnum);
630 
631     if (lFlags) FIXME("unsupported flags 0x%08x\n", lFlags);
632 
633     hr = parse_path( strClass, &path );
634     if (hr != S_OK) return hr;
635 
636     hr = create_instance_enum( path, ppEnum );
637     free_path( path );
638     return hr;
639 }
640 
641 static HRESULT WINAPI wbem_services_CreateInstanceEnumAsync(
642     IWbemServices *iface,
643     const BSTR strFilter,
644     LONG lFlags,
645     IWbemContext *pCtx,
646     IWbemObjectSink *pResponseHandler )
647 {
648     FIXME("\n");
649     return WBEM_E_FAILED;
650 }
651 
652 static HRESULT WINAPI wbem_services_ExecQuery(
653     IWbemServices *iface,
654     const BSTR strQueryLanguage,
655     const BSTR strQuery,
656     LONG lFlags,
657     IWbemContext *pCtx,
658     IEnumWbemClassObject **ppEnum )
659 {
660     static const WCHAR wqlW[] = {'W','Q','L',0};
661 
662     TRACE("%p, %s, %s, 0x%08x, %p, %p\n", iface, debugstr_w(strQueryLanguage),
663           debugstr_w(strQuery), lFlags, pCtx, ppEnum);
664 
665     if (!strQueryLanguage || !strQuery || !strQuery[0]) return WBEM_E_INVALID_PARAMETER;
666     if (wcsicmp( strQueryLanguage, wqlW )) return WBEM_E_INVALID_QUERY_TYPE;
667     return exec_query( strQuery, ppEnum );
668 }
669 
670 static void async_exec_query( struct async_header *hdr )
671 {
672     struct async_query *query = (struct async_query *)hdr;
673     IEnumWbemClassObject *result;
674     IWbemClassObject *obj;
675     ULONG count;
676     HRESULT hr;
677 
678     hr = exec_query( query->str, &result );
679     if (hr == S_OK)
680     {
681         for (;;)
682         {
683             IEnumWbemClassObject_Next( result, WBEM_INFINITE, 1, &obj, &count );
684             if (!count) break;
685             IWbemObjectSink_Indicate( query->hdr.sink, 1, &obj );
686             IWbemClassObject_Release( obj );
687         }
688         IEnumWbemClassObject_Release( result );
689     }
690     IWbemObjectSink_SetStatus( query->hdr.sink, WBEM_STATUS_COMPLETE, hr, NULL, NULL );
691     heap_free( query->str );
692 }
693 
694 static HRESULT WINAPI wbem_services_ExecQueryAsync(
695     IWbemServices *iface,
696     const BSTR strQueryLanguage,
697     const BSTR strQuery,
698     LONG lFlags,
699     IWbemContext *pCtx,
700     IWbemObjectSink *pResponseHandler )
701 {
702     struct wbem_services *services = impl_from_IWbemServices( iface );
703     IWbemObjectSink *sink;
704     HRESULT hr = E_OUTOFMEMORY;
705     struct async_header *async;
706     struct async_query *query;
707 
708     TRACE("%p, %s, %s, 0x%08x, %p, %p\n", iface, debugstr_w(strQueryLanguage), debugstr_w(strQuery),
709           lFlags, pCtx, pResponseHandler);
710 
711     if (!pResponseHandler) return WBEM_E_INVALID_PARAMETER;
712 
713     hr = IWbemObjectSink_QueryInterface( pResponseHandler, &IID_IWbemObjectSink, (void **)&sink );
714     if (FAILED(hr)) return hr;
715 
716     EnterCriticalSection( &services->cs );
717 
718     if (services->async)
719     {
720         FIXME("handle more than one pending async\n");
721         hr = WBEM_E_FAILED;
722         goto done;
723     }
724     if (!(query = heap_alloc_zero( sizeof(*query) ))) goto done;
725     async = (struct async_header *)query;
726 
727     if (!(init_async( async, sink, async_exec_query )))
728     {
729         free_async( async );
730         goto done;
731     }
732     if (!(query->str = heap_strdupW( strQuery )))
733     {
734         free_async( async );
735         goto done;
736     }
737     hr = queue_async( async );
738     if (hr == S_OK) services->async = async;
739     else
740     {
741         heap_free( query->str );
742         free_async( async );
743     }
744 
745 done:
746     LeaveCriticalSection( &services->cs );
747     IWbemObjectSink_Release( sink );
748     return hr;
749 }
750 
751 static HRESULT WINAPI wbem_services_ExecNotificationQuery(
752     IWbemServices *iface,
753     const BSTR strQueryLanguage,
754     const BSTR strQuery,
755     LONG lFlags,
756     IWbemContext *pCtx,
757     IEnumWbemClassObject **ppEnum )
758 {
759     FIXME("\n");
760     return WBEM_E_FAILED;
761 }
762 
763 static HRESULT WINAPI wbem_services_ExecNotificationQueryAsync(
764     IWbemServices *iface,
765     const BSTR strQueryLanguage,
766     const BSTR strQuery,
767     LONG lFlags,
768     IWbemContext *pCtx,
769     IWbemObjectSink *pResponseHandler )
770 {
771     struct wbem_services *services = impl_from_IWbemServices( iface );
772     IWbemObjectSink *sink;
773     HRESULT hr = E_OUTOFMEMORY;
774     struct async_header *async;
775     struct async_query *query;
776 
777     TRACE("%p, %s, %s, 0x%08x, %p, %p\n", iface, debugstr_w(strQueryLanguage), debugstr_w(strQuery),
778           lFlags, pCtx, pResponseHandler);
779 
780     if (!pResponseHandler) return WBEM_E_INVALID_PARAMETER;
781 
782     hr = IWbemObjectSink_QueryInterface( pResponseHandler, &IID_IWbemObjectSink, (void **)&sink );
783     if (FAILED(hr)) return hr;
784 
785     EnterCriticalSection( &services->cs );
786 
787     if (services->async)
788     {
789         FIXME("handle more than one pending async\n");
790         hr = WBEM_E_FAILED;
791         goto done;
792     }
793     if (!(query = heap_alloc_zero( sizeof(*query) ))) goto done;
794     async = (struct async_header *)query;
795 
796     if (!(init_async( async, sink, async_exec_query )))
797     {
798         free_async( async );
799         goto done;
800     }
801     if (!(query->str = heap_strdupW( strQuery )))
802     {
803         free_async( async );
804         goto done;
805     }
806     hr = queue_async( async );
807     if (hr == S_OK) services->async = async;
808     else
809     {
810         heap_free( query->str );
811         free_async( async );
812     }
813 
814 done:
815     LeaveCriticalSection( &services->cs );
816     IWbemObjectSink_Release( sink );
817     return hr;
818 }
819 
820 static HRESULT WINAPI wbem_services_ExecMethod(
821     IWbemServices *iface,
822     const BSTR strObjectPath,
823     const BSTR strMethodName,
824     LONG lFlags,
825     IWbemContext *pCtx,
826     IWbemClassObject *pInParams,
827     IWbemClassObject **ppOutParams,
828     IWbemCallResult **ppCallResult )
829 {
830     IEnumWbemClassObject *result = NULL;
831     IWbemClassObject *obj = NULL;
832     struct query *query = NULL;
833     struct path *path;
834     WCHAR *str;
835     class_method *func;
836     struct table *table;
837     HRESULT hr;
838 
839     TRACE("%p, %s, %s, %08x, %p, %p, %p, %p\n", iface, debugstr_w(strObjectPath),
840           debugstr_w(strMethodName), lFlags, pCtx, pInParams, ppOutParams, ppCallResult);
841 
842     if (lFlags) FIXME("flags %08x not supported\n", lFlags);
843 
844     if ((hr = parse_path( strObjectPath, &path )) != S_OK) return hr;
845     if (!(str = query_from_path( path )))
846     {
847         hr = E_OUTOFMEMORY;
848         goto done;
849     }
850     if (!(query = create_query()))
851     {
852         hr = E_OUTOFMEMORY;
853         goto done;
854     }
855     hr = parse_query( str, &query->view, &query->mem );
856     if (hr != S_OK) goto done;
857 
858     hr = execute_view( query->view );
859     if (hr != S_OK) goto done;
860 
861     hr = EnumWbemClassObject_create( query, (void **)&result );
862     if (hr != S_OK) goto done;
863 
864     table = get_view_table( query->view, 0 );
865     hr = create_class_object( table->name, result, 0, NULL, &obj );
866     if (hr != S_OK) goto done;
867 
868     hr = get_method( table, strMethodName, &func );
869     if (hr != S_OK) goto done;
870 
871     hr = func( obj, pInParams, ppOutParams );
872 
873 done:
874     if (result) IEnumWbemClassObject_Release( result );
875     if (obj) IWbemClassObject_Release( obj );
876     free_query( query );
877     free_path( path );
878     heap_free( str );
879     return hr;
880 }
881 
882 static HRESULT WINAPI wbem_services_ExecMethodAsync(
883     IWbemServices *iface,
884     const BSTR strObjectPath,
885     const BSTR strMethodName,
886     LONG lFlags,
887     IWbemContext *pCtx,
888     IWbemClassObject *pInParams,
889     IWbemObjectSink *pResponseHandler )
890 {
891     FIXME("\n");
892     return WBEM_E_FAILED;
893 }
894 
895 static const IWbemServicesVtbl wbem_services_vtbl =
896 {
897     wbem_services_QueryInterface,
898     wbem_services_AddRef,
899     wbem_services_Release,
900     wbem_services_OpenNamespace,
901     wbem_services_CancelAsyncCall,
902     wbem_services_QueryObjectSink,
903     wbem_services_GetObject,
904     wbem_services_GetObjectAsync,
905     wbem_services_PutClass,
906     wbem_services_PutClassAsync,
907     wbem_services_DeleteClass,
908     wbem_services_DeleteClassAsync,
909     wbem_services_CreateClassEnum,
910     wbem_services_CreateClassEnumAsync,
911     wbem_services_PutInstance,
912     wbem_services_PutInstanceAsync,
913     wbem_services_DeleteInstance,
914     wbem_services_DeleteInstanceAsync,
915     wbem_services_CreateInstanceEnum,
916     wbem_services_CreateInstanceEnumAsync,
917     wbem_services_ExecQuery,
918     wbem_services_ExecQueryAsync,
919     wbem_services_ExecNotificationQuery,
920     wbem_services_ExecNotificationQueryAsync,
921     wbem_services_ExecMethod,
922     wbem_services_ExecMethodAsync
923 };
924 
925 HRESULT WbemServices_create( const WCHAR *namespace, LPVOID *ppObj )
926 {
927     struct wbem_services *ws;
928 
929     TRACE("(%p)\n", ppObj);
930 
931     ws = heap_alloc( sizeof(*ws) );
932     if (!ws) return E_OUTOFMEMORY;
933 
934     ws->IWbemServices_iface.lpVtbl = &wbem_services_vtbl;
935     ws->refs      = 1;
936     ws->namespace = heap_strdupW( namespace );
937     ws->async     = NULL;
938     InitializeCriticalSection( &ws->cs );
939     ws->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": wbemprox_services.cs");
940 
941     *ppObj = &ws->IWbemServices_iface;
942 
943     TRACE("returning iface %p\n", *ppObj);
944     return S_OK;
945 }
946