mirror of
https://gitlab.winehq.org/wine/wine.git
synced 2025-08-28 18:23:54 +02:00
582 lines
16 KiB
C
582 lines
16 KiB
C
/*
|
|
* 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 "errhandlingapi.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 | COINIT_DISABLE_OLE1DDE);
|
|
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);
|
|
}
|
|
else
|
|
{
|
|
ERR("Class %s not found in %s, hr %#lx.\n", wine_dbgstr_hstring(classid), debugstr_w(library), hr);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* RoFailFastWithErrorContextInternal2 (combase.@)
|
|
*/
|
|
void WINAPI RoFailFastWithErrorContextInternal2(HRESULT error, ULONG exception_count, /* PSTOWED_EXCEPTION_INFORMATION_V2 */void *information)
|
|
{
|
|
FIXME("%#lx, %lu, %p stub.\n", error, exception_count, information);
|
|
RaiseFailFastException(NULL, NULL, 0);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* 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;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* RoReportUnhandledError (combase.@)
|
|
*/
|
|
HRESULT WINAPI RoReportUnhandledError(IRestrictedErrorInfo *info)
|
|
{
|
|
FIXME("(%p): stub\n", info);
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* RoSetErrorReportingFlags (combase.@)
|
|
*/
|
|
HRESULT WINAPI RoSetErrorReportingFlags(UINT32 flags)
|
|
{
|
|
FIXME("(%08x): stub\n", flags);
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* RoGetErrorReportingFlags (combase.@)
|
|
*/
|
|
HRESULT WINAPI RoGetErrorReportingFlags(UINT32 *flags)
|
|
{
|
|
FIXME("(%p): stub\n", flags);
|
|
|
|
if (!flags)
|
|
return E_POINTER;
|
|
|
|
*flags = RO_ERROR_REPORTING_USESETERRORINFO;
|
|
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;
|
|
}
|