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