mirror of
https://gitlab.winehq.org/wine/wine.git
synced 2025-08-29 02:33:58 +02:00
532 lines
14 KiB
C
532 lines
14 KiB
C
/*
|
|
* Copyright 2025 Piotr Caban
|
|
* Copyright 2025 Vibhav Pant
|
|
*
|
|
* 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 <stdbool.h>
|
|
|
|
#include "initguid.h"
|
|
#include "roapi.h"
|
|
#include "weakreference.h"
|
|
#include "winstring.h"
|
|
#define WIDL_using_Windows_Foundation
|
|
#include "windows.foundation.h"
|
|
#include "wine/asm.h"
|
|
#include "wine/debug.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(vccorlib);
|
|
|
|
HRESULT __cdecl InitializeData(int type)
|
|
{
|
|
HRESULT hres;
|
|
|
|
FIXME("(%d) semi-stub\n", type);
|
|
|
|
if (!type) return S_OK;
|
|
|
|
hres = RoInitialize(type == 1 ? RO_INIT_SINGLETHREADED : RO_INIT_MULTITHREADED);
|
|
if (FAILED(hres)) return hres;
|
|
return S_OK;
|
|
}
|
|
|
|
void __cdecl UninitializeData(int type)
|
|
{
|
|
TRACE("(%d)\n", type);
|
|
|
|
if (type) RoUninitialize();
|
|
}
|
|
|
|
HRESULT WINAPI GetActivationFactoryByPCWSTR(const WCHAR *name, const GUID *iid, void **out)
|
|
{
|
|
HSTRING_HEADER hdr;
|
|
HSTRING str;
|
|
HRESULT hr;
|
|
|
|
TRACE("(%s, %s, %p)\n", debugstr_w(name), debugstr_guid(iid), out);
|
|
|
|
/* Use a fast-pass string to avoid an allocation. */
|
|
hr = WindowsCreateStringReference(name, wcslen(name), &hdr, &str);
|
|
if (FAILED(hr)) return hr;
|
|
|
|
return RoGetActivationFactory(str, iid, out);
|
|
}
|
|
|
|
HRESULT WINAPI GetIidsFn(unsigned int count, unsigned int *copied, const GUID *src, GUID **dest)
|
|
{
|
|
TRACE("(%u, %p, %p, %p)\n", count, copied, src, dest);
|
|
|
|
if (!(*dest = CoTaskMemAlloc(count * sizeof(*src))))
|
|
{
|
|
*copied = 0;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
*copied = count;
|
|
memcpy(*dest, src, count * sizeof(*src));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void *__cdecl Allocate(size_t size)
|
|
{
|
|
void *addr;
|
|
|
|
TRACE("(%Iu)\n", size);
|
|
|
|
addr = malloc(size);
|
|
/* TODO: Throw a COMException on allocation failure. */
|
|
if (!addr)
|
|
FIXME("allocation failure\n");
|
|
return addr;
|
|
}
|
|
|
|
void __cdecl Free(void *addr)
|
|
{
|
|
TRACE("(%p)\n", addr);
|
|
|
|
free(addr);
|
|
}
|
|
|
|
struct control_block
|
|
{
|
|
IWeakReference IWeakReference_iface;
|
|
LONG ref_weak;
|
|
LONG ref_strong;
|
|
IUnknown *object;
|
|
bool is_inline;
|
|
UINT16 unknown;
|
|
#ifdef _WIN32
|
|
char _padding[4];
|
|
#endif
|
|
};
|
|
|
|
static inline struct control_block *impl_from_IWeakReference(IWeakReference *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct control_block, IWeakReference_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI control_block_QueryInterface(IWeakReference *iface, const GUID *iid, void **out)
|
|
{
|
|
struct control_block *impl = impl_from_IWeakReference(iface);
|
|
|
|
TRACE("(%p, %s, %p)", iface, debugstr_guid(iid), out);
|
|
|
|
if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IWeakReference))
|
|
{
|
|
IWeakReference_AddRef((*out = &impl->IWeakReference_iface));
|
|
return S_OK;
|
|
}
|
|
|
|
*out = NULL;
|
|
ERR("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI control_block_AddRef(IWeakReference *iface)
|
|
{
|
|
struct control_block *impl = impl_from_IWeakReference(iface);
|
|
|
|
TRACE("(%p)\n", iface);
|
|
|
|
return InterlockedIncrement(&impl->ref_weak);
|
|
}
|
|
|
|
static ULONG WINAPI control_block_Release(IWeakReference *iface)
|
|
{
|
|
struct control_block *impl = impl_from_IWeakReference(iface);
|
|
ULONG ref = InterlockedDecrement(&impl->ref_weak);
|
|
|
|
TRACE("(%p)\n", iface);
|
|
|
|
if (!ref) Free(impl);
|
|
return ref;
|
|
}
|
|
|
|
static HRESULT WINAPI control_block_Resolve(IWeakReference *iface, const GUID *iid, IInspectable **out)
|
|
{
|
|
struct control_block *impl = impl_from_IWeakReference(iface);
|
|
HRESULT hr;
|
|
LONG ref;
|
|
|
|
TRACE("(%p, %s, %p)\n", iface, debugstr_guid(iid), out);
|
|
|
|
do
|
|
{
|
|
ref = ReadNoFence(&impl->ref_strong);
|
|
if (ref <= 0)
|
|
return S_OK;
|
|
} while (ref != InterlockedCompareExchange(&impl->ref_strong, ref + 1, ref));
|
|
|
|
hr = IUnknown_QueryInterface(impl->object, iid, (void **)out);
|
|
IUnknown_Release(impl->object);
|
|
return hr;
|
|
}
|
|
|
|
static const IWeakReferenceVtbl control_block_vtbl =
|
|
{
|
|
control_block_QueryInterface,
|
|
control_block_AddRef,
|
|
control_block_Release,
|
|
control_block_Resolve,
|
|
};
|
|
|
|
void *__cdecl AllocateWithWeakRef(ptrdiff_t offset, size_t size)
|
|
{
|
|
const size_t inline_max = sizeof(void *) == 8 ? 128 : 64;
|
|
struct control_block *weakref;
|
|
void *object;
|
|
|
|
TRACE("(%Iu, %Iu)\n", offset, size);
|
|
|
|
if (size > inline_max)
|
|
{
|
|
weakref = Allocate(sizeof(*weakref));
|
|
object = Allocate(size);
|
|
weakref->is_inline = FALSE;
|
|
}
|
|
else /* Perform an inline allocation */
|
|
{
|
|
weakref = Allocate(sizeof(*weakref) + size);
|
|
object = (char *)weakref + sizeof(*weakref);
|
|
weakref->is_inline = TRUE;
|
|
}
|
|
|
|
*(struct control_block **)((char *)object + offset) = weakref;
|
|
weakref->IWeakReference_iface.lpVtbl = &control_block_vtbl;
|
|
weakref->object = object;
|
|
weakref->ref_strong = weakref->ref_weak = 1;
|
|
weakref->unknown = 0;
|
|
|
|
return weakref->object;
|
|
}
|
|
|
|
DEFINE_THISCALL_WRAPPER(control_block_ReleaseTarget, 4)
|
|
void __thiscall control_block_ReleaseTarget(struct control_block *weakref)
|
|
{
|
|
void *object;
|
|
|
|
TRACE("(%p)\n", weakref);
|
|
|
|
if (weakref->is_inline || ReadNoFence(&weakref->ref_strong) >= 0) return;
|
|
if ((object = InterlockedCompareExchangePointer((void *)&weakref->object, NULL, weakref->object)))
|
|
Free(object);
|
|
}
|
|
|
|
struct __abi_type_descriptor
|
|
{
|
|
const WCHAR *name;
|
|
int type_id;
|
|
};
|
|
|
|
struct platform_type
|
|
{
|
|
IClosable IClosable_iface;
|
|
IUnknown *marshal;
|
|
const struct __abi_type_descriptor *desc;
|
|
LONG ref;
|
|
};
|
|
|
|
static inline struct platform_type *impl_from_IClosable(IClosable *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, struct platform_type, IClosable_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI platform_type_QueryInterface(IClosable *iface, const GUID *iid, void **out)
|
|
{
|
|
struct platform_type *impl = impl_from_IClosable(iface);
|
|
|
|
TRACE("(%p, %s, %p)\n", iface, debugstr_guid(iid), out);
|
|
|
|
if (IsEqualGUID(iid, &IID_IUnknown) ||
|
|
IsEqualGUID(iid, &IID_IInspectable) ||
|
|
IsEqualGUID(iid, &IID_IClosable) ||
|
|
IsEqualGUID(iid, &IID_IAgileObject))
|
|
{
|
|
IClosable_AddRef((*out = &impl->IClosable_iface));
|
|
return S_OK;
|
|
}
|
|
if (IsEqualGUID(iid, &IID_IMarshal))
|
|
return IUnknown_QueryInterface(impl->marshal, iid, out);
|
|
|
|
ERR("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
|
|
*out = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI platform_type_AddRef(IClosable *iface)
|
|
{
|
|
struct platform_type *impl = impl_from_IClosable(iface);
|
|
TRACE("(%p)\n", iface);
|
|
return InterlockedIncrement(&impl->ref);
|
|
}
|
|
|
|
static ULONG WINAPI platform_type_Release(IClosable *iface)
|
|
{
|
|
struct platform_type *impl = impl_from_IClosable(iface);
|
|
ULONG ref = InterlockedDecrement(&impl->ref);
|
|
|
|
TRACE("(%p)\n", iface);
|
|
|
|
if (!ref)
|
|
{
|
|
IUnknown_Release(impl->marshal);
|
|
Free(impl);
|
|
}
|
|
return ref;
|
|
}
|
|
|
|
static HRESULT WINAPI platform_type_GetIids(IClosable *iface, ULONG *count, GUID **iids)
|
|
{
|
|
FIXME("(%p, %p, %p) stub\n", iface, count, iids);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI platform_type_GetRuntimeClassName(IClosable *iface, HSTRING *name)
|
|
{
|
|
static const WCHAR *str = L"Platform.Type";
|
|
|
|
TRACE("(%p, %p)\n", iface, name);
|
|
return WindowsCreateString(str, wcslen(str), name);
|
|
}
|
|
|
|
static HRESULT WINAPI platform_type_GetTrustLevel(IClosable *iface, TrustLevel *level)
|
|
{
|
|
FIXME("(%p, %p) stub\n", iface, level);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI platform_type_Close(IClosable *iface)
|
|
{
|
|
FIXME("(%p) stub\n", iface);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static const IClosableVtbl platform_type_closable_vtbl =
|
|
{
|
|
/* IUnknown */
|
|
platform_type_QueryInterface,
|
|
platform_type_AddRef,
|
|
platform_type_Release,
|
|
/* IInspectable */
|
|
platform_type_GetIids,
|
|
platform_type_GetRuntimeClassName,
|
|
platform_type_GetTrustLevel,
|
|
/* ICloseable */
|
|
platform_type_Close
|
|
};
|
|
|
|
static const char *debugstr_abi_type_descriptor(const struct __abi_type_descriptor *desc)
|
|
{
|
|
if (!desc) return "(null)";
|
|
|
|
return wine_dbg_sprintf("{%s, %d}", debugstr_w(desc->name), desc->type_id);
|
|
}
|
|
|
|
void *WINAPI __abi_make_type_id(const struct __abi_type_descriptor *desc)
|
|
{
|
|
/* TODO:
|
|
* Emit RTTI for Platform::Type.
|
|
* Implement IEquatable and IPrintable.
|
|
* Throw a COMException if CoCreateFreeThreadedMarshaler fails. */
|
|
struct platform_type *obj;
|
|
HRESULT hr;
|
|
|
|
TRACE("(%s)\n", debugstr_abi_type_descriptor(desc));
|
|
|
|
obj = Allocate(sizeof(*obj));
|
|
obj->IClosable_iface.lpVtbl = &platform_type_closable_vtbl;
|
|
obj->desc = desc;
|
|
obj->ref = 1;
|
|
hr = CoCreateFreeThreadedMarshaler((IUnknown *)&obj->IClosable_iface, &obj->marshal);
|
|
if (FAILED(hr))
|
|
{
|
|
FIXME("CoCreateFreeThreadedMarshaler failed: %#lx\n", hr);
|
|
Free(obj);
|
|
return NULL;
|
|
}
|
|
return &obj->IClosable_iface;
|
|
}
|
|
|
|
bool __cdecl platform_type_Equals_Object(struct platform_type *this, struct platform_type *object)
|
|
{
|
|
TRACE("(%p, %p)\n", this, object);
|
|
|
|
return this == object || (this && object && this->desc == object->desc);
|
|
}
|
|
|
|
int __cdecl platform_type_GetTypeCode(struct platform_type *this)
|
|
{
|
|
TRACE("(%p)\n", this);
|
|
|
|
return this->desc->type_id;
|
|
}
|
|
|
|
HSTRING __cdecl platform_type_ToString(struct platform_type *this)
|
|
{
|
|
HSTRING str = NULL;
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p)\n", this);
|
|
|
|
/* TODO: Throw a COMException if this fails */
|
|
hr = WindowsCreateString(this->desc->name, this->desc->name ? wcslen(this->desc->name) : 0, &str);
|
|
if (FAILED(hr))
|
|
FIXME("WindowsCreateString failed: %#lx\n", hr);
|
|
return str;
|
|
}
|
|
|
|
HSTRING __cdecl platform_type_get_FullName(struct platform_type *type)
|
|
{
|
|
TRACE("(%p)\n", type);
|
|
|
|
return platform_type_ToString(type);
|
|
}
|
|
|
|
enum typecode
|
|
{
|
|
TYPECODE_BOOLEAN = 3,
|
|
TYPECODE_CHAR16 = 4,
|
|
TYPECODE_UINT8 = 6,
|
|
TYPECODE_INT16 = 7,
|
|
TYPECODE_UINT16 = 8,
|
|
TYPECODE_INT32 = 9,
|
|
TYPECODE_UINT32 = 10,
|
|
TYPECODE_INT64 = 11,
|
|
TYPECODE_UINT64 = 12,
|
|
TYPECODE_SINGLE = 13,
|
|
TYPECODE_DOUBLE = 14,
|
|
TYPECODE_DATETIME = 16,
|
|
TYPECODE_STRING = 18,
|
|
TYPECODE_TIMESPAN = 19,
|
|
TYPECODE_POINT = 20,
|
|
TYPECODE_SIZE = 21,
|
|
TYPECODE_RECT = 22,
|
|
TYPECODE_GUID = 23,
|
|
};
|
|
|
|
static const char *debugstr_typecode(int typecode)
|
|
{
|
|
static const char *str[] = {
|
|
[TYPECODE_BOOLEAN] = "Boolean",
|
|
[TYPECODE_CHAR16] = "char16",
|
|
[TYPECODE_UINT8] = "uint8",
|
|
[TYPECODE_INT16] = "int16",
|
|
[TYPECODE_UINT16] = "uint16",
|
|
[TYPECODE_INT32] = "int32",
|
|
[TYPECODE_UINT32] = "uint32",
|
|
[TYPECODE_INT64] = "int64",
|
|
[TYPECODE_UINT64] = "uint64",
|
|
[TYPECODE_SINGLE] = "float32",
|
|
[TYPECODE_DOUBLE] = "double",
|
|
[TYPECODE_DATETIME] = "DateTime",
|
|
[TYPECODE_STRING] = "String",
|
|
[TYPECODE_POINT] = "Point",
|
|
[TYPECODE_SIZE] = "Size",
|
|
[TYPECODE_RECT] = "Rect",
|
|
[TYPECODE_GUID] = "Guid",
|
|
};
|
|
if (typecode > ARRAY_SIZE(str) || !str[typecode]) return wine_dbg_sprintf("%d", typecode);
|
|
return wine_dbg_sprintf("%s", str[typecode]);
|
|
}
|
|
|
|
void *WINAPI CreateValue(int typecode, const void *val)
|
|
{
|
|
IPropertyValueStatics *statics;
|
|
IInspectable *obj;
|
|
HRESULT hr;
|
|
|
|
TRACE("(%s, %p)\n", debugstr_typecode(typecode), val);
|
|
|
|
hr = GetActivationFactoryByPCWSTR(RuntimeClass_Windows_Foundation_PropertyValue, &IID_IPropertyValueStatics,
|
|
(void **)&statics);
|
|
if (FAILED(hr))
|
|
{
|
|
FIXME("GetActivationFactoryByPCWSTR failed: %#lx\n", hr);
|
|
return NULL;
|
|
}
|
|
switch (typecode)
|
|
{
|
|
case TYPECODE_BOOLEAN:
|
|
hr = IPropertyValueStatics_CreateBoolean(statics, *(boolean *)val, &obj);
|
|
break;
|
|
case TYPECODE_CHAR16:
|
|
hr = IPropertyValueStatics_CreateChar16(statics, *(WCHAR *)val, &obj);
|
|
break;
|
|
case TYPECODE_UINT8:
|
|
hr = IPropertyValueStatics_CreateUInt8(statics, *(BYTE *)val, &obj);
|
|
break;
|
|
case TYPECODE_UINT16:
|
|
hr = IPropertyValueStatics_CreateUInt16(statics, *(UINT16 *)val, &obj);
|
|
break;
|
|
case TYPECODE_INT16:
|
|
hr = IPropertyValueStatics_CreateInt16(statics, *(INT16 *)val, &obj);
|
|
break;
|
|
case TYPECODE_INT32:
|
|
hr = IPropertyValueStatics_CreateInt32(statics, *(INT32 *)val, &obj);
|
|
break;
|
|
case TYPECODE_UINT32:
|
|
hr = IPropertyValueStatics_CreateUInt32(statics, *(UINT32 *)val, &obj);
|
|
break;
|
|
case TYPECODE_INT64:
|
|
hr = IPropertyValueStatics_CreateInt64(statics, *(INT64 *)val, &obj);
|
|
break;
|
|
case TYPECODE_UINT64:
|
|
hr = IPropertyValueStatics_CreateUInt64(statics, *(UINT64 *)val, &obj);
|
|
break;
|
|
case TYPECODE_SINGLE:
|
|
hr = IPropertyValueStatics_CreateSingle(statics, *(FLOAT *)val, &obj);
|
|
break;
|
|
case TYPECODE_DOUBLE:
|
|
hr = IPropertyValueStatics_CreateDouble(statics, *(DOUBLE *)val, &obj);
|
|
break;
|
|
case TYPECODE_DATETIME:
|
|
hr = IPropertyValueStatics_CreateDateTime(statics, *(DateTime *)val, &obj);
|
|
break;
|
|
case TYPECODE_STRING:
|
|
hr = IPropertyValueStatics_CreateString(statics, *(HSTRING *)val, &obj);
|
|
break;
|
|
case TYPECODE_TIMESPAN:
|
|
hr = IPropertyValueStatics_CreateTimeSpan(statics, *(TimeSpan *)val, &obj);
|
|
break;
|
|
case TYPECODE_POINT:
|
|
hr = IPropertyValueStatics_CreatePoint(statics, *(Point *)val, &obj);
|
|
break;
|
|
case TYPECODE_SIZE:
|
|
hr = IPropertyValueStatics_CreateSize(statics, *(Size *)val, &obj);
|
|
break;
|
|
case TYPECODE_RECT:
|
|
hr = IPropertyValueStatics_CreateRect(statics, *(Rect *)val, &obj);
|
|
break;
|
|
case TYPECODE_GUID:
|
|
hr = IPropertyValueStatics_CreateGuid(statics, *(GUID *)val, &obj);
|
|
break;
|
|
default:
|
|
obj = NULL;
|
|
hr = S_OK;
|
|
break;
|
|
}
|
|
|
|
IPropertyValueStatics_Release(statics);
|
|
if (FAILED(hr))
|
|
{
|
|
FIXME("Failed to create IPropertyValue object: %#lx\n", hr);
|
|
return NULL;
|
|
}
|
|
return obj;
|
|
}
|