/* * Copyright 2014 Martin Storsjo * Copyright 2016 Michael Müller * * 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 "objbase.h" #include "initguid.h" #include "roapi.h" #include "roparameterizediid.h" #include "roerrorapi.h" #include "winstring.h" #include "combase_private.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(combase); struct activatable_class_data { ULONG size; DWORD unk; DWORD module_len; DWORD module_offset; DWORD threading_model; }; static HRESULT get_library_for_classid(const WCHAR *classid, WCHAR **out) { ACTCTX_SECTION_KEYED_DATA data; HKEY hkey_root, hkey_class; DWORD type, size; HRESULT hr; WCHAR *buf = NULL; *out = NULL; /* search activation context first */ data.cbSize = sizeof(data); if (FindActCtxSectionStringW(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL, ACTIVATION_CONTEXT_SECTION_WINRT_ACTIVATABLE_CLASSES, classid, &data)) { struct activatable_class_data *activatable_class = (struct activatable_class_data *)data.lpData; void *ptr = (BYTE *)data.lpSectionBase + activatable_class->module_offset; *out = wcsdup(ptr); return S_OK; } /* load class registry key */ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\WindowsRuntime\\ActivatableClassId", 0, KEY_READ, &hkey_root)) return REGDB_E_READREGDB; if (RegOpenKeyExW(hkey_root, classid, 0, KEY_READ, &hkey_class)) { WARN("Class %s not found in registry\n", debugstr_w(classid)); RegCloseKey(hkey_root); return REGDB_E_CLASSNOTREG; } RegCloseKey(hkey_root); /* load (and expand) DllPath registry value */ if (RegQueryValueExW(hkey_class, L"DllPath", NULL, &type, NULL, &size)) { hr = REGDB_E_READREGDB; goto done; } if (type != REG_SZ && type != REG_EXPAND_SZ) { hr = REGDB_E_READREGDB; goto done; } if (!(buf = malloc(size))) { hr = E_OUTOFMEMORY; goto done; } if (RegQueryValueExW(hkey_class, L"DllPath", NULL, NULL, (BYTE *)buf, &size)) { hr = REGDB_E_READREGDB; goto done; } if (type == REG_EXPAND_SZ) { WCHAR *expanded; DWORD len = ExpandEnvironmentStringsW(buf, NULL, 0); if (!(expanded = malloc(len * sizeof(WCHAR)))) { hr = E_OUTOFMEMORY; goto done; } ExpandEnvironmentStringsW(buf, expanded, len); free(buf); buf = expanded; } *out = buf; return S_OK; done: free(buf); RegCloseKey(hkey_class); return hr; } /*********************************************************************** * RoInitialize (combase.@) */ HRESULT WINAPI RoInitialize(RO_INIT_TYPE type) { switch (type) { case RO_INIT_SINGLETHREADED: return CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); default: FIXME("type %d\n", type); case RO_INIT_MULTITHREADED: return CoInitializeEx(NULL, COINIT_MULTITHREADED); } } /*********************************************************************** * RoUninitialize (combase.@) */ void WINAPI RoUninitialize(void) { CoUninitialize(); } /*********************************************************************** * RoGetActivationFactory (combase.@) */ HRESULT WINAPI DECLSPEC_HOTPATCH RoGetActivationFactory(HSTRING classid, REFIID iid, void **class_factory) { PFNGETACTIVATIONFACTORY pDllGetActivationFactory; IActivationFactory *factory; WCHAR *library; HMODULE module; HRESULT hr; FIXME("(%s, %s, %p): semi-stub\n", debugstr_hstring(classid), debugstr_guid(iid), class_factory); if (!iid || !class_factory) return E_INVALIDARG; if (FAILED(hr = ensure_mta())) return hr; hr = get_library_for_classid(WindowsGetStringRawBuffer(classid, NULL), &library); if (FAILED(hr)) { ERR("Failed to find library for %s\n", debugstr_hstring(classid)); return hr; } if (!(module = LoadLibraryW(library))) { ERR("Failed to load module %s\n", debugstr_w(library)); hr = HRESULT_FROM_WIN32(GetLastError()); goto done; } if (!(pDllGetActivationFactory = (void *)GetProcAddress(module, "DllGetActivationFactory"))) { ERR("Module %s does not implement DllGetActivationFactory\n", debugstr_w(library)); hr = E_FAIL; goto done; } TRACE("Found library %s for class %s\n", debugstr_w(library), debugstr_hstring(classid)); hr = pDllGetActivationFactory(classid, &factory); if (SUCCEEDED(hr)) { hr = IActivationFactory_QueryInterface(factory, iid, class_factory); if (SUCCEEDED(hr)) { TRACE("Created interface %p\n", *class_factory); module = NULL; } IActivationFactory_Release(factory); } done: free(library); if (module) FreeLibrary(module); return hr; } /*********************************************************************** * RoGetParameterizedTypeInstanceIID (combase.@) */ HRESULT WINAPI RoGetParameterizedTypeInstanceIID(UINT32 name_element_count, const WCHAR **name_elements, const IRoMetaDataLocator *meta_data_locator, GUID *iid, ROPARAMIIDHANDLE *hiid) { FIXME("stub: %d %p %p %p %p\n", name_element_count, name_elements, meta_data_locator, iid, hiid); if (iid) *iid = GUID_NULL; if (hiid) *hiid = INVALID_HANDLE_VALUE; return E_NOTIMPL; } /*********************************************************************** * RoActivateInstance (combase.@) */ HRESULT WINAPI RoActivateInstance(HSTRING classid, IInspectable **instance) { IActivationFactory *factory; HRESULT hr; FIXME("(%p, %p): semi-stub\n", classid, instance); hr = RoGetActivationFactory(classid, &IID_IActivationFactory, (void **)&factory); if (SUCCEEDED(hr)) { hr = IActivationFactory_ActivateInstance(factory, instance); IActivationFactory_Release(factory); } return hr; } struct agile_reference { IAgileReference IAgileReference_iface; enum AgileReferenceOptions option; IStream *marshal_stream; CRITICAL_SECTION cs; IUnknown *obj; LONG ref; }; static HRESULT marshal_object_in_agile_reference(struct agile_reference *ref, REFIID riid, IUnknown *obj) { HRESULT hr; hr = CreateStreamOnHGlobal(0, TRUE, &ref->marshal_stream); if (FAILED(hr)) return hr; hr = CoMarshalInterface(ref->marshal_stream, riid, obj, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLESTRONG); if (FAILED(hr)) { IStream_Release(ref->marshal_stream); ref->marshal_stream = NULL; } return hr; } static inline struct agile_reference *impl_from_IAgileReference(IAgileReference *iface) { return CONTAINING_RECORD(iface, struct agile_reference, IAgileReference_iface); } static HRESULT WINAPI agile_ref_QueryInterface(IAgileReference *iface, REFIID riid, void **obj) { TRACE("(%p, %s, %p)\n", iface, debugstr_guid(riid), obj); if (!riid || !obj) return E_INVALIDARG; if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IAgileObject) || IsEqualGUID(riid, &IID_IAgileReference)) { IUnknown_AddRef(iface); *obj = iface; return S_OK; } *obj = NULL; FIXME("interface %s is not implemented\n", debugstr_guid(riid)); return E_NOINTERFACE; } static ULONG WINAPI agile_ref_AddRef(IAgileReference *iface) { struct agile_reference *impl = impl_from_IAgileReference(iface); return InterlockedIncrement(&impl->ref); } static ULONG WINAPI agile_ref_Release(IAgileReference *iface) { struct agile_reference *impl = impl_from_IAgileReference(iface); LONG ref = InterlockedDecrement(&impl->ref); if (!ref) { TRACE("destroying %p\n", iface); if (impl->obj) IUnknown_Release(impl->obj); if (impl->marshal_stream) { LARGE_INTEGER zero = {0}; IStream_Seek(impl->marshal_stream, zero, STREAM_SEEK_SET, NULL); CoReleaseMarshalData(impl->marshal_stream); IStream_Release(impl->marshal_stream); } DeleteCriticalSection(&impl->cs); free(impl); } return ref; } static HRESULT WINAPI agile_ref_Resolve(IAgileReference *iface, REFIID riid, void **obj) { struct agile_reference *impl = impl_from_IAgileReference(iface); LARGE_INTEGER zero = {0}; HRESULT hr; TRACE("(%p, %s, %p)\n", iface, debugstr_guid(riid), obj); EnterCriticalSection(&impl->cs); if (impl->option == AGILEREFERENCE_DELAYEDMARSHAL && impl->marshal_stream == NULL) { if (FAILED(hr = marshal_object_in_agile_reference(impl, riid, impl->obj))) { LeaveCriticalSection(&impl->cs); return hr; } IUnknown_Release(impl->obj); impl->obj = NULL; } if (SUCCEEDED(hr = IStream_Seek(impl->marshal_stream, zero, STREAM_SEEK_SET, NULL))) hr = CoUnmarshalInterface(impl->marshal_stream, riid, obj); LeaveCriticalSection(&impl->cs); return hr; } static const IAgileReferenceVtbl agile_ref_vtbl = { agile_ref_QueryInterface, agile_ref_AddRef, agile_ref_Release, agile_ref_Resolve, }; /*********************************************************************** * RoGetAgileReference (combase.@) */ HRESULT WINAPI RoGetAgileReference(enum AgileReferenceOptions option, REFIID riid, IUnknown *obj, IAgileReference **agile_reference) { struct agile_reference *impl; IUnknown *unknown; HRESULT hr; TRACE("(%d, %s, %p, %p).\n", option, debugstr_guid(riid), obj, agile_reference); if (option != AGILEREFERENCE_DEFAULT && option != AGILEREFERENCE_DELAYEDMARSHAL) return E_INVALIDARG; if (!InternalIsProcessInitialized()) { ERR("Apartment not initialized\n"); return CO_E_NOTINITIALIZED; } hr = IUnknown_QueryInterface(obj, riid, (void **)&unknown); if (FAILED(hr)) return E_NOINTERFACE; IUnknown_Release(unknown); hr = IUnknown_QueryInterface(obj, &IID_INoMarshal, (void **)&unknown); if (SUCCEEDED(hr)) { IUnknown_Release(unknown); return CO_E_NOT_SUPPORTED; } impl = calloc(1, sizeof(*impl)); if (!impl) return E_OUTOFMEMORY; impl->IAgileReference_iface.lpVtbl = &agile_ref_vtbl; impl->option = option; impl->ref = 1; if (option == AGILEREFERENCE_DEFAULT) { if (FAILED(hr = marshal_object_in_agile_reference(impl, riid, obj))) { free(impl); return hr; } } else if (option == AGILEREFERENCE_DELAYEDMARSHAL) { impl->obj = obj; IUnknown_AddRef(impl->obj); } InitializeCriticalSection(&impl->cs); *agile_reference = &impl->IAgileReference_iface; return S_OK; } /*********************************************************************** * RoGetApartmentIdentifier (combase.@) */ HRESULT WINAPI RoGetApartmentIdentifier(UINT64 *identifier) { FIXME("(%p): stub\n", identifier); if (!identifier) return E_INVALIDARG; *identifier = 0xdeadbeef; return S_OK; } /*********************************************************************** * RoRegisterForApartmentShutdown (combase.@) */ HRESULT WINAPI RoRegisterForApartmentShutdown(IApartmentShutdown *callback, UINT64 *identifier, APARTMENT_SHUTDOWN_REGISTRATION_COOKIE *cookie) { HRESULT hr; FIXME("(%p, %p, %p): stub\n", callback, identifier, cookie); hr = RoGetApartmentIdentifier(identifier); if (FAILED(hr)) return hr; if (cookie) *cookie = (void *)0xcafecafe; return S_OK; } /*********************************************************************** * RoGetServerActivatableClasses (combase.@) */ HRESULT WINAPI RoGetServerActivatableClasses(HSTRING name, HSTRING **classes, DWORD *count) { FIXME("(%p, %p, %p): stub\n", name, classes, count); if (count) *count = 0; return S_OK; } /*********************************************************************** * RoRegisterActivationFactories (combase.@) */ HRESULT WINAPI RoRegisterActivationFactories(HSTRING *classes, PFNGETACTIVATIONFACTORY *callbacks, UINT32 count, RO_REGISTRATION_COOKIE *cookie) { FIXME("(%p, %p, %d, %p): stub\n", classes, callbacks, count, cookie); return S_OK; } /*********************************************************************** * GetRestrictedErrorInfo (combase.@) */ HRESULT WINAPI GetRestrictedErrorInfo(IRestrictedErrorInfo **info) { FIXME( "(%p)\n", info ); return E_NOTIMPL; } /*********************************************************************** * SetRestrictedErrorInfo (combase.@) */ HRESULT WINAPI SetRestrictedErrorInfo(IRestrictedErrorInfo *info) { FIXME( "(%p)\n", info ); return E_NOTIMPL; } /*********************************************************************** * RoOriginateLanguageException (combase.@) */ BOOL WINAPI RoOriginateLanguageException(HRESULT error, HSTRING message, IUnknown *language_exception) { FIXME("%#lx, %s, %p: stub\n", error, debugstr_hstring(message), language_exception); return FALSE; } /*********************************************************************** * RoOriginateError (combase.@) */ BOOL WINAPI RoOriginateError(HRESULT error, HSTRING message) { FIXME("%#lx, %s: stub\n", error, debugstr_hstring(message)); return FALSE; } /*********************************************************************** * RoOriginateErrorW (combase.@) */ BOOL WINAPI RoOriginateErrorW(HRESULT error, UINT max_len, const WCHAR *message) { FIXME("%#lx, %u, %p: stub\n", error, max_len, message); return FALSE; } /*********************************************************************** * RoSetErrorReportingFlags (combase.@) */ HRESULT WINAPI RoSetErrorReportingFlags(UINT32 flags) { FIXME("(%08x): stub\n", flags); return S_OK; } /*********************************************************************** * CleanupTlsOleState (combase.@) */ void WINAPI CleanupTlsOleState(void *unknown) { FIXME("(%p): stub\n", unknown); } /*********************************************************************** * DllGetActivationFactory (combase.@) */ HRESULT WINAPI DllGetActivationFactory(HSTRING classid, IActivationFactory **factory) { FIXME("(%s, %p): stub\n", debugstr_hstring(classid), factory); return REGDB_E_CLASSNOTREG; }