/* * Copyright 2012 Hans Leidekker for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #define COBJMACROS #include #include "windef.h" #include "winbase.h" #include "objbase.h" #include "wbemcli.h" #include "wine/debug.h" #include "wbemprox_private.h" WINE_DEFAULT_DEBUG_CHANNEL(wbemprox); struct client_security { IClientSecurity IClientSecurity_iface; }; static inline struct client_security *impl_from_IClientSecurity( IClientSecurity *iface ) { return CONTAINING_RECORD( iface, struct client_security, IClientSecurity_iface ); } static HRESULT WINAPI client_security_QueryInterface( IClientSecurity *iface, REFIID riid, void **ppvObject ) { struct client_security *cs = impl_from_IClientSecurity( iface ); TRACE("%p %s %p\n", cs, debugstr_guid( riid ), ppvObject ); if ( IsEqualGUID( riid, &IID_IClientSecurity ) || IsEqualGUID( riid, &IID_IUnknown ) ) { *ppvObject = cs; } else { FIXME("interface %s not implemented\n", debugstr_guid(riid)); return E_NOINTERFACE; } IClientSecurity_AddRef( iface ); return S_OK; } static ULONG WINAPI client_security_AddRef( IClientSecurity *iface ) { FIXME("%p\n", iface); return 2; } static ULONG WINAPI client_security_Release( IClientSecurity *iface ) { FIXME("%p\n", iface); return 1; } static HRESULT WINAPI client_security_QueryBlanket( IClientSecurity *iface, IUnknown *pProxy, DWORD *pAuthnSvc, DWORD *pAuthzSvc, OLECHAR **pServerPrincName, DWORD *pAuthnLevel, DWORD *pImpLevel, void **pAuthInfo, DWORD *pCapabilities ) { FIXME("semi-stub.\n"); if (pAuthnSvc) *pAuthnSvc = RPC_C_AUTHN_NONE; if (pAuthzSvc) *pAuthzSvc = RPC_C_AUTHZ_NONE; if (pServerPrincName) *pServerPrincName = NULL; if (pAuthnLevel) *pAuthnLevel = RPC_C_AUTHN_LEVEL_NONE; if (pImpLevel) *pImpLevel = RPC_C_IMP_LEVEL_DEFAULT; if (pAuthInfo) *pAuthInfo = NULL; if (pCapabilities) *pCapabilities = 0; return WBEM_NO_ERROR; } static HRESULT WINAPI client_security_SetBlanket( IClientSecurity *iface, IUnknown *pProxy, DWORD AuthnSvc, DWORD AuthzSvc, OLECHAR *pServerPrincName, DWORD AuthnLevel, DWORD ImpLevel, void *pAuthInfo, DWORD Capabilities ) { const OLECHAR *princname = (pServerPrincName == COLE_DEFAULT_PRINCIPAL) ? L"" : pServerPrincName; FIXME("%p, %p, %u, %u, %s, %u, %u, %p, 0x%08x\n", iface, pProxy, AuthnSvc, AuthzSvc, debugstr_w(princname), AuthnLevel, ImpLevel, pAuthInfo, Capabilities); return WBEM_NO_ERROR; } static HRESULT WINAPI client_security_CopyProxy( IClientSecurity *iface, IUnknown *pProxy, IUnknown **ppCopy ) { FIXME("\n"); return WBEM_E_FAILED; } static const IClientSecurityVtbl client_security_vtbl = { client_security_QueryInterface, client_security_AddRef, client_security_Release, client_security_QueryBlanket, client_security_SetBlanket, client_security_CopyProxy }; 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; IWbemContext *context; }; static inline struct wbem_services *impl_from_IWbemServices( IWbemServices *iface ) { return CONTAINING_RECORD( iface, struct wbem_services, IWbemServices_iface ); } static ULONG WINAPI wbem_services_AddRef( IWbemServices *iface ) { struct wbem_services *ws = impl_from_IWbemServices( iface ); return InterlockedIncrement( &ws->refs ); } static ULONG WINAPI wbem_services_Release( IWbemServices *iface ) { struct wbem_services *ws = impl_from_IWbemServices( iface ); LONG refs = InterlockedDecrement( &ws->refs ); 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 ); if (ws->context) IWbemContext_Release( ws->context ); heap_free( ws->namespace ); heap_free( ws ); } return refs; } static HRESULT WINAPI wbem_services_QueryInterface( IWbemServices *iface, REFIID riid, void **ppvObject ) { struct wbem_services *ws = impl_from_IWbemServices( iface ); TRACE("%p %s %p\n", ws, debugstr_guid( riid ), ppvObject ); if ( IsEqualGUID( riid, &IID_IWbemServices ) || IsEqualGUID( riid, &IID_IUnknown ) ) { *ppvObject = ws; } else if ( IsEqualGUID( riid, &IID_IClientSecurity ) ) { *ppvObject = &client_security; return S_OK; } else { FIXME("interface %s not implemented\n", debugstr_guid(riid)); return E_NOINTERFACE; } IWbemServices_AddRef( iface ); return S_OK; } static HRESULT WINAPI wbem_services_OpenNamespace( IWbemServices *iface, const BSTR strNamespace, LONG lFlags, IWbemContext *pCtx, IWbemServices **ppWorkingNamespace, IWbemCallResult **ppResult ) { struct wbem_services *ws = impl_from_IWbemServices( iface ); TRACE("%p, %s, 0x%08x, %p, %p, %p\n", iface, debugstr_w(strNamespace), lFlags, pCtx, ppWorkingNamespace, ppResult); if ((wcsicmp( strNamespace, L"cimv2" ) && wcsicmp( strNamespace, L"default" )) || ws->namespace) return WBEM_E_INVALID_NAMESPACE; return WbemServices_create( L"cimv2", NULL, (void **)ppWorkingNamespace ); } static HRESULT WINAPI wbem_services_CancelAsyncCall( IWbemServices *iface, IWbemObjectSink *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 ); WaitForSingleObject( async->wait, INFINITE ); free_async( async ); return S_OK; } static HRESULT WINAPI wbem_services_QueryObjectSink( IWbemServices *iface, LONG lFlags, IWbemObjectSink **ppResponseHandler ) { FIXME("\n"); return WBEM_E_FAILED; } HRESULT parse_path( const WCHAR *str, struct path **ret ) { struct path *path; const WCHAR *p = str, *q; UINT len; if (!(path = heap_alloc_zero( sizeof(*path) ))) return E_OUTOFMEMORY; if (*p == '\\') { static const WCHAR cimv2W[] = L"ROOT\\CIMV2"; WCHAR server[MAX_COMPUTERNAME_LENGTH+1]; DWORD server_len = ARRAY_SIZE(server); p++; if (*p != '\\') { heap_free( path ); return WBEM_E_INVALID_OBJECT_PATH; } p++; q = p; while (*p && *p != '\\') p++; if (!*p) { heap_free( path ); return WBEM_E_INVALID_OBJECT_PATH; } len = p - q; if (!GetComputerNameW( server, &server_len ) || server_len != len || wcsnicmp( q, server, server_len )) { heap_free( path ); return WBEM_E_NOT_SUPPORTED; } q = ++p; while (*p && *p != ':') p++; if (!*p) { heap_free( path ); return WBEM_E_INVALID_OBJECT_PATH; } len = p - q; if (len != ARRAY_SIZE(cimv2W) - 1 || wcsnicmp( q, cimv2W, ARRAY_SIZE(cimv2W) - 1 )) { heap_free( path ); return WBEM_E_INVALID_NAMESPACE; } p++; } q = p; while (*p && *p != '.') p++; len = p - q; if (!(path->class = heap_alloc( (len + 1) * sizeof(WCHAR) ))) { heap_free( path ); return E_OUTOFMEMORY; } memcpy( path->class, q, len * sizeof(WCHAR) ); path->class[len] = 0; path->class_len = len; if (p[0] == '.' && p[1]) { q = ++p; while (*q) q++; len = q - p; if (!(path->filter = heap_alloc( (len + 1) * sizeof(WCHAR) ))) { heap_free( path->class ); heap_free( path ); return E_OUTOFMEMORY; } memcpy( path->filter, p, len * sizeof(WCHAR) ); path->filter[len] = 0; path->filter_len = len; } *ret = path; return S_OK; } void free_path( struct path *path ) { if (!path) return; heap_free( path->class ); heap_free( path->filter ); heap_free( path ); } WCHAR *query_from_path( const struct path *path ) { static const WCHAR selectW[] = L"SELECT * FROM %s WHERE %s"; static const WCHAR select_allW[] = L"SELECT * FROM "; WCHAR *query; UINT len; if (path->filter) { len = path->class_len + path->filter_len + ARRAY_SIZE(selectW); if (!(query = heap_alloc( len * sizeof(WCHAR) ))) return NULL; swprintf( query, len, selectW, path->class, path->filter ); } else { len = path->class_len + ARRAY_SIZE(select_allW); if (!(query = heap_alloc( len * sizeof(WCHAR) ))) return NULL; lstrcpyW( query, select_allW ); lstrcatW( query, path->class ); } return query; } static HRESULT create_instance_enum( const struct path *path, IEnumWbemClassObject **iter ) { WCHAR *query; HRESULT hr; if (!(query = query_from_path( path ))) return E_OUTOFMEMORY; hr = exec_query( query, iter ); heap_free( query ); return hr; } HRESULT get_object( const WCHAR *object_path, IWbemClassObject **obj ) { IEnumWbemClassObject *iter; struct path *path; ULONG count; HRESULT hr; hr = parse_path( object_path, &path ); if (hr != S_OK) return hr; hr = create_instance_enum( path, &iter ); if (hr != S_OK) { free_path( path ); return hr; } hr = IEnumWbemClassObject_Next( iter, WBEM_INFINITE, 1, obj, &count ); if (hr == WBEM_S_FALSE) { hr = WBEM_E_NOT_FOUND; *obj = NULL; } IEnumWbemClassObject_Release( iter ); free_path( path ); return hr; } static HRESULT WINAPI wbem_services_GetObject( IWbemServices *iface, const BSTR strObjectPath, LONG lFlags, IWbemContext *pCtx, IWbemClassObject **ppObject, IWbemCallResult **ppCallResult ) { TRACE("%p, %s, 0x%08x, %p, %p, %p\n", iface, debugstr_w(strObjectPath), lFlags, pCtx, ppObject, ppCallResult); if (lFlags) FIXME("unsupported flags 0x%08x\n", lFlags); if (!strObjectPath || !strObjectPath[0]) return create_class_object( NULL, NULL, 0, NULL, ppObject ); return get_object( strObjectPath, ppObject ); } static HRESULT WINAPI wbem_services_GetObjectAsync( IWbemServices *iface, const BSTR strObjectPath, LONG lFlags, IWbemContext *pCtx, IWbemObjectSink *pResponseHandler ) { FIXME("\n"); return WBEM_E_FAILED; } static HRESULT WINAPI wbem_services_PutClass( IWbemServices *iface, IWbemClassObject *pObject, LONG lFlags, IWbemContext *pCtx, IWbemCallResult **ppCallResult ) { FIXME("\n"); return WBEM_E_FAILED; } static HRESULT WINAPI wbem_services_PutClassAsync( IWbemServices *iface, IWbemClassObject *pObject, LONG lFlags, IWbemContext *pCtx, IWbemObjectSink *pResponseHandler ) { FIXME("\n"); return WBEM_E_FAILED; } static HRESULT WINAPI wbem_services_DeleteClass( IWbemServices *iface, const BSTR strClass, LONG lFlags, IWbemContext *pCtx, IWbemCallResult **ppCallResult ) { FIXME("\n"); return WBEM_E_FAILED; } static HRESULT WINAPI wbem_services_DeleteClassAsync( IWbemServices *iface, const BSTR strClass, LONG lFlags, IWbemContext *pCtx, IWbemObjectSink *pResponseHandler ) { FIXME("\n"); return WBEM_E_FAILED; } static HRESULT WINAPI wbem_services_CreateClassEnum( IWbemServices *iface, const BSTR strSuperclass, LONG lFlags, IWbemContext *pCtx, IEnumWbemClassObject **ppEnum ) { FIXME("\n"); return WBEM_E_FAILED; } static HRESULT WINAPI wbem_services_CreateClassEnumAsync( IWbemServices *iface, const BSTR strSuperclass, LONG lFlags, IWbemContext *pCtx, IWbemObjectSink *pResponseHandler ) { FIXME("\n"); return WBEM_E_FAILED; } static HRESULT WINAPI wbem_services_PutInstance( IWbemServices *iface, IWbemClassObject *pInst, LONG lFlags, IWbemContext *pCtx, IWbemCallResult **ppCallResult ) { FIXME("\n"); return WBEM_E_FAILED; } static HRESULT WINAPI wbem_services_PutInstanceAsync( IWbemServices *iface, IWbemClassObject *pInst, LONG lFlags, IWbemContext *pCtx, IWbemObjectSink *pResponseHandler ) { FIXME("\n"); return WBEM_E_FAILED; } static HRESULT WINAPI wbem_services_DeleteInstance( IWbemServices *iface, const BSTR strObjectPath, LONG lFlags, IWbemContext *pCtx, IWbemCallResult **ppCallResult ) { FIXME("\n"); return WBEM_E_FAILED; } static HRESULT WINAPI wbem_services_DeleteInstanceAsync( IWbemServices *iface, const BSTR strObjectPath, LONG lFlags, IWbemContext *pCtx, IWbemObjectSink *pResponseHandler ) { FIXME("\n"); return WBEM_E_FAILED; } static HRESULT WINAPI wbem_services_CreateInstanceEnum( IWbemServices *iface, const BSTR strClass, LONG lFlags, IWbemContext *pCtx, IEnumWbemClassObject **ppEnum ) { struct path *path; HRESULT hr; TRACE("%p, %s, 0%08x, %p, %p\n", iface, debugstr_w(strClass), lFlags, pCtx, ppEnum); if (lFlags) FIXME("unsupported flags 0x%08x\n", lFlags); hr = parse_path( strClass, &path ); if (hr != S_OK) return hr; hr = create_instance_enum( path, ppEnum ); free_path( path ); return hr; } static HRESULT WINAPI wbem_services_CreateInstanceEnumAsync( IWbemServices *iface, const BSTR strFilter, LONG lFlags, IWbemContext *pCtx, IWbemObjectSink *pResponseHandler ) { FIXME("\n"); return WBEM_E_FAILED; } static HRESULT WINAPI wbem_services_ExecQuery( IWbemServices *iface, const BSTR strQueryLanguage, const BSTR strQuery, LONG lFlags, IWbemContext *pCtx, IEnumWbemClassObject **ppEnum ) { TRACE("%p, %s, %s, 0x%08x, %p, %p\n", iface, debugstr_w(strQueryLanguage), debugstr_w(strQuery), lFlags, pCtx, ppEnum); if (!strQueryLanguage || !strQuery || !strQuery[0]) return WBEM_E_INVALID_PARAMETER; if (wcsicmp( strQueryLanguage, L"WQL" )) return WBEM_E_INVALID_QUERY_TYPE; 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, const BSTR strQuery, LONG lFlags, IWbemContext *pCtx, IWbemObjectSink *pResponseHandler ) { 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( IWbemServices *iface, const BSTR strQueryLanguage, const BSTR strQuery, LONG lFlags, IWbemContext *pCtx, IEnumWbemClassObject **ppEnum ) { FIXME("\n"); return WBEM_E_FAILED; } static HRESULT WINAPI wbem_services_ExecNotificationQueryAsync( IWbemServices *iface, const BSTR strQueryLanguage, const BSTR strQuery, LONG lFlags, IWbemContext *pCtx, IWbemObjectSink *pResponseHandler ) { 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_ExecMethod( IWbemServices *iface, const BSTR strObjectPath, const BSTR strMethodName, LONG lFlags, IWbemContext *pCtx, IWbemClassObject *pInParams, IWbemClassObject **ppOutParams, IWbemCallResult **ppCallResult ) { IEnumWbemClassObject *result = NULL; IWbemClassObject *obj = NULL; struct query *query = NULL; struct path *path; WCHAR *str; class_method *func; struct table *table; HRESULT hr; TRACE("%p, %s, %s, %08x, %p, %p, %p, %p\n", iface, debugstr_w(strObjectPath), debugstr_w(strMethodName), lFlags, pCtx, pInParams, ppOutParams, ppCallResult); if (lFlags) FIXME("flags %08x not supported\n", lFlags); if ((hr = parse_path( strObjectPath, &path )) != S_OK) return hr; if (!(str = query_from_path( path ))) { hr = E_OUTOFMEMORY; goto done; } if (!(query = create_query())) { hr = E_OUTOFMEMORY; goto done; } hr = parse_query( str, &query->view, &query->mem ); if (hr != S_OK) goto done; hr = execute_view( query->view ); if (hr != S_OK) goto done; hr = EnumWbemClassObject_create( query, (void **)&result ); if (hr != S_OK) goto done; table = get_view_table( query->view, 0 ); hr = create_class_object( table->name, result, 0, NULL, &obj ); if (hr != S_OK) goto done; hr = get_method( table, strMethodName, &func ); if (hr != S_OK) goto done; hr = func( obj, NULL, pInParams, ppOutParams ); done: if (result) IEnumWbemClassObject_Release( result ); if (obj) IWbemClassObject_Release( obj ); free_query( query ); free_path( path ); heap_free( str ); return hr; } static HRESULT WINAPI wbem_services_ExecMethodAsync( IWbemServices *iface, const BSTR strObjectPath, const BSTR strMethodName, LONG lFlags, IWbemContext *pCtx, IWbemClassObject *pInParams, IWbemObjectSink *pResponseHandler ) { FIXME("\n"); return WBEM_E_FAILED; } static const IWbemServicesVtbl wbem_services_vtbl = { wbem_services_QueryInterface, wbem_services_AddRef, wbem_services_Release, wbem_services_OpenNamespace, wbem_services_CancelAsyncCall, wbem_services_QueryObjectSink, wbem_services_GetObject, wbem_services_GetObjectAsync, wbem_services_PutClass, wbem_services_PutClassAsync, wbem_services_DeleteClass, wbem_services_DeleteClassAsync, wbem_services_CreateClassEnum, wbem_services_CreateClassEnumAsync, wbem_services_PutInstance, wbem_services_PutInstanceAsync, wbem_services_DeleteInstance, wbem_services_DeleteInstanceAsync, wbem_services_CreateInstanceEnum, wbem_services_CreateInstanceEnumAsync, wbem_services_ExecQuery, wbem_services_ExecQueryAsync, wbem_services_ExecNotificationQuery, wbem_services_ExecNotificationQueryAsync, wbem_services_ExecMethod, wbem_services_ExecMethodAsync }; HRESULT WbemServices_create( const WCHAR *namespace, IWbemContext *context, LPVOID *ppObj ) { struct wbem_services *ws; TRACE("(%p)\n", ppObj); ws = heap_alloc_zero( sizeof(*ws) ); if (!ws) return E_OUTOFMEMORY; ws->IWbemServices_iface.lpVtbl = &wbem_services_vtbl; ws->refs = 1; ws->namespace = heap_strdupW( namespace ); InitializeCriticalSection( &ws->cs ); ws->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": wbemprox_services.cs"); if (context) IWbemContext_Clone( context, &ws->context ); *ppObj = &ws->IWbemServices_iface; TRACE("returning iface %p\n", *ppObj); return S_OK; } struct wbem_context_value { struct list entry; WCHAR *name; VARIANT value; }; struct wbem_context { IWbemContext IWbemContext_iface; LONG refs; struct list values; }; static void wbem_context_delete_values(struct wbem_context *context) { struct wbem_context_value *value, *next; LIST_FOR_EACH_ENTRY_SAFE(value, next, &context->values, struct wbem_context_value, entry) { list_remove( &value->entry ); VariantClear( &value->value ); heap_free( value->name ); heap_free( value ); } } static struct wbem_context *impl_from_IWbemContext( IWbemContext *iface ) { return CONTAINING_RECORD( iface, struct wbem_context, IWbemContext_iface ); } static HRESULT WINAPI wbem_context_QueryInterface( IWbemContext *iface, REFIID riid, void **obj) { TRACE("%p, %s, %p\n", iface, debugstr_guid( riid ), obj ); if ( IsEqualGUID( riid, &IID_IWbemContext ) || IsEqualGUID( riid, &IID_IUnknown ) ) { *obj = iface; } else { FIXME("interface %s not implemented\n", debugstr_guid(riid)); return E_NOINTERFACE; } IWbemContext_AddRef( iface ); return S_OK; } static ULONG WINAPI wbem_context_AddRef( IWbemContext *iface ) { struct wbem_context *context = impl_from_IWbemContext( iface ); return InterlockedIncrement( &context->refs ); } static ULONG WINAPI wbem_context_Release( IWbemContext *iface ) { struct wbem_context *context = impl_from_IWbemContext( iface ); LONG refs = InterlockedDecrement( &context->refs ); if (!refs) { TRACE("destroying %p\n", context); wbem_context_delete_values( context ); heap_free( context ); } return refs; } static HRESULT WINAPI wbem_context_Clone( IWbemContext *iface, IWbemContext **newcopy ) { struct wbem_context *context = impl_from_IWbemContext( iface ); struct wbem_context_value *value; IWbemContext *cloned_context; HRESULT hr; TRACE("%p, %p\n", iface, newcopy); if (SUCCEEDED(hr = WbemContext_create( (void **)&cloned_context ))) { LIST_FOR_EACH_ENTRY( value, &context->values, struct wbem_context_value, entry ) { if (FAILED(hr = IWbemContext_SetValue( cloned_context, value->name, 0, &value->value ))) break; } } if (SUCCEEDED(hr)) { *newcopy = cloned_context; } else { *newcopy = NULL; IWbemContext_Release( cloned_context ); } return hr; } static HRESULT WINAPI wbem_context_GetNames( IWbemContext *iface, LONG flags, SAFEARRAY **names ) { FIXME("%p, %#x, %p\n", iface, flags, names); return E_NOTIMPL; } static HRESULT WINAPI wbem_context_BeginEnumeration( IWbemContext *iface, LONG flags ) { FIXME("%p, %#x\n", iface, flags); return E_NOTIMPL; } static HRESULT WINAPI wbem_context_Next( IWbemContext *iface, LONG flags, BSTR *name, VARIANT *value ) { FIXME("%p, %#x, %p, %p\n", iface, flags, name, value); return E_NOTIMPL; } static HRESULT WINAPI wbem_context_EndEnumeration( IWbemContext *iface ) { FIXME("%p\n", iface); return E_NOTIMPL; } static struct wbem_context_value *wbem_context_get_value( struct wbem_context *context, const WCHAR *name ) { struct wbem_context_value *value; LIST_FOR_EACH_ENTRY( value, &context->values, struct wbem_context_value, entry ) { if (!lstrcmpiW( value->name, name )) return value; } return NULL; } static HRESULT WINAPI wbem_context_SetValue( IWbemContext *iface, LPCWSTR name, LONG flags, VARIANT *var ) { struct wbem_context *context = impl_from_IWbemContext( iface ); struct wbem_context_value *value; HRESULT hr; TRACE("%p, %s, %#x, %s\n", iface, debugstr_w(name), flags, debugstr_variant(var)); if (!name || !var) return WBEM_E_INVALID_PARAMETER; if ((value = wbem_context_get_value( context, name ))) { VariantClear( &value->value ); hr = VariantCopy( &value->value, var ); } else { if (!(value = heap_alloc_zero( sizeof(*value) ))) return E_OUTOFMEMORY; if (!(value->name = heap_strdupW( name ))) { heap_free( value ); return E_OUTOFMEMORY; } if (FAILED(hr = VariantCopy( &value->value, var ))) { heap_free( value->name ); heap_free( value ); return hr; } list_add_tail( &context->values, &value->entry ); } return hr; } static HRESULT WINAPI wbem_context_GetValue( IWbemContext *iface, LPCWSTR name, LONG flags, VARIANT *var ) { struct wbem_context *context = impl_from_IWbemContext( iface ); struct wbem_context_value *value; TRACE("%p, %s, %#x, %p\n", iface, debugstr_w(name), flags, var); if (!name || !var) return WBEM_E_INVALID_PARAMETER; if (!(value = wbem_context_get_value( context, name ))) return WBEM_E_NOT_FOUND; V_VT(var) = VT_EMPTY; return VariantCopy( var, &value->value ); } static HRESULT WINAPI wbem_context_DeleteValue( IWbemContext *iface, LPCWSTR name, LONG flags ) { FIXME("%p, %s, %#x\n", iface, debugstr_w(name), flags); return E_NOTIMPL; } static HRESULT WINAPI wbem_context_DeleteAll( IWbemContext *iface ) { FIXME("%p\n", iface); return E_NOTIMPL; } static const IWbemContextVtbl wbem_context_vtbl = { wbem_context_QueryInterface, wbem_context_AddRef, wbem_context_Release, wbem_context_Clone, wbem_context_GetNames, wbem_context_BeginEnumeration, wbem_context_Next, wbem_context_EndEnumeration, wbem_context_SetValue, wbem_context_GetValue, wbem_context_DeleteValue, wbem_context_DeleteAll, }; HRESULT WbemContext_create( void **obj ) { struct wbem_context *context; TRACE("(%p)\n", obj); context = heap_alloc( sizeof(*context) ); if (!context) return E_OUTOFMEMORY; context->IWbemContext_iface.lpVtbl = &wbem_context_vtbl; context->refs = 1; list_init(&context->values); *obj = &context->IWbemContext_iface; TRACE("returning iface %p\n", *obj); return S_OK; }